| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2016 Minio, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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 | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 	"crypto/tls" | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-12-06 06:49:32 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 	"net" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	serverShutdownPoll = 500 * time.Millisecond | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-10 23:44:41 +08:00
										 |  |  | // The value chosen below is longest word chosen
 | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | // from all the http verbs comprising of
 | 
					
						
							|  |  |  | // "PRI", "OPTIONS", "GET", "HEAD", "POST",
 | 
					
						
							|  |  |  | // "PUT", "DELETE", "TRACE", "CONNECT".
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	maxHTTPVerbLen = 7 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | var defaultHTTP2Methods = []string{ | 
					
						
							|  |  |  | 	"PRI", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var defaultHTTP1Methods = []string{ | 
					
						
							|  |  |  | 	"OPTIONS", | 
					
						
							|  |  |  | 	"GET", | 
					
						
							|  |  |  | 	"HEAD", | 
					
						
							|  |  |  | 	"POST", | 
					
						
							|  |  |  | 	"PUT", | 
					
						
							|  |  |  | 	"DELETE", | 
					
						
							|  |  |  | 	"TRACE", | 
					
						
							|  |  |  | 	"CONNECT", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | // ConnMux - Peeks into the incoming connection for relevant
 | 
					
						
							|  |  |  | // protocol without advancing the underlying net.Conn (io.Reader).
 | 
					
						
							|  |  |  | // ConnMux - allows us to multiplex between TLS and Regular HTTP
 | 
					
						
							|  |  |  | // connections on the same listeners.
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | type ConnMux struct { | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 	net.Conn | 
					
						
							| 
									
										
										
										
											2017-02-07 01:29:53 +08:00
										 |  |  | 	// To peek net.Conn incoming data
 | 
					
						
							|  |  |  | 	peeker *bufio.Reader | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewConnMux - creates a new ConnMux instance
 | 
					
						
							|  |  |  | func NewConnMux(c net.Conn) *ConnMux { | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | 	br := bufio.NewReader(c) | 
					
						
							|  |  |  | 	return &ConnMux{ | 
					
						
							| 
									
										
										
										
											2017-02-07 01:29:53 +08:00
										 |  |  | 		Conn:   c, | 
					
						
							|  |  |  | 		peeker: bufio.NewReader(br), | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | // List of protocols to be detected by PeekProtocol function.
 | 
					
						
							| 
									
										
										
										
											2017-01-19 04:24:34 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	protocolTLS   = "tls" | 
					
						
							|  |  |  | 	protocolHTTP1 = "http" | 
					
						
							|  |  |  | 	protocolHTTP2 = "http2" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | // PeekProtocol - reads the first bytes, then checks if it is similar
 | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | // to one of the default http methods. Returns error if there are any
 | 
					
						
							|  |  |  | // errors in peeking over the connection.
 | 
					
						
							|  |  |  | func (c *ConnMux) PeekProtocol() (string, error) { | 
					
						
							|  |  |  | 	// Peek for HTTP verbs.
 | 
					
						
							| 
									
										
										
										
											2017-02-07 01:29:53 +08:00
										 |  |  | 	buf, err := c.peeker.Peek(maxHTTPVerbLen) | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 		return "", err | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check for HTTP2 methods first.
 | 
					
						
							|  |  |  | 	for _, m := range defaultHTTP2Methods { | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | 		if strings.HasPrefix(string(buf), m) { | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 			return protocolHTTP2, nil | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check for HTTP1 methods.
 | 
					
						
							|  |  |  | 	for _, m := range defaultHTTP1Methods { | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | 		if strings.HasPrefix(string(buf), m) { | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 			return protocolHTTP1, nil | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Default to TLS, this is not a real indication
 | 
					
						
							|  |  |  | 	// that the connection is TLS but that will be
 | 
					
						
							|  |  |  | 	// validated later by doing a handshake.
 | 
					
						
							|  |  |  | 	return protocolTLS, nil | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | // Read reads from the tcp session for data sent by
 | 
					
						
							|  |  |  | // the client, additionally sets deadline for 15 secs
 | 
					
						
							|  |  |  | // after each successful read. Deadline cancels and
 | 
					
						
							|  |  |  | // returns error if the client does not send any
 | 
					
						
							|  |  |  | // data in 15 secs. Also keeps track of the total
 | 
					
						
							|  |  |  | // bytes received from the client.
 | 
					
						
							|  |  |  | func (c *ConnMux) Read(b []byte) (n int, err error) { | 
					
						
							|  |  |  | 	// Update total incoming number of bytes.
 | 
					
						
							| 
									
										
										
										
											2017-04-21 22:15:53 +08:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		globalConnStats.incInputBytes(n) | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	n, err = c.peeker.Read(b) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return n, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-07 01:29:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | 	// Read deadline was already set previously, set again
 | 
					
						
							|  |  |  | 	// after a successful read operation for future read
 | 
					
						
							|  |  |  | 	// operations.
 | 
					
						
							|  |  |  | 	c.Conn.SetReadDeadline(UTCNow().Add(defaultTCPReadTimeout)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Success.
 | 
					
						
							|  |  |  | 	return n, nil | 
					
						
							| 
									
										
										
										
											2017-02-07 01:29:53 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | // Write to the client over a tcp session, additionally
 | 
					
						
							|  |  |  | // keeps track of the total bytes written by the server.
 | 
					
						
							|  |  |  | func (c *ConnMux) Write(b []byte) (n int, err error) { | 
					
						
							|  |  |  | 	// Update total outgoing number of bytes.
 | 
					
						
							| 
									
										
										
										
											2017-04-21 22:15:53 +08:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		globalConnStats.incOutputBytes(n) | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Call the conn write wrapper.
 | 
					
						
							| 
									
										
										
										
											2017-02-07 01:29:53 +08:00
										 |  |  | 	return c.Conn.Write(b) | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | // Close closes the underlying tcp connection.
 | 
					
						
							| 
									
										
										
										
											2016-11-06 03:57:31 +08:00
										 |  |  | func (c *ConnMux) Close() (err error) { | 
					
						
							| 
									
										
										
										
											2017-01-20 03:19:57 +08:00
										 |  |  | 	// Make sure that we always close a connection,
 | 
					
						
							| 
									
										
										
										
											2017-02-07 01:29:53 +08:00
										 |  |  | 	return c.Conn.Close() | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 00:43:28 +08:00
										 |  |  | // ListenerMux wraps the standard net.Listener to inspect
 | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | // the communication protocol upon network connection
 | 
					
						
							| 
									
										
										
										
											2016-11-06 00:43:28 +08:00
										 |  |  | // ListenerMux also wraps net.Listener to ensure that once
 | 
					
						
							|  |  |  | // Listener.Close returns, the underlying socket has been closed.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // - https://github.com/golang/go/issues/10527
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The default Listener returns from Close before the underlying
 | 
					
						
							|  |  |  | // socket has been closed if another goroutine has an active
 | 
					
						
							|  |  |  | // reference (e.g. is in Accept).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The following sequence of events can happen:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Goroutine 1 is running Accept, and is blocked, waiting for epoll
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Goroutine 2 calls Close. It sees an extra reference, and so cannot
 | 
					
						
							|  |  |  | //  destroy the socket, but instead decrements a reference, marks the
 | 
					
						
							|  |  |  | //  connection as closed and unblocks epoll.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Goroutine 2 returns to the caller, makes a new connection.
 | 
					
						
							|  |  |  | // The new connection is sent to the socket (since it hasn't been destroyed)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Goroutine 1 returns from epoll, and accepts the new connection.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // To avoid accepting connections after Close, we block Goroutine 2
 | 
					
						
							|  |  |  | // from returning from Close till Accept returns an error to the user.
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | type ListenerMux struct { | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 	net.Listener | 
					
						
							|  |  |  | 	config *tls.Config | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 	// acceptResCh is a channel for transporting wrapped net.Conn (regular or tls)
 | 
					
						
							|  |  |  | 	// after peeking the content of the latter
 | 
					
						
							|  |  |  | 	acceptResCh chan ListenerMuxAcceptRes | 
					
						
							| 
									
										
										
										
											2016-11-06 00:43:28 +08:00
										 |  |  | 	// Cond is used to signal Close when there are no references to the listener.
 | 
					
						
							|  |  |  | 	cond *sync.Cond | 
					
						
							|  |  |  | 	refs int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | // ListenerMuxAcceptRes contains then final net.Conn data (wrapper by tls or not) to be sent to the http handler
 | 
					
						
							|  |  |  | type ListenerMuxAcceptRes struct { | 
					
						
							|  |  |  | 	conn net.Conn | 
					
						
							|  |  |  | 	err  error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-16 19:38:06 +08:00
										 |  |  | // Default keep alive interval timeout, on your Linux system to figure out
 | 
					
						
							|  |  |  | // maximum probes sent
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | //     > cat /proc/sys/net/ipv4/tcp_keepalive_probes
 | 
					
						
							|  |  |  | //     ! 9
 | 
					
						
							| 
									
										
										
										
											2017-01-16 19:38:06 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | // Final value of total keep-alive comes upto 9 x 10 * seconds = 1.5 minutes.
 | 
					
						
							|  |  |  | const defaultKeepAliveTimeout = 10 * time.Second // 10 seconds.
 | 
					
						
							| 
									
										
										
										
											2017-01-16 19:38:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | // Timeout to close and return error to the client when not sending any data.
 | 
					
						
							|  |  |  | const defaultTCPReadTimeout = 15 * time.Second // 15 seconds.
 | 
					
						
							| 
									
										
										
										
											2017-01-23 06:48:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | // newListenerMux listens and wraps accepted connections with tls after protocol peeking
 | 
					
						
							|  |  |  | func newListenerMux(listener net.Listener, config *tls.Config) *ListenerMux { | 
					
						
							|  |  |  | 	l := ListenerMux{ | 
					
						
							|  |  |  | 		Listener:    listener, | 
					
						
							|  |  |  | 		config:      config, | 
					
						
							|  |  |  | 		cond:        sync.NewCond(&sync.Mutex{}), | 
					
						
							|  |  |  | 		acceptResCh: make(chan ListenerMuxAcceptRes), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start listening, wrap connections with tls when needed
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2017-01-24 01:55:34 +08:00
										 |  |  | 		// Extract tcp listener.
 | 
					
						
							|  |  |  | 		tcpListener, ok := l.Listener.(*net.TCPListener) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			l.acceptResCh <- ListenerMuxAcceptRes{err: errInvalidArgument} | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 		// Loop for accepting new connections
 | 
					
						
							|  |  |  | 		for { | 
					
						
							| 
									
										
										
										
											2017-01-16 19:38:06 +08:00
										 |  |  | 			// Use accept TCP method to receive the connection.
 | 
					
						
							|  |  |  | 			conn, err := tcpListener.AcceptTCP() | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				l.acceptResCh <- ListenerMuxAcceptRes{err: err} | 
					
						
							| 
									
										
										
										
											2017-01-24 01:55:34 +08:00
										 |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-16 19:38:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 06:48:27 +08:00
										 |  |  | 			// Enable Read timeout
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | 			conn.SetReadDeadline(UTCNow().Add(defaultTCPReadTimeout)) | 
					
						
							| 
									
										
										
										
											2017-01-23 06:48:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-16 19:38:06 +08:00
										 |  |  | 			// Enable keep alive for each connection.
 | 
					
						
							|  |  |  | 			conn.SetKeepAlive(true) | 
					
						
							|  |  |  | 			conn.SetKeepAlivePeriod(defaultKeepAliveTimeout) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 			// Allocate new conn muxer.
 | 
					
						
							|  |  |  | 			connMux := NewConnMux(conn) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 			// Wrap the connection with ConnMux to be able to peek the data in the incoming connection
 | 
					
						
							|  |  |  | 			// and decide if we need to wrap the connection itself with a TLS or not
 | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 			go func(connMux *ConnMux) { | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | 				protocol, cerr := connMux.PeekProtocol() | 
					
						
							|  |  |  | 				if cerr != nil { | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 					// io.EOF is usually returned by non-http clients,
 | 
					
						
							|  |  |  | 					// just close the connection to avoid any leak.
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | 					if cerr != io.EOF { | 
					
						
							|  |  |  | 						errorIf(cerr, "Unable to peek into incoming protocol") | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					connMux.Close() | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				switch protocol { | 
					
						
							|  |  |  | 				case protocolTLS: | 
					
						
							|  |  |  | 					tlsConn := tls.Server(connMux, l.config) | 
					
						
							|  |  |  | 					// Make sure to handshake so that we know that this
 | 
					
						
							|  |  |  | 					// is a TLS connection, if not we should close and reject
 | 
					
						
							|  |  |  | 					// such a connection.
 | 
					
						
							| 
									
										
										
										
											2017-04-20 04:16:06 +08:00
										 |  |  | 					if cerr = tlsConn.Handshake(); cerr != nil { | 
					
						
							| 
									
										
										
										
											2017-05-03 18:23:15 +08:00
										 |  |  | 						// Close for junk message.
 | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 						tlsConn.Close() | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-01-19 04:24:34 +08:00
										 |  |  | 					l.acceptResCh <- ListenerMuxAcceptRes{ | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 						conn: tlsConn, | 
					
						
							| 
									
										
										
										
											2017-01-19 04:24:34 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 				default: | 
					
						
							| 
									
										
										
										
											2017-01-19 04:24:34 +08:00
										 |  |  | 					l.acceptResCh <- ListenerMuxAcceptRes{ | 
					
						
							|  |  |  | 						conn: connMux, | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 			}(connMux) | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	return &l | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 00:43:28 +08:00
										 |  |  | // IsClosed - Returns if the underlying listener is closed fully.
 | 
					
						
							|  |  |  | func (l *ListenerMux) IsClosed() bool { | 
					
						
							|  |  |  | 	l.cond.L.Lock() | 
					
						
							|  |  |  | 	defer l.cond.L.Unlock() | 
					
						
							|  |  |  | 	return l.refs == 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (l *ListenerMux) incRef() { | 
					
						
							|  |  |  | 	l.cond.L.Lock() | 
					
						
							|  |  |  | 	l.refs++ | 
					
						
							|  |  |  | 	l.cond.L.Unlock() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (l *ListenerMux) decRef() { | 
					
						
							|  |  |  | 	l.cond.L.Lock() | 
					
						
							|  |  |  | 	l.refs-- | 
					
						
							|  |  |  | 	newRefs := l.refs | 
					
						
							|  |  |  | 	l.cond.L.Unlock() | 
					
						
							|  |  |  | 	if newRefs == 0 { | 
					
						
							|  |  |  | 		l.cond.Broadcast() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Close closes the listener.
 | 
					
						
							|  |  |  | // Any blocked Accept operations will be unblocked and return errors.
 | 
					
						
							|  |  |  | func (l *ListenerMux) Close() error { | 
					
						
							|  |  |  | 	if l == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := l.Listener.Close(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	l.cond.L.Lock() | 
					
						
							|  |  |  | 	for l.refs > 0 { | 
					
						
							|  |  |  | 		l.cond.Wait() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	l.cond.L.Unlock() | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Accept - peek the protocol to decide if we should wrap the
 | 
					
						
							|  |  |  | // network stream with the TLS server
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | func (l *ListenerMux) Accept() (net.Conn, error) { | 
					
						
							| 
									
										
										
										
											2016-11-06 00:43:28 +08:00
										 |  |  | 	l.incRef() | 
					
						
							|  |  |  | 	defer l.decRef() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 	res := <-l.acceptResCh | 
					
						
							|  |  |  | 	return res.conn, res.err | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | // ServerMux - the main mux server
 | 
					
						
							|  |  |  | type ServerMux struct { | 
					
						
							| 
									
										
										
										
											2017-02-04 14:53:30 +08:00
										 |  |  | 	Addr      string | 
					
						
							|  |  |  | 	handler   http.Handler | 
					
						
							|  |  |  | 	listeners []*ListenerMux | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 	// Current number of concurrent http requests
 | 
					
						
							|  |  |  | 	currentReqs int32 | 
					
						
							|  |  |  | 	// Time to wait before forcing server shutdown
 | 
					
						
							| 
									
										
										
										
											2017-02-04 14:53:30 +08:00
										 |  |  | 	gracefulTimeout time.Duration | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-03 02:00:22 +08:00
										 |  |  | 	mu      sync.RWMutex // guards closing, and listeners
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 	closing bool | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | // NewServerMux constructor to create a ServerMux
 | 
					
						
							|  |  |  | func NewServerMux(addr string, handler http.Handler) *ServerMux { | 
					
						
							|  |  |  | 	m := &ServerMux{ | 
					
						
							| 
									
										
										
										
											2017-02-04 14:53:30 +08:00
										 |  |  | 		Addr:    addr, | 
					
						
							|  |  |  | 		handler: handler, | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 		// Wait for 5 seconds for new incoming connnections, otherwise
 | 
					
						
							|  |  |  | 		// forcibly close them during graceful stop or restart.
 | 
					
						
							| 
									
										
										
										
											2017-02-04 14:53:30 +08:00
										 |  |  | 		gracefulTimeout: 5 * time.Second, | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Returns configured HTTP server.
 | 
					
						
							|  |  |  | 	return m | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | // Initialize listeners on all ports.
 | 
					
						
							|  |  |  | func initListeners(serverAddr string, tls *tls.Config) ([]*ListenerMux, error) { | 
					
						
							|  |  |  | 	host, port, err := net.SplitHostPort(serverAddr) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var listeners []*ListenerMux | 
					
						
							|  |  |  | 	if host == "" { | 
					
						
							|  |  |  | 		var listener net.Listener | 
					
						
							|  |  |  | 		listener, err = net.Listen("tcp", serverAddr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 		listeners = append(listeners, newListenerMux(listener, tls)) | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 		return listeners, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var addrs []string | 
					
						
							|  |  |  | 	if net.ParseIP(host) != nil { | 
					
						
							|  |  |  | 		addrs = append(addrs, host) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		addrs, err = net.LookupHost(host) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(addrs) == 0 { | 
					
						
							|  |  |  | 			return nil, errUnexpected | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, addr := range addrs { | 
					
						
							|  |  |  | 		var listener net.Listener | 
					
						
							|  |  |  | 		listener, err = net.Listen("tcp", net.JoinHostPort(addr, port)) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-07 03:41:01 +08:00
										 |  |  | 		listeners = append(listeners, newListenerMux(listener, tls)) | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return listeners, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | // 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 != "" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 04:14:00 +08:00
										 |  |  | 	config := &tls.Config{ | 
					
						
							|  |  |  | 		// Causes servers to use Go's default ciphersuite preferences,
 | 
					
						
							|  |  |  | 		// which are tuned to avoid attacks. Does nothing on clients.
 | 
					
						
							|  |  |  | 		PreferServerCipherSuites: true, | 
					
						
							|  |  |  | 		// Set minimum version to TLS 1.2
 | 
					
						
							|  |  |  | 		MinVersion: tls.VersionTLS12, | 
					
						
							|  |  |  | 	} // Always instantiate.
 | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 	go m.handleServiceSignals() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 14:53:30 +08:00
										 |  |  | 	listeners, err := initListeners(m.Addr, config) | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	m.mu.Lock() | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 	m.listeners = listeners | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	m.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | 	// 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{ | 
					
						
							| 
									
										
										
										
											2017-01-19 04:24:34 +08:00
										 |  |  | 				Scheme:   httpsScheme, | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | 				Opaque:   r.URL.Opaque, | 
					
						
							|  |  |  | 				User:     r.URL.User, | 
					
						
							|  |  |  | 				Host:     r.Host, | 
					
						
							|  |  |  | 				Path:     r.URL.Path, | 
					
						
							|  |  |  | 				RawQuery: r.URL.RawQuery, | 
					
						
							|  |  |  | 				Fragment: r.URL.Fragment, | 
					
						
							| 
									
										
										
										
											2016-11-06 00:43:28 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-11-12 07:04:51 +08:00
										 |  |  | 			http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect) | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Return ServiceUnavailable for clients which are sending requests
 | 
					
						
							|  |  |  | 			// in shutdown phase
 | 
					
						
							| 
									
										
										
										
											2017-03-03 02:00:22 +08:00
										 |  |  | 			m.mu.RLock() | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 			closing := m.closing | 
					
						
							| 
									
										
										
										
											2017-03-03 02:00:22 +08:00
										 |  |  | 			m.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 			if closing { | 
					
						
							|  |  |  | 				w.WriteHeader(http.StatusServiceUnavailable) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Execute registered handlers, update currentReqs to keep
 | 
					
						
							|  |  |  | 			// tracks of current requests currently processed by the server
 | 
					
						
							|  |  |  | 			atomic.AddInt32(&m.currentReqs, 1) | 
					
						
							| 
									
										
										
										
											2017-02-04 14:53:30 +08:00
										 |  |  | 			m.handler.ServeHTTP(w, r) | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 			atomic.AddInt32(&m.currentReqs, -1) | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 	var wg = &sync.WaitGroup{} | 
					
						
							|  |  |  | 	for _, listener := range listeners { | 
					
						
							|  |  |  | 		wg.Add(1) | 
					
						
							|  |  |  | 		go func(listener *ListenerMux) { | 
					
						
							|  |  |  | 			defer wg.Done() | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | 			serr := http.Serve(listener, httpHandler) | 
					
						
							| 
									
										
										
										
											2016-11-06 00:43:28 +08:00
										 |  |  | 			// Do not print the error if the listener is closed.
 | 
					
						
							|  |  |  | 			if !listener.IsClosed() { | 
					
						
							|  |  |  | 				errorIf(serr, "Unable to serve incoming requests.") | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 		}(listener) | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-06 11:32:13 +08:00
										 |  |  | 	// Wait for all http.Serve's to return.
 | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 	wg.Wait() | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-07-25 03:30:57 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Close initiates the graceful shutdown
 | 
					
						
							| 
									
										
										
										
											2016-09-03 10:07:42 +08:00
										 |  |  | func (m *ServerMux) Close() error { | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	m.mu.Lock() | 
					
						
							| 
									
										
										
										
											2017-02-04 14:53:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 	if m.closing { | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 		m.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 		return errors.New("Server has been closed") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 	// Closed completely.
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 	m.closing = true | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 06:38:28 +08:00
										 |  |  | 	// Close the listeners.
 | 
					
						
							|  |  |  | 	for _, listener := range m.listeners { | 
					
						
							|  |  |  | 		if err := listener.Close(); err != nil { | 
					
						
							|  |  |  | 			m.mu.Unlock() | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-17 15:18:23 +08:00
										 |  |  | 	m.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:28:54 +08:00
										 |  |  | 	// Starting graceful shutdown. Check if all requests are finished
 | 
					
						
							|  |  |  | 	// in regular interval or force the shutdown
 | 
					
						
							|  |  |  | 	ticker := time.NewTicker(serverShutdownPoll) | 
					
						
							|  |  |  | 	defer ticker.Stop() | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-time.After(m.gracefulTimeout): | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		case <-ticker.C: | 
					
						
							|  |  |  | 			if atomic.LoadInt32(&m.currentReqs) <= 0 { | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-12 12:33:55 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |