| 
									
										
										
										
											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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 07:23:42 +08:00
										 |  |  | package cmd | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2016-02-20 13:45:37 +08:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2016-02-26 21:19:35 +08:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											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
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 06:57:20 +08:00
										 |  |  | // HandlerFunc - useful to chain different middleware http.Handler
 | 
					
						
							|  |  |  | type HandlerFunc func(http.Handler) http.Handler | 
					
						
							| 
									
										
										
										
											2015-09-16 07:59:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 06:57:20 +08:00
										 |  |  | func registerHandlers(mux *router.Router, handlerFns ...HandlerFunc) http.Handler { | 
					
						
							| 
									
										
										
										
											2015-10-09 10:56:41 +08:00
										 |  |  | 	var f http.Handler | 
					
						
							|  |  |  | 	f = mux | 
					
						
							| 
									
										
										
										
											2016-02-05 06:57:20 +08:00
										 |  |  | 	for _, hFn := range handlerFns { | 
					
						
							|  |  |  | 		f = hFn(f) | 
					
						
							| 
									
										
										
										
											2015-10-09 10:56:41 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return f | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-29 03:02:22 +08:00
										 |  |  | // Adds limiting body size middleware
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Set the body size limit to 6 Gb = Maximum object size + other possible data
 | 
					
						
							|  |  |  | // in the same request
 | 
					
						
							|  |  |  | const requestMaxBodySize = 1024 * 1024 * 1024 * (5 + 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type requestSizeLimitHandler struct { | 
					
						
							|  |  |  | 	handler     http.Handler | 
					
						
							|  |  |  | 	maxBodySize int64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func setRequestSizeLimitHandler(h http.Handler) http.Handler { | 
					
						
							|  |  |  | 	return requestSizeLimitHandler{handler: h, maxBodySize: requestMaxBodySize} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h requestSizeLimitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	// Restricting read data to a given maximum length
 | 
					
						
							|  |  |  | 	r.Body = http.MaxBytesReader(w, r.Body, h.maxBodySize) | 
					
						
							|  |  |  | 	h.handler.ServeHTTP(w, r) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | // Adds redirect rules for incoming requests.
 | 
					
						
							|  |  |  | type redirectHandler struct { | 
					
						
							|  |  |  | 	handler        http.Handler | 
					
						
							|  |  |  | 	locationPrefix string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | // Reserved bucket.
 | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | 	reservedBucket = "/minio" | 
					
						
							| 
									
										
										
										
											2016-03-13 08:08:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | func setBrowserRedirectHandler(h http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | 	return redirectHandler{handler: h, locationPrefix: reservedBucket} | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	// Re-direction handled specifically for browsers.
 | 
					
						
							| 
									
										
										
										
											2016-08-17 15:16:59 +08:00
										 |  |  | 	if strings.Contains(r.Header.Get("User-Agent"), "Mozilla") && !isRequestSignatureV4(r) { | 
					
						
							| 
									
										
										
										
											2016-02-22 14:38:38 +08:00
										 |  |  | 		// '/' is redirected to 'locationPrefix/'
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 		// '/webrpc' is redirected to 'locationPrefix/webrpc'
 | 
					
						
							| 
									
										
										
										
											2016-02-22 14:38:38 +08:00
										 |  |  | 		// '/login' is redirected to 'locationPrefix/login'
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 		switch r.URL.Path { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 		case "/", "/webrpc", "/login", "/favicon.ico": | 
					
						
							| 
									
										
										
										
											2016-02-22 14:38:38 +08:00
										 |  |  | 			location := h.locationPrefix + r.URL.Path | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 			// Redirect to new location.
 | 
					
						
							|  |  |  | 			http.Redirect(w, r, location, http.StatusTemporaryRedirect) | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2015-05-01 07:29:03 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 	h.handler.ServeHTTP(w, r) | 
					
						
							| 
									
										
										
										
											2015-04-27 18:54:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 05:57:56 +08:00
										 |  |  | // Adds Cache-Control header
 | 
					
						
							|  |  |  | type cacheControlHandler struct { | 
					
						
							|  |  |  | 	handler http.Handler | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | func setBrowserCacheControlHandler(h http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2016-02-05 05:57:56 +08:00
										 |  |  | 	return cacheControlHandler{h} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h cacheControlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 	if r.Method == "GET" && strings.Contains(r.Header.Get("User-Agent"), "Mozilla") { | 
					
						
							| 
									
										
										
										
											2016-02-26 21:19:35 +08:00
										 |  |  | 		// For all browser requests set appropriate Cache-Control policies
 | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | 		match, e := regexp.MatchString(reservedBucket+`/([^/]+\.js|favicon.ico)`, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2016-02-26 21:19:35 +08:00
										 |  |  | 		if e != nil { | 
					
						
							| 
									
										
										
										
											2016-03-10 18:24:52 +08:00
										 |  |  | 			writeErrorResponse(w, r, ErrInternalError, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2016-02-26 21:19:35 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if match { | 
					
						
							|  |  |  | 			// For assets set cache expiry of one year. For each release, the name
 | 
					
						
							|  |  |  | 			// of the asset name will change and hence it can not be served from cache.
 | 
					
						
							|  |  |  | 			w.Header().Set("Cache-Control", "max-age=31536000") | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | 		} else if strings.HasPrefix(r.URL.Path, reservedBucket+"/") { | 
					
						
							| 
									
										
										
										
											2016-02-26 21:19:35 +08:00
										 |  |  | 			// For non asset requests we serve index.html which will never be cached.
 | 
					
						
							|  |  |  | 			w.Header().Set("Cache-Control", "no-store") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	h.handler.ServeHTTP(w, r) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Adds verification for incoming paths.
 | 
					
						
							|  |  |  | type minioPrivateBucketHandler struct { | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | 	handler        http.Handler | 
					
						
							|  |  |  | 	reservedBucket string | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func setPrivateBucketHandler(h http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | 	return minioPrivateBucketHandler{handler: h, reservedBucket: reservedBucket} | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h minioPrivateBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2016-03-28 03:37:21 +08:00
										 |  |  | 	// For all non browser requests, reject access to 'reservedBucket'.
 | 
					
						
							|  |  |  | 	if !strings.Contains(r.Header.Get("User-Agent"), "Mozilla") && path.Clean(r.URL.Path) == reservedBucket { | 
					
						
							| 
									
										
										
										
											2016-03-10 18:24:52 +08:00
										 |  |  | 		writeErrorResponse(w, r, ErrAllAccessDisabled, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2016-02-05 05:57:56 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	h.handler.ServeHTTP(w, r) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | // Supported Amz date formats.
 | 
					
						
							|  |  |  | var amzDateFormats = []string{ | 
					
						
							| 
									
										
										
										
											2016-03-08 01:52:20 +08:00
										 |  |  | 	time.RFC1123, | 
					
						
							|  |  |  | 	time.RFC1123Z, | 
					
						
							|  |  |  | 	iso8601Format, | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	// Add new AMZ date formats here.
 | 
					
						
							| 
									
										
										
										
											2016-03-08 01:52:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | // parseAmzDate - parses date string into supported amz date formats.
 | 
					
						
							|  |  |  | func parseAmzDate(amzDateStr string) (amzDate time.Time, apiErr APIErrorCode) { | 
					
						
							|  |  |  | 	for _, dateFormat := range amzDateFormats { | 
					
						
							|  |  |  | 		amzDate, e := time.Parse(dateFormat, amzDateStr) | 
					
						
							| 
									
										
										
										
											2016-03-08 01:52:20 +08:00
										 |  |  | 		if e == nil { | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 			return amzDate, ErrNone | 
					
						
							| 
									
										
										
										
											2016-03-08 01:52:20 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	return time.Time{}, ErrMalformedDate | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Supported Amz date headers.
 | 
					
						
							|  |  |  | var amzDateHeaders = []string{ | 
					
						
							| 
									
										
										
										
											2016-03-08 01:52:20 +08:00
										 |  |  | 	"x-amz-date", | 
					
						
							|  |  |  | 	"date", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | // parseAmzDateHeader - parses supported amz date headers, in
 | 
					
						
							|  |  |  | // supported amz date formats.
 | 
					
						
							|  |  |  | func parseAmzDateHeader(req *http.Request) (time.Time, APIErrorCode) { | 
					
						
							|  |  |  | 	for _, amzDateHeader := range amzDateHeaders { | 
					
						
							|  |  |  | 		amzDateStr := req.Header.Get(http.CanonicalHeaderKey(amzDateHeader)) | 
					
						
							|  |  |  | 		if amzDateStr != "" { | 
					
						
							|  |  |  | 			return parseAmzDate(amzDateStr) | 
					
						
							| 
									
										
										
										
											2016-03-08 01:52:20 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 	// Date header missing.
 | 
					
						
							|  |  |  | 	return time.Time{}, ErrMissingDateHeader | 
					
						
							| 
									
										
										
										
											2016-03-08 01:52:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | type timeHandler struct { | 
					
						
							|  |  |  | 	handler http.Handler | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 06:57:20 +08:00
										 |  |  | // setTimeValidityHandler to validate parsable time over http header
 | 
					
						
							|  |  |  | func setTimeValidityHandler(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
 | 
					
						
							| 
									
										
											  
											
												config/main: Re-write config files - add to new config v3
- New config format.
```
{
	"version": "3",
	"address": ":9000",
    "backend": {
          "type": "fs",
          "disk": "/path"
    },
	"credential": {
		"accessKey": "WLGDGYAQYIGI833EV05A",
		"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
	},
	"region": "us-east-1",
	"logger": {
		"file": {
			"enable": false,
			"fileName": "",
			"level": "error"
		},
		"syslog": {
			"enable": false,
			"address": "",
			"level": "debug"
		},
		"console": {
			"enable": true,
			"level": "fatal"
		}
	}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
											
										 
											2016-02-13 07:27:10 +08:00
										 |  |  | 	if _, ok := r.Header["Authorization"]; ok { | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 		amzDate, apiErr := parseAmzDateHeader(r) | 
					
						
							|  |  |  | 		if apiErr != ErrNone { | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | 			// All our internal APIs are sensitive towards Date
 | 
					
						
							|  |  |  | 			// header, for all requests where Date header is not
 | 
					
						
							|  |  |  | 			// present we will reject such clients.
 | 
					
						
							| 
									
										
										
										
											2016-03-31 11:04:51 +08:00
										 |  |  | 			writeErrorResponse(w, r, apiErr, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2015-04-30 09:30:17 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-10 06:33:35 +08:00
										 |  |  | 		// Verify if the request date header is shifted by less than maxSkewTime parameter in the past
 | 
					
						
							|  |  |  | 		// or in the future, reject request otherwise.
 | 
					
						
							|  |  |  | 		curTime := time.Now().UTC() | 
					
						
							|  |  |  | 		if curTime.Sub(amzDate) > maxSkewTime || amzDate.Sub(curTime) > maxSkewTime { | 
					
						
							| 
									
										
										
										
											2016-03-10 18:24:52 +08:00
										 |  |  | 			writeErrorResponse(w, r, ErrRequestTimeTooSkewed, 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) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | type resourceHandler struct { | 
					
						
							|  |  |  | 	handler http.Handler | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 06:57:20 +08:00
										 |  |  | // setCorsHandler handler for CORS (Cross Origin Resource Sharing)
 | 
					
						
							|  |  |  | func setCorsHandler(h http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2015-10-31 02:49:08 +08:00
										 |  |  | 	c := cors.New(cors.Options{ | 
					
						
							|  |  |  | 		AllowedOrigins: []string{"*"}, | 
					
						
							| 
									
										
										
										
											2016-01-29 01:23:05 +08:00
										 |  |  | 		AllowedMethods: []string{"GET", "HEAD", "POST", "PUT"}, | 
					
						
							| 
									
										
										
										
											2015-10-31 02:49:08 +08:00
										 |  |  | 		AllowedHeaders: []string{"*"}, | 
					
						
							| 
									
										
										
										
											2016-05-19 10:17:17 +08:00
										 |  |  | 		ExposedHeaders: []string{"ETag"}, | 
					
						
							| 
									
										
										
										
											2015-10-31 02:49:08 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	return c.Handler(h) | 
					
						
							| 
									
										
										
										
											2015-09-01 05:40:12 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 06:57:20 +08:00
										 |  |  | // setIgnoreResourcesHandler -
 | 
					
						
							| 
									
										
										
										
											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
 | 
					
						
							| 
									
										
										
										
											2016-02-17 10:50:36 +08:00
										 |  |  | // valid error message indicating that requested feature is not implemented.
 | 
					
						
							| 
									
										
										
										
											2016-02-05 06:57:20 +08:00
										 |  |  | func setIgnoreResourcesHandler(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-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) { | 
					
						
							| 
									
										
										
										
											2016-02-10 13:38:50 +08:00
										 |  |  | 	// Skip the first element which is usually '/' and split the rest.
 | 
					
						
							| 
									
										
										
										
											2015-12-08 03:57:33 +08:00
										 |  |  | 	splits := strings.SplitN(r.URL.Path[1:], "/", 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Save bucketName and objectName extracted from url Path.
 | 
					
						
							|  |  |  | 	var bucketName, objectName string | 
					
						
							|  |  |  | 	if len(splits) == 1 { | 
					
						
							|  |  |  | 		bucketName = splits[0] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(splits) == 2 { | 
					
						
							|  |  |  | 		bucketName = splits[0] | 
					
						
							|  |  |  | 		objectName = splits[1] | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-09 11:56:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If bucketName is present and not objectName check for bucket level resource queries.
 | 
					
						
							| 
									
										
										
										
											2015-12-08 03:57:33 +08:00
										 |  |  | 	if bucketName != "" && objectName == "" { | 
					
						
							| 
									
										
										
										
											2015-10-08 11:36:36 +08:00
										 |  |  | 		if ignoreNotImplementedBucketResources(r) { | 
					
						
							| 
									
										
										
										
											2016-03-10 18:24:52 +08:00
										 |  |  | 			writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2015-10-08 11:36:36 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-08 03:57:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// If bucketName and objectName are present check for its resource queries.
 | 
					
						
							|  |  |  | 	if bucketName != "" && objectName != "" { | 
					
						
							| 
									
										
										
										
											2015-10-08 11:36:36 +08:00
										 |  |  | 		if ignoreNotImplementedObjectResources(r) { | 
					
						
							| 
									
										
										
										
											2016-03-10 18:24:52 +08:00
										 |  |  | 			writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2015-10-08 11:36:36 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-19 04:15:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-08 03:57:33 +08:00
										 |  |  | 	// A put method on path "/" doesn't make sense, ignore it.
 | 
					
						
							|  |  |  | 	if r.Method == "PUT" && r.URL.Path == "/" { | 
					
						
							| 
									
										
										
										
											2016-03-10 18:24:52 +08:00
										 |  |  | 		writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path) | 
					
						
							| 
									
										
										
										
											2015-12-08 03:57:33 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-09 11:56:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Serve HTTP.
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	for name := range req.URL.Query() { | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	for name := range req.URL.Query() { | 
					
						
							| 
									
										
										
										
											2015-04-30 06:28:04 +08:00
										 |  |  | 		if notimplementedObjectResourceNames[name] { | 
					
						
							| 
									
										
										
										
											2015-02-11 19:23:15 +08:00
										 |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // List of not implemented bucket queries
 | 
					
						
							|  |  |  | var notimplementedBucketResourceNames = map[string]bool{ | 
					
						
							| 
									
										
										
											
												accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
   "*":                             true,
   "s3:*":                          true,
   "s3:GetObject":                  true,
   "s3:ListBucket":                 true,
   "s3:PutObject":                  true,
   "s3:CreateBucket":               true,
   "s3:GetBucketLocation":          true,
   "s3:DeleteBucket":               true,
   "s3:DeleteObject":               true,
   "s3:AbortMultipartUpload":       true,
   "s3:ListBucketMultipartUploads": true,
   "s3:ListMultipartUploadParts":   true,
following conditions for "StringEquals" and "StringNotEquals"
   "s3:prefix", "s3:max-keys"
											
										 
											2016-02-04 08:46:56 +08:00
										 |  |  | 	"acl":            true, | 
					
						
							| 
									
										
										
										
											2016-02-20 08:04:29 +08:00
										 |  |  | 	"cors":           true, | 
					
						
							|  |  |  | 	"lifecycle":      true, | 
					
						
							|  |  |  | 	"logging":        true, | 
					
						
							|  |  |  | 	"replication":    true, | 
					
						
							|  |  |  | 	"tagging":        true, | 
					
						
							|  |  |  | 	"versions":       true, | 
					
						
							|  |  |  | 	"requestPayment": true, | 
					
						
							|  |  |  | 	"versioning":     true, | 
					
						
							|  |  |  | 	"website":        true, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // List of not implemented object queries
 | 
					
						
							|  |  |  | var notimplementedObjectResourceNames = map[string]bool{ | 
					
						
							|  |  |  | 	"torrent": true, | 
					
						
							|  |  |  | 	"acl":     true, | 
					
						
							|  |  |  | 	"policy":  true, | 
					
						
							|  |  |  | } |