diff --git a/main.go b/main.go index ec465d7e9..27dd9b1ff 100644 --- a/main.go +++ b/main.go @@ -45,6 +45,11 @@ var flags = []cli.Flag{ Usage: "ADDRESS:PORT for management console access", }, */ + cli.IntFlag{ + Name: "conn-limit", + Value: 16, + Usage: "Set per IP connection limit quota for server: [DEFAULT: 16]", + }, cli.StringFlag{ Name: "cert", Hide: true, @@ -79,10 +84,11 @@ func getAPIServerConfig(c *cli.Context) httpserver.Config { } tls := (certFile != "" && keyFile != "") return httpserver.Config{ - Address: c.GlobalString("address"), - TLS: tls, - CertFile: certFile, - KeyFile: keyFile, + Address: c.GlobalString("address"), + TLS: tls, + CertFile: certFile, + KeyFile: keyFile, + ConnectionLimit: c.GlobalInt("conn-limit"), } } diff --git a/pkg/api/api_router.go b/pkg/api/api_router.go index 941e24a2a..ac832ba89 100644 --- a/pkg/api/api_router.go +++ b/pkg/api/api_router.go @@ -25,16 +25,31 @@ import ( "github.com/minio/minio/pkg/storage/drivers" ) -// private use type minioAPI struct { driver drivers.Driver } +// Config api configurable parameters +type Config struct { + ConnectionLimit int + driver drivers.Driver +} + +// GetDriver - get a an existing set driver +func (c Config) GetDriver() drivers.Driver { + return c.driver +} + +// SetDriver - set a new driver +func (c *Config) SetDriver(driver drivers.Driver) { + c.driver = driver +} + // HTTPHandler - http wrapper handler -func HTTPHandler(driver drivers.Driver) http.Handler { +func HTTPHandler(config Config) http.Handler { var mux *router.Router var api = minioAPI{} - api.driver = driver + api.driver = config.GetDriver() mux = router.NewRouter() mux.HandleFunc("/", api.listBucketsHandler).Methods("GET") @@ -50,15 +65,15 @@ func HTTPHandler(driver drivers.Driver) http.Handler { mux.HandleFunc("/{bucket}/{object:.*}", api.getObjectHandler).Methods("GET") mux.HandleFunc("/{bucket}/{object:.*}", api.putObjectHandler).Methods("PUT") - h := validContentTypeHandler(mux) - h = timeValidityHandler(h) - h = ignoreResourcesHandler(h) - h = validateAuthHeaderHandler(h) + handler := validContentTypeHandler(mux) + handler = timeValidityHandler(handler) + handler = ignoreResourcesHandler(handler) + handler = validateAuthHeaderHandler(handler) // h = quota.BandwidthCap(h, 25*1024*1024, time.Duration(30*time.Minute)) // h = quota.BandwidthCap(h, 100*1024*1024, time.Duration(24*time.Hour)) // h = quota.RequestLimit(h, 100, time.Duration(30*time.Minute)) // h = quota.RequestLimit(h, 1000, time.Duration(24*time.Hour)) - h = quota.ConnectionLimit(h, 4) - h = logging.LogHandler(h) - return h + handler = quota.ConnectionLimit(handler, config.ConnectionLimit) + handler = logging.LogHandler(handler) + return handler } diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 981bb1ca9..4311616bc 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -123,6 +123,12 @@ func setDummyAuthHeader(req *http.Request) { req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) } +func setConfig(driver drivers.Driver) Config { + conf := Config{ConnectionLimit: 16} + conf.SetDriver(driver) + return conf +} + func (s *MySuite) TestNonExistantBucket(c *C) { switch driver := s.Driver.(type) { case *mocks.Driver: @@ -131,7 +137,7 @@ func (s *MySuite) TestNonExistantBucket(c *C) { } } driver := s.Driver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -169,7 +175,7 @@ func (s *MySuite) TestEmptyObject(c *C) { typedDriver.On("GetObjectMetadata", "bucket", "object").Return(metadata, nil).Once() typedDriver.On("GetObject", mock.Anything, "bucket", "object").Return(int64(0), nil).Once() typedDriver.On("GetObjectMetadata", "bucket", "object").Return(metadata, nil).Once() - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -212,7 +218,7 @@ func (s *MySuite) TestBucket(c *C) { typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once() typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Once() - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -252,7 +258,7 @@ func (s *MySuite) TestObject(c *C) { typedDriver.SetGetObjectWriter("bucket", "object", []byte("hello world")) typedDriver.On("GetObject", mock.Anything, "bucket", "object").Return(int64(0), nil).Once() - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -311,7 +317,7 @@ func (s *MySuite) TestMultipleObjects(c *C) { Md5: "4e74ad3b92e2843e208a13ae1cf0d52c", Size: 11, } - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -441,7 +447,7 @@ func (s *MySuite) TestNotImplemented(c *C) { } } driver := s.Driver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -466,7 +472,7 @@ func (s *MySuite) TestHeader(c *C) { driver := s.Driver typedDriver := s.MockDriver typedDriver.AssertExpectations(c) - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -535,7 +541,7 @@ func (s *MySuite) TestPutBucket(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -572,7 +578,7 @@ func (s *MySuite) TestPutObject(c *C) { } driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -661,7 +667,7 @@ func (s *MySuite) TestListBuckets(c *C) { } driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -754,7 +760,7 @@ func (s *MySuite) TestNotBeAbleToCreateObjectInNonexistantBucket(c *C) { } driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -788,7 +794,7 @@ func (s *MySuite) TestHeadOnObject(c *C) { } driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -842,7 +848,7 @@ func (s *MySuite) TestHeadOnBucket(c *C) { } driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -876,7 +882,7 @@ func (s *MySuite) TestDateFormat(c *C) { } driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -924,7 +930,7 @@ func (s *MySuite) TestXMLNameNotInBucketListJson(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -957,7 +963,7 @@ func (s *MySuite) TestXMLNameNotInObjectListJson(c *C) { } driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -1002,7 +1008,7 @@ func (s *MySuite) TestContentTypePersists(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -1117,7 +1123,7 @@ func (s *MySuite) TestPartialContent(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() @@ -1175,7 +1181,7 @@ func (s *MySuite) TestListObjectsHandlerErrors(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1242,7 +1248,7 @@ func (s *MySuite) TestListBucketsErrors(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1279,7 +1285,7 @@ func (s *MySuite) TestPutBucketErrors(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1339,7 +1345,7 @@ func (s *MySuite) TestGetObjectErrors(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1412,7 +1418,7 @@ func (s *MySuite) TestGetObjectRangeErrors(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1456,7 +1462,7 @@ func (s *MySuite) TestObjectMultipartAbort(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1539,7 +1545,7 @@ func (s *MySuite) TestBucketMultipartList(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1628,7 +1634,7 @@ func (s *MySuite) TestObjectMultipartList(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} @@ -1712,7 +1718,7 @@ func (s *MySuite) TestObjectMultipart(c *C) { driver := s.Driver typedDriver := s.MockDriver - httpHandler := HTTPHandler(driver) + httpHandler := HTTPHandler(setConfig(driver)) testServer := httptest.NewServer(httpHandler) defer testServer.Close() client := http.Client{} diff --git a/pkg/server/httpserver/httpserver.go b/pkg/server/httpserver/httpserver.go index d19c4015b..951908333 100644 --- a/pkg/server/httpserver/httpserver.go +++ b/pkg/server/httpserver/httpserver.go @@ -25,10 +25,11 @@ import ( // Config - http server config type Config struct { - Address string - TLS bool - CertFile string - KeyFile string + Address string + TLS bool + CertFile string + KeyFile string + ConnectionLimit int } // Server - http server related diff --git a/pkg/server/server.go b/pkg/server/server.go index 392420576..372a3ccc1 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -43,7 +43,9 @@ type MemoryFactory struct { func (f MemoryFactory) GetStartServerFunc() StartServerFunc { return func() (chan<- string, <-chan error) { _, _, driver := memory.Start(f.MaxMemory, f.Expiration) - ctrl, status, _ := httpserver.Start(api.HTTPHandler(driver), f.Config) + conf := api.Config{ConnectionLimit: f.ConnectionLimit} + conf.SetDriver(driver) + ctrl, status, _ := httpserver.Start(api.HTTPHandler(conf), f.Config) return ctrl, status } } @@ -58,7 +60,9 @@ type FilesystemFactory struct { func (f FilesystemFactory) GetStartServerFunc() StartServerFunc { return func() (chan<- string, <-chan error) { _, _, driver := fs.Start(f.Path) - ctrl, status, _ := httpserver.Start(api.HTTPHandler(driver), f.Config) + conf := api.Config{ConnectionLimit: f.ConnectionLimit} + conf.SetDriver(driver) + ctrl, status, _ := httpserver.Start(api.HTTPHandler(conf), f.Config) return ctrl, status } } @@ -86,7 +90,9 @@ type DonutFactory struct { func (f DonutFactory) GetStartServerFunc() StartServerFunc { return func() (chan<- string, <-chan error) { _, _, driver := donut.Start(f.Paths) - ctrl, status, _ := httpserver.Start(api.HTTPHandler(driver), f.Config) + conf := api.Config{ConnectionLimit: f.ConnectionLimit} + conf.SetDriver(driver) + ctrl, status, _ := httpserver.Start(api.HTTPHandler(conf), f.Config) return ctrl, status } }