| 
									
										
										
										
											2015-02-15 16:48:15 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2015-07-25 08:51:40 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2015 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2015-02-15 16:48:15 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-19 15:52:01 +08:00
										 |  |  | package main | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2015-10-08 11:36:36 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 10:56:41 +08:00
										 |  |  | 	router "github.com/gorilla/mux" | 
					
						
							| 
									
										
										
										
											2015-09-01 05:40:12 +08:00
										 |  |  | 	"github.com/rs/cors" | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 09:53:40 +08:00
										 |  |  | // MiddlewareHandler - useful to chain different middleware http.Handler
 | 
					
						
							| 
									
										
										
										
											2015-09-16 07:59:43 +08:00
										 |  |  | type MiddlewareHandler func(http.Handler) http.Handler | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 10:56:41 +08:00
										 |  |  | func registerCustomMiddleware(mux *router.Router, mwHandlers ...MiddlewareHandler) http.Handler { | 
					
						
							|  |  |  | 	var f http.Handler | 
					
						
							|  |  |  | 	f = mux | 
					
						
							|  |  |  | 	for _, mw := range mwHandlers { | 
					
						
							|  |  |  | 		f = mw(f) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return f | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 10:56:41 +08:00
										 |  |  | type timeHandler struct { | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	handler http.Handler | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | type resourceHandler struct { | 
					
						
							| 
									
										
										
										
											2015-02-19 04:15:33 +08:00
										 |  |  | 	handler http.Handler | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-01 05:42:29 +08:00
										 |  |  | func parseDate(req *http.Request) (time.Time, error) { | 
					
						
							| 
									
										
										
										
											2015-07-11 08:21:53 +08:00
										 |  |  | 	amzDate := req.Header.Get(http.CanonicalHeaderKey("x-amz-date")) | 
					
						
							| 
									
										
										
										
											2015-05-09 07:01:49 +08:00
										 |  |  | 	switch { | 
					
						
							|  |  |  | 	case amzDate != "": | 
					
						
							|  |  |  | 		if _, err := time.Parse(time.RFC1123, amzDate); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(time.RFC1123, amzDate) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := time.Parse(time.RFC1123Z, amzDate); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(time.RFC1123Z, amzDate) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-07-09 07:54:32 +08:00
										 |  |  | 		if _, err := time.Parse(iso8601Format, amzDate); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(iso8601Format, amzDate) | 
					
						
							| 
									
										
										
										
											2015-05-01 07:29:03 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-09 10:56:41 +08:00
										 |  |  | 	minioDate := req.Header.Get(http.CanonicalHeaderKey("x-minio-date")) | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case minioDate != "": | 
					
						
							|  |  |  | 		if _, err := time.Parse(time.RFC1123, minioDate); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(time.RFC1123, minioDate) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := time.Parse(time.RFC1123Z, minioDate); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(time.RFC1123Z, minioDate) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := time.Parse(iso8601Format, minioDate); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(iso8601Format, minioDate) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-09 07:01:49 +08:00
										 |  |  | 	date := req.Header.Get("Date") | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case date != "": | 
					
						
							|  |  |  | 		if _, err := time.Parse(time.RFC1123, date); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(time.RFC1123, date) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := time.Parse(time.RFC1123Z, date); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(time.RFC1123Z, date) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-07-09 07:54:32 +08:00
										 |  |  | 		if _, err := time.Parse(iso8601Format, amzDate); err == nil { | 
					
						
							|  |  |  | 			return time.Parse(iso8601Format, amzDate) | 
					
						
							| 
									
										
										
										
											2015-05-01 07:29:03 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return time.Time{}, errors.New("invalid request") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-15 05:29:56 +08:00
										 |  |  | // TimeValidityHandler to validate parsable time over http header
 | 
					
						
							| 
									
										
										
										
											2015-07-01 11:15:48 +08:00
										 |  |  | func TimeValidityHandler(h http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2015-05-14 03:19:41 +08:00
										 |  |  | 	return timeHandler{h} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	// Verify if date headers are set, if not reject the request
 | 
					
						
							| 
									
										
										
										
											2015-04-30 09:30:17 +08:00
										 |  |  | 	if r.Header.Get("Authorization") != "" { | 
					
						
							| 
									
										
										
										
											2015-10-09 10:56:41 +08:00
										 |  |  | 		if r.Header.Get(http.CanonicalHeaderKey("x-amz-date")) == "" && r.Header.Get(http.CanonicalHeaderKey("x-minio-date")) == "" && r.Header.Get("Date") == "" { | 
					
						
							| 
									
										
										
										
											2015-04-30 09:30:17 +08:00
										 |  |  | 			// there is no way to knowing if this is a valid request, could be a attack reject such clients
 | 
					
						
							| 
									
										
										
										
											2015-10-04 15:27:49 +08:00
										 |  |  | 			writeErrorResponse(w, r, RequestTimeTooSkewed, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2015-04-30 09:30:17 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-07-01 05:42:29 +08:00
										 |  |  | 		date, err := parseDate(r) | 
					
						
							| 
									
										
										
										
											2015-04-30 09:30:17 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			// there is no way to knowing if this is a valid request, could be a attack reject such clients
 | 
					
						
							| 
									
										
										
										
											2015-10-04 15:27:49 +08:00
										 |  |  | 			writeErrorResponse(w, r, RequestTimeTooSkewed, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2015-04-30 09:30:17 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		duration := time.Since(date) | 
					
						
							|  |  |  | 		minutes := time.Duration(5) * time.Minute | 
					
						
							|  |  |  | 		if duration.Minutes() > minutes.Minutes() { | 
					
						
							| 
									
										
										
										
											2015-10-04 15:27:49 +08:00
										 |  |  | 			writeErrorResponse(w, r, RequestTimeTooSkewed, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2015-04-30 09:30:17 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	h.handler.ServeHTTP(w, r) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 09:53:40 +08:00
										 |  |  | // CorsHandler handler for CORS (Cross Origin Resource Sharing)
 | 
					
						
							| 
									
										
										
										
											2015-09-01 05:40:12 +08:00
										 |  |  | func CorsHandler(h http.Handler) http.Handler { | 
					
						
							|  |  |  | 	return cors.Default().Handler(h) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-01 11:15:48 +08:00
										 |  |  | // IgnoreResourcesHandler -
 | 
					
						
							| 
									
										
										
										
											2015-02-24 08:46:48 +08:00
										 |  |  | // Ignore resources handler is wrapper handler used for API request resource validation
 | 
					
						
							|  |  |  | // Since we do not support all the S3 queries, it is necessary for us to throw back a
 | 
					
						
							| 
									
										
										
										
											2015-06-04 09:27:13 +08:00
										 |  |  | // valid error message indicating such a feature is not implemented.
 | 
					
						
							| 
									
										
										
										
											2015-07-01 11:15:48 +08:00
										 |  |  | func IgnoreResourcesHandler(h http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	return resourceHandler{h} | 
					
						
							| 
									
										
										
										
											2015-02-19 04:15:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-18 03:01:19 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	separator = "/" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-03 18:36:12 +08:00
										 |  |  | // Resource handler ServeHTTP() wrapper
 | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2015-10-18 03:01:19 +08:00
										 |  |  | 	splits := strings.SplitN(r.URL.Path, separator, 3) | 
					
						
							| 
									
										
										
										
											2015-10-08 11:36:36 +08:00
										 |  |  | 	switch len(splits) { | 
					
						
							|  |  |  | 	// bucket exists
 | 
					
						
							|  |  |  | 	case 2: | 
					
						
							|  |  |  | 		if ignoreNotImplementedBucketResources(r) { | 
					
						
							|  |  |  | 			writeErrorResponse(w, r, NotImplemented, r.URL.Path) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	// object exists
 | 
					
						
							|  |  |  | 	case 3: | 
					
						
							|  |  |  | 		if ignoreNotImplementedObjectResources(r) { | 
					
						
							|  |  |  | 			writeErrorResponse(w, r, NotImplemented, r.URL.Path) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-19 04:15:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	h.handler.ServeHTTP(w, r) | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //// helpers
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | // Checks requests for not implemented Bucket resources
 | 
					
						
							|  |  |  | func ignoreNotImplementedBucketResources(req *http.Request) bool { | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	q := req.URL.Query() | 
					
						
							|  |  |  | 	for name := range q { | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 		if notimplementedBucketResourceNames[name] { | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | // Checks requests for not implemented Object resources
 | 
					
						
							|  |  |  | func ignoreNotImplementedObjectResources(req *http.Request) bool { | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 	q := req.URL.Query() | 
					
						
							|  |  |  | 	for name := range q { | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 		if notimplementedObjectResourceNames[name] { | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } |