ws.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. // Copyright 2021 The NATS Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package nats
  14. import (
  15. "bufio"
  16. "bytes"
  17. "compress/flate"
  18. "crypto/rand"
  19. "crypto/sha1"
  20. "encoding/base64"
  21. "encoding/binary"
  22. "errors"
  23. "fmt"
  24. "io"
  25. "io/ioutil"
  26. mrand "math/rand"
  27. "net/http"
  28. "net/url"
  29. "strings"
  30. "time"
  31. "unicode/utf8"
  32. )
  33. type wsOpCode int
  34. const (
  35. // From https://tools.ietf.org/html/rfc6455#section-5.2
  36. wsTextMessage = wsOpCode(1)
  37. wsBinaryMessage = wsOpCode(2)
  38. wsCloseMessage = wsOpCode(8)
  39. wsPingMessage = wsOpCode(9)
  40. wsPongMessage = wsOpCode(10)
  41. wsFinalBit = 1 << 7
  42. wsRsv1Bit = 1 << 6 // Used for compression, from https://tools.ietf.org/html/rfc7692#section-6
  43. wsRsv2Bit = 1 << 5
  44. wsRsv3Bit = 1 << 4
  45. wsMaskBit = 1 << 7
  46. wsContinuationFrame = 0
  47. wsMaxFrameHeaderSize = 14
  48. wsMaxControlPayloadSize = 125
  49. // From https://tools.ietf.org/html/rfc6455#section-11.7
  50. wsCloseStatusNormalClosure = 1000
  51. wsCloseStatusNoStatusReceived = 1005
  52. wsCloseStatusAbnormalClosure = 1006
  53. wsCloseStatusInvalidPayloadData = 1007
  54. wsScheme = "ws"
  55. wsSchemeTLS = "wss"
  56. wsPMCExtension = "permessage-deflate" // per-message compression
  57. wsPMCSrvNoCtx = "server_no_context_takeover"
  58. wsPMCCliNoCtx = "client_no_context_takeover"
  59. wsPMCReqHeaderValue = wsPMCExtension + "; " + wsPMCSrvNoCtx + "; " + wsPMCCliNoCtx
  60. )
  61. // From https://tools.ietf.org/html/rfc6455#section-1.3
  62. var wsGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
  63. // As per https://tools.ietf.org/html/rfc7692#section-7.2.2
  64. // add 0x00, 0x00, 0xff, 0xff and then a final block so that flate reader
  65. // does not report unexpected EOF.
  66. var compressFinalBlock = []byte{0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff}
  67. type websocketReader struct {
  68. r io.Reader
  69. pending [][]byte
  70. ib []byte
  71. ff bool
  72. fc bool
  73. dc io.ReadCloser
  74. nc *Conn
  75. }
  76. type websocketWriter struct {
  77. w io.Writer
  78. compress bool
  79. compressor *flate.Writer
  80. ctrlFrames [][]byte // pending frames that should be sent at the next Write()
  81. cm []byte // close message that needs to be sent when everything else has been sent
  82. cmDone bool // a close message has been added or sent (never going back to false)
  83. noMoreSend bool // if true, even if there is a Write() call, we should not send anything
  84. }
  85. type decompressorBuffer struct {
  86. buf []byte
  87. rem int
  88. off int
  89. final bool
  90. }
  91. func newDecompressorBuffer(buf []byte) *decompressorBuffer {
  92. return &decompressorBuffer{buf: buf, rem: len(buf)}
  93. }
  94. func (d *decompressorBuffer) Read(p []byte) (int, error) {
  95. if d.buf == nil {
  96. return 0, io.EOF
  97. }
  98. lim := d.rem
  99. if len(p) < lim {
  100. lim = len(p)
  101. }
  102. n := copy(p, d.buf[d.off:d.off+lim])
  103. d.off += n
  104. d.rem -= n
  105. d.checkRem()
  106. return n, nil
  107. }
  108. func (d *decompressorBuffer) checkRem() {
  109. if d.rem != 0 {
  110. return
  111. }
  112. if !d.final {
  113. d.buf = compressFinalBlock
  114. d.off = 0
  115. d.rem = len(d.buf)
  116. d.final = true
  117. } else {
  118. d.buf = nil
  119. }
  120. }
  121. func (d *decompressorBuffer) ReadByte() (byte, error) {
  122. if d.buf == nil {
  123. return 0, io.EOF
  124. }
  125. b := d.buf[d.off]
  126. d.off++
  127. d.rem--
  128. d.checkRem()
  129. return b, nil
  130. }
  131. func wsNewReader(r io.Reader) *websocketReader {
  132. return &websocketReader{r: r, ff: true}
  133. }
  134. func (r *websocketReader) Read(p []byte) (int, error) {
  135. var err error
  136. var buf []byte
  137. if l := len(r.ib); l > 0 {
  138. buf = r.ib
  139. r.ib = nil
  140. } else {
  141. if len(r.pending) > 0 {
  142. return r.drainPending(p), nil
  143. }
  144. // Get some data from the underlying reader.
  145. n, err := r.r.Read(p)
  146. if err != nil {
  147. return 0, err
  148. }
  149. buf = p[:n]
  150. }
  151. // Now parse this and decode frames. We will possibly read more to
  152. // ensure that we get a full frame.
  153. var (
  154. tmpBuf []byte
  155. pos int
  156. max = len(buf)
  157. rem = 0
  158. )
  159. for pos < max {
  160. b0 := buf[pos]
  161. frameType := wsOpCode(b0 & 0xF)
  162. final := b0&wsFinalBit != 0
  163. compressed := b0&wsRsv1Bit != 0
  164. pos++
  165. tmpBuf, pos, err = wsGet(r.r, buf, pos, 1)
  166. if err != nil {
  167. return 0, err
  168. }
  169. b1 := tmpBuf[0]
  170. // Store size in case it is < 125
  171. rem = int(b1 & 0x7F)
  172. switch frameType {
  173. case wsPingMessage, wsPongMessage, wsCloseMessage:
  174. if rem > wsMaxControlPayloadSize {
  175. return 0, fmt.Errorf(
  176. fmt.Sprintf("control frame length bigger than maximum allowed of %v bytes",
  177. wsMaxControlPayloadSize))
  178. }
  179. if compressed {
  180. return 0, errors.New("control frame should not be compressed")
  181. }
  182. if !final {
  183. return 0, errors.New("control frame does not have final bit set")
  184. }
  185. case wsTextMessage, wsBinaryMessage:
  186. if !r.ff {
  187. return 0, errors.New("new message started before final frame for previous message was received")
  188. }
  189. r.ff = final
  190. r.fc = compressed
  191. case wsContinuationFrame:
  192. // Compressed bit must be only set in the first frame
  193. if r.ff || compressed {
  194. return 0, errors.New("invalid continuation frame")
  195. }
  196. r.ff = final
  197. default:
  198. return 0, fmt.Errorf("unknown opcode %v", frameType)
  199. }
  200. // If the encoded size is <= 125, then `rem` is simply the remainder size of the
  201. // frame. If it is 126, then the actual size is encoded as a uint16. For larger
  202. // frames, `rem` will initially be 127 and the actual size is encoded as a uint64.
  203. switch rem {
  204. case 126:
  205. tmpBuf, pos, err = wsGet(r.r, buf, pos, 2)
  206. if err != nil {
  207. return 0, err
  208. }
  209. rem = int(binary.BigEndian.Uint16(tmpBuf))
  210. case 127:
  211. tmpBuf, pos, err = wsGet(r.r, buf, pos, 8)
  212. if err != nil {
  213. return 0, err
  214. }
  215. rem = int(binary.BigEndian.Uint64(tmpBuf))
  216. }
  217. // Handle control messages in place...
  218. if wsIsControlFrame(frameType) {
  219. pos, err = r.handleControlFrame(frameType, buf, pos, rem)
  220. if err != nil {
  221. return 0, err
  222. }
  223. rem = 0
  224. continue
  225. }
  226. var b []byte
  227. b, pos, err = wsGet(r.r, buf, pos, rem)
  228. if err != nil {
  229. return 0, err
  230. }
  231. rem = 0
  232. if r.fc {
  233. br := newDecompressorBuffer(b)
  234. if r.dc == nil {
  235. r.dc = flate.NewReader(br)
  236. } else {
  237. r.dc.(flate.Resetter).Reset(br, nil)
  238. }
  239. // TODO: When Go 1.15 support is dropped, replace with io.ReadAll()
  240. b, err = ioutil.ReadAll(r.dc)
  241. if err != nil {
  242. return 0, err
  243. }
  244. r.fc = false
  245. }
  246. r.pending = append(r.pending, b)
  247. }
  248. // At this point we should have pending slices.
  249. return r.drainPending(p), nil
  250. }
  251. func (r *websocketReader) drainPending(p []byte) int {
  252. var n int
  253. var max = len(p)
  254. for i, buf := range r.pending {
  255. if n+len(buf) <= max {
  256. copy(p[n:], buf)
  257. n += len(buf)
  258. } else {
  259. // Is there room left?
  260. if n < max {
  261. // Write the partial and update this slice.
  262. rem := max - n
  263. copy(p[n:], buf[:rem])
  264. n += rem
  265. r.pending[i] = buf[rem:]
  266. }
  267. // These are the remaining slices that will need to be used at
  268. // the next Read() call.
  269. r.pending = r.pending[i:]
  270. return n
  271. }
  272. }
  273. r.pending = r.pending[:0]
  274. return n
  275. }
  276. func wsGet(r io.Reader, buf []byte, pos, needed int) ([]byte, int, error) {
  277. avail := len(buf) - pos
  278. if avail >= needed {
  279. return buf[pos : pos+needed], pos + needed, nil
  280. }
  281. b := make([]byte, needed)
  282. start := copy(b, buf[pos:])
  283. for start != needed {
  284. n, err := r.Read(b[start:cap(b)])
  285. start += n
  286. if err != nil {
  287. return b, start, err
  288. }
  289. }
  290. return b, pos + avail, nil
  291. }
  292. func (r *websocketReader) handleControlFrame(frameType wsOpCode, buf []byte, pos, rem int) (int, error) {
  293. var payload []byte
  294. var err error
  295. statusPos := pos
  296. if rem > 0 {
  297. payload, pos, err = wsGet(r.r, buf, pos, rem)
  298. if err != nil {
  299. return pos, err
  300. }
  301. }
  302. switch frameType {
  303. case wsCloseMessage:
  304. status := wsCloseStatusNoStatusReceived
  305. body := ""
  306. // If there is a payload, it should contain 2 unsigned bytes
  307. // that represent the status code and then optional payload.
  308. if len(payload) >= 2 {
  309. status = int(binary.BigEndian.Uint16(buf[statusPos : statusPos+2]))
  310. body = string(buf[statusPos+2 : statusPos+len(payload)])
  311. if body != "" && !utf8.ValidString(body) {
  312. // https://tools.ietf.org/html/rfc6455#section-5.5.1
  313. // If body is present, it must be a valid utf8
  314. status = wsCloseStatusInvalidPayloadData
  315. body = "invalid utf8 body in close frame"
  316. }
  317. }
  318. r.nc.wsEnqueueCloseMsg(status, body)
  319. // Return io.EOF so that readLoop will close the connection as ClientClosed
  320. // after processing pending buffers.
  321. return pos, io.EOF
  322. case wsPingMessage:
  323. r.nc.wsEnqueueControlMsg(wsPongMessage, payload)
  324. case wsPongMessage:
  325. // Nothing to do..
  326. }
  327. return pos, nil
  328. }
  329. func (w *websocketWriter) Write(p []byte) (int, error) {
  330. if w.noMoreSend {
  331. return 0, nil
  332. }
  333. var total int
  334. var n int
  335. var err error
  336. // If there are control frames, they can be sent now. Actually spec says
  337. // that they should be sent ASAP, so we will send before any application data.
  338. if len(w.ctrlFrames) > 0 {
  339. n, err = w.writeCtrlFrames()
  340. if err != nil {
  341. return n, err
  342. }
  343. total += n
  344. }
  345. // Do the following only if there is something to send.
  346. // We will end with checking for need to send close message.
  347. if len(p) > 0 {
  348. if w.compress {
  349. buf := &bytes.Buffer{}
  350. if w.compressor == nil {
  351. w.compressor, _ = flate.NewWriter(buf, flate.BestSpeed)
  352. } else {
  353. w.compressor.Reset(buf)
  354. }
  355. w.compressor.Write(p)
  356. w.compressor.Close()
  357. b := buf.Bytes()
  358. p = b[:len(b)-4]
  359. }
  360. fh, key := wsCreateFrameHeader(w.compress, wsBinaryMessage, len(p))
  361. wsMaskBuf(key, p)
  362. n, err = w.w.Write(fh)
  363. total += n
  364. if err == nil {
  365. n, err = w.w.Write(p)
  366. total += n
  367. }
  368. }
  369. if err == nil && w.cm != nil {
  370. n, err = w.writeCloseMsg()
  371. total += n
  372. }
  373. return total, err
  374. }
  375. func (w *websocketWriter) writeCtrlFrames() (int, error) {
  376. var (
  377. n int
  378. total int
  379. i int
  380. err error
  381. )
  382. for ; i < len(w.ctrlFrames); i++ {
  383. buf := w.ctrlFrames[i]
  384. n, err = w.w.Write(buf)
  385. total += n
  386. if err != nil {
  387. break
  388. }
  389. }
  390. if i != len(w.ctrlFrames) {
  391. w.ctrlFrames = w.ctrlFrames[i+1:]
  392. } else {
  393. w.ctrlFrames = w.ctrlFrames[:0]
  394. }
  395. return total, err
  396. }
  397. func (w *websocketWriter) writeCloseMsg() (int, error) {
  398. n, err := w.w.Write(w.cm)
  399. w.cm, w.noMoreSend = nil, true
  400. return n, err
  401. }
  402. func wsMaskBuf(key, buf []byte) {
  403. for i := 0; i < len(buf); i++ {
  404. buf[i] ^= key[i&3]
  405. }
  406. }
  407. // Create the frame header.
  408. // Encodes the frame type and optional compression flag, and the size of the payload.
  409. func wsCreateFrameHeader(compressed bool, frameType wsOpCode, l int) ([]byte, []byte) {
  410. fh := make([]byte, wsMaxFrameHeaderSize)
  411. n, key := wsFillFrameHeader(fh, compressed, frameType, l)
  412. return fh[:n], key
  413. }
  414. func wsFillFrameHeader(fh []byte, compressed bool, frameType wsOpCode, l int) (int, []byte) {
  415. var n int
  416. b := byte(frameType)
  417. b |= wsFinalBit
  418. if compressed {
  419. b |= wsRsv1Bit
  420. }
  421. b1 := byte(wsMaskBit)
  422. switch {
  423. case l <= 125:
  424. n = 2
  425. fh[0] = b
  426. fh[1] = b1 | byte(l)
  427. case l < 65536:
  428. n = 4
  429. fh[0] = b
  430. fh[1] = b1 | 126
  431. binary.BigEndian.PutUint16(fh[2:], uint16(l))
  432. default:
  433. n = 10
  434. fh[0] = b
  435. fh[1] = b1 | 127
  436. binary.BigEndian.PutUint64(fh[2:], uint64(l))
  437. }
  438. var key []byte
  439. var keyBuf [4]byte
  440. if _, err := io.ReadFull(rand.Reader, keyBuf[:4]); err != nil {
  441. kv := mrand.Int31()
  442. binary.LittleEndian.PutUint32(keyBuf[:4], uint32(kv))
  443. }
  444. copy(fh[n:], keyBuf[:4])
  445. key = fh[n : n+4]
  446. n += 4
  447. return n, key
  448. }
  449. func (nc *Conn) wsInitHandshake(u *url.URL) error {
  450. compress := nc.Opts.Compression
  451. tlsRequired := u.Scheme == wsSchemeTLS || nc.Opts.Secure || nc.Opts.TLSConfig != nil
  452. // Do TLS here as needed.
  453. if tlsRequired {
  454. if err := nc.makeTLSConn(); err != nil {
  455. return err
  456. }
  457. } else {
  458. nc.bindToNewConn()
  459. }
  460. var err error
  461. // For http request, we need the passed URL to contain either http or https scheme.
  462. scheme := "http"
  463. if tlsRequired {
  464. scheme = "https"
  465. }
  466. ustr := fmt.Sprintf("%s://%s", scheme, u.Host)
  467. u, err = url.Parse(ustr)
  468. if err != nil {
  469. return err
  470. }
  471. req := &http.Request{
  472. Method: "GET",
  473. URL: u,
  474. Proto: "HTTP/1.1",
  475. ProtoMajor: 1,
  476. ProtoMinor: 1,
  477. Header: make(http.Header),
  478. Host: u.Host,
  479. }
  480. wsKey, err := wsMakeChallengeKey()
  481. if err != nil {
  482. return err
  483. }
  484. req.Header["Upgrade"] = []string{"websocket"}
  485. req.Header["Connection"] = []string{"Upgrade"}
  486. req.Header["Sec-WebSocket-Key"] = []string{wsKey}
  487. req.Header["Sec-WebSocket-Version"] = []string{"13"}
  488. if compress {
  489. req.Header.Add("Sec-WebSocket-Extensions", wsPMCReqHeaderValue)
  490. }
  491. if err := req.Write(nc.conn); err != nil {
  492. return err
  493. }
  494. var resp *http.Response
  495. br := bufio.NewReaderSize(nc.conn, 4096)
  496. nc.conn.SetReadDeadline(time.Now().Add(nc.Opts.Timeout))
  497. resp, err = http.ReadResponse(br, req)
  498. if err == nil &&
  499. (resp.StatusCode != 101 ||
  500. !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
  501. !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
  502. resp.Header.Get("Sec-Websocket-Accept") != wsAcceptKey(wsKey)) {
  503. err = fmt.Errorf("invalid websocket connection")
  504. }
  505. // Check compression extension...
  506. if err == nil && compress {
  507. // Check that not only permessage-deflate extension is present, but that
  508. // we also have server and client no context take over.
  509. srvCompress, noCtxTakeover := wsPMCExtensionSupport(resp.Header)
  510. // If server does not support compression, then simply disable it in our side.
  511. if !srvCompress {
  512. compress = false
  513. } else if !noCtxTakeover {
  514. err = fmt.Errorf("compression negotiation error")
  515. }
  516. }
  517. if resp != nil {
  518. resp.Body.Close()
  519. }
  520. nc.conn.SetReadDeadline(time.Time{})
  521. if err != nil {
  522. return err
  523. }
  524. wsr := wsNewReader(nc.br.r)
  525. wsr.nc = nc
  526. // We have to slurp whatever is in the bufio reader and copy to br.r
  527. if n := br.Buffered(); n != 0 {
  528. wsr.ib, _ = br.Peek(n)
  529. }
  530. nc.br.r = wsr
  531. nc.bw.w = &websocketWriter{w: nc.bw.w, compress: compress}
  532. nc.ws = true
  533. return nil
  534. }
  535. func (nc *Conn) wsClose() {
  536. nc.mu.Lock()
  537. defer nc.mu.Unlock()
  538. if !nc.ws {
  539. return
  540. }
  541. nc.wsEnqueueCloseMsgLocked(wsCloseStatusNormalClosure, _EMPTY_)
  542. }
  543. func (nc *Conn) wsEnqueueCloseMsg(status int, payload string) {
  544. // In some low-level unit tests it will happen...
  545. if nc == nil {
  546. return
  547. }
  548. nc.mu.Lock()
  549. nc.wsEnqueueCloseMsgLocked(status, payload)
  550. nc.mu.Unlock()
  551. }
  552. func (nc *Conn) wsEnqueueCloseMsgLocked(status int, payload string) {
  553. wr, ok := nc.bw.w.(*websocketWriter)
  554. if !ok || wr.cmDone {
  555. return
  556. }
  557. statusAndPayloadLen := 2 + len(payload)
  558. frame := make([]byte, 2+4+statusAndPayloadLen)
  559. n, key := wsFillFrameHeader(frame, false, wsCloseMessage, statusAndPayloadLen)
  560. // Set the status
  561. binary.BigEndian.PutUint16(frame[n:], uint16(status))
  562. // If there is a payload, copy
  563. if len(payload) > 0 {
  564. copy(frame[n+2:], payload)
  565. }
  566. // Mask status + payload
  567. wsMaskBuf(key, frame[n:n+statusAndPayloadLen])
  568. wr.cm = frame
  569. wr.cmDone = true
  570. nc.bw.flush()
  571. }
  572. func (nc *Conn) wsEnqueueControlMsg(frameType wsOpCode, payload []byte) {
  573. // In some low-level unit tests it will happen...
  574. if nc == nil {
  575. return
  576. }
  577. fh, key := wsCreateFrameHeader(false, frameType, len(payload))
  578. nc.mu.Lock()
  579. wr, ok := nc.bw.w.(*websocketWriter)
  580. if !ok {
  581. nc.mu.Unlock()
  582. return
  583. }
  584. wr.ctrlFrames = append(wr.ctrlFrames, fh)
  585. if len(payload) > 0 {
  586. wsMaskBuf(key, payload)
  587. wr.ctrlFrames = append(wr.ctrlFrames, payload)
  588. }
  589. nc.bw.flush()
  590. nc.mu.Unlock()
  591. }
  592. func wsPMCExtensionSupport(header http.Header) (bool, bool) {
  593. for _, extensionList := range header["Sec-Websocket-Extensions"] {
  594. extensions := strings.Split(extensionList, ",")
  595. for _, extension := range extensions {
  596. extension = strings.Trim(extension, " \t")
  597. params := strings.Split(extension, ";")
  598. for i, p := range params {
  599. p = strings.Trim(p, " \t")
  600. if strings.EqualFold(p, wsPMCExtension) {
  601. var snc bool
  602. var cnc bool
  603. for j := i + 1; j < len(params); j++ {
  604. p = params[j]
  605. p = strings.Trim(p, " \t")
  606. if strings.EqualFold(p, wsPMCSrvNoCtx) {
  607. snc = true
  608. } else if strings.EqualFold(p, wsPMCCliNoCtx) {
  609. cnc = true
  610. }
  611. if snc && cnc {
  612. return true, true
  613. }
  614. }
  615. return true, false
  616. }
  617. }
  618. }
  619. }
  620. return false, false
  621. }
  622. func wsMakeChallengeKey() (string, error) {
  623. p := make([]byte, 16)
  624. if _, err := io.ReadFull(rand.Reader, p); err != nil {
  625. return "", err
  626. }
  627. return base64.StdEncoding.EncodeToString(p), nil
  628. }
  629. func wsAcceptKey(key string) string {
  630. h := sha1.New()
  631. h.Write([]byte(key))
  632. h.Write(wsGUID)
  633. return base64.StdEncoding.EncodeToString(h.Sum(nil))
  634. }
  635. // Returns true if the op code corresponds to a control frame.
  636. func wsIsControlFrame(frameType wsOpCode) bool {
  637. return frameType >= wsCloseMessage
  638. }
  639. func isWebsocketScheme(u *url.URL) bool {
  640. return u.Scheme == wsScheme || u.Scheme == wsSchemeTLS
  641. }