server.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright 2013 Gary Burd. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package websocket
  5. import (
  6. "bufio"
  7. "errors"
  8. "net"
  9. "net/http"
  10. "net/url"
  11. "strings"
  12. "time"
  13. )
  14. // HandshakeError describes an error with the handshake from the peer.
  15. type HandshakeError struct {
  16. message string
  17. }
  18. func (e HandshakeError) Error() string { return e.message }
  19. const (
  20. defaultReadBufferSize = 4096
  21. defaultWriteBufferSize = 4096
  22. )
  23. type Upgrader struct {
  24. // HandshakeTimeout specifies the duration for the handshake to complete.
  25. HandshakeTimeout time.Duration
  26. // Input and output buffer sizes. If the buffer size is zero, then
  27. // default values will be used.
  28. ReadBufferSize, WriteBufferSize int
  29. // Subprotocols specifies the server's supported protocols. If Subprotocols
  30. // is nil, then Upgrade does not negotiate a subprotocol.
  31. Subprotocols []string
  32. // Error specifies the function for generating HTTP error responses. If Error
  33. // is nil, then http.Error is used to generate the HTTP response.
  34. Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
  35. // CheckOrigin returns true if the request Origin header is acceptable.
  36. // If CheckOrigin is nil, the host in the Origin header must match
  37. // the host of the request.
  38. CheckOrigin func(r *http.Request) bool
  39. }
  40. // Return an error depending on settings on the Upgrader
  41. func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
  42. err := HandshakeError{reason}
  43. if u.Error != nil {
  44. u.Error(w, r, status, err)
  45. } else {
  46. http.Error(w, reason, status)
  47. }
  48. return nil, err
  49. }
  50. // Check if the passed subprotocol is supported by the server
  51. func (u *Upgrader) hasSubprotocol(subprotocol string) bool {
  52. if u.Subprotocols == nil {
  53. return false
  54. }
  55. for _, s := range u.Subprotocols {
  56. if s == subprotocol {
  57. return true
  58. }
  59. }
  60. return false
  61. }
  62. // Check if host in Origin header matches host of request
  63. func (u *Upgrader) checkSameOrigin(r *http.Request) bool {
  64. origin := r.Header.Get("Origin")
  65. if origin == "" {
  66. return false
  67. }
  68. uri, err := url.ParseRequestURI(origin)
  69. if err != nil {
  70. return false
  71. }
  72. return uri.Host == r.Host
  73. }
  74. // Upgrade upgrades the HTTP server connection to the WebSocket protocol.
  75. //
  76. // The responseHeader is included in the response to the client's upgrade
  77. // request. Use the responseHeader to specify cookies (Set-Cookie).
  78. //
  79. // The connection buffers IO to the underlying network connection.
  80. // Messages can be larger than the buffers.
  81. //
  82. // If the request is not a valid WebSocket handshake, then Upgrade returns an
  83. // error of type HandshakeError. Depending on settings on the Upgrader,
  84. // an error message already has been returned to the caller.
  85. func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
  86. if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" {
  87. return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
  88. }
  89. if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
  90. return u.returnError(w, r, http.StatusBadRequest, "websocket: connection header != upgrade")
  91. }
  92. if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
  93. return u.returnError(w, r, http.StatusBadRequest, "websocket: upgrade != websocket")
  94. }
  95. checkOrigin := u.CheckOrigin
  96. if checkOrigin == nil {
  97. checkOrigin = u.checkSameOrigin
  98. }
  99. if !checkOrigin(r) {
  100. return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
  101. }
  102. var challengeKey string
  103. values := r.Header["Sec-Websocket-Key"]
  104. if len(values) == 0 || values[0] == "" {
  105. return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
  106. }
  107. challengeKey = values[0]
  108. var (
  109. netConn net.Conn
  110. br *bufio.Reader
  111. err error
  112. )
  113. h, ok := w.(http.Hijacker)
  114. if !ok {
  115. return nil, errors.New("websocket: response does not implement http.Hijacker")
  116. }
  117. var rw *bufio.ReadWriter
  118. netConn, rw, err = h.Hijack()
  119. br = rw.Reader
  120. if br.Buffered() > 0 {
  121. netConn.Close()
  122. return nil, errors.New("websocket: client sent data before handshake is complete")
  123. }
  124. readBufSize := u.ReadBufferSize
  125. if readBufSize == 0 {
  126. readBufSize = defaultReadBufferSize
  127. }
  128. writeBufSize := u.WriteBufferSize
  129. if writeBufSize == 0 {
  130. writeBufSize = defaultWriteBufferSize
  131. }
  132. c := newConn(netConn, true, readBufSize, writeBufSize)
  133. if u.Subprotocols != nil {
  134. for _, proto := range Subprotocols(r) {
  135. if u.hasSubprotocol(proto) {
  136. c.subprotocol = proto
  137. break
  138. }
  139. }
  140. } else if responseHeader != nil {
  141. c.subprotocol = responseHeader.Get("Sec-Websocket-Protocol")
  142. }
  143. p := c.writeBuf[:0]
  144. p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
  145. p = append(p, computeAcceptKey(challengeKey)...)
  146. p = append(p, "\r\n"...)
  147. if c.subprotocol != "" {
  148. p = append(p, "Sec-Websocket-Protocol: "...)
  149. p = append(p, c.subprotocol...)
  150. p = append(p, "\r\n"...)
  151. }
  152. for k, vs := range responseHeader {
  153. if k == "Sec-Websocket-Protocol" {
  154. continue
  155. }
  156. for _, v := range vs {
  157. p = append(p, k...)
  158. p = append(p, ": "...)
  159. for i := 0; i < len(v); i++ {
  160. b := v[i]
  161. if b <= 31 {
  162. // prevent response splitting.
  163. b = ' '
  164. }
  165. p = append(p, b)
  166. }
  167. p = append(p, "\r\n"...)
  168. }
  169. }
  170. p = append(p, "\r\n"...)
  171. if u.HandshakeTimeout > 0 {
  172. netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
  173. }
  174. if _, err = netConn.Write(p); err != nil {
  175. netConn.Close()
  176. return nil, err
  177. }
  178. return c, nil
  179. }
  180. // This method is deprecated, use websocket.Upgrader instead.
  181. //
  182. // Upgrade upgrades the HTTP server connection to the WebSocket protocol.
  183. //
  184. // The application is responsible for checking the request origin before
  185. // calling Upgrade. An example implementation of the same origin policy is:
  186. //
  187. // if req.Header.Get("Origin") != "http://"+req.Host {
  188. // http.Error(w, "Origin not allowed", 403)
  189. // return
  190. // }
  191. //
  192. // If the endpoint supports subprotocols, then the application is responsible
  193. // for negotiating the protocol used on the connection. Use the Subprotocols()
  194. // function to get the subprotocols requested by the client. Use the
  195. // Sec-Websocket-Protocol response header to specify the subprotocol selected
  196. // by the application.
  197. //
  198. // The responseHeader is included in the response to the client's upgrade
  199. // request. Use the responseHeader to specify cookies (Set-Cookie) and the
  200. // negotiated subprotocol (Sec-Websocket-Protocol).
  201. //
  202. // The connection buffers IO to the underlying network connection. The
  203. // readBufSize and writeBufSize parameters specify the size of the buffers to
  204. // use. Messages can be larger than the buffers.
  205. //
  206. // If the request is not a valid WebSocket handshake, then Upgrade returns an
  207. // error of type HandshakeError. Applications should handle this error by
  208. // replying to the client with an HTTP error response.
  209. func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
  210. u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
  211. u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
  212. // don't return errors to maintain backwards compatibility
  213. }
  214. u.CheckOrigin = func(r *http.Request) bool {
  215. // allow all connections by default
  216. return true
  217. }
  218. return u.Upgrade(w, r, responseHeader)
  219. }
  220. // Subprotocols returns the subprotocols requested by the client in the
  221. // Sec-Websocket-Protocol header.
  222. func Subprotocols(r *http.Request) []string {
  223. h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
  224. if h == "" {
  225. return nil
  226. }
  227. protocols := strings.Split(h, ",")
  228. for i := range protocols {
  229. protocols[i] = strings.TrimSpace(protocols[i])
  230. }
  231. return protocols
  232. }