summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gorilla
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gorilla')
-rw-r--r--vendor/github.com/gorilla/handlers/README.md2
-rw-r--r--vendor/github.com/gorilla/handlers/handlers.go2
-rw-r--r--vendor/github.com/gorilla/handlers/handlers_go18.go21
-rw-r--r--vendor/github.com/gorilla/handlers/handlers_go18_test.go34
-rw-r--r--vendor/github.com/gorilla/handlers/handlers_pre18.go7
-rw-r--r--vendor/github.com/gorilla/mux/.travis.yml1
-rw-r--r--vendor/github.com/gorilla/mux/README.md1
-rw-r--r--vendor/github.com/gorilla/mux/bench_test.go2
-rw-r--r--vendor/github.com/gorilla/mux/mux_test.go2
-rw-r--r--vendor/github.com/gorilla/mux/route.go2
-rw-r--r--vendor/github.com/gorilla/websocket/.travis.yml1
-rw-r--r--vendor/github.com/gorilla/websocket/client.go36
-rw-r--r--vendor/github.com/gorilla/websocket/client_clone.go16
-rw-r--r--vendor/github.com/gorilla/websocket/client_clone_legacy.go38
-rw-r--r--vendor/github.com/gorilla/websocket/compression.go73
-rw-r--r--vendor/github.com/gorilla/websocket/compression_test.go49
-rw-r--r--vendor/github.com/gorilla/websocket/conn.go144
-rw-r--r--vendor/github.com/gorilla/websocket/conn_broadcast_test.go134
-rw-r--r--vendor/github.com/gorilla/websocket/conn_test.go32
-rw-r--r--vendor/github.com/gorilla/websocket/doc.go23
-rw-r--r--vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json1
-rw-r--r--vendor/github.com/gorilla/websocket/examples/autobahn/server.go29
-rw-r--r--vendor/github.com/gorilla/websocket/examples/chat/home.html4
-rw-r--r--vendor/github.com/gorilla/websocket/examples/chat/main.go5
-rw-r--r--vendor/github.com/gorilla/websocket/examples/command/README.md2
-rw-r--r--vendor/github.com/gorilla/websocket/examples/command/home.html56
-rw-r--r--vendor/github.com/gorilla/websocket/examples/command/main.go9
-rw-r--r--vendor/github.com/gorilla/websocket/examples/filewatch/main.go2
-rw-r--r--vendor/github.com/gorilla/websocket/mask.go12
-rw-r--r--vendor/github.com/gorilla/websocket/mask_safe.go15
-rw-r--r--vendor/github.com/gorilla/websocket/mask_test.go2
-rw-r--r--vendor/github.com/gorilla/websocket/prepared.go103
-rw-r--r--vendor/github.com/gorilla/websocket/prepared_test.go74
-rw-r--r--vendor/github.com/gorilla/websocket/server.go35
34 files changed, 818 insertions, 151 deletions
diff --git a/vendor/github.com/gorilla/handlers/README.md b/vendor/github.com/gorilla/handlers/README.md
index a782c4152..4a6895dcf 100644
--- a/vendor/github.com/gorilla/handlers/README.md
+++ b/vendor/github.com/gorilla/handlers/README.md
@@ -1,6 +1,8 @@
gorilla/handlers
================
[![GoDoc](https://godoc.org/github.com/gorilla/handlers?status.svg)](https://godoc.org/github.com/gorilla/handlers) [![Build Status](https://travis-ci.org/gorilla/handlers.svg?branch=master)](https://travis-ci.org/gorilla/handlers)
+[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/handlers/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/handlers?badge)
+
Package handlers is a collection of handlers (aka "HTTP middleware") for use
with Go's `net/http` package (or any framework supporting `http.Handler`), including:
diff --git a/vendor/github.com/gorilla/handlers/handlers.go b/vendor/github.com/gorilla/handlers/handlers.go
index 9544d2f0a..551f8ff05 100644
--- a/vendor/github.com/gorilla/handlers/handlers.go
+++ b/vendor/github.com/gorilla/handlers/handlers.go
@@ -94,7 +94,7 @@ func makeLogger(w http.ResponseWriter) loggingResponseWriter {
return logger
}
-type loggingResponseWriter interface {
+type commonLoggingResponseWriter interface {
http.ResponseWriter
http.Flusher
Status() int
diff --git a/vendor/github.com/gorilla/handlers/handlers_go18.go b/vendor/github.com/gorilla/handlers/handlers_go18.go
new file mode 100644
index 000000000..35eb8d4f5
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/handlers_go18.go
@@ -0,0 +1,21 @@
+// +build go1.8
+
+package handlers
+
+import (
+ "fmt"
+ "net/http"
+)
+
+type loggingResponseWriter interface {
+ commonLoggingResponseWriter
+ http.Pusher
+}
+
+func (l *responseLogger) Push(target string, opts *http.PushOptions) error {
+ p, ok := l.w.(http.Pusher)
+ if !ok {
+ return fmt.Errorf("responseLogger does not implement http.Pusher")
+ }
+ return p.Push(target, opts)
+}
diff --git a/vendor/github.com/gorilla/handlers/handlers_go18_test.go b/vendor/github.com/gorilla/handlers/handlers_go18_test.go
new file mode 100644
index 000000000..c8cfa722f
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/handlers_go18_test.go
@@ -0,0 +1,34 @@
+// +build go1.8
+
+package handlers
+
+import (
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func TestLoggingHandlerWithPush(t *testing.T) {
+ handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ if _, ok := w.(http.Pusher); !ok {
+ t.Fatalf("%T from LoggingHandler does not satisfy http.Pusher interface when built with Go >=1.8", w)
+ }
+ w.WriteHeader(200)
+ })
+
+ logger := LoggingHandler(ioutil.Discard, handler)
+ logger.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/"))
+}
+
+func TestCombinedLoggingHandlerWithPush(t *testing.T) {
+ handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ if _, ok := w.(http.Pusher); !ok {
+ t.Fatalf("%T from CombinedLoggingHandler does not satisfy http.Pusher interface when built with Go >=1.8", w)
+ }
+ w.WriteHeader(200)
+ })
+
+ logger := CombinedLoggingHandler(ioutil.Discard, handler)
+ logger.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/"))
+}
diff --git a/vendor/github.com/gorilla/handlers/handlers_pre18.go b/vendor/github.com/gorilla/handlers/handlers_pre18.go
new file mode 100644
index 000000000..197836abb
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/handlers_pre18.go
@@ -0,0 +1,7 @@
+// +build !go1.8
+
+package handlers
+
+type loggingResponseWriter interface {
+ commonLoggingResponseWriter
+}
diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml
index f93ce56d1..ca377e61c 100644
--- a/vendor/github.com/gorilla/mux/.travis.yml
+++ b/vendor/github.com/gorilla/mux/.travis.yml
@@ -9,6 +9,7 @@ matrix:
- go: 1.5
- go: 1.6
- go: 1.7
+ - go: 1.8
- go: tip
install:
diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md
index 94d396ca4..cdab8784d 100644
--- a/vendor/github.com/gorilla/mux/README.md
+++ b/vendor/github.com/gorilla/mux/README.md
@@ -2,6 +2,7 @@ gorilla/mux
===
[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
+[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
diff --git a/vendor/github.com/gorilla/mux/bench_test.go b/vendor/github.com/gorilla/mux/bench_test.go
index 946289b92..522156dcc 100644
--- a/vendor/github.com/gorilla/mux/bench_test.go
+++ b/vendor/github.com/gorilla/mux/bench_test.go
@@ -24,7 +24,7 @@ func BenchmarkMux(b *testing.B) {
func BenchmarkMuxAlternativeInRegexp(b *testing.B) {
router := new(Router)
handler := func(w http.ResponseWriter, r *http.Request) {}
- router.HandleFunc("/v1/{v1:(a|b)}", handler)
+ router.HandleFunc("/v1/{v1:(?:a|b)}", handler)
requestA, _ := http.NewRequest("GET", "/v1/a", nil)
requestB, _ := http.NewRequest("GET", "/v1/b", nil)
diff --git a/vendor/github.com/gorilla/mux/mux_test.go b/vendor/github.com/gorilla/mux/mux_test.go
index 405aca6de..1dec7abef 100644
--- a/vendor/github.com/gorilla/mux/mux_test.go
+++ b/vendor/github.com/gorilla/mux/mux_test.go
@@ -1393,7 +1393,7 @@ func TestSubrouterErrorHandling(t *testing.T) {
func TestPanicOnCapturingGroups(t *testing.T) {
defer func() {
if recover() == nil {
- t.Errorf("(Test that capturing groups now fail fast) Expected panic, however test completed sucessfully.\n")
+ t.Errorf("(Test that capturing groups now fail fast) Expected panic, however test completed successfully.\n")
}
}()
NewRouter().NewRoute().Path("/{type:(promo|special)}/{promoId}.json")
diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go
index 922191592..5544c1fd6 100644
--- a/vendor/github.com/gorilla/mux/route.go
+++ b/vendor/github.com/gorilla/mux/route.go
@@ -153,7 +153,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
}
r.regexp = r.getRegexpGroup()
if !matchHost && !matchQuery {
- if tpl == "/" && (len(tpl) == 0 || tpl[0] != '/') {
+ if len(tpl) > 0 && tpl[0] != '/' {
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
}
if r.regexp.path != nil {
diff --git a/vendor/github.com/gorilla/websocket/.travis.yml b/vendor/github.com/gorilla/websocket/.travis.yml
index 4ea1e7a1f..3d8d29cf3 100644
--- a/vendor/github.com/gorilla/websocket/.travis.yml
+++ b/vendor/github.com/gorilla/websocket/.travis.yml
@@ -7,6 +7,7 @@ matrix:
- go: 1.5
- go: 1.6
- go: 1.7
+ - go: 1.8
- go: tip
allow_failures:
- go: tip
diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go
index 78d932877..43a87c753 100644
--- a/vendor/github.com/gorilla/websocket/client.go
+++ b/vendor/github.com/gorilla/websocket/client.go
@@ -66,8 +66,9 @@ type Dialer struct {
// HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration
- // Input and output buffer sizes. If the buffer size is zero, then a
- // default value of 4096 is used.
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
+ // size is zero, then a useful default size is used. The I/O buffer sizes
+ // do not limit the size of the messages that can be sent or received.
ReadBufferSize, WriteBufferSize int
// Subprotocols specifies the client's requested subprotocols.
@@ -368,7 +369,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
return nil, resp, ErrBadHandshake
}
- for _, ext := range parseExtensions(req.Header) {
+ for _, ext := range parseExtensions(resp.Header) {
if ext[""] != "permessage-deflate" {
continue
}
@@ -389,32 +390,3 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
netConn = nil // to avoid close in defer.
return conn, resp, nil
}
-
-// cloneTLSConfig clones all public fields except the fields
-// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
-// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
-// config in active use.
-func cloneTLSConfig(cfg *tls.Config) *tls.Config {
- if cfg == nil {
- return &tls.Config{}
- }
- return &tls.Config{
- Rand: cfg.Rand,
- Time: cfg.Time,
- Certificates: cfg.Certificates,
- NameToCertificate: cfg.NameToCertificate,
- GetCertificate: cfg.GetCertificate,
- RootCAs: cfg.RootCAs,
- NextProtos: cfg.NextProtos,
- ServerName: cfg.ServerName,
- ClientAuth: cfg.ClientAuth,
- ClientCAs: cfg.ClientCAs,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- CipherSuites: cfg.CipherSuites,
- PreferServerCipherSuites: cfg.PreferServerCipherSuites,
- ClientSessionCache: cfg.ClientSessionCache,
- MinVersion: cfg.MinVersion,
- MaxVersion: cfg.MaxVersion,
- CurvePreferences: cfg.CurvePreferences,
- }
-}
diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go
new file mode 100644
index 000000000..4f0d94372
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/client_clone.go
@@ -0,0 +1,16 @@
+// 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.
+
+// +build go1.8
+
+package websocket
+
+import "crypto/tls"
+
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+ if cfg == nil {
+ return &tls.Config{}
+ }
+ return cfg.Clone()
+}
diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go
new file mode 100644
index 000000000..babb007fb
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/client_clone_legacy.go
@@ -0,0 +1,38 @@
+// 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.
+
+// +build !go1.8
+
+package websocket
+
+import "crypto/tls"
+
+// cloneTLSConfig clones all public fields except the fields
+// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
+// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
+// config in active use.
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+ if cfg == nil {
+ return &tls.Config{}
+ }
+ return &tls.Config{
+ Rand: cfg.Rand,
+ Time: cfg.Time,
+ Certificates: cfg.Certificates,
+ NameToCertificate: cfg.NameToCertificate,
+ GetCertificate: cfg.GetCertificate,
+ RootCAs: cfg.RootCAs,
+ NextProtos: cfg.NextProtos,
+ ServerName: cfg.ServerName,
+ ClientAuth: cfg.ClientAuth,
+ ClientCAs: cfg.ClientCAs,
+ InsecureSkipVerify: cfg.InsecureSkipVerify,
+ CipherSuites: cfg.CipherSuites,
+ PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+ ClientSessionCache: cfg.ClientSessionCache,
+ MinVersion: cfg.MinVersion,
+ MaxVersion: cfg.MaxVersion,
+ CurvePreferences: cfg.CurvePreferences,
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go
index 72c166b2a..813ffb1e8 100644
--- a/vendor/github.com/gorilla/websocket/compression.go
+++ b/vendor/github.com/gorilla/websocket/compression.go
@@ -12,31 +12,45 @@ import (
"sync"
)
+const (
+ minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
+ maxCompressionLevel = flate.BestCompression
+ defaultCompressionLevel = 1
+)
+
var (
- flateWriterPool = sync.Pool{}
+ flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
+ flateReaderPool = sync.Pool{New: func() interface{} {
+ return flate.NewReader(nil)
+ }}
)
-func decompressNoContextTakeover(r io.Reader) io.Reader {
+func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
const tail =
// Add four bytes as specified in RFC
"\x00\x00\xff\xff" +
// Add final block to squelch unexpected EOF error from flate reader.
"\x01\x00\x00\xff\xff"
- return flate.NewReader(io.MultiReader(r, strings.NewReader(tail)))
+
+ fr, _ := flateReaderPool.Get().(io.ReadCloser)
+ fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil)
+ return &flateReadWrapper{fr}
}
-func compressNoContextTakeover(w io.WriteCloser) (io.WriteCloser, error) {
+func isValidCompressionLevel(level int) bool {
+ return minCompressionLevel <= level && level <= maxCompressionLevel
+}
+
+func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
+ p := &flateWriterPools[level-minCompressionLevel]
tw := &truncWriter{w: w}
- i := flateWriterPool.Get()
- var fw *flate.Writer
- var err error
- if i == nil {
- fw, err = flate.NewWriter(tw, 3)
+ fw, _ := p.Get().(*flate.Writer)
+ if fw == nil {
+ fw, _ = flate.NewWriter(tw, level)
} else {
- fw = i.(*flate.Writer)
fw.Reset(tw)
}
- return &flateWrapper{fw: fw, tw: tw}, err
+ return &flateWriteWrapper{fw: fw, tw: tw, p: p}
}
// truncWriter is an io.Writer that writes all but the last four bytes of the
@@ -75,24 +89,25 @@ func (w *truncWriter) Write(p []byte) (int, error) {
return n + nn, err
}
-type flateWrapper struct {
+type flateWriteWrapper struct {
fw *flate.Writer
tw *truncWriter
+ p *sync.Pool
}
-func (w *flateWrapper) Write(p []byte) (int, error) {
+func (w *flateWriteWrapper) Write(p []byte) (int, error) {
if w.fw == nil {
return 0, errWriteClosed
}
return w.fw.Write(p)
}
-func (w *flateWrapper) Close() error {
+func (w *flateWriteWrapper) Close() error {
if w.fw == nil {
return errWriteClosed
}
err1 := w.fw.Flush()
- flateWriterPool.Put(w.fw)
+ w.p.Put(w.fw)
w.fw = nil
if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
@@ -103,3 +118,31 @@ func (w *flateWrapper) Close() error {
}
return err2
}
+
+type flateReadWrapper struct {
+ fr io.ReadCloser
+}
+
+func (r *flateReadWrapper) Read(p []byte) (int, error) {
+ if r.fr == nil {
+ return 0, io.ErrClosedPipe
+ }
+ n, err := r.fr.Read(p)
+ if err == io.EOF {
+ // Preemptively place the reader back in the pool. This helps with
+ // scenarios where the application does not call NextReader() soon after
+ // this final read.
+ r.Close()
+ }
+ return n, err
+}
+
+func (r *flateReadWrapper) Close() error {
+ if r.fr == nil {
+ return io.ErrClosedPipe
+ }
+ err := r.fr.Close()
+ flateReaderPool.Put(r.fr)
+ r.fr = nil
+ return err
+}
diff --git a/vendor/github.com/gorilla/websocket/compression_test.go b/vendor/github.com/gorilla/websocket/compression_test.go
index cad70fb51..659cf4215 100644
--- a/vendor/github.com/gorilla/websocket/compression_test.go
+++ b/vendor/github.com/gorilla/websocket/compression_test.go
@@ -2,7 +2,9 @@ package websocket
import (
"bytes"
+ "fmt"
"io"
+ "io/ioutil"
"testing"
)
@@ -29,3 +31,50 @@ func TestTruncWriter(t *testing.T) {
}
}
}
+
+func textMessages(num int) [][]byte {
+ messages := make([][]byte, num)
+ for i := 0; i < num; i++ {
+ msg := fmt.Sprintf("planet: %d, country: %d, city: %d, street: %d", i, i, i, i)
+ messages[i] = []byte(msg)
+ }
+ return messages
+}
+
+func BenchmarkWriteNoCompression(b *testing.B) {
+ w := ioutil.Discard
+ c := newConn(fakeNetConn{Reader: nil, Writer: w}, false, 1024, 1024)
+ messages := textMessages(100)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.WriteMessage(TextMessage, messages[i%len(messages)])
+ }
+ b.ReportAllocs()
+}
+
+func BenchmarkWriteWithCompression(b *testing.B) {
+ w := ioutil.Discard
+ c := newConn(fakeNetConn{Reader: nil, Writer: w}, false, 1024, 1024)
+ messages := textMessages(100)
+ c.enableWriteCompression = true
+ c.newCompressionWriter = compressNoContextTakeover
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.WriteMessage(TextMessage, messages[i%len(messages)])
+ }
+ b.ReportAllocs()
+}
+
+func TestValidCompressionLevel(t *testing.T) {
+ c := newConn(fakeNetConn{}, false, 1024, 1024)
+ for _, level := range []int{minCompressionLevel - 1, maxCompressionLevel + 1} {
+ if err := c.SetCompressionLevel(level); err == nil {
+ t.Errorf("no error for level %d", level)
+ }
+ }
+ for _, level := range []int{minCompressionLevel, maxCompressionLevel} {
+ if err := c.SetCompressionLevel(level); err != nil {
+ t.Errorf("error for level %d", level)
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go
index ce7f0a615..97e1dbacb 100644
--- a/vendor/github.com/gorilla/websocket/conn.go
+++ b/vendor/github.com/gorilla/websocket/conn.go
@@ -10,6 +10,7 @@ import (
"errors"
"io"
"io/ioutil"
+ "math/rand"
"net"
"strconv"
"sync"
@@ -180,6 +181,11 @@ var (
errInvalidControlFrame = errors.New("websocket: invalid control frame")
)
+func newMaskKey() [4]byte {
+ n := rand.Uint32()
+ return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
+}
+
func hideTempErr(err error) error {
if e, ok := err.(net.Error); ok && e.Temporary() {
err = &netError{msg: e.Error(), timeout: e.Timeout()}
@@ -235,9 +241,11 @@ type Conn struct {
writeErr error
enableWriteCompression bool
- newCompressionWriter func(io.WriteCloser) (io.WriteCloser, error)
+ compressionLevel int
+ newCompressionWriter func(io.WriteCloser, int) io.WriteCloser
// Read fields
+ reader io.ReadCloser // the current reader returned to the application
readErr error
br *bufio.Reader
readRemaining int64 // bytes remaining in current frame.
@@ -253,31 +261,76 @@ type Conn struct {
messageReader *messageReader // the current low-level reader
readDecompress bool // whether last read frame had RSV1 set
- newDecompressionReader func(io.Reader) io.Reader
+ newDecompressionReader func(io.Reader) io.ReadCloser
}
func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
+ return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil)
+}
+
+type writeHook struct {
+ p []byte
+}
+
+func (wh *writeHook) Write(p []byte) (int, error) {
+ wh.p = p
+ return len(p), nil
+}
+
+func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn {
mu := make(chan bool, 1)
mu <- true
- if readBufferSize == 0 {
- readBufferSize = defaultReadBufferSize
+ var br *bufio.Reader
+ if readBufferSize == 0 && brw != nil && brw.Reader != nil {
+ // Reuse the supplied bufio.Reader if the buffer has a useful size.
+ // This code assumes that peek on a reader returns
+ // bufio.Reader.buf[:0].
+ brw.Reader.Reset(conn)
+ if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 {
+ br = brw.Reader
+ }
}
- if readBufferSize < maxControlFramePayloadSize {
- readBufferSize = maxControlFramePayloadSize
+ if br == nil {
+ if readBufferSize == 0 {
+ readBufferSize = defaultReadBufferSize
+ }
+ if readBufferSize < maxControlFramePayloadSize {
+ readBufferSize = maxControlFramePayloadSize
+ }
+ br = bufio.NewReaderSize(conn, readBufferSize)
+ }
+
+ var writeBuf []byte
+ if writeBufferSize == 0 && brw != nil && brw.Writer != nil {
+ // Use the bufio.Writer's buffer if the buffer has a useful size. This
+ // code assumes that bufio.Writer.buf[:1] is passed to the
+ // bufio.Writer's underlying writer.
+ var wh writeHook
+ brw.Writer.Reset(&wh)
+ brw.Writer.WriteByte(0)
+ brw.Flush()
+ if cap(wh.p) >= maxFrameHeaderSize+256 {
+ writeBuf = wh.p[:cap(wh.p)]
+ }
}
- if writeBufferSize == 0 {
- writeBufferSize = defaultWriteBufferSize
+
+ if writeBuf == nil {
+ if writeBufferSize == 0 {
+ writeBufferSize = defaultWriteBufferSize
+ }
+ writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize)
}
c := &Conn{
isServer: isServer,
- br: bufio.NewReaderSize(conn, readBufferSize),
+ br: br,
conn: conn,
mu: mu,
readFinal: true,
- writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
+ writeBuf: writeBuf,
enableWriteCompression: true,
+ compressionLevel: defaultCompressionLevel,
}
c.SetCloseHandler(nil)
c.SetPingHandler(nil)
@@ -443,11 +496,7 @@ func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
}
c.writer = mw
if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
- w, err := c.newCompressionWriter(c.writer)
- if err != nil {
- c.writer = nil
- return nil, err
- }
+ w := c.newCompressionWriter(c.writer, c.compressionLevel)
mw.compress = true
c.writer = w
}
@@ -654,12 +703,33 @@ func (w *messageWriter) Close() error {
return nil
}
+// WritePreparedMessage writes prepared message into connection.
+func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error {
+ frameType, frameData, err := pm.frame(prepareKey{
+ isServer: c.isServer,
+ compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType),
+ compressionLevel: c.compressionLevel,
+ })
+ if err != nil {
+ return err
+ }
+ if c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = true
+ err = c.write(frameType, c.writeDeadline, frameData, nil)
+ if !c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = false
+ return err
+}
+
// WriteMessage is a helper method for getting a writer using NextWriter,
// writing the message and closing the writer.
func (c *Conn) WriteMessage(messageType int, data []byte) error {
if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) {
-
// Fast path with no allocations and single frame.
if err := c.prepWrite(messageType); err != nil {
@@ -855,6 +925,11 @@ func (c *Conn) handleProtocolError(message string) error {
// permanent. Once this method returns a non-nil error, all subsequent calls to
// this method return the same error.
func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
+ // Close previous reader, only relevant for decompression.
+ if c.reader != nil {
+ c.reader.Close()
+ c.reader = nil
+ }
c.messageReader = nil
c.readLength = 0
@@ -867,11 +942,11 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
}
if frameType == TextMessage || frameType == BinaryMessage {
c.messageReader = &messageReader{c}
- var r io.Reader = c.messageReader
+ c.reader = c.messageReader
if c.readDecompress {
- r = c.newDecompressionReader(r)
+ c.reader = c.newDecompressionReader(c.reader)
}
- return frameType, r, nil
+ return frameType, c.reader, nil
}
}
@@ -933,6 +1008,10 @@ func (r *messageReader) Read(b []byte) (int, error) {
return 0, err
}
+func (r *messageReader) Close() error {
+ return nil
+}
+
// ReadMessage is a helper method for getting a reader using NextReader and
// reading from that reader to a buffer.
func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
@@ -969,6 +1048,15 @@ func (c *Conn) CloseHandler() func(code int, text string) error {
// The code argument to h is the received close code or CloseNoStatusReceived
// if the close message is empty. The default close handler sends a close frame
// back to the peer.
+//
+// The application must read the connection to process close messages as
+// described in the section on Control Frames above.
+//
+// The connection read methods return a CloseError when a close frame is
+// received. Most applications should handle close messages as part of their
+// normal error handling. Applications should only set a close handler when the
+// application must perform some action before sending a close frame back to
+// the peer.
func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
if h == nil {
h = func(code int, text string) error {
@@ -991,6 +1079,9 @@ func (c *Conn) PingHandler() func(appData string) error {
// SetPingHandler sets the handler for ping messages received from the peer.
// The appData argument to h is the PING frame application data. The default
// ping handler sends a pong to the peer.
+//
+// The application must read the connection to process ping messages as
+// described in the section on Control Frames above.
func (c *Conn) SetPingHandler(h func(appData string) error) {
if h == nil {
h = func(message string) error {
@@ -1014,6 +1105,9 @@ func (c *Conn) PongHandler() func(appData string) error {
// SetPongHandler sets the handler for pong messages received from the peer.
// The appData argument to h is the PONG frame application data. The default
// pong handler does nothing.
+//
+// The application must read the connection to process ping messages as
+// described in the section on Control Frames above.
func (c *Conn) SetPongHandler(h func(appData string) error) {
if h == nil {
h = func(string) error { return nil }
@@ -1034,6 +1128,18 @@ func (c *Conn) EnableWriteCompression(enable bool) {
c.enableWriteCompression = enable
}
+// SetCompressionLevel sets the flate compression level for subsequent text and
+// binary messages. This function is a noop if compression was not negotiated
+// with the peer. See the compress/flate package for a description of
+// compression levels.
+func (c *Conn) SetCompressionLevel(level int) error {
+ if !isValidCompressionLevel(level) {
+ return errors.New("websocket: invalid compression level")
+ }
+ c.compressionLevel = level
+ return nil
+}
+
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
func FormatCloseMessage(closeCode int, text string) []byte {
buf := make([]byte, 2+len(text))
diff --git a/vendor/github.com/gorilla/websocket/conn_broadcast_test.go b/vendor/github.com/gorilla/websocket/conn_broadcast_test.go
new file mode 100644
index 000000000..45038e488
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/conn_broadcast_test.go
@@ -0,0 +1,134 @@
+// Copyright 2017 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.
+
+// +build go1.7
+
+package websocket
+
+import (
+ "io"
+ "io/ioutil"
+ "sync/atomic"
+ "testing"
+)
+
+// broadcastBench allows to run broadcast benchmarks.
+// In every broadcast benchmark we create many connections, then send the same
+// message into every connection and wait for all writes complete. This emulates
+// an application where many connections listen to the same data - i.e. PUB/SUB
+// scenarios with many subscribers in one channel.
+type broadcastBench struct {
+ w io.Writer
+ message *broadcastMessage
+ closeCh chan struct{}
+ doneCh chan struct{}
+ count int32
+ conns []*broadcastConn
+ compression bool
+ usePrepared bool
+}
+
+type broadcastMessage struct {
+ payload []byte
+ prepared *PreparedMessage
+}
+
+type broadcastConn struct {
+ conn *Conn
+ msgCh chan *broadcastMessage
+}
+
+func newBroadcastConn(c *Conn) *broadcastConn {
+ return &broadcastConn{
+ conn: c,
+ msgCh: make(chan *broadcastMessage, 1),
+ }
+}
+
+func newBroadcastBench(usePrepared, compression bool) *broadcastBench {
+ bench := &broadcastBench{
+ w: ioutil.Discard,
+ doneCh: make(chan struct{}),
+ closeCh: make(chan struct{}),
+ usePrepared: usePrepared,
+ compression: compression,
+ }
+ msg := &broadcastMessage{
+ payload: textMessages(1)[0],
+ }
+ if usePrepared {
+ pm, _ := NewPreparedMessage(TextMessage, msg.payload)
+ msg.prepared = pm
+ }
+ bench.message = msg
+ bench.makeConns(10000)
+ return bench
+}
+
+func (b *broadcastBench) makeConns(numConns int) {
+ conns := make([]*broadcastConn, numConns)
+
+ for i := 0; i < numConns; i++ {
+ c := newConn(fakeNetConn{Reader: nil, Writer: b.w}, true, 1024, 1024)
+ if b.compression {
+ c.enableWriteCompression = true
+ c.newCompressionWriter = compressNoContextTakeover
+ }
+ conns[i] = newBroadcastConn(c)
+ go func(c *broadcastConn) {
+ for {
+ select {
+ case msg := <-c.msgCh:
+ if b.usePrepared {
+ c.conn.WritePreparedMessage(msg.prepared)
+ } else {
+ c.conn.WriteMessage(TextMessage, msg.payload)
+ }
+ val := atomic.AddInt32(&b.count, 1)
+ if val%int32(numConns) == 0 {
+ b.doneCh <- struct{}{}
+ }
+ case <-b.closeCh:
+ return
+ }
+ }
+ }(conns[i])
+ }
+ b.conns = conns
+}
+
+func (b *broadcastBench) close() {
+ close(b.closeCh)
+}
+
+func (b *broadcastBench) runOnce() {
+ for _, c := range b.conns {
+ c.msgCh <- b.message
+ }
+ <-b.doneCh
+}
+
+func BenchmarkBroadcast(b *testing.B) {
+ benchmarks := []struct {
+ name string
+ usePrepared bool
+ compression bool
+ }{
+ {"NoCompression", false, false},
+ {"WithCompression", false, true},
+ {"NoCompressionPrepared", true, false},
+ {"WithCompressionPrepared", true, true},
+ }
+ for _, bm := range benchmarks {
+ b.Run(bm.name, func(b *testing.B) {
+ bench := newBroadcastBench(bm.usePrepared, bm.compression)
+ defer bench.close()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bench.runOnce()
+ }
+ b.ReportAllocs()
+ })
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/conn_test.go b/vendor/github.com/gorilla/websocket/conn_test.go
index 7431383b1..06e9bc3f5 100644
--- a/vendor/github.com/gorilla/websocket/conn_test.go
+++ b/vendor/github.com/gorilla/websocket/conn_test.go
@@ -463,3 +463,35 @@ func TestFailedConnectionReadPanic(t *testing.T) {
}
t.Fatal("should not get here")
}
+
+func TestBufioReuse(t *testing.T) {
+ brw := bufio.NewReadWriter(bufio.NewReader(nil), bufio.NewWriter(nil))
+ c := newConnBRW(nil, false, 0, 0, brw)
+
+ if c.br != brw.Reader {
+ t.Error("connection did not reuse bufio.Reader")
+ }
+
+ var wh writeHook
+ brw.Writer.Reset(&wh)
+ brw.WriteByte(0)
+ brw.Flush()
+ if &c.writeBuf[0] != &wh.p[0] {
+ t.Error("connection did not reuse bufio.Writer")
+ }
+
+ brw = bufio.NewReadWriter(bufio.NewReaderSize(nil, 0), bufio.NewWriterSize(nil, 0))
+ c = newConnBRW(nil, false, 0, 0, brw)
+
+ if c.br == brw.Reader {
+ t.Error("connection used bufio.Reader with small size")
+ }
+
+ brw.Writer.Reset(&wh)
+ brw.WriteByte(0)
+ brw.Flush()
+ if &c.writeBuf[0] != &wh.p[0] {
+ t.Error("connection used bufio.Writer with small size")
+ }
+
+}
diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go
index 610acf712..e291a952c 100644
--- a/vendor/github.com/gorilla/websocket/doc.go
+++ b/vendor/github.com/gorilla/websocket/doc.go
@@ -118,9 +118,10 @@
//
// Applications are responsible for ensuring that no more than one goroutine
// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
-// WriteJSON) concurrently and that no more than one goroutine calls the read
-// methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler,
-// SetPingHandler) concurrently.
+// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and
+// that no more than one goroutine calls the read methods (NextReader,
+// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler)
+// concurrently.
//
// The Close and WriteControl methods can be called concurrently with all other
// methods.
@@ -150,19 +151,25 @@
// application's responsibility to check the Origin header before calling
// Upgrade.
//
-// Compression [Experimental]
+// Compression EXPERIMENTAL
//
// Per message compression extensions (RFC 7692) are experimentally supported
// by this package in a limited capacity. Setting the EnableCompression option
// to true in Dialer or Upgrader will attempt to negotiate per message deflate
-// support. If compression was successfully negotiated with the connection's
-// peer, any message received in compressed form will be automatically
-// decompressed. All Read methods will return uncompressed bytes.
+// support.
+//
+// var upgrader = websocket.Upgrader{
+// EnableCompression: true,
+// }
+//
+// If compression was successfully negotiated with the connection's peer, any
+// message received in compressed form will be automatically decompressed.
+// All Read methods will return uncompressed bytes.
//
// Per message compression of messages written to a connection can be enabled
// or disabled by calling the corresponding Conn method:
//
-// conn.EnableWriteCompression(true)
+// conn.EnableWriteCompression(false)
//
// Currently this package does not support compression with "context takeover".
// This means that messages must be compressed and decompressed in isolation,
diff --git a/vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json b/vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json
index 27d5a5b14..aa3a0bc0a 100644
--- a/vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json
+++ b/vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json
@@ -4,6 +4,7 @@
"outdir": "./reports/clients",
"servers": [
{"agent": "ReadAllWriteMessage", "url": "ws://localhost:9000/m", "options": {"version": 18}},
+ {"agent": "ReadAllWritePreparedMessage", "url": "ws://localhost:9000/p", "options": {"version": 18}},
{"agent": "ReadAllWrite", "url": "ws://localhost:9000/r", "options": {"version": 18}},
{"agent": "CopyFull", "url": "ws://localhost:9000/f", "options": {"version": 18}},
{"agent": "CopyWriterOnly", "url": "ws://localhost:9000/c", "options": {"version": 18}}
diff --git a/vendor/github.com/gorilla/websocket/examples/autobahn/server.go b/vendor/github.com/gorilla/websocket/examples/autobahn/server.go
index e98563be9..3db880f90 100644
--- a/vendor/github.com/gorilla/websocket/examples/autobahn/server.go
+++ b/vendor/github.com/gorilla/websocket/examples/autobahn/server.go
@@ -85,7 +85,7 @@ func echoCopyFull(w http.ResponseWriter, r *http.Request) {
// echoReadAll echoes messages from the client by reading the entire message
// with ioutil.ReadAll.
-func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage bool) {
+func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage, writePrepared bool) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade:", err)
@@ -109,9 +109,21 @@ func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage bool) {
}
}
if writeMessage {
- err = conn.WriteMessage(mt, b)
- if err != nil {
- log.Println("WriteMessage:", err)
+ if !writePrepared {
+ err = conn.WriteMessage(mt, b)
+ if err != nil {
+ log.Println("WriteMessage:", err)
+ }
+ } else {
+ pm, err := websocket.NewPreparedMessage(mt, b)
+ if err != nil {
+ log.Println("NewPreparedMessage:", err)
+ return
+ }
+ err = conn.WritePreparedMessage(pm)
+ if err != nil {
+ log.Println("WritePreparedMessage:", err)
+ }
}
} else {
w, err := conn.NextWriter(mt)
@@ -132,11 +144,15 @@ func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage bool) {
}
func echoReadAllWriter(w http.ResponseWriter, r *http.Request) {
- echoReadAll(w, r, false)
+ echoReadAll(w, r, false, false)
}
func echoReadAllWriteMessage(w http.ResponseWriter, r *http.Request) {
- echoReadAll(w, r, true)
+ echoReadAll(w, r, true, false)
+}
+
+func echoReadAllWritePreparedMessage(w http.ResponseWriter, r *http.Request) {
+ echoReadAll(w, r, true, true)
}
func serveHome(w http.ResponseWriter, r *http.Request) {
@@ -161,6 +177,7 @@ func main() {
http.HandleFunc("/f", echoCopyFull)
http.HandleFunc("/r", echoReadAllWriter)
http.HandleFunc("/m", echoReadAllWriteMessage)
+ http.HandleFunc("/p", echoReadAllWritePreparedMessage)
err := http.ListenAndServe(*addr, nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
diff --git a/vendor/github.com/gorilla/websocket/examples/chat/home.html b/vendor/github.com/gorilla/websocket/examples/chat/home.html
index 7262918ec..a39a0c276 100644
--- a/vendor/github.com/gorilla/websocket/examples/chat/home.html
+++ b/vendor/github.com/gorilla/websocket/examples/chat/home.html
@@ -9,7 +9,7 @@ window.onload = function () {
var log = document.getElementById("log");
function appendLog(item) {
- var doScroll = log.scrollTop === log.scrollHeight - log.clientHeight;
+ var doScroll = log.scrollTop > log.scrollHeight - log.clientHeight - 1;
log.appendChild(item);
if (doScroll) {
log.scrollTop = log.scrollHeight - log.clientHeight;
@@ -29,7 +29,7 @@ window.onload = function () {
};
if (window["WebSocket"]) {
- conn = new WebSocket("ws://{{$}}/ws");
+ conn = new WebSocket("ws://" + document.location.host + "/ws");
conn.onclose = function (evt) {
var item = document.createElement("div");
item.innerHTML = "<b>Connection closed.</b>";
diff --git a/vendor/github.com/gorilla/websocket/examples/chat/main.go b/vendor/github.com/gorilla/websocket/examples/chat/main.go
index a865ffec5..74615d59c 100644
--- a/vendor/github.com/gorilla/websocket/examples/chat/main.go
+++ b/vendor/github.com/gorilla/websocket/examples/chat/main.go
@@ -8,11 +8,9 @@ import (
"flag"
"log"
"net/http"
- "text/template"
)
var addr = flag.String("addr", ":8080", "http service address")
-var homeTemplate = template.Must(template.ParseFiles("home.html"))
func serveHome(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL)
@@ -24,8 +22,7 @@ func serveHome(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Method not allowed", 405)
return
}
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- homeTemplate.Execute(w, r.Host)
+ http.ServeFile(w, r, "home.html")
}
func main() {
diff --git a/vendor/github.com/gorilla/websocket/examples/command/README.md b/vendor/github.com/gorilla/websocket/examples/command/README.md
index c30d3979a..ed6f78684 100644
--- a/vendor/github.com/gorilla/websocket/examples/command/README.md
+++ b/vendor/github.com/gorilla/websocket/examples/command/README.md
@@ -2,7 +2,7 @@
This example connects a websocket connection to stdin and stdout of a command.
Received messages are written to stdin followed by a `\n`. Each line read from
-from standard out is sent as a message to the client.
+standard out is sent as a message to the client.
$ go get github.com/gorilla/websocket
$ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/command`
diff --git a/vendor/github.com/gorilla/websocket/examples/command/home.html b/vendor/github.com/gorilla/websocket/examples/command/home.html
index 72fd02b2a..19c46128a 100644
--- a/vendor/github.com/gorilla/websocket/examples/command/home.html
+++ b/vendor/github.com/gorilla/websocket/examples/command/home.html
@@ -2,47 +2,53 @@
<html lang="en">
<head>
<title>Command Example</title>
-<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script type="text/javascript">
- $(function() {
-
+window.onload = function () {
var conn;
- var msg = $("#msg");
- var log = $("#log");
+ var msg = document.getElementById("msg");
+ var log = document.getElementById("log");
- function appendLog(msg) {
- var d = log[0]
- var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
- msg.appendTo(log)
+ function appendLog(item) {
+ var doScroll = log.scrollTop > log.scrollHeight - log.clientHeight - 1;
+ log.appendChild(item);
if (doScroll) {
- d.scrollTop = d.scrollHeight - d.clientHeight;
+ log.scrollTop = log.scrollHeight - log.clientHeight;
}
}
- $("#form").submit(function() {
+ document.getElementById("form").onsubmit = function () {
if (!conn) {
return false;
}
- if (!msg.val()) {
+ if (!msg.value) {
return false;
}
- conn.send(msg.val());
- msg.val("");
- return false
- });
+ conn.send(msg.value);
+ msg.value = "";
+ return false;
+ };
if (window["WebSocket"]) {
- conn = new WebSocket("ws://{{$}}/ws");
- conn.onclose = function(evt) {
- appendLog($("<div><b>Connection closed.</b></div>"))
- }
- conn.onmessage = function(evt) {
- appendLog($("<pre/>").text(evt.data))
- }
+ conn = new WebSocket("ws://" + document.location.host + "/ws");
+ conn.onclose = function (evt) {
+ var item = document.createElement("div");
+ item.innerHTML = "<b>Connection closed.</b>";
+ appendLog(item);
+ };
+ conn.onmessage = function (evt) {
+ var messages = evt.data.split('\n');
+ for (var i = 0; i < messages.length; i++) {
+ var item = document.createElement("div");
+ item.innerText = messages[i];
+ appendLog(item);
+ }
+ };
} else {
- appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
+ var item = document.createElement("div");
+ item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
+ appendLog(item);
}
- });
+};
</script>
<style type="text/css">
html {
diff --git a/vendor/github.com/gorilla/websocket/examples/command/main.go b/vendor/github.com/gorilla/websocket/examples/command/main.go
index 438fb8328..239c5c85c 100644
--- a/vendor/github.com/gorilla/websocket/examples/command/main.go
+++ b/vendor/github.com/gorilla/websocket/examples/command/main.go
@@ -12,16 +12,14 @@ import (
"net/http"
"os"
"os/exec"
- "text/template"
"time"
"github.com/gorilla/websocket"
)
var (
- addr = flag.String("addr", "127.0.0.1:8080", "http service address")
- cmdPath string
- homeTempl = template.Must(template.ParseFiles("home.html"))
+ addr = flag.String("addr", "127.0.0.1:8080", "http service address")
+ cmdPath string
)
const (
@@ -176,8 +174,7 @@ func serveHome(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Method not allowed", 405)
return
}
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- homeTempl.Execute(w, r.Host)
+ http.ServeFile(w, r, "home.html")
}
func main() {
diff --git a/vendor/github.com/gorilla/websocket/examples/filewatch/main.go b/vendor/github.com/gorilla/websocket/examples/filewatch/main.go
index 2ac2b324f..f5f9da5c3 100644
--- a/vendor/github.com/gorilla/websocket/examples/filewatch/main.go
+++ b/vendor/github.com/gorilla/websocket/examples/filewatch/main.go
@@ -6,12 +6,12 @@ package main
import (
"flag"
+ "html/template"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
- "text/template"
"time"
"github.com/gorilla/websocket"
diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go
index 6758a2cb7..6a88bbc74 100644
--- a/vendor/github.com/gorilla/websocket/mask.go
+++ b/vendor/github.com/gorilla/websocket/mask.go
@@ -2,20 +2,14 @@
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.
+// +build !appengine
+
package websocket
-import (
- "math/rand"
- "unsafe"
-)
+import "unsafe"
const wordSize = int(unsafe.Sizeof(uintptr(0)))
-func newMaskKey() [4]byte {
- n := rand.Uint32()
- return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
-}
-
func maskBytes(key [4]byte, pos int, b []byte) int {
// Mask one byte at a time for small buffers.
diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go
new file mode 100644
index 000000000..2aac060e5
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/mask_safe.go
@@ -0,0 +1,15 @@
+// Copyright 2016 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.
+
+// +build appengine
+
+package websocket
+
+func maskBytes(key [4]byte, pos int, b []byte) int {
+ for i := range b {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+ return pos & 3
+}
diff --git a/vendor/github.com/gorilla/websocket/mask_test.go b/vendor/github.com/gorilla/websocket/mask_test.go
index de0602993..298a1e509 100644
--- a/vendor/github.com/gorilla/websocket/mask_test.go
+++ b/vendor/github.com/gorilla/websocket/mask_test.go
@@ -3,7 +3,7 @@
// LICENSE file.
// Require 1.7 for sub-bencmarks
-// +build go1.7
+// +build go1.7,!appengine
package websocket
diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go
new file mode 100644
index 000000000..1efffbd1e
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/prepared.go
@@ -0,0 +1,103 @@
+// Copyright 2017 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 websocket
+
+import (
+ "bytes"
+ "net"
+ "sync"
+ "time"
+)
+
+// PreparedMessage caches on the wire representations of a message payload.
+// Use PreparedMessage to efficiently send a message payload to multiple
+// connections. PreparedMessage is especially useful when compression is used
+// because the CPU and memory expensive compression operation can be executed
+// once for a given set of compression options.
+type PreparedMessage struct {
+ messageType int
+ data []byte
+ err error
+ mu sync.Mutex
+ frames map[prepareKey]*preparedFrame
+}
+
+// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage.
+type prepareKey struct {
+ isServer bool
+ compress bool
+ compressionLevel int
+}
+
+// preparedFrame contains data in wire representation.
+type preparedFrame struct {
+ once sync.Once
+ data []byte
+}
+
+// NewPreparedMessage returns an initialized PreparedMessage. You can then send
+// it to connection using WritePreparedMessage method. Valid wire
+// representation will be calculated lazily only once for a set of current
+// connection options.
+func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) {
+ pm := &PreparedMessage{
+ messageType: messageType,
+ frames: make(map[prepareKey]*preparedFrame),
+ data: data,
+ }
+
+ // Prepare a plain server frame.
+ _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false})
+ if err != nil {
+ return nil, err
+ }
+
+ // To protect against caller modifying the data argument, remember the data
+ // copied to the plain server frame.
+ pm.data = frameData[len(frameData)-len(data):]
+ return pm, nil
+}
+
+func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
+ pm.mu.Lock()
+ frame, ok := pm.frames[key]
+ if !ok {
+ frame = &preparedFrame{}
+ pm.frames[key] = frame
+ }
+ pm.mu.Unlock()
+
+ var err error
+ frame.once.Do(func() {
+ // Prepare a frame using a 'fake' connection.
+ // TODO: Refactor code in conn.go to allow more direct construction of
+ // the frame.
+ mu := make(chan bool, 1)
+ mu <- true
+ var nc prepareConn
+ c := &Conn{
+ conn: &nc,
+ mu: mu,
+ isServer: key.isServer,
+ compressionLevel: key.compressionLevel,
+ enableWriteCompression: true,
+ writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize),
+ }
+ if key.compress {
+ c.newCompressionWriter = compressNoContextTakeover
+ }
+ err = c.WriteMessage(pm.messageType, pm.data)
+ frame.data = nc.buf.Bytes()
+ })
+ return pm.messageType, frame.data, err
+}
+
+type prepareConn struct {
+ buf bytes.Buffer
+ net.Conn
+}
+
+func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) }
+func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }
diff --git a/vendor/github.com/gorilla/websocket/prepared_test.go b/vendor/github.com/gorilla/websocket/prepared_test.go
new file mode 100644
index 000000000..cf98c6c10
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/prepared_test.go
@@ -0,0 +1,74 @@
+// Copyright 2017 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 websocket
+
+import (
+ "bytes"
+ "compress/flate"
+ "math/rand"
+ "testing"
+)
+
+var preparedMessageTests = []struct {
+ messageType int
+ isServer bool
+ enableWriteCompression bool
+ compressionLevel int
+}{
+ // Server
+ {TextMessage, true, false, flate.BestSpeed},
+ {TextMessage, true, true, flate.BestSpeed},
+ {TextMessage, true, true, flate.BestCompression},
+ {PingMessage, true, false, flate.BestSpeed},
+ {PingMessage, true, true, flate.BestSpeed},
+
+ // Client
+ {TextMessage, false, false, flate.BestSpeed},
+ {TextMessage, false, true, flate.BestSpeed},
+ {TextMessage, false, true, flate.BestCompression},
+ {PingMessage, false, false, flate.BestSpeed},
+ {PingMessage, false, true, flate.BestSpeed},
+}
+
+func TestPreparedMessage(t *testing.T) {
+ for _, tt := range preparedMessageTests {
+ var data = []byte("this is a test")
+ var buf bytes.Buffer
+ c := newConn(fakeNetConn{Reader: nil, Writer: &buf}, tt.isServer, 1024, 1024)
+ if tt.enableWriteCompression {
+ c.newCompressionWriter = compressNoContextTakeover
+ }
+ c.SetCompressionLevel(tt.compressionLevel)
+
+ // Seed random number generator for consistent frame mask.
+ rand.Seed(1234)
+
+ if err := c.WriteMessage(tt.messageType, data); err != nil {
+ t.Fatal(err)
+ }
+ want := buf.String()
+
+ pm, err := NewPreparedMessage(tt.messageType, data)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Scribble on data to ensure that NewPreparedMessage takes a snapshot.
+ copy(data, "hello world")
+
+ // Seed random number generator for consistent frame mask.
+ rand.Seed(1234)
+
+ buf.Reset()
+ if err := c.WritePreparedMessage(pm); err != nil {
+ t.Fatal(err)
+ }
+ got := buf.String()
+
+ if got != want {
+ t.Errorf("write message != prepared message for %+v", tt)
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go
index aaedebdbe..3495e0f1a 100644
--- a/vendor/github.com/gorilla/websocket/server.go
+++ b/vendor/github.com/gorilla/websocket/server.go
@@ -28,8 +28,9 @@ type Upgrader struct {
HandshakeTimeout time.Duration
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
- // size is zero, then a default value of 4096 is used. The I/O buffer sizes
- // do not limit the size of the messages that can be sent or received.
+ // 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
// Subprotocols specifies the server's supported protocols in order of
@@ -104,23 +105,23 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header
// response.
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
if r.Method != "GET" {
- return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET")
+ return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET")
}
if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
- return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific Sec-Websocket-Extensions headers are unsupported")
- }
-
- if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
+ return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported")
}
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'")
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header")
}
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'")
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header")
+ }
+
+ if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
}
checkOrigin := u.CheckOrigin
@@ -128,12 +129,12 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
checkOrigin = checkSameOrigin
}
if !checkOrigin(r) {
- return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
+ return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed")
}
challengeKey := r.Header.Get("Sec-Websocket-Key")
if challengeKey == "" {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-Websocket-Key' header is missing or blank")
}
subprotocol := u.selectSubprotocol(r, responseHeader)
@@ -152,7 +153,6 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
var (
netConn net.Conn
- br *bufio.Reader
err error
)
@@ -160,19 +160,18 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
if !ok {
return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
}
- var rw *bufio.ReadWriter
- netConn, rw, err = h.Hijack()
+ var brw *bufio.ReadWriter
+ netConn, brw, err = h.Hijack()
if err != nil {
return u.returnError(w, r, http.StatusInternalServerError, err.Error())
}
- br = rw.Reader
- if br.Buffered() > 0 {
+ if brw.Reader.Buffered() > 0 {
netConn.Close()
return nil, errors.New("websocket: client sent data before handshake is complete")
}
- c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
+ c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw)
c.subprotocol = subprotocol
if compress {