github.com/simonmittag/ws@v1.1.0-rc.5.0.20210419231947-82b846128245/server.go (about)

     1  package ws
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"net/http"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/gobwas/httphead"
    14  	"github.com/gobwas/pool/pbufio"
    15  )
    16  
    17  // Constants used by ConnUpgrader.
    18  const (
    19  	DefaultServerReadBufferSize  = 4096
    20  	DefaultServerWriteBufferSize = 512
    21  )
    22  
    23  // Errors used by both client and server when preparing WebSocket handshake.
    24  var (
    25  	ErrHandshakeBadProtocol = RejectConnectionError(
    26  		RejectionStatus(http.StatusHTTPVersionNotSupported),
    27  		RejectionReason(fmt.Sprintf("handshake error: bad HTTP protocol version")),
    28  	)
    29  	ErrHandshakeBadMethod = RejectConnectionError(
    30  		RejectionStatus(http.StatusMethodNotAllowed),
    31  		RejectionReason(fmt.Sprintf("handshake error: bad HTTP request method")),
    32  	)
    33  	ErrHandshakeBadHost = RejectConnectionError(
    34  		RejectionStatus(http.StatusBadRequest),
    35  		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerHost)),
    36  	)
    37  	ErrHandshakeBadUpgrade = RejectConnectionError(
    38  		RejectionStatus(http.StatusBadRequest),
    39  		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerUpgrade)),
    40  	)
    41  	ErrHandshakeBadConnection = RejectConnectionError(
    42  		RejectionStatus(http.StatusBadRequest),
    43  		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerConnection)),
    44  	)
    45  	ErrHandshakeBadSecAccept = RejectConnectionError(
    46  		RejectionStatus(http.StatusBadRequest),
    47  		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecAccept)),
    48  	)
    49  	ErrHandshakeBadSecKey = RejectConnectionError(
    50  		RejectionStatus(http.StatusBadRequest),
    51  		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecKey)),
    52  	)
    53  	ErrHandshakeBadSecVersion = RejectConnectionError(
    54  		RejectionStatus(http.StatusBadRequest),
    55  		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
    56  	)
    57  )
    58  
    59  // ErrMalformedResponse is returned by Dialer to indicate that server response
    60  // can not be parsed.
    61  var ErrMalformedResponse = fmt.Errorf("malformed HTTP response")
    62  
    63  // ErrMalformedRequest is returned when HTTP request can not be parsed.
    64  var ErrMalformedRequest = RejectConnectionError(
    65  	RejectionStatus(http.StatusBadRequest),
    66  	RejectionReason("malformed HTTP request"),
    67  )
    68  
    69  // ErrHandshakeUpgradeRequired is returned by Upgrader to indicate that
    70  // connection is rejected because given WebSocket version is malformed.
    71  //
    72  // According to RFC6455:
    73  // If this version does not match a version understood by the server, the
    74  // server MUST abort the WebSocket handshake described in this section and
    75  // instead send an appropriate HTTP error code (such as 426 Upgrade Required)
    76  // and a |Sec-WebSocket-Version| header field indicating the version(s) the
    77  // server is capable of understanding.
    78  var ErrHandshakeUpgradeRequired = RejectConnectionError(
    79  	RejectionStatus(http.StatusUpgradeRequired),
    80  	RejectionHeader(HandshakeHeaderString(headerSecVersion+": 13\r\n")),
    81  	RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
    82  )
    83  
    84  // ErrNotHijacker is an error returned when http.ResponseWriter does not
    85  // implement http.Hijacker interface.
    86  var ErrNotHijacker = RejectConnectionError(
    87  	RejectionStatus(http.StatusInternalServerError),
    88  	RejectionReason("given http.ResponseWriter is not a http.Hijacker"),
    89  )
    90  
    91  // DefaultHTTPUpgrader is an HTTPUpgrader that holds no options and is used by
    92  // UpgradeHTTP function.
    93  var DefaultHTTPUpgrader HTTPUpgrader
    94  
    95  // UpgradeHTTP is like HTTPUpgrader{}.Upgrade().
    96  func UpgradeHTTP(r *http.Request, w http.ResponseWriter) (net.Conn, *bufio.ReadWriter, Handshake, error) {
    97  	return DefaultHTTPUpgrader.Upgrade(r, w)
    98  }
    99  
   100  // DefaultUpgrader is an Upgrader that holds no options and is used by Upgrade
   101  // function.
   102  var DefaultUpgrader Upgrader
   103  
   104  // Upgrade is like Upgrader{}.Upgrade().
   105  func Upgrade(conn io.ReadWriter) (Handshake, error) {
   106  	return DefaultUpgrader.Upgrade(conn)
   107  }
   108  
   109  // HTTPUpgrader contains options for upgrading connection to websocket from
   110  // net/http Handler arguments.
   111  type HTTPUpgrader struct {
   112  	// Timeout is the maximum amount of time an Upgrade() will spent while
   113  	// writing handshake response.
   114  	//
   115  	// The default is no timeout.
   116  	Timeout time.Duration
   117  
   118  	// Header is an optional http.Header mapping that could be used to
   119  	// write additional headers to the handshake response.
   120  	//
   121  	// Note that if present, it will be written in any result of handshake.
   122  	Header http.Header
   123  
   124  	// Protocol is the select function that is used to select subprotocol from
   125  	// list requested by client. If this field is set, then the first matched
   126  	// protocol is sent to a client as negotiated.
   127  	Protocol func(string) bool
   128  
   129  	// Extension is the select function that is used to select extensions from
   130  	// list requested by client. If this field is set, then the all matched
   131  	// extensions are sent to a client as negotiated.
   132  	//
   133  	// DEPRECATED. Use Negotiate instead.
   134  	Extension func(httphead.Option) bool
   135  
   136  	// Negotiate is the callback that is used to negotiate extensions from
   137  	// the client's offer. If this field is set, then the returned non-zero
   138  	// extensions are sent to the client as accepted extensions in the
   139  	// response.
   140  	//
   141  	// The argument is only valid until the Negotiate callback returns.
   142  	//
   143  	// If returned error is non-nil then connection is rejected and response is
   144  	// sent with appropriate HTTP error code and body set to error message.
   145  	//
   146  	// RejectConnectionError could be used to get more control on response.
   147  	Negotiate func(httphead.Option) (httphead.Option, error)
   148  }
   149  
   150  // Upgrade upgrades http connection to the websocket connection.
   151  //
   152  // It hijacks net.Conn from w and returns received net.Conn and
   153  // bufio.ReadWriter. On successful handshake it returns Handshake struct
   154  // describing handshake info.
   155  func (u HTTPUpgrader) Upgrade(r *http.Request, w http.ResponseWriter) (conn net.Conn, rw *bufio.ReadWriter, hs Handshake, err error) {
   156  	// Hijack connection first to get the ability to write rejection errors the
   157  	// same way as in Upgrader.
   158  	hj, ok := w.(http.Hijacker)
   159  	if ok {
   160  		conn, rw, err = hj.Hijack()
   161  	} else {
   162  		err = ErrNotHijacker
   163  	}
   164  	if err != nil {
   165  		httpError(w, err.Error(), http.StatusInternalServerError)
   166  		return
   167  	}
   168  
   169  	// See https://tools.ietf.org/html/rfc6455#section-4.1
   170  	// The method of the request MUST be GET, and the HTTP version MUST be at least 1.1.
   171  	var nonce string
   172  	if r.Method != http.MethodGet {
   173  		err = ErrHandshakeBadMethod
   174  	} else if r.ProtoMajor < 1 || (r.ProtoMajor == 1 && r.ProtoMinor < 1) {
   175  		err = ErrHandshakeBadProtocol
   176  	} else if r.Host == "" {
   177  		err = ErrHandshakeBadHost
   178  	} else if u := httpGetHeader(r.Header, headerUpgradeCanonical); u != "websocket" && !strings.EqualFold(u, "websocket") {
   179  		err = ErrHandshakeBadUpgrade
   180  	} else if c := httpGetHeader(r.Header, headerConnectionCanonical); c != "Upgrade" && !strHasToken(c, "upgrade") {
   181  		err = ErrHandshakeBadConnection
   182  	} else if nonce = httpGetHeader(r.Header, headerSecKeyCanonical); len(nonce) != nonceSize {
   183  		err = ErrHandshakeBadSecKey
   184  	} else if v := httpGetHeader(r.Header, headerSecVersionCanonical); v != "13" {
   185  		// According to RFC6455:
   186  		//
   187  		// If this version does not match a version understood by the server,
   188  		// the server MUST abort the WebSocket handshake described in this
   189  		// section and instead send an appropriate HTTP error code (such as 426
   190  		// Upgrade Required) and a |Sec-WebSocket-Version| header field
   191  		// indicating the version(s) the server is capable of understanding.
   192  		//
   193  		// So we branching here cause empty or not present version does not
   194  		// meet the ABNF rules of RFC6455:
   195  		//
   196  		// version = DIGIT | (NZDIGIT DIGIT) |
   197  		// ("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
   198  		// ; Limited to 0-255 range, with no leading zeros
   199  		//
   200  		// That is, if version is really invalid – we sent 426 status, if it
   201  		// not present or empty – it is 400.
   202  		if v != "" {
   203  			err = ErrHandshakeUpgradeRequired
   204  		} else {
   205  			err = ErrHandshakeBadSecVersion
   206  		}
   207  	}
   208  	if check := u.Protocol; err == nil && check != nil {
   209  		ps := r.Header[headerSecProtocolCanonical]
   210  		for i := 0; i < len(ps) && err == nil && hs.Protocol == ""; i++ {
   211  			var ok bool
   212  			hs.Protocol, ok = strSelectProtocol(ps[i], check)
   213  			if !ok {
   214  				err = ErrMalformedRequest
   215  			}
   216  		}
   217  	}
   218  	if f := u.Negotiate; err == nil && f != nil {
   219  		for _, h := range r.Header[headerSecExtensionsCanonical] {
   220  			hs.Extensions, err = negotiateExtensions(strToBytes(h), hs.Extensions, f)
   221  			if err != nil {
   222  				break
   223  			}
   224  		}
   225  	}
   226  	// DEPRECATED path.
   227  	if check := u.Extension; err == nil && check != nil && u.Negotiate == nil {
   228  		xs := r.Header[headerSecExtensionsCanonical]
   229  		for i := 0; i < len(xs) && err == nil; i++ {
   230  			var ok bool
   231  			hs.Extensions, ok = btsSelectExtensions(strToBytes(xs[i]), hs.Extensions, check)
   232  			if !ok {
   233  				err = ErrMalformedRequest
   234  			}
   235  		}
   236  	}
   237  
   238  	// Clear deadlines set by server.
   239  	conn.SetDeadline(noDeadline)
   240  	if t := u.Timeout; t != 0 {
   241  		conn.SetWriteDeadline(time.Now().Add(t))
   242  		defer conn.SetWriteDeadline(noDeadline)
   243  	}
   244  
   245  	var header handshakeHeader
   246  	if h := u.Header; h != nil {
   247  		header[0] = HandshakeHeaderHTTP(h)
   248  	}
   249  	if err == nil {
   250  		httpWriteResponseUpgrade(rw.Writer, strToBytes(nonce), hs, header.WriteTo)
   251  		err = rw.Writer.Flush()
   252  	} else {
   253  		var code int
   254  		if rej, ok := err.(*RejectConnectionErrorType); ok {
   255  			code = rej.code
   256  			header[1] = rej.header
   257  		}
   258  		if code == 0 {
   259  			code = http.StatusInternalServerError
   260  		}
   261  		httpWriteResponseError(rw.Writer, err, code, header.WriteTo)
   262  		// Do not store Flush() error to not override already existing one.
   263  		rw.Writer.Flush()
   264  	}
   265  	return
   266  }
   267  
   268  // Upgrader contains options for upgrading connection to websocket.
   269  type Upgrader struct {
   270  	// ReadBufferSize and WriteBufferSize is an I/O buffer sizes.
   271  	// They used to read and write http data while upgrading to WebSocket.
   272  	// Allocated buffers are pooled with sync.Pool to avoid extra allocations.
   273  	//
   274  	// If a size is zero then default value is used.
   275  	//
   276  	// Usually it is useful to set read buffer size bigger than write buffer
   277  	// size because incoming request could contain long header values, such as
   278  	// Cookie. Response, in other way, could be big only if user write multiple
   279  	// custom headers. Usually response takes less than 256 bytes.
   280  	ReadBufferSize, WriteBufferSize int
   281  
   282  	// Protocol is a select function that is used to select subprotocol
   283  	// from list requested by client. If this field is set, then the first matched
   284  	// protocol is sent to a client as negotiated.
   285  	//
   286  	// The argument is only valid until the callback returns.
   287  	Protocol func([]byte) bool
   288  
   289  	// ProtocolCustrom allow user to parse Sec-WebSocket-Protocol header manually.
   290  	// Note that returned bytes must be valid until Upgrade returns.
   291  	// If ProtocolCustom is set, it used instead of Protocol function.
   292  	ProtocolCustom func([]byte) (string, bool)
   293  
   294  	// Extension is a select function that is used to select extensions
   295  	// from list requested by client. If this field is set, then the all matched
   296  	// extensions are sent to a client as negotiated.
   297  	//
   298  	// Note that Extension may be called multiple times and implementations
   299  	// must track uniqueness of accepted extensions manually.
   300  	//
   301  	// The argument is only valid until the callback returns.
   302  	//
   303  	// According to the RFC6455 order of extensions passed by a client is
   304  	// significant. That is, returning true from this function means that no
   305  	// other extension with the same name should be checked because server
   306  	// accepted the most preferable extension right now:
   307  	// "Note that the order of extensions is significant.  Any interactions between
   308  	// multiple extensions MAY be defined in the documents defining the extensions.
   309  	// In the absence of such definitions, the interpretation is that the header
   310  	// fields listed by the client in its request represent a preference of the
   311  	// header fields it wishes to use, with the first options listed being most
   312  	// preferable."
   313  	//
   314  	// DEPRECATED. Use Negotiate instead.
   315  	Extension func(httphead.Option) bool
   316  
   317  	// ExtensionCustom allow user to parse Sec-WebSocket-Extensions header
   318  	// manually.
   319  	//
   320  	// If ExtensionCustom() decides to accept received extension, it must
   321  	// append appropriate option to the given slice of httphead.Option.
   322  	// It returns results of append() to the given slice and a flag that
   323  	// reports whether given header value is wellformed or not.
   324  	//
   325  	// Note that ExtensionCustom may be called multiple times and
   326  	// implementations must track uniqueness of accepted extensions manually.
   327  	//
   328  	// Note that returned options should be valid until Upgrade returns.
   329  	// If ExtensionCustom is set, it used instead of Extension function.
   330  	ExtensionCustom func([]byte, []httphead.Option) ([]httphead.Option, bool)
   331  
   332  	// Negotiate is the callback that is used to negotiate extensions from
   333  	// the client's offer. If this field is set, then the returned non-zero
   334  	// extensions are sent to the client as accepted extensions in the
   335  	// response.
   336  	//
   337  	// The argument is only valid until the Negotiate callback returns.
   338  	//
   339  	// If returned error is non-nil then connection is rejected and response is
   340  	// sent with appropriate HTTP error code and body set to error message.
   341  	//
   342  	// RejectConnectionError could be used to get more control on response.
   343  	Negotiate func(httphead.Option) (httphead.Option, error)
   344  
   345  	// Header is an optional HandshakeHeader instance that could be used to
   346  	// write additional headers to the handshake response.
   347  	//
   348  	// It used instead of any key-value mappings to avoid allocations in user
   349  	// land.
   350  	//
   351  	// Note that if present, it will be written in any result of handshake.
   352  	Header HandshakeHeader
   353  
   354  	// OnRequest is a callback that will be called after request line
   355  	// successful parsing.
   356  	//
   357  	// The arguments are only valid until the callback returns.
   358  	//
   359  	// If returned error is non-nil then connection is rejected and response is
   360  	// sent with appropriate HTTP error code and body set to error message.
   361  	//
   362  	// RejectConnectionError could be used to get more control on response.
   363  	OnRequest func(uri []byte) error
   364  
   365  	// OnHost is a callback that will be called after "Host" header successful
   366  	// parsing.
   367  	//
   368  	// It is separated from OnHeader callback because the Host header must be
   369  	// present in each request since HTTP/1.1. Thus Host header is non-optional
   370  	// and required for every WebSocket handshake.
   371  	//
   372  	// The arguments are only valid until the callback returns.
   373  	//
   374  	// If returned error is non-nil then connection is rejected and response is
   375  	// sent with appropriate HTTP error code and body set to error message.
   376  	//
   377  	// RejectConnectionError could be used to get more control on response.
   378  	OnHost func(host []byte) error
   379  
   380  	// OnHeader is a callback that will be called after successful parsing of
   381  	// header, that is not used during WebSocket handshake procedure. That is,
   382  	// it will be called with non-websocket headers, which could be relevant
   383  	// for application-level logic.
   384  	//
   385  	// The arguments are only valid until the callback returns.
   386  	//
   387  	// If returned error is non-nil then connection is rejected and response is
   388  	// sent with appropriate HTTP error code and body set to error message.
   389  	//
   390  	// RejectConnectionError could be used to get more control on response.
   391  	OnHeader func(key, value []byte) error
   392  
   393  	// OnBeforeUpgrade is a callback that will be called before sending
   394  	// successful upgrade response.
   395  	//
   396  	// Setting OnBeforeUpgrade allows user to make final application-level
   397  	// checks and decide whether this connection is allowed to successfully
   398  	// upgrade to WebSocket.
   399  	//
   400  	// It must return non-nil either HandshakeHeader or error and never both.
   401  	//
   402  	// If returned error is non-nil then connection is rejected and response is
   403  	// sent with appropriate HTTP error code and body set to error message.
   404  	//
   405  	// RejectConnectionError could be used to get more control on response.
   406  	OnBeforeUpgrade func() (header HandshakeHeader, err error)
   407  }
   408  
   409  // Upgrade zero-copy upgrades connection to WebSocket. It interprets given conn
   410  // as connection with incoming HTTP Upgrade request.
   411  //
   412  // It is a caller responsibility to manage i/o timeouts on conn.
   413  //
   414  // Non-nil error means that request for the WebSocket upgrade is invalid or
   415  // malformed and usually connection should be closed.
   416  // Even when error is non-nil Upgrade will write appropriate response into
   417  // connection in compliance with RFC.
   418  func (u Upgrader) Upgrade(conn io.ReadWriter) (hs Handshake, err error) {
   419  	// headerSeen constants helps to report whether or not some header was seen
   420  	// during reading request bytes.
   421  	const (
   422  		headerSeenHost = 1 << iota
   423  		headerSeenUpgrade
   424  		headerSeenConnection
   425  		headerSeenSecVersion
   426  		headerSeenSecKey
   427  
   428  		// headerSeenAll is the value that we expect to receive at the end of
   429  		// headers read/parse loop.
   430  		headerSeenAll = 0 |
   431  			headerSeenHost |
   432  			headerSeenUpgrade |
   433  			headerSeenConnection |
   434  			headerSeenSecVersion |
   435  			headerSeenSecKey
   436  	)
   437  
   438  	// Prepare I/O buffers.
   439  	// TODO(gobwas): make it configurable.
   440  	br := pbufio.GetReader(conn,
   441  		nonZero(u.ReadBufferSize, DefaultServerReadBufferSize),
   442  	)
   443  	bw := pbufio.GetWriter(conn,
   444  		nonZero(u.WriteBufferSize, DefaultServerWriteBufferSize),
   445  	)
   446  	defer func() {
   447  		pbufio.PutReader(br)
   448  		pbufio.PutWriter(bw)
   449  	}()
   450  
   451  	// Read HTTP request line like "GET /ws HTTP/1.1".
   452  	rl, err := readLine(br)
   453  	if err != nil {
   454  		return
   455  	}
   456  	// Parse request line data like HTTP version, uri and method.
   457  	req, err := httpParseRequestLine(rl)
   458  	if err != nil {
   459  		return
   460  	}
   461  
   462  	// Prepare stack-based handshake header list.
   463  	header := handshakeHeader{
   464  		0: u.Header,
   465  	}
   466  
   467  	// Parse and check HTTP request.
   468  	// As RFC6455 says:
   469  	//   The client's opening handshake consists of the following parts. If the
   470  	//   server, while reading the handshake, finds that the client did not
   471  	//   send a handshake that matches the description below (note that as per
   472  	//   [RFC2616], the order of the header fields is not important), including
   473  	//   but not limited to any violations of the ABNF grammar specified for
   474  	//   the components of the handshake, the server MUST stop processing the
   475  	//   client's handshake and return an HTTP response with an appropriate
   476  	//   error code (such as 400 Bad Request).
   477  	//
   478  	// See https://tools.ietf.org/html/rfc6455#section-4.2.1
   479  
   480  	// An HTTP/1.1 or higher GET request, including a "Request-URI".
   481  	//
   482  	// Even if RFC says "1.1 or higher" without mentioning the part of the
   483  	// version, we apply it only to minor part.
   484  	switch {
   485  	case req.major != 1 || req.minor < 1:
   486  		// Abort processing the whole request because we do not even know how
   487  		// to actually parse it.
   488  		err = ErrHandshakeBadProtocol
   489  
   490  	case btsToString(req.method) != http.MethodGet:
   491  		err = ErrHandshakeBadMethod
   492  
   493  	default:
   494  		if onRequest := u.OnRequest; onRequest != nil {
   495  			err = onRequest(req.uri)
   496  		}
   497  	}
   498  	// Start headers read/parse loop.
   499  	var (
   500  		// headerSeen reports which header was seen by setting corresponding
   501  		// bit on.
   502  		headerSeen byte
   503  
   504  		nonce = make([]byte, nonceSize)
   505  	)
   506  	for err == nil {
   507  		line, e := readLine(br)
   508  		if e != nil {
   509  			return hs, e
   510  		}
   511  		if len(line) == 0 {
   512  			// Blank line, no more lines to read.
   513  			break
   514  		}
   515  
   516  		k, v, ok := httpParseHeaderLine(line)
   517  		if !ok {
   518  			err = ErrMalformedRequest
   519  			break
   520  		}
   521  
   522  		switch btsToString(k) {
   523  		case headerHostCanonical:
   524  			headerSeen |= headerSeenHost
   525  			if onHost := u.OnHost; onHost != nil {
   526  				err = onHost(v)
   527  			}
   528  
   529  		case headerUpgradeCanonical:
   530  			headerSeen |= headerSeenUpgrade
   531  			if !bytes.Equal(v, specHeaderValueUpgrade) && !bytes.EqualFold(v, specHeaderValueUpgrade) {
   532  				err = ErrHandshakeBadUpgrade
   533  			}
   534  
   535  		case headerConnectionCanonical:
   536  			headerSeen |= headerSeenConnection
   537  			if !bytes.Equal(v, specHeaderValueConnection) && !btsHasToken(v, specHeaderValueConnectionLower) {
   538  				err = ErrHandshakeBadConnection
   539  			}
   540  
   541  		case headerSecVersionCanonical:
   542  			headerSeen |= headerSeenSecVersion
   543  			if !bytes.Equal(v, specHeaderValueSecVersion) {
   544  				err = ErrHandshakeUpgradeRequired
   545  			}
   546  
   547  		case headerSecKeyCanonical:
   548  			headerSeen |= headerSeenSecKey
   549  			if len(v) != nonceSize {
   550  				err = ErrHandshakeBadSecKey
   551  			} else {
   552  				copy(nonce[:], v)
   553  			}
   554  
   555  		case headerSecProtocolCanonical:
   556  			if custom, check := u.ProtocolCustom, u.Protocol; hs.Protocol == "" && (custom != nil || check != nil) {
   557  				var ok bool
   558  				if custom != nil {
   559  					hs.Protocol, ok = custom(v)
   560  				} else {
   561  					hs.Protocol, ok = btsSelectProtocol(v, check)
   562  				}
   563  				if !ok {
   564  					err = ErrMalformedRequest
   565  				}
   566  			}
   567  
   568  		case headerSecExtensionsCanonical:
   569  			if f := u.Negotiate; err == nil && f != nil {
   570  				hs.Extensions, err = negotiateExtensions(v, hs.Extensions, f)
   571  			}
   572  			// DEPRECATED path.
   573  			if custom, check := u.ExtensionCustom, u.Extension; u.Negotiate == nil && (custom != nil || check != nil) {
   574  				var ok bool
   575  				if custom != nil {
   576  					hs.Extensions, ok = custom(v, hs.Extensions)
   577  				} else {
   578  					hs.Extensions, ok = btsSelectExtensions(v, hs.Extensions, check)
   579  				}
   580  				if !ok {
   581  					err = ErrMalformedRequest
   582  				}
   583  			}
   584  
   585  		default:
   586  			if onHeader := u.OnHeader; onHeader != nil {
   587  				err = onHeader(k, v)
   588  			}
   589  		}
   590  	}
   591  	switch {
   592  	case err == nil && headerSeen != headerSeenAll:
   593  		switch {
   594  		case headerSeen&headerSeenHost == 0:
   595  			// As RFC2616 says:
   596  			//   A client MUST include a Host header field in all HTTP/1.1
   597  			//   request messages. If the requested URI does not include an
   598  			//   Internet host name for the service being requested, then the
   599  			//   Host header field MUST be given with an empty value. An
   600  			//   HTTP/1.1 proxy MUST ensure that any request message it
   601  			//   forwards does contain an appropriate Host header field that
   602  			//   identifies the service being requested by the proxy. All
   603  			//   Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad
   604  			//   Request) status code to any HTTP/1.1 request message which
   605  			//   lacks a Host header field.
   606  			err = ErrHandshakeBadHost
   607  		case headerSeen&headerSeenUpgrade == 0:
   608  			err = ErrHandshakeBadUpgrade
   609  		case headerSeen&headerSeenConnection == 0:
   610  			err = ErrHandshakeBadConnection
   611  		case headerSeen&headerSeenSecVersion == 0:
   612  			// In case of empty or not present version we do not send 426 status,
   613  			// because it does not meet the ABNF rules of RFC6455:
   614  			//
   615  			// version = DIGIT | (NZDIGIT DIGIT) |
   616  			// ("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
   617  			// ; Limited to 0-255 range, with no leading zeros
   618  			//
   619  			// That is, if version is really invalid – we sent 426 status as above, if it
   620  			// not present – it is 400.
   621  			err = ErrHandshakeBadSecVersion
   622  		case headerSeen&headerSeenSecKey == 0:
   623  			err = ErrHandshakeBadSecKey
   624  		default:
   625  			panic("unknown headers state")
   626  		}
   627  
   628  	case err == nil && u.OnBeforeUpgrade != nil:
   629  		header[1], err = u.OnBeforeUpgrade()
   630  	}
   631  	if err != nil {
   632  		var code int
   633  		if rej, ok := err.(*RejectConnectionErrorType); ok {
   634  			code = rej.code
   635  			header[1] = rej.header
   636  		}
   637  		if code == 0 {
   638  			code = http.StatusInternalServerError
   639  		}
   640  		httpWriteResponseError(bw, err, code, header.WriteTo)
   641  		// Do not store Flush() error to not override already existing one.
   642  		bw.Flush()
   643  		return
   644  	}
   645  
   646  	httpWriteResponseUpgrade(bw, nonce, hs, header.WriteTo)
   647  	err = bw.Flush()
   648  
   649  	return
   650  }
   651  
   652  type handshakeHeader [2]HandshakeHeader
   653  
   654  func (hs handshakeHeader) WriteTo(w io.Writer) (n int64, err error) {
   655  	for i := 0; i < len(hs) && err == nil; i++ {
   656  		if h := hs[i]; h != nil {
   657  			var m int64
   658  			m, err = h.WriteTo(w)
   659  			n += m
   660  		}
   661  	}
   662  	return n, err
   663  }