diff --git a/cmd/server-main.go b/cmd/server-main.go index 3881042ff..f0204e2d9 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -487,12 +487,11 @@ func serverMain(c *cli.Context) { // Start server, automatically configures TLS if certs are available. go func(tls bool) { var lerr error + cert, key := "", "" if tls { - lerr = apiServer.ListenAndServeTLS(mustGetCertFile(), mustGetKeyFile()) - } else { - // Fallback to http. - lerr = apiServer.ListenAndServe() + cert, key = mustGetCertFile(), mustGetKeyFile() } + lerr = apiServer.ListenAndServe(cert, key) fatalIf(lerr, "Failed to start minio server.") }(tls) diff --git a/cmd/server-mux.go b/cmd/server-mux.go index 33b0f35ce..3c1c33e51 100644 --- a/cmd/server-mux.go +++ b/cmd/server-mux.go @@ -281,18 +281,24 @@ func initListeners(serverAddr string, tls *tls.Config) ([]*ListenerMux, error) { return listeners, nil } -// ListenAndServeTLS - similar to the http.Server version. However, it has the -// ability to redirect http requests to the correct HTTPS url if the client -// mistakenly initiates a http connection over the https port -func (m *ServerMux) ListenAndServeTLS(certFile, keyFile string) (err error) { +// ListenAndServe - serve HTTP requests with protocol multiplexing support +// TLS is actived when certFile and keyFile parameters are not empty. +func (m *ServerMux) ListenAndServe(certFile, keyFile string) (err error) { + + tlsEnabled := certFile != "" && keyFile != "" + config := &tls.Config{} // Always instantiate. - if config.NextProtos == nil { - config.NextProtos = []string{"http/1.1", "h2"} - } - config.Certificates = make([]tls.Certificate, 1) - config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - return err + + if tlsEnabled { + // Configure TLS in the server + if config.NextProtos == nil { + config.NextProtos = []string{"http/1.1", "h2"} + } + config.Certificates = make([]tls.Certificate, 1) + config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } } go m.handleServiceSignals() @@ -306,68 +312,39 @@ func (m *ServerMux) ListenAndServeTLS(certFile, keyFile string) (err error) { m.listeners = listeners m.mu.Unlock() - var wg = &sync.WaitGroup{} - for _, listener := range listeners { - wg.Add(1) - go func(listener *ListenerMux) { - defer wg.Done() - serr := http.Serve(listener, - http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // We reach here when ListenerMux.ConnMux is not wrapped with tls.Server - if r.TLS == nil { - u := url.URL{ - Scheme: "https", - Opaque: r.URL.Opaque, - User: r.URL.User, - Host: r.Host, - Path: r.URL.Path, - RawQuery: r.URL.RawQuery, - Fragment: r.URL.Fragment, - } - http.Redirect(w, r, u.String(), http.StatusMovedPermanently) - } else { - // Execute registered handlers - m.Server.Handler.ServeHTTP(w, r) - } - }), - ) - // Do not print the error if the listener is closed. - if !listener.IsClosed() { - errorIf(serr, "Unable to serve incoming requests.") + // All http requests start to be processed by httpHandler + httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if tlsEnabled && r.TLS == nil { + // TLS is enabled but Request is not TLS configured + u := url.URL{ + Scheme: "https", + Opaque: r.URL.Opaque, + User: r.URL.User, + Host: r.Host, + Path: r.URL.Path, + RawQuery: r.URL.RawQuery, + Fragment: r.URL.Fragment, } - }(listener) - } - // Waits for all http.Serve's to return. - wg.Wait() - return nil -} - -// ListenAndServe - Same as the http.Server version -func (m *ServerMux) ListenAndServe() error { - go m.handleServiceSignals() - - listeners, err := initListeners(m.Server.Addr, &tls.Config{}) - if err != nil { - return err - } - - m.mu.Lock() - m.listeners = listeners - m.mu.Unlock() + http.Redirect(w, r, u.String(), http.StatusMovedPermanently) + } else { + // Execute registered handlers + m.Server.Handler.ServeHTTP(w, r) + } + }) var wg = &sync.WaitGroup{} for _, listener := range listeners { wg.Add(1) go func(listener *ListenerMux) { defer wg.Done() - serr := m.Server.Serve(listener) + serr := http.Serve(listener, httpHandler) // Do not print the error if the listener is closed. if !listener.IsClosed() { errorIf(serr, "Unable to serve incoming requests.") } }(listener) } - // Wait for all the http.Serve to finish. + // Wait for all http.Serve's to return. wg.Wait() return nil } diff --git a/cmd/server-mux_test.go b/cmd/server-mux_test.go index e7d49476d..af29fb29f 100644 --- a/cmd/server-mux_test.go +++ b/cmd/server-mux_test.go @@ -306,7 +306,7 @@ func TestListenAndServePlain(t *testing.T) { })) // ListenAndServe in a goroutine, but we don't know when it's ready - go func() { errc <- m.ListenAndServe() }() + go func() { errc <- m.ListenAndServe("", "") }() wg := &sync.WaitGroup{} wg.Add(1) @@ -370,7 +370,7 @@ func TestListenAndServeTLS(t *testing.T) { } // ListenAndServe in a goroutine, but we don't know when it's ready - go func() { errc <- m.ListenAndServeTLS(certFile, keyFile) }() + go func() { errc <- m.ListenAndServe(certFile, keyFile) }() wg := &sync.WaitGroup{} wg.Add(1)