49 |
50 | Notes:
51 |
52 | 1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
53 | 2. The application can get the type of a received data message by implementing
54 | a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
55 | function.
56 | 3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
57 | Read returns when the input buffer is full or a frame boundary is
58 | encountered. Each call to Write sends a single frame message. The Gorilla
59 | io.Reader and io.WriteCloser operate on a single WebSocket message.
60 |
61 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/client.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Gorilla WebSocket Authors. 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 |
5 | package websocket
6 |
7 | import (
8 | "bufio"
9 | "bytes"
10 | "crypto/tls"
11 | "encoding/base64"
12 | "errors"
13 | "io"
14 | "io/ioutil"
15 | "net"
16 | "net/http"
17 | "net/url"
18 | "strings"
19 | "time"
20 | )
21 |
22 | // ErrBadHandshake is returned when the server response to opening handshake is
23 | // invalid.
24 | var ErrBadHandshake = errors.New("websocket: bad handshake")
25 |
26 | var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
27 |
28 | // NewClient creates a new client connection using the given net connection.
29 | // The URL u specifies the host and request URI. Use requestHeader to specify
30 | // the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
31 | // (Cookie). Use the response.Header to get the selected subprotocol
32 | // (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
33 | //
34 | // If the WebSocket handshake fails, ErrBadHandshake is returned along with a
35 | // non-nil *http.Response so that callers can handle redirects, authentication,
36 | // etc.
37 | //
38 | // Deprecated: Use Dialer instead.
39 | func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
40 | d := Dialer{
41 | ReadBufferSize: readBufSize,
42 | WriteBufferSize: writeBufSize,
43 | NetDial: func(net, addr string) (net.Conn, error) {
44 | return netConn, nil
45 | },
46 | }
47 | return d.Dial(u.String(), requestHeader)
48 | }
49 |
50 | // A Dialer contains options for connecting to WebSocket server.
51 | type Dialer struct {
52 | // NetDial specifies the dial function for creating TCP connections. If
53 | // NetDial is nil, net.Dial is used.
54 | NetDial func(network, addr string) (net.Conn, error)
55 |
56 | // Proxy specifies a function to return a proxy for a given
57 | // Request. If the function returns a non-nil error, the
58 | // request is aborted with the provided error.
59 | // If Proxy is nil or returns a nil *URL, no proxy is used.
60 | Proxy func(*http.Request) (*url.URL, error)
61 |
62 | // TLSClientConfig specifies the TLS configuration to use with tls.Client.
63 | // If nil, the default configuration is used.
64 | TLSClientConfig *tls.Config
65 |
66 | // HandshakeTimeout specifies the duration for the handshake to complete.
67 | HandshakeTimeout time.Duration
68 |
69 | // Input and output buffer sizes. If the buffer size is zero, then a
70 | // default value of 4096 is used.
71 | ReadBufferSize, WriteBufferSize int
72 |
73 | // Subprotocols specifies the client's requested subprotocols.
74 | Subprotocols []string
75 |
76 | // EnableCompression specifies if the client should attempt to negotiate
77 | // per message compression (RFC 7692). Setting this value to true does not
78 | // guarantee that compression will be supported. Currently only "no context
79 | // takeover" modes are supported.
80 | EnableCompression bool
81 |
82 | // Jar specifies the cookie jar.
83 | // If Jar is nil, cookies are not sent in requests and ignored
84 | // in responses.
85 | Jar http.CookieJar
86 | }
87 |
88 | var errMalformedURL = errors.New("malformed ws or wss URL")
89 |
90 | // parseURL parses the URL.
91 | //
92 | // This function is a replacement for the standard library url.Parse function.
93 | // In Go 1.4 and earlier, url.Parse loses information from the path.
94 | func parseURL(s string) (*url.URL, error) {
95 | // From the RFC:
96 | //
97 | // ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
98 | // wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
99 | var u url.URL
100 | switch {
101 | case strings.HasPrefix(s, "ws://"):
102 | u.Scheme = "ws"
103 | s = s[len("ws://"):]
104 | case strings.HasPrefix(s, "wss://"):
105 | u.Scheme = "wss"
106 | s = s[len("wss://"):]
107 | default:
108 | return nil, errMalformedURL
109 | }
110 |
111 | if i := strings.Index(s, "?"); i >= 0 {
112 | u.RawQuery = s[i+1:]
113 | s = s[:i]
114 | }
115 |
116 | if i := strings.Index(s, "/"); i >= 0 {
117 | u.Opaque = s[i:]
118 | s = s[:i]
119 | } else {
120 | u.Opaque = "/"
121 | }
122 |
123 | u.Host = s
124 |
125 | if strings.Contains(u.Host, "@") {
126 | // Don't bother parsing user information because user information is
127 | // not allowed in websocket URIs.
128 | return nil, errMalformedURL
129 | }
130 |
131 | return &u, nil
132 | }
133 |
134 | func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
135 | hostPort = u.Host
136 | hostNoPort = u.Host
137 | if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
138 | hostNoPort = hostNoPort[:i]
139 | } else {
140 | switch u.Scheme {
141 | case "wss":
142 | hostPort += ":443"
143 | case "https":
144 | hostPort += ":443"
145 | default:
146 | hostPort += ":80"
147 | }
148 | }
149 | return hostPort, hostNoPort
150 | }
151 |
152 | // DefaultDialer is a dialer with all fields set to the default zero values.
153 | var DefaultDialer = &Dialer{
154 | Proxy: http.ProxyFromEnvironment,
155 | }
156 |
157 | // Dial creates a new client connection. Use requestHeader to specify the
158 | // origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
159 | // Use the response.Header to get the selected subprotocol
160 | // (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
161 | //
162 | // If the WebSocket handshake fails, ErrBadHandshake is returned along with a
163 | // non-nil *http.Response so that callers can handle redirects, authentication,
164 | // etcetera. The response body may not contain the entire response and does not
165 | // need to be closed by the application.
166 | func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
167 |
168 | if d == nil {
169 | d = &Dialer{
170 | Proxy: http.ProxyFromEnvironment,
171 | }
172 | }
173 |
174 | challengeKey, err := generateChallengeKey()
175 | if err != nil {
176 | return nil, nil, err
177 | }
178 |
179 | u, err := parseURL(urlStr)
180 | if err != nil {
181 | return nil, nil, err
182 | }
183 |
184 | switch u.Scheme {
185 | case "ws":
186 | u.Scheme = "http"
187 | case "wss":
188 | u.Scheme = "https"
189 | default:
190 | return nil, nil, errMalformedURL
191 | }
192 |
193 | if u.User != nil {
194 | // User name and password are not allowed in websocket URIs.
195 | return nil, nil, errMalformedURL
196 | }
197 |
198 | req := &http.Request{
199 | Method: "GET",
200 | URL: u,
201 | Proto: "HTTP/1.1",
202 | ProtoMajor: 1,
203 | ProtoMinor: 1,
204 | Header: make(http.Header),
205 | Host: u.Host,
206 | }
207 |
208 | // Set the cookies present in the cookie jar of the dialer
209 | if d.Jar != nil {
210 | for _, cookie := range d.Jar.Cookies(u) {
211 | req.AddCookie(cookie)
212 | }
213 | }
214 |
215 | // Set the request headers using the capitalization for names and values in
216 | // RFC examples. Although the capitalization shouldn't matter, there are
217 | // servers that depend on it. The Header.Set method is not used because the
218 | // method canonicalizes the header names.
219 | req.Header["Upgrade"] = []string{"websocket"}
220 | req.Header["Connection"] = []string{"Upgrade"}
221 | req.Header["Sec-WebSocket-Key"] = []string{challengeKey}
222 | req.Header["Sec-WebSocket-Version"] = []string{"13"}
223 | if len(d.Subprotocols) > 0 {
224 | req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")}
225 | }
226 | for k, vs := range requestHeader {
227 | switch {
228 | case k == "Host":
229 | if len(vs) > 0 {
230 | req.Host = vs[0]
231 | }
232 | case k == "Upgrade" ||
233 | k == "Connection" ||
234 | k == "Sec-Websocket-Key" ||
235 | k == "Sec-Websocket-Version" ||
236 | k == "Sec-Websocket-Extensions" ||
237 | (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
238 | return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
239 | default:
240 | req.Header[k] = vs
241 | }
242 | }
243 |
244 | if d.EnableCompression {
245 | req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
246 | }
247 |
248 | hostPort, hostNoPort := hostPortNoPort(u)
249 |
250 | var proxyURL *url.URL
251 | // Check wether the proxy method has been configured
252 | if d.Proxy != nil {
253 | proxyURL, err = d.Proxy(req)
254 | }
255 | if err != nil {
256 | return nil, nil, err
257 | }
258 |
259 | var targetHostPort string
260 | if proxyURL != nil {
261 | targetHostPort, _ = hostPortNoPort(proxyURL)
262 | } else {
263 | targetHostPort = hostPort
264 | }
265 |
266 | var deadline time.Time
267 | if d.HandshakeTimeout != 0 {
268 | deadline = time.Now().Add(d.HandshakeTimeout)
269 | }
270 |
271 | netDial := d.NetDial
272 | if netDial == nil {
273 | netDialer := &net.Dialer{Deadline: deadline}
274 | netDial = netDialer.Dial
275 | }
276 |
277 | netConn, err := netDial("tcp", targetHostPort)
278 | if err != nil {
279 | return nil, nil, err
280 | }
281 |
282 | defer func() {
283 | if netConn != nil {
284 | netConn.Close()
285 | }
286 | }()
287 |
288 | if err := netConn.SetDeadline(deadline); err != nil {
289 | return nil, nil, err
290 | }
291 |
292 | if proxyURL != nil {
293 | connectHeader := make(http.Header)
294 | if user := proxyURL.User; user != nil {
295 | proxyUser := user.Username()
296 | if proxyPassword, passwordSet := user.Password(); passwordSet {
297 | credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
298 | connectHeader.Set("Proxy-Authorization", "Basic "+credential)
299 | }
300 | }
301 | connectReq := &http.Request{
302 | Method: "CONNECT",
303 | URL: &url.URL{Opaque: hostPort},
304 | Host: hostPort,
305 | Header: connectHeader,
306 | }
307 |
308 | connectReq.Write(netConn)
309 |
310 | // Read response.
311 | // Okay to use and discard buffered reader here, because
312 | // TLS server will not speak until spoken to.
313 | br := bufio.NewReader(netConn)
314 | resp, err := http.ReadResponse(br, connectReq)
315 | if err != nil {
316 | return nil, nil, err
317 | }
318 | if resp.StatusCode != 200 {
319 | f := strings.SplitN(resp.Status, " ", 2)
320 | return nil, nil, errors.New(f[1])
321 | }
322 | }
323 |
324 | if u.Scheme == "https" {
325 | cfg := cloneTLSConfig(d.TLSClientConfig)
326 | if cfg.ServerName == "" {
327 | cfg.ServerName = hostNoPort
328 | }
329 | tlsConn := tls.Client(netConn, cfg)
330 | netConn = tlsConn
331 | if err := tlsConn.Handshake(); err != nil {
332 | return nil, nil, err
333 | }
334 | if !cfg.InsecureSkipVerify {
335 | if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
336 | return nil, nil, err
337 | }
338 | }
339 | }
340 |
341 | conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize)
342 |
343 | if err := req.Write(netConn); err != nil {
344 | return nil, nil, err
345 | }
346 |
347 | resp, err := http.ReadResponse(conn.br, req)
348 | if err != nil {
349 | return nil, nil, err
350 | }
351 |
352 | if d.Jar != nil {
353 | if rc := resp.Cookies(); len(rc) > 0 {
354 | d.Jar.SetCookies(u, rc)
355 | }
356 | }
357 |
358 | if resp.StatusCode != 101 ||
359 | !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
360 | !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
361 | resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
362 | // Before closing the network connection on return from this
363 | // function, slurp up some of the response to aid application
364 | // debugging.
365 | buf := make([]byte, 1024)
366 | n, _ := io.ReadFull(resp.Body, buf)
367 | resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n]))
368 | return nil, resp, ErrBadHandshake
369 | }
370 |
371 | for _, ext := range parseExtensions(req.Header) {
372 | if ext[""] != "permessage-deflate" {
373 | continue
374 | }
375 | _, snct := ext["server_no_context_takeover"]
376 | _, cnct := ext["client_no_context_takeover"]
377 | if !snct || !cnct {
378 | return nil, resp, errInvalidCompression
379 | }
380 | conn.newCompressionWriter = compressNoContextTakeover
381 | conn.newDecompressionReader = decompressNoContextTakeover
382 | break
383 | }
384 |
385 | resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
386 | conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
387 |
388 | netConn.SetDeadline(time.Time{})
389 | netConn = nil // to avoid close in defer.
390 | return conn, resp, nil
391 | }
392 |
393 | // cloneTLSConfig clones all public fields except the fields
394 | // SessionTicketsDisabled and SessionTicketKey. This avoids copying the
395 | // sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
396 | // config in active use.
397 | func cloneTLSConfig(cfg *tls.Config) *tls.Config {
398 | if cfg == nil {
399 | return &tls.Config{}
400 | }
401 | return &tls.Config{
402 | Rand: cfg.Rand,
403 | Time: cfg.Time,
404 | Certificates: cfg.Certificates,
405 | NameToCertificate: cfg.NameToCertificate,
406 | GetCertificate: cfg.GetCertificate,
407 | RootCAs: cfg.RootCAs,
408 | NextProtos: cfg.NextProtos,
409 | ServerName: cfg.ServerName,
410 | ClientAuth: cfg.ClientAuth,
411 | ClientCAs: cfg.ClientCAs,
412 | InsecureSkipVerify: cfg.InsecureSkipVerify,
413 | CipherSuites: cfg.CipherSuites,
414 | PreferServerCipherSuites: cfg.PreferServerCipherSuites,
415 | ClientSessionCache: cfg.ClientSessionCache,
416 | MinVersion: cfg.MinVersion,
417 | MaxVersion: cfg.MaxVersion,
418 | CurvePreferences: cfg.CurvePreferences,
419 | }
420 | }
421 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/compression.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The Gorilla WebSocket Authors. 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 |
5 | package websocket
6 |
7 | import (
8 | "compress/flate"
9 | "errors"
10 | "io"
11 | "strings"
12 | )
13 |
14 | func decompressNoContextTakeover(r io.Reader) io.Reader {
15 | const tail =
16 | // Add four bytes as specified in RFC
17 | "\x00\x00\xff\xff" +
18 | // Add final block to squelch unexpected EOF error from flate reader.
19 | "\x01\x00\x00\xff\xff"
20 |
21 | return flate.NewReader(io.MultiReader(r, strings.NewReader(tail)))
22 | }
23 |
24 | func compressNoContextTakeover(w io.WriteCloser) (io.WriteCloser, error) {
25 | tw := &truncWriter{w: w}
26 | fw, err := flate.NewWriter(tw, 3)
27 | return &flateWrapper{fw: fw, tw: tw}, err
28 | }
29 |
30 | // truncWriter is an io.Writer that writes all but the last four bytes of the
31 | // stream to another io.Writer.
32 | type truncWriter struct {
33 | w io.WriteCloser
34 | n int
35 | p [4]byte
36 | }
37 |
38 | func (w *truncWriter) Write(p []byte) (int, error) {
39 | n := 0
40 |
41 | // fill buffer first for simplicity.
42 | if w.n < len(w.p) {
43 | n = copy(w.p[w.n:], p)
44 | p = p[n:]
45 | w.n += n
46 | if len(p) == 0 {
47 | return n, nil
48 | }
49 | }
50 |
51 | m := len(p)
52 | if m > len(w.p) {
53 | m = len(w.p)
54 | }
55 |
56 | if nn, err := w.w.Write(w.p[:m]); err != nil {
57 | return n + nn, err
58 | }
59 |
60 | copy(w.p[:], w.p[m:])
61 | copy(w.p[len(w.p)-m:], p[len(p)-m:])
62 | nn, err := w.w.Write(p[:len(p)-m])
63 | return n + nn, err
64 | }
65 |
66 | type flateWrapper struct {
67 | fw *flate.Writer
68 | tw *truncWriter
69 | }
70 |
71 | func (w *flateWrapper) Write(p []byte) (int, error) {
72 | return w.fw.Write(p)
73 | }
74 |
75 | func (w *flateWrapper) Close() error {
76 | err1 := w.fw.Flush()
77 | if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
78 | return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
79 | }
80 | err2 := w.tw.w.Close()
81 | if err1 != nil {
82 | return err1
83 | }
84 | return err2
85 | }
86 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/conn_read.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The Gorilla WebSocket Authors. 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 |
5 | // +build go1.5
6 |
7 | package websocket
8 |
9 | import "io"
10 |
11 | func (c *Conn) read(n int) ([]byte, error) {
12 | p, err := c.br.Peek(n)
13 | if err == io.EOF {
14 | err = errUnexpectedEOF
15 | }
16 | c.br.Discard(len(p))
17 | return p, err
18 | }
19 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/conn_read_legacy.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The Gorilla WebSocket Authors. 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 |
5 | // +build !go1.5
6 |
7 | package websocket
8 |
9 | import "io"
10 |
11 | func (c *Conn) read(n int) ([]byte, error) {
12 | p, err := c.br.Peek(n)
13 | if err == io.EOF {
14 | err = errUnexpectedEOF
15 | }
16 | if len(p) > 0 {
17 | // advance over the bytes just read
18 | io.ReadFull(c.br, p)
19 | }
20 | return p, err
21 | }
22 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Gorilla WebSocket Authors. 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 |
5 | // Package websocket implements the WebSocket protocol defined in RFC 6455.
6 | //
7 | // Overview
8 | //
9 | // The Conn type represents a WebSocket connection. A server application uses
10 | // the Upgrade function from an Upgrader object with a HTTP request handler
11 | // to get a pointer to a Conn:
12 | //
13 | // var upgrader = websocket.Upgrader{
14 | // ReadBufferSize: 1024,
15 | // WriteBufferSize: 1024,
16 | // }
17 | //
18 | // func handler(w http.ResponseWriter, r *http.Request) {
19 | // conn, err := upgrader.Upgrade(w, r, nil)
20 | // if err != nil {
21 | // log.Println(err)
22 | // return
23 | // }
24 | // ... Use conn to send and receive messages.
25 | // }
26 | //
27 | // Call the connection's WriteMessage and ReadMessage methods to send and
28 | // receive messages as a slice of bytes. This snippet of code shows how to echo
29 | // messages using these methods:
30 | //
31 | // for {
32 | // messageType, p, err := conn.ReadMessage()
33 | // if err != nil {
34 | // return
35 | // }
36 | // if err = conn.WriteMessage(messageType, p); err != nil {
37 | // return err
38 | // }
39 | // }
40 | //
41 | // In above snippet of code, p is a []byte and messageType is an int with value
42 | // websocket.BinaryMessage or websocket.TextMessage.
43 | //
44 | // An application can also send and receive messages using the io.WriteCloser
45 | // and io.Reader interfaces. To send a message, call the connection NextWriter
46 | // method to get an io.WriteCloser, write the message to the writer and close
47 | // the writer when done. To receive a message, call the connection NextReader
48 | // method to get an io.Reader and read until io.EOF is returned. This snippet
49 | // shows how to echo messages using the NextWriter and NextReader methods:
50 | //
51 | // for {
52 | // messageType, r, err := conn.NextReader()
53 | // if err != nil {
54 | // return
55 | // }
56 | // w, err := conn.NextWriter(messageType)
57 | // if err != nil {
58 | // return err
59 | // }
60 | // if _, err := io.Copy(w, r); err != nil {
61 | // return err
62 | // }
63 | // if err := w.Close(); err != nil {
64 | // return err
65 | // }
66 | // }
67 | //
68 | // Data Messages
69 | //
70 | // The WebSocket protocol distinguishes between text and binary data messages.
71 | // Text messages are interpreted as UTF-8 encoded text. The interpretation of
72 | // binary messages is left to the application.
73 | //
74 | // This package uses the TextMessage and BinaryMessage integer constants to
75 | // identify the two data message types. The ReadMessage and NextReader methods
76 | // return the type of the received message. The messageType argument to the
77 | // WriteMessage and NextWriter methods specifies the type of a sent message.
78 | //
79 | // It is the application's responsibility to ensure that text messages are
80 | // valid UTF-8 encoded text.
81 | //
82 | // Control Messages
83 | //
84 | // The WebSocket protocol defines three types of control messages: close, ping
85 | // and pong. Call the connection WriteControl, WriteMessage or NextWriter
86 | // methods to send a control message to the peer.
87 | //
88 | // Connections handle received close messages by sending a close message to the
89 | // peer and returning a *CloseError from the the NextReader, ReadMessage or the
90 | // message Read method.
91 | //
92 | // Connections handle received ping and pong messages by invoking callback
93 | // functions set with SetPingHandler and SetPongHandler methods. The callback
94 | // functions are called from the NextReader, ReadMessage and the message Read
95 | // methods.
96 | //
97 | // The default ping handler sends a pong to the peer. The application's reading
98 | // goroutine can block for a short time while the handler writes the pong data
99 | // to the connection.
100 | //
101 | // The application must read the connection to process ping, pong and close
102 | // messages sent from the peer. If the application is not otherwise interested
103 | // in messages from the peer, then the application should start a goroutine to
104 | // read and discard messages from the peer. A simple example is:
105 | //
106 | // func readLoop(c *websocket.Conn) {
107 | // for {
108 | // if _, _, err := c.NextReader(); err != nil {
109 | // c.Close()
110 | // break
111 | // }
112 | // }
113 | // }
114 | //
115 | // Concurrency
116 | //
117 | // Connections support one concurrent reader and one concurrent writer.
118 | //
119 | // Applications are responsible for ensuring that no more than one goroutine
120 | // calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
121 | // WriteJSON) concurrently and that no more than one goroutine calls the read
122 | // methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler,
123 | // SetPingHandler) concurrently.
124 | //
125 | // The Close and WriteControl methods can be called concurrently with all other
126 | // methods.
127 | //
128 | // Origin Considerations
129 | //
130 | // Web browsers allow Javascript applications to open a WebSocket connection to
131 | // any host. It's up to the server to enforce an origin policy using the Origin
132 | // request header sent by the browser.
133 | //
134 | // The Upgrader calls the function specified in the CheckOrigin field to check
135 | // the origin. If the CheckOrigin function returns false, then the Upgrade
136 | // method fails the WebSocket handshake with HTTP status 403.
137 | //
138 | // If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
139 | // the handshake if the Origin request header is present and not equal to the
140 | // Host request header.
141 | //
142 | // An application can allow connections from any origin by specifying a
143 | // function that always returns true:
144 | //
145 | // var upgrader = websocket.Upgrader{
146 | // CheckOrigin: func(r *http.Request) bool { return true },
147 | // }
148 | //
149 | // The deprecated Upgrade function does not enforce an origin policy. It's the
150 | // application's responsibility to check the Origin header before calling
151 | // Upgrade.
152 | //
153 | // Compression [Experimental]
154 | //
155 | // Per message compression extensions (RFC 7692) are experimentally supported
156 | // by this package in a limited capacity. Setting the EnableCompression option
157 | // to true in Dialer or Upgrader will attempt to negotiate per message deflate
158 | // support. If compression was successfully negotiated with the connection's
159 | // peer, any message received in compressed form will be automatically
160 | // decompressed. All Read methods will return uncompressed bytes.
161 | //
162 | // Per message compression of messages written to a connection can be enabled
163 | // or disabled by calling the corresponding Conn method:
164 | //
165 | // conn.EnableWriteCompression(true)
166 | //
167 | // Currently this package does not support compression with "context takeover".
168 | // This means that messages must be compressed and decompressed in isolation,
169 | // without retaining sliding window or dictionary state across messages. For
170 | // more details refer to RFC 7692.
171 | //
172 | // Use of compression is experimental and may result in decreased performance.
173 | package websocket
174 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/json.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Gorilla WebSocket Authors. 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 |
5 | package websocket
6 |
7 | import (
8 | "encoding/json"
9 | "io"
10 | )
11 |
12 | // WriteJSON is deprecated, use c.WriteJSON instead.
13 | func WriteJSON(c *Conn, v interface{}) error {
14 | return c.WriteJSON(v)
15 | }
16 |
17 | // WriteJSON writes the JSON encoding of v to the connection.
18 | //
19 | // See the documentation for encoding/json Marshal for details about the
20 | // conversion of Go values to JSON.
21 | func (c *Conn) WriteJSON(v interface{}) error {
22 | w, err := c.NextWriter(TextMessage)
23 | if err != nil {
24 | return err
25 | }
26 | err1 := json.NewEncoder(w).Encode(v)
27 | err2 := w.Close()
28 | if err1 != nil {
29 | return err1
30 | }
31 | return err2
32 | }
33 |
34 | // ReadJSON is deprecated, use c.ReadJSON instead.
35 | func ReadJSON(c *Conn, v interface{}) error {
36 | return c.ReadJSON(v)
37 | }
38 |
39 | // ReadJSON reads the next JSON-encoded message from the connection and stores
40 | // it in the value pointed to by v.
41 | //
42 | // See the documentation for the encoding/json Unmarshal function for details
43 | // about the conversion of JSON to a Go value.
44 | func (c *Conn) ReadJSON(v interface{}) error {
45 | _, r, err := c.NextReader()
46 | if err != nil {
47 | return err
48 | }
49 | err = json.NewDecoder(r).Decode(v)
50 | if err == io.EOF {
51 | // One value is expected in the message.
52 | err = io.ErrUnexpectedEOF
53 | }
54 | return err
55 | }
56 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/server.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Gorilla WebSocket Authors. 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 |
5 | package websocket
6 |
7 | import (
8 | "bufio"
9 | "errors"
10 | "net"
11 | "net/http"
12 | "net/url"
13 | "strings"
14 | "time"
15 | )
16 |
17 | // HandshakeError describes an error with the handshake from the peer.
18 | type HandshakeError struct {
19 | message string
20 | }
21 |
22 | func (e HandshakeError) Error() string { return e.message }
23 |
24 | // Upgrader specifies parameters for upgrading an HTTP connection to a
25 | // WebSocket connection.
26 | type Upgrader struct {
27 | // HandshakeTimeout specifies the duration for the handshake to complete.
28 | HandshakeTimeout time.Duration
29 |
30 | // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
31 | // size is zero, then a default value of 4096 is used. The I/O buffer sizes
32 | // do not limit the size of the messages that can be sent or received.
33 | ReadBufferSize, WriteBufferSize int
34 |
35 | // Subprotocols specifies the server's supported protocols in order of
36 | // preference. If this field is set, then the Upgrade method negotiates a
37 | // subprotocol by selecting the first match in this list with a protocol
38 | // requested by the client.
39 | Subprotocols []string
40 |
41 | // Error specifies the function for generating HTTP error responses. If Error
42 | // is nil, then http.Error is used to generate the HTTP response.
43 | Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
44 |
45 | // CheckOrigin returns true if the request Origin header is acceptable. If
46 | // CheckOrigin is nil, the host in the Origin header must not be set or
47 | // must match the host of the request.
48 | CheckOrigin func(r *http.Request) bool
49 |
50 | // EnableCompression specify if the server should attempt to negotiate per
51 | // message compression (RFC 7692). Setting this value to true does not
52 | // guarantee that compression will be supported. Currently only "no context
53 | // takeover" modes are supported.
54 | EnableCompression bool
55 | }
56 |
57 | func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
58 | err := HandshakeError{reason}
59 | if u.Error != nil {
60 | u.Error(w, r, status, err)
61 | } else {
62 | w.Header().Set("Sec-Websocket-Version", "13")
63 | http.Error(w, http.StatusText(status), status)
64 | }
65 | return nil, err
66 | }
67 |
68 | // checkSameOrigin returns true if the origin is not set or is equal to the request host.
69 | func checkSameOrigin(r *http.Request) bool {
70 | origin := r.Header["Origin"]
71 | if len(origin) == 0 {
72 | return true
73 | }
74 | u, err := url.Parse(origin[0])
75 | if err != nil {
76 | return false
77 | }
78 | return u.Host == r.Host
79 | }
80 |
81 | func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
82 | if u.Subprotocols != nil {
83 | clientProtocols := Subprotocols(r)
84 | for _, serverProtocol := range u.Subprotocols {
85 | for _, clientProtocol := range clientProtocols {
86 | if clientProtocol == serverProtocol {
87 | return clientProtocol
88 | }
89 | }
90 | }
91 | } else if responseHeader != nil {
92 | return responseHeader.Get("Sec-Websocket-Protocol")
93 | }
94 | return ""
95 | }
96 |
97 | // Upgrade upgrades the HTTP server connection to the WebSocket protocol.
98 | //
99 | // The responseHeader is included in the response to the client's upgrade
100 | // request. Use the responseHeader to specify cookies (Set-Cookie) and the
101 | // application negotiated subprotocol (Sec-Websocket-Protocol).
102 | //
103 | // If the upgrade fails, then Upgrade replies to the client with an HTTP error
104 | // response.
105 | func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
106 | if r.Method != "GET" {
107 | return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET")
108 | }
109 |
110 | if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
111 | return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific Sec-Websocket-Extensions headers are unsupported")
112 | }
113 |
114 | if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
115 | return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
116 | }
117 |
118 | if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
119 | return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'")
120 | }
121 |
122 | if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
123 | return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'")
124 | }
125 |
126 | checkOrigin := u.CheckOrigin
127 | if checkOrigin == nil {
128 | checkOrigin = checkSameOrigin
129 | }
130 | if !checkOrigin(r) {
131 | return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
132 | }
133 |
134 | challengeKey := r.Header.Get("Sec-Websocket-Key")
135 | if challengeKey == "" {
136 | return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
137 | }
138 |
139 | subprotocol := u.selectSubprotocol(r, responseHeader)
140 |
141 | // Negotiate PMCE
142 | var compress bool
143 | if u.EnableCompression {
144 | for _, ext := range parseExtensions(r.Header) {
145 | if ext[""] != "permessage-deflate" {
146 | continue
147 | }
148 | compress = true
149 | break
150 | }
151 | }
152 |
153 | var (
154 | netConn net.Conn
155 | br *bufio.Reader
156 | err error
157 | )
158 |
159 | h, ok := w.(http.Hijacker)
160 | if !ok {
161 | return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
162 | }
163 | var rw *bufio.ReadWriter
164 | netConn, rw, err = h.Hijack()
165 | if err != nil {
166 | return u.returnError(w, r, http.StatusInternalServerError, err.Error())
167 | }
168 | br = rw.Reader
169 |
170 | if br.Buffered() > 0 {
171 | netConn.Close()
172 | return nil, errors.New("websocket: client sent data before handshake is complete")
173 | }
174 |
175 | c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
176 | c.subprotocol = subprotocol
177 |
178 | if compress {
179 | c.newCompressionWriter = compressNoContextTakeover
180 | c.newDecompressionReader = decompressNoContextTakeover
181 | }
182 |
183 | p := c.writeBuf[:0]
184 | p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
185 | p = append(p, computeAcceptKey(challengeKey)...)
186 | p = append(p, "\r\n"...)
187 | if c.subprotocol != "" {
188 | p = append(p, "Sec-Websocket-Protocol: "...)
189 | p = append(p, c.subprotocol...)
190 | p = append(p, "\r\n"...)
191 | }
192 | if compress {
193 | p = append(p, "Sec-Websocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
194 | }
195 | for k, vs := range responseHeader {
196 | if k == "Sec-Websocket-Protocol" {
197 | continue
198 | }
199 | for _, v := range vs {
200 | p = append(p, k...)
201 | p = append(p, ": "...)
202 | for i := 0; i < len(v); i++ {
203 | b := v[i]
204 | if b <= 31 {
205 | // prevent response splitting.
206 | b = ' '
207 | }
208 | p = append(p, b)
209 | }
210 | p = append(p, "\r\n"...)
211 | }
212 | }
213 | p = append(p, "\r\n"...)
214 |
215 | // Clear deadlines set by HTTP server.
216 | netConn.SetDeadline(time.Time{})
217 |
218 | if u.HandshakeTimeout > 0 {
219 | netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
220 | }
221 | if _, err = netConn.Write(p); err != nil {
222 | netConn.Close()
223 | return nil, err
224 | }
225 | if u.HandshakeTimeout > 0 {
226 | netConn.SetWriteDeadline(time.Time{})
227 | }
228 |
229 | return c, nil
230 | }
231 |
232 | // Upgrade upgrades the HTTP server connection to the WebSocket protocol.
233 | //
234 | // This function is deprecated, use websocket.Upgrader instead.
235 | //
236 | // The application is responsible for checking the request origin before
237 | // calling Upgrade. An example implementation of the same origin policy is:
238 | //
239 | // if req.Header.Get("Origin") != "http://"+req.Host {
240 | // http.Error(w, "Origin not allowed", 403)
241 | // return
242 | // }
243 | //
244 | // If the endpoint supports subprotocols, then the application is responsible
245 | // for negotiating the protocol used on the connection. Use the Subprotocols()
246 | // function to get the subprotocols requested by the client. Use the
247 | // Sec-Websocket-Protocol response header to specify the subprotocol selected
248 | // by the application.
249 | //
250 | // The responseHeader is included in the response to the client's upgrade
251 | // request. Use the responseHeader to specify cookies (Set-Cookie) and the
252 | // negotiated subprotocol (Sec-Websocket-Protocol).
253 | //
254 | // The connection buffers IO to the underlying network connection. The
255 | // readBufSize and writeBufSize parameters specify the size of the buffers to
256 | // use. Messages can be larger than the buffers.
257 | //
258 | // If the request is not a valid WebSocket handshake, then Upgrade returns an
259 | // error of type HandshakeError. Applications should handle this error by
260 | // replying to the client with an HTTP error response.
261 | func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
262 | u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
263 | u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
264 | // don't return errors to maintain backwards compatibility
265 | }
266 | u.CheckOrigin = func(r *http.Request) bool {
267 | // allow all connections by default
268 | return true
269 | }
270 | return u.Upgrade(w, r, responseHeader)
271 | }
272 |
273 | // Subprotocols returns the subprotocols requested by the client in the
274 | // Sec-Websocket-Protocol header.
275 | func Subprotocols(r *http.Request) []string {
276 | h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
277 | if h == "" {
278 | return nil
279 | }
280 | protocols := strings.Split(h, ",")
281 | for i := range protocols {
282 | protocols[i] = strings.TrimSpace(protocols[i])
283 | }
284 | return protocols
285 | }
286 |
287 | // IsWebSocketUpgrade returns true if the client requested upgrade to the
288 | // WebSocket protocol.
289 | func IsWebSocketUpgrade(r *http.Request) bool {
290 | return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
291 | tokenListContainsValue(r.Header, "Upgrade", "websocket")
292 | }
293 |
--------------------------------------------------------------------------------
/vendor/github.com/gorilla/websocket/util.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Gorilla WebSocket Authors. 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 |
5 | package websocket
6 |
7 | import (
8 | "crypto/rand"
9 | "crypto/sha1"
10 | "encoding/base64"
11 | "io"
12 | "net/http"
13 | "strings"
14 | )
15 |
16 | var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
17 |
18 | func computeAcceptKey(challengeKey string) string {
19 | h := sha1.New()
20 | h.Write([]byte(challengeKey))
21 | h.Write(keyGUID)
22 | return base64.StdEncoding.EncodeToString(h.Sum(nil))
23 | }
24 |
25 | func generateChallengeKey() (string, error) {
26 | p := make([]byte, 16)
27 | if _, err := io.ReadFull(rand.Reader, p); err != nil {
28 | return "", err
29 | }
30 | return base64.StdEncoding.EncodeToString(p), nil
31 | }
32 |
33 | // Octet types from RFC 2616.
34 | var octetTypes [256]byte
35 |
36 | const (
37 | isTokenOctet = 1 << iota
38 | isSpaceOctet
39 | )
40 |
41 | func init() {
42 | // From RFC 2616
43 | //
44 | // OCTET =