// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package websocketimport ()// HandshakeError describes an error with the handshake from the peer.typeHandshakeErrorstruct { message string}func ( HandshakeError) () string { return .message }// Upgrader specifies parameters for upgrading an HTTP connection to a// WebSocket connection.//// It is safe to call Upgrader's methods concurrently.typeUpgraderstruct {// HandshakeTimeout specifies the duration for the handshake to complete. HandshakeTimeout time.Duration// ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer // size is zero, then buffers allocated by the HTTP server are used. The // I/O buffer sizes do not limit the size of the messages that can be sent // or received. ReadBufferSize, WriteBufferSize int// WriteBufferPool is a pool of buffers for write operations. If the value // is not set, then write buffers are allocated to the connection for the // lifetime of the connection. // // A pool is most useful when the application has a modest volume of writes // across a large number of connections. // // Applications should use a single pool for each unique value of // WriteBufferSize. WriteBufferPool BufferPool// Subprotocols specifies the server's supported protocols in order of // preference. If this field is not nil, then the Upgrade method negotiates a // subprotocol by selecting the first match in this list with a protocol // requested by the client. If there's no match, then no protocol is // negotiated (the Sec-Websocket-Protocol header is not included in the // handshake response). Subprotocols []string// Error specifies the function for generating HTTP error responses. If Error // is nil, then http.Error is used to generate the HTTP response. Error func(w http.ResponseWriter, r *http.Request, status int, reason error)// CheckOrigin returns true if the request Origin header is acceptable. If // CheckOrigin is nil, then a safe default is used: return false if the // Origin request header is present and the origin host is not equal to // request Host header. // // A CheckOrigin function should carefully validate the request origin to // prevent cross-site request forgery. CheckOrigin func(r *http.Request) bool// EnableCompression specify if the server should attempt to negotiate per // message compression (RFC 7692). Setting this value to true does not // guarantee that compression will be supported. Currently only "no context // takeover" modes are supported. EnableCompression bool}func ( *Upgrader) ( http.ResponseWriter, *http.Request, int, string) (*Conn, error) { := HandshakeError{}if .Error != nil { .Error(, , , ) } else { .Header().Set("Sec-Websocket-Version", "13")http.Error(, http.StatusText(), ) }returnnil, }// checkSameOrigin returns true if the origin is not set or is equal to the request host.func checkSameOrigin( *http.Request) bool { := .Header["Origin"]iflen() == 0 {returntrue } , := url.Parse([0])if != nil {returnfalse }returnequalASCIIFold(.Host, .Host)}func ( *Upgrader) ( *http.Request, http.Header) string {if .Subprotocols != nil { := Subprotocols()for , := range .Subprotocols {for , := range {if == {return } } } } elseif != nil {return .Get("Sec-Websocket-Protocol") }return""}// Upgrade upgrades the HTTP server connection to the WebSocket protocol.//// The responseHeader is included in the response to the client's upgrade// request. Use the responseHeader to specify cookies (Set-Cookie). To specify// subprotocols supported by the server, set Upgrader.Subprotocols directly.//// If the upgrade fails, then Upgrade replies to the client with an HTTP error// response.func ( *Upgrader) ( http.ResponseWriter, *http.Request, http.Header) (*Conn, error) {const = "websocket: the client is not using the websocket protocol: "if !tokenListContainsValue(.Header, "Connection", "upgrade") {return .returnError(, , http.StatusBadRequest, +"'upgrade' token not found in 'Connection' header") }if !tokenListContainsValue(.Header, "Upgrade", "websocket") {return .returnError(, , http.StatusBadRequest, +"'websocket' token not found in 'Upgrade' header") }if .Method != http.MethodGet {return .returnError(, , http.StatusMethodNotAllowed, +"request method is not GET") }if !tokenListContainsValue(.Header, "Sec-Websocket-Version", "13") {return .returnError(, , http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header") }if , := ["Sec-Websocket-Extensions"]; {return .returnError(, , http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported") } := .CheckOriginif == nil { = checkSameOrigin }if !() {return .returnError(, , http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin") } := .Header.Get("Sec-Websocket-Key")if !isValidChallengeKey() {return .returnError(, , http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header must be Base64 encoded value of 16-byte in length") } := .selectSubprotocol(, )// Negotiate PMCEvarboolif .EnableCompression {for , := rangeparseExtensions(.Header) {if [""] != "permessage-deflate" {continue } = truebreak } } , := .(http.Hijacker)if ! {return .returnError(, , http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") }var *bufio.ReadWriter , , := .Hijack()if != nil {return .returnError(, , http.StatusInternalServerError, .Error()) }if .Reader.Buffered() > 0 { .Close()returnnil, errors.New("websocket: client sent data before handshake is complete") }var *bufio.Readerif .ReadBufferSize == 0 && bufioReaderSize(, .Reader) > 256 {// Reuse hijacked buffered reader as connection reader. = .Reader } := bufioWriterBuffer(, .Writer)var []byteif .WriteBufferPool == nil && .WriteBufferSize == 0 && len() >= maxFrameHeaderSize+256 {// Reuse hijacked write buffer as connection buffer. = } := newConn(, true, .ReadBufferSize, .WriteBufferSize, .WriteBufferPool, , ) .subprotocol = if { .newCompressionWriter = compressNoContextTakeover .newDecompressionReader = decompressNoContextTakeover }// Use larger of hijacked buffer and connection write buffer for header. := iflen(.writeBuf) > len() { = .writeBuf } = [:0] = append(, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) = append(, computeAcceptKey()...) = append(, "\r\n"...)if .subprotocol != "" { = append(, "Sec-WebSocket-Protocol: "...) = append(, .subprotocol...) = append(, "\r\n"...) }if { = append(, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...) }for , := range {if == "Sec-Websocket-Protocol" {continue }for , := range { = append(, ...) = append(, ": "...)for := 0; < len(); ++ { := []if <= 31 {// prevent response splitting. = ' ' } = append(, ) } = append(, "\r\n"...) } } = append(, "\r\n"...)// Clear deadlines set by HTTP server. .SetDeadline(time.Time{})if .HandshakeTimeout > 0 { .SetWriteDeadline(time.Now().Add(.HandshakeTimeout)) }if _, = .Write(); != nil { .Close()returnnil, }if .HandshakeTimeout > 0 { .SetWriteDeadline(time.Time{}) }return , nil}// Upgrade upgrades the HTTP server connection to the WebSocket protocol.//// Deprecated: Use websocket.Upgrader instead.//// Upgrade does not perform origin checking. The application is responsible for// checking the Origin header before calling Upgrade. An example implementation// of the same origin policy check is://// if req.Header.Get("Origin") != "http://"+req.Host {// http.Error(w, "Origin not allowed", http.StatusForbidden)// return// }//// If the endpoint supports subprotocols, then the application is responsible// for negotiating the protocol used on the connection. Use the Subprotocols()// function to get the subprotocols requested by the client. Use the// Sec-Websocket-Protocol response header to specify the subprotocol selected// by the application.//// The responseHeader is included in the response to the client's upgrade// request. Use the responseHeader to specify cookies (Set-Cookie) and the// negotiated subprotocol (Sec-Websocket-Protocol).//// The connection buffers IO to the underlying network connection. The// readBufSize and writeBufSize parameters specify the size of the buffers to// use. Messages can be larger than the buffers.//// If the request is not a valid WebSocket handshake, then Upgrade returns an// error of type HandshakeError. Applications should handle this error by// replying to the client with an HTTP error response.func ( http.ResponseWriter, *http.Request, http.Header, , int) (*Conn, error) { := Upgrader{ReadBufferSize: , WriteBufferSize: } .Error = func( http.ResponseWriter, *http.Request, int, error) {// don't return errors to maintain backwards compatibility } .CheckOrigin = func( *http.Request) bool {// allow all connections by defaultreturntrue }return .Upgrade(, , )}// Subprotocols returns the subprotocols requested by the client in the// Sec-Websocket-Protocol header.func ( *http.Request) []string { := strings.TrimSpace(.Header.Get("Sec-Websocket-Protocol"))if == "" {returnnil } := strings.Split(, ",")for := range { [] = strings.TrimSpace([]) }return}// IsWebSocketUpgrade returns true if the client requested upgrade to the// WebSocket protocol.func ( *http.Request) bool {returntokenListContainsValue(.Header, "Connection", "upgrade") &&tokenListContainsValue(.Header, "Upgrade", "websocket")}// bufioReaderSize size returns the size of a bufio.Reader.func bufioReaderSize( io.Reader, *bufio.Reader) int {// This code assumes that peek on a reset reader returns // bufio.Reader.buf[:0]. // TODO: Use bufio.Reader.Size() after Go 1.10 .Reset()if , := .Peek(0); == nil {returncap() }return0}// writeHook is an io.Writer that records the last slice passed to it vio// io.Writer.Write.type writeHook struct { p []byte}func ( *writeHook) ( []byte) (int, error) { .p = returnlen(), nil}// bufioWriterBuffer grabs the buffer from a bufio.Writer.func bufioWriterBuffer( io.Writer, *bufio.Writer) []byte {// This code assumes that bufio.Writer.buf[:1] is passed to the // bufio.Writer's underlying writer.varwriteHook .Reset(&) .WriteByte(0) .Flush() .Reset()return .p[:cap(.p)]}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.