summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gorilla/websocket
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gorilla/websocket')
-rw-r--r--vendor/github.com/gorilla/websocket/.travis.yml19
-rw-r--r--vendor/github.com/gorilla/websocket/README.md10
-rw-r--r--vendor/github.com/gorilla/websocket/client.go4
-rw-r--r--vendor/github.com/gorilla/websocket/conn.go112
-rw-r--r--vendor/github.com/gorilla/websocket/doc.go47
-rw-r--r--vendor/github.com/gorilla/websocket/go.mod3
-rw-r--r--vendor/github.com/gorilla/websocket/go.sum2
-rw-r--r--vendor/github.com/gorilla/websocket/join.go42
-rw-r--r--vendor/github.com/gorilla/websocket/proxy.go8
-rw-r--r--vendor/github.com/gorilla/websocket/server.go4
-rw-r--r--vendor/github.com/gorilla/websocket/util.go132
11 files changed, 270 insertions, 113 deletions
diff --git a/vendor/github.com/gorilla/websocket/.travis.yml b/vendor/github.com/gorilla/websocket/.travis.yml
deleted file mode 100644
index a49db51c..00000000
--- a/vendor/github.com/gorilla/websocket/.travis.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-language: go
-sudo: false
-
-matrix:
- include:
- - go: 1.7.x
- - go: 1.8.x
- - go: 1.9.x
- - go: 1.10.x
- - go: 1.11.x
- - go: tip
- allow_failures:
- - go: tip
-
-script:
- - go get -t -v ./...
- - diff -u <(echo -n) <(gofmt -d .)
- - go vet $(go list ./... | grep -v /vendor/)
- - go test -v -race ./...
diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md
index 20e391f8..0827d059 100644
--- a/vendor/github.com/gorilla/websocket/README.md
+++ b/vendor/github.com/gorilla/websocket/README.md
@@ -1,11 +1,11 @@
# Gorilla WebSocket
+[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
+[![CircleCI](https://circleci.com/gh/gorilla/websocket.svg?style=svg)](https://circleci.com/gh/gorilla/websocket)
+
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
-[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket)
-[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
-
### Documentation
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
@@ -27,7 +27,7 @@ package API is stable.
### Protocol Compliance
The Gorilla WebSocket package passes the server tests in the [Autobahn Test
-Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn
+Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn
subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
### Gorilla WebSocket compared with other packages
@@ -40,7 +40,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
</tr>
<tr>
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
-<tr><td>Passes <a href="http://autobahn.ws/testsuite/">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr>
+<tr><td>Passes <a href="https://github.com/crossbario/autobahn-testsuite">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr>
<tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>
diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go
index 2e32fd50..962c06a3 100644
--- a/vendor/github.com/gorilla/websocket/client.go
+++ b/vendor/github.com/gorilla/websocket/client.go
@@ -70,7 +70,7 @@ type Dialer struct {
// HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration
- // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. 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
@@ -140,7 +140,7 @@ var nilDialer = *DefaultDialer
// Use the response.Header to get the selected subprotocol
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
//
-// The context will be used in the request and in the Dialer
+// The context will be used in the request and in the Dialer.
//
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
// non-nil *http.Response so that callers can handle redirects, authentication,
diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go
index d2a21c14..6f17cd29 100644
--- a/vendor/github.com/gorilla/websocket/conn.go
+++ b/vendor/github.com/gorilla/websocket/conn.go
@@ -260,10 +260,12 @@ type Conn struct {
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.
+ reader io.ReadCloser // the current reader returned to the application
+ readErr error
+ br *bufio.Reader
+ // bytes remaining in current frame.
+ // set setReadRemaining to safely update this value and prevent overflow
+ readRemaining int64
readFinal bool // true the current message has more frames.
readLength int64 // Message size.
readLimit int64 // Maximum message size.
@@ -320,6 +322,17 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int,
return c
}
+// setReadRemaining tracks the number of bytes remaining on the connection. If n
+// overflows, an ErrReadLimit is returned.
+func (c *Conn) setReadRemaining(n int64) error {
+ if n < 0 {
+ return ErrReadLimit
+ }
+
+ c.readRemaining = n
+ return nil
+}
+
// Subprotocol returns the negotiated protocol for the connection.
func (c *Conn) Subprotocol() string {
return c.subprotocol
@@ -451,7 +464,8 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
return err
}
-func (c *Conn) prepWrite(messageType int) error {
+// beginMessage prepares a connection and message writer for a new message.
+func (c *Conn) beginMessage(mw *messageWriter, messageType int) error {
// Close previous writer if not already closed by the application. It's
// probably better to return an error in this situation, but we cannot
// change this without breaking existing applications.
@@ -471,6 +485,10 @@ func (c *Conn) prepWrite(messageType int) error {
return err
}
+ mw.c = c
+ mw.frameType = messageType
+ mw.pos = maxFrameHeaderSize
+
if c.writeBuf == nil {
wpd, ok := c.writePool.Get().(writePoolData)
if ok {
@@ -491,16 +509,11 @@ func (c *Conn) prepWrite(messageType int) error {
// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
// PongMessage) are supported.
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
- if err := c.prepWrite(messageType); err != nil {
+ var mw messageWriter
+ if err := c.beginMessage(&mw, messageType); err != nil {
return nil, err
}
-
- mw := &messageWriter{
- c: c,
- frameType: messageType,
- pos: maxFrameHeaderSize,
- }
- c.writer = mw
+ c.writer = &mw
if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
w := c.newCompressionWriter(c.writer, c.compressionLevel)
mw.compress = true
@@ -517,10 +530,16 @@ type messageWriter struct {
err error
}
-func (w *messageWriter) fatal(err error) error {
+func (w *messageWriter) endMessage(err error) error {
if w.err != nil {
- w.err = err
- w.c.writer = nil
+ return err
+ }
+ c := w.c
+ w.err = err
+ c.writer = nil
+ if c.writePool != nil {
+ c.writePool.Put(writePoolData{buf: c.writeBuf})
+ c.writeBuf = nil
}
return err
}
@@ -534,7 +553,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
// Check for invalid control frames.
if isControl(w.frameType) &&
(!final || length > maxControlFramePayloadSize) {
- return w.fatal(errInvalidControlFrame)
+ return w.endMessage(errInvalidControlFrame)
}
b0 := byte(w.frameType)
@@ -579,7 +598,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
if len(extra) > 0 {
- return c.writeFatal(errors.New("websocket: internal error, extra used in client mode"))
+ return w.endMessage(c.writeFatal(errors.New("websocket: internal error, extra used in client mode")))
}
}
@@ -600,15 +619,11 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
c.isWriting = false
if err != nil {
- return w.fatal(err)
+ return w.endMessage(err)
}
if final {
- c.writer = nil
- if c.writePool != nil {
- c.writePool.Put(writePoolData{buf: c.writeBuf})
- c.writeBuf = nil
- }
+ w.endMessage(errWriteClosed)
return nil
}
@@ -706,11 +721,7 @@ func (w *messageWriter) Close() error {
if w.err != nil {
return w.err
}
- if err := w.flushFrame(true, nil); err != nil {
- return err
- }
- w.err = errWriteClosed
- return nil
+ return w.flushFrame(true, nil)
}
// WritePreparedMessage writes prepared message into connection.
@@ -742,10 +753,10 @@ 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 {
+ var mw messageWriter
+ if err := c.beginMessage(&mw, messageType); err != nil {
return err
}
- mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize}
n := copy(c.writeBuf[mw.pos:], data)
mw.pos += n
data = data[n:]
@@ -792,7 +803,7 @@ func (c *Conn) advanceFrame() (int, error) {
final := p[0]&finalBit != 0
frameType := int(p[0] & 0xf)
mask := p[1]&maskBit != 0
- c.readRemaining = int64(p[1] & 0x7f)
+ c.setReadRemaining(int64(p[1] & 0x7f))
c.readDecompress = false
if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
@@ -826,7 +837,17 @@ func (c *Conn) advanceFrame() (int, error) {
return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType))
}
- // 3. Read and parse frame length.
+ // 3. Read and parse frame length as per
+ // https://tools.ietf.org/html/rfc6455#section-5.2
+ //
+ // The length of the "Payload data", in bytes: if 0-125, that is the payload
+ // length.
+ // - If 126, the following 2 bytes interpreted as a 16-bit unsigned
+ // integer are the payload length.
+ // - If 127, the following 8 bytes interpreted as
+ // a 64-bit unsigned integer (the most significant bit MUST be 0) are the
+ // payload length. Multibyte length quantities are expressed in network byte
+ // order.
switch c.readRemaining {
case 126:
@@ -834,13 +855,19 @@ func (c *Conn) advanceFrame() (int, error) {
if err != nil {
return noFrame, err
}
- c.readRemaining = int64(binary.BigEndian.Uint16(p))
+
+ if err := c.setReadRemaining(int64(binary.BigEndian.Uint16(p))); err != nil {
+ return noFrame, err
+ }
case 127:
p, err := c.read(8)
if err != nil {
return noFrame, err
}
- c.readRemaining = int64(binary.BigEndian.Uint64(p))
+
+ if err := c.setReadRemaining(int64(binary.BigEndian.Uint64(p))); err != nil {
+ return noFrame, err
+ }
}
// 4. Handle frame masking.
@@ -863,6 +890,12 @@ func (c *Conn) advanceFrame() (int, error) {
if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
c.readLength += c.readRemaining
+ // Don't allow readLength to overflow in the presence of a large readRemaining
+ // counter.
+ if c.readLength < 0 {
+ return noFrame, ErrReadLimit
+ }
+
if c.readLimit > 0 && c.readLength > c.readLimit {
c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
return noFrame, ErrReadLimit
@@ -876,7 +909,7 @@ func (c *Conn) advanceFrame() (int, error) {
var payload []byte
if c.readRemaining > 0 {
payload, err = c.read(int(c.readRemaining))
- c.readRemaining = 0
+ c.setReadRemaining(0)
if err != nil {
return noFrame, err
}
@@ -949,6 +982,7 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
c.readErr = hideTempErr(err)
break
}
+
if frameType == TextMessage || frameType == BinaryMessage {
c.messageReader = &messageReader{c}
c.reader = c.messageReader
@@ -989,7 +1023,9 @@ func (r *messageReader) Read(b []byte) (int, error) {
if c.isServer {
c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
}
- c.readRemaining -= int64(n)
+ rem := c.readRemaining
+ rem -= int64(n)
+ c.setReadRemaining(rem)
if c.readRemaining > 0 && c.readErr == io.EOF {
c.readErr = errUnexpectedEOF
}
@@ -1041,7 +1077,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
-// SetReadLimit sets the maximum size for a message read from the peer. If a
+// SetReadLimit sets the maximum size in bytes for a message read from the peer. If a
// message exceeds the limit, the connection sends a close message to the peer
// and returns ErrReadLimit to the application.
func (c *Conn) SetReadLimit(limit int64) {
diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go
index dcce1a63..c6f4df89 100644
--- a/vendor/github.com/gorilla/websocket/doc.go
+++ b/vendor/github.com/gorilla/websocket/doc.go
@@ -151,6 +151,53 @@
// checking. The application is responsible for checking the Origin header
// before calling the Upgrade function.
//
+// Buffers
+//
+// Connections buffer network input and output to reduce the number
+// of system calls when reading or writing messages.
+//
+// Write buffers are also used for constructing WebSocket frames. See RFC 6455,
+// Section 5 for a discussion of message framing. A WebSocket frame header is
+// written to the network each time a write buffer is flushed to the network.
+// Decreasing the size of the write buffer can increase the amount of framing
+// overhead on the connection.
+//
+// The buffer sizes in bytes are specified by the ReadBufferSize and
+// WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default
+// size of 4096 when a buffer size field is set to zero. The Upgrader reuses
+// buffers created by the HTTP server when a buffer size field is set to zero.
+// The HTTP server buffers have a size of 4096 at the time of this writing.
+//
+// The buffer sizes do not limit the size of a message that can be read or
+// written by a connection.
+//
+// Buffers are held for the lifetime of the connection by default. If the
+// Dialer or Upgrader WriteBufferPool field is set, then a connection holds the
+// write buffer only when writing a message.
+//
+// Applications should tune the buffer sizes to balance memory use and
+// performance. Increasing the buffer size uses more memory, but can reduce the
+// number of system calls to read or write the network. In the case of writing,
+// increasing the buffer size can reduce the number of frame headers written to
+// the network.
+//
+// Some guidelines for setting buffer parameters are:
+//
+// Limit the buffer sizes to the maximum expected message size. Buffers larger
+// than the largest message do not provide any benefit.
+//
+// Depending on the distribution of message sizes, setting the buffer size to
+// to a value less than the maximum expected message size can greatly reduce
+// memory use with a small impact on performance. Here's an example: If 99% of
+// the messages are smaller than 256 bytes and the maximum message size is 512
+// bytes, then a buffer size of 256 bytes will result in 1.01 more system calls
+// than a buffer size of 512 bytes. The memory savings is 50%.
+//
+// A write buffer pool is useful when the application has a modest number
+// writes over a large number of connections. when buffers are pooled, a larger
+// buffer size has a reduced impact on total memory use and has the benefit of
+// reducing system calls and frame overhead.
+//
// Compression EXPERIMENTAL
//
// Per message compression extensions (RFC 7692) are experimentally supported
diff --git a/vendor/github.com/gorilla/websocket/go.mod b/vendor/github.com/gorilla/websocket/go.mod
new file mode 100644
index 00000000..1a7afd50
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/go.mod
@@ -0,0 +1,3 @@
+module github.com/gorilla/websocket
+
+go 1.12
diff --git a/vendor/github.com/gorilla/websocket/go.sum b/vendor/github.com/gorilla/websocket/go.sum
new file mode 100644
index 00000000..cf4fbbaa
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/go.sum
@@ -0,0 +1,2 @@
+github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
diff --git a/vendor/github.com/gorilla/websocket/join.go b/vendor/github.com/gorilla/websocket/join.go
new file mode 100644
index 00000000..c64f8c82
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/join.go
@@ -0,0 +1,42 @@
+// Copyright 2019 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 (
+ "io"
+ "strings"
+)
+
+// JoinMessages concatenates received messages to create a single io.Reader.
+// The string term is appended to each message. The returned reader does not
+// support concurrent calls to the Read method.
+func JoinMessages(c *Conn, term string) io.Reader {
+ return &joinReader{c: c, term: term}
+}
+
+type joinReader struct {
+ c *Conn
+ term string
+ r io.Reader
+}
+
+func (r *joinReader) Read(p []byte) (int, error) {
+ if r.r == nil {
+ var err error
+ _, r.r, err = r.c.NextReader()
+ if err != nil {
+ return 0, err
+ }
+ if r.term != "" {
+ r.r = io.MultiReader(r.r, strings.NewReader(r.term))
+ }
+ }
+ n, err := r.r.Read(p)
+ if err == io.EOF {
+ err = nil
+ r.r = nil
+ }
+ return n, err
+}
diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go
index bf2478e4..e87a8c9f 100644
--- a/vendor/github.com/gorilla/websocket/proxy.go
+++ b/vendor/github.com/gorilla/websocket/proxy.go
@@ -22,18 +22,18 @@ func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
func init() {
proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
- return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil
+ return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil
})
}
type httpProxyDialer struct {
- proxyURL *url.URL
- fowardDial func(network, addr string) (net.Conn, error)
+ proxyURL *url.URL
+ forwardDial func(network, addr string) (net.Conn, error)
}
func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
hostPort, _ := hostPortNoPort(hpd.proxyURL)
- conn, err := hpd.fowardDial(network, hostPort)
+ conn, err := hpd.forwardDial(network, hostPort)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go
index a761824b..887d5589 100644
--- a/vendor/github.com/gorilla/websocket/server.go
+++ b/vendor/github.com/gorilla/websocket/server.go
@@ -27,7 +27,7 @@ type Upgrader struct {
// HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration
- // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
// size is zero, then buffers allocated by the HTTP server are used. The
// I/O buffer sizes do not limit the size of the messages that can be sent
// or received.
@@ -153,7 +153,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
challengeKey := r.Header.Get("Sec-Websocket-Key")
if challengeKey == "" {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is 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)
diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go
index 354001e1..7bf2f66c 100644
--- a/vendor/github.com/gorilla/websocket/util.go
+++ b/vendor/github.com/gorilla/websocket/util.go
@@ -31,68 +31,113 @@ func generateChallengeKey() (string, error) {
return base64.StdEncoding.EncodeToString(p), nil
}
-// Octet types from RFC 2616.
-var octetTypes [256]byte
-
-const (
- isTokenOctet = 1 << iota
- isSpaceOctet
-)
-
-func init() {
- // From RFC 2616
- //
- // OCTET = <any 8-bit sequence of data>
- // CHAR = <any US-ASCII character (octets 0 - 127)>
- // CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
- // CR = <US-ASCII CR, carriage return (13)>
- // LF = <US-ASCII LF, linefeed (10)>
- // SP = <US-ASCII SP, space (32)>
- // HT = <US-ASCII HT, horizontal-tab (9)>
- // <"> = <US-ASCII double-quote mark (34)>
- // CRLF = CR LF
- // LWS = [CRLF] 1*( SP | HT )
- // TEXT = <any OCTET except CTLs, but including LWS>
- // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
- // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
- // token = 1*<any CHAR except CTLs or separators>
- // qdtext = <any TEXT except <">>
-
- for c := 0; c < 256; c++ {
- var t byte
- isCtl := c <= 31 || c == 127
- isChar := 0 <= c && c <= 127
- isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
- if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
- t |= isSpaceOctet
- }
- if isChar && !isCtl && !isSeparator {
- t |= isTokenOctet
- }
- octetTypes[c] = t
- }
+// Token octets per RFC 2616.
+var isTokenOctet = [256]bool{
+ '!': true,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '*': true,
+ '+': true,
+ '-': true,
+ '.': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'W': true,
+ 'V': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '|': true,
+ '~': true,
}
+// skipSpace returns a slice of the string s with all leading RFC 2616 linear
+// whitespace removed.
func skipSpace(s string) (rest string) {
i := 0
for ; i < len(s); i++ {
- if octetTypes[s[i]]&isSpaceOctet == 0 {
+ if b := s[i]; b != ' ' && b != '\t' {
break
}
}
return s[i:]
}
+// nextToken returns the leading RFC 2616 token of s and the string following
+// the token.
func nextToken(s string) (token, rest string) {
i := 0
for ; i < len(s); i++ {
- if octetTypes[s[i]]&isTokenOctet == 0 {
+ if !isTokenOctet[s[i]] {
break
}
}
return s[:i], s[i:]
}
+// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616
+// and the string following the token or quoted string.
func nextTokenOrQuoted(s string) (value string, rest string) {
if !strings.HasPrefix(s, "\"") {
return nextToken(s)
@@ -128,7 +173,8 @@ func nextTokenOrQuoted(s string) (value string, rest string) {
return "", ""
}
-// equalASCIIFold returns true if s is equal to t with ASCII case folding.
+// equalASCIIFold returns true if s is equal to t with ASCII case folding as
+// defined in RFC 4790.
func equalASCIIFold(s, t string) bool {
for s != "" && t != "" {
sr, size := utf8.DecodeRuneInString(s)