TUN-3375: Upgrade x/text and gorilla websocket deps
This commit is contained in:
parent
22d771b51d
commit
7acea1ac99
3
go.mod
3
go.mod
|
@ -32,7 +32,7 @@ require (
|
||||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/gorilla/mux v1.7.3
|
github.com/gorilla/mux v1.7.3
|
||||||
github.com/gorilla/websocket v1.4.0
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
|
@ -63,6 +63,7 @@ require (
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
||||||
|
golang.org/x/text v0.3.3 // indirect
|
||||||
google.golang.org/appengine v1.5.0 // indirect
|
google.golang.org/appengine v1.5.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20191007204434-a023cd5227bd // indirect
|
google.golang.org/genproto v0.0.0-20191007204434-a023cd5227bd // indirect
|
||||||
google.golang.org/grpc v1.24.0 // indirect
|
google.golang.org/grpc v1.24.0 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -102,6 +102,8 @@ github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
|
||||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
@ -265,6 +267,8 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
|
|
@ -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 ./...
|
|
|
@ -1,14 +1,14 @@
|
||||||
# Gorilla WebSocket
|
# 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
|
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
|
||||||
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
|
[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
|
### Documentation
|
||||||
|
|
||||||
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
|
* [API Reference](https://pkg.go.dev/github.com/gorilla/websocket?tab=doc)
|
||||||
* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
|
* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
|
||||||
* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command)
|
* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command)
|
||||||
* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo)
|
* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo)
|
||||||
|
@ -27,7 +27,7 @@ package API is stable.
|
||||||
### Protocol Compliance
|
### Protocol Compliance
|
||||||
|
|
||||||
The Gorilla WebSocket package passes the server tests in the [Autobahn Test
|
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).
|
subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
|
||||||
|
|
||||||
### Gorilla WebSocket compared with other packages
|
### Gorilla WebSocket compared with other packages
|
||||||
|
@ -40,7 +40,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></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>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.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>
|
<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>
|
||||||
|
|
|
@ -70,7 +70,7 @@ type Dialer struct {
|
||||||
// HandshakeTimeout specifies the duration for the handshake to complete.
|
// HandshakeTimeout specifies the duration for the handshake to complete.
|
||||||
HandshakeTimeout time.Duration
|
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
|
// 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.
|
// do not limit the size of the messages that can be sent or received.
|
||||||
ReadBufferSize, WriteBufferSize int
|
ReadBufferSize, WriteBufferSize int
|
||||||
|
@ -140,7 +140,7 @@ var nilDialer = *DefaultDialer
|
||||||
// Use the response.Header to get the selected subprotocol
|
// Use the response.Header to get the selected subprotocol
|
||||||
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
|
// (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
|
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
|
||||||
// non-nil *http.Response so that callers can handle redirects, authentication,
|
// non-nil *http.Response so that callers can handle redirects, authentication,
|
||||||
|
|
|
@ -244,8 +244,8 @@ type Conn struct {
|
||||||
subprotocol string
|
subprotocol string
|
||||||
|
|
||||||
// Write fields
|
// Write fields
|
||||||
mu chan bool // used as mutex to protect write to conn
|
mu chan struct{} // used as mutex to protect write to conn
|
||||||
writeBuf []byte // frame is constructed in this buffer.
|
writeBuf []byte // frame is constructed in this buffer.
|
||||||
writePool BufferPool
|
writePool BufferPool
|
||||||
writeBufSize int
|
writeBufSize int
|
||||||
writeDeadline time.Time
|
writeDeadline time.Time
|
||||||
|
@ -260,10 +260,12 @@ type Conn struct {
|
||||||
newCompressionWriter func(io.WriteCloser, int) io.WriteCloser
|
newCompressionWriter func(io.WriteCloser, int) io.WriteCloser
|
||||||
|
|
||||||
// Read fields
|
// Read fields
|
||||||
reader io.ReadCloser // the current reader returned to the application
|
reader io.ReadCloser // the current reader returned to the application
|
||||||
readErr error
|
readErr error
|
||||||
br *bufio.Reader
|
br *bufio.Reader
|
||||||
readRemaining int64 // bytes remaining in current frame.
|
// 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.
|
readFinal bool // true the current message has more frames.
|
||||||
readLength int64 // Message size.
|
readLength int64 // Message size.
|
||||||
readLimit int64 // Maximum message size.
|
readLimit int64 // Maximum message size.
|
||||||
|
@ -300,8 +302,8 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int,
|
||||||
writeBuf = make([]byte, writeBufferSize)
|
writeBuf = make([]byte, writeBufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
mu := make(chan bool, 1)
|
mu := make(chan struct{}, 1)
|
||||||
mu <- true
|
mu <- struct{}{}
|
||||||
c := &Conn{
|
c := &Conn{
|
||||||
isServer: isServer,
|
isServer: isServer,
|
||||||
br: br,
|
br: br,
|
||||||
|
@ -320,6 +322,17 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int,
|
||||||
return c
|
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.
|
// Subprotocol returns the negotiated protocol for the connection.
|
||||||
func (c *Conn) Subprotocol() string {
|
func (c *Conn) Subprotocol() string {
|
||||||
return c.subprotocol
|
return c.subprotocol
|
||||||
|
@ -364,7 +377,7 @@ func (c *Conn) read(n int) ([]byte, error) {
|
||||||
|
|
||||||
func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
|
func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
|
||||||
<-c.mu
|
<-c.mu
|
||||||
defer func() { c.mu <- true }()
|
defer func() { c.mu <- struct{}{} }()
|
||||||
|
|
||||||
c.writeErrMu.Lock()
|
c.writeErrMu.Lock()
|
||||||
err := c.writeErr
|
err := c.writeErr
|
||||||
|
@ -416,7 +429,7 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
|
||||||
maskBytes(key, 0, buf[6:])
|
maskBytes(key, 0, buf[6:])
|
||||||
}
|
}
|
||||||
|
|
||||||
d := time.Hour * 1000
|
d := 1000 * time.Hour
|
||||||
if !deadline.IsZero() {
|
if !deadline.IsZero() {
|
||||||
d = deadline.Sub(time.Now())
|
d = deadline.Sub(time.Now())
|
||||||
if d < 0 {
|
if d < 0 {
|
||||||
|
@ -431,7 +444,7 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return errWriteTimeout
|
return errWriteTimeout
|
||||||
}
|
}
|
||||||
defer func() { c.mu <- true }()
|
defer func() { c.mu <- struct{}{} }()
|
||||||
|
|
||||||
c.writeErrMu.Lock()
|
c.writeErrMu.Lock()
|
||||||
err := c.writeErr
|
err := c.writeErr
|
||||||
|
@ -451,7 +464,8 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
|
||||||
return err
|
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
|
// Close previous writer if not already closed by the application. It's
|
||||||
// probably better to return an error in this situation, but we cannot
|
// probably better to return an error in this situation, but we cannot
|
||||||
// change this without breaking existing applications.
|
// change this without breaking existing applications.
|
||||||
|
@ -471,6 +485,10 @@ func (c *Conn) prepWrite(messageType int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mw.c = c
|
||||||
|
mw.frameType = messageType
|
||||||
|
mw.pos = maxFrameHeaderSize
|
||||||
|
|
||||||
if c.writeBuf == nil {
|
if c.writeBuf == nil {
|
||||||
wpd, ok := c.writePool.Get().(writePoolData)
|
wpd, ok := c.writePool.Get().(writePoolData)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -491,16 +509,11 @@ func (c *Conn) prepWrite(messageType int) error {
|
||||||
// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
|
// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
|
||||||
// PongMessage) are supported.
|
// PongMessage) are supported.
|
||||||
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
c.writer = &mw
|
||||||
mw := &messageWriter{
|
|
||||||
c: c,
|
|
||||||
frameType: messageType,
|
|
||||||
pos: maxFrameHeaderSize,
|
|
||||||
}
|
|
||||||
c.writer = mw
|
|
||||||
if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
|
if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
|
||||||
w := c.newCompressionWriter(c.writer, c.compressionLevel)
|
w := c.newCompressionWriter(c.writer, c.compressionLevel)
|
||||||
mw.compress = true
|
mw.compress = true
|
||||||
|
@ -517,10 +530,16 @@ type messageWriter struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *messageWriter) fatal(err error) error {
|
func (w *messageWriter) endMessage(err error) error {
|
||||||
if w.err != nil {
|
if w.err != nil {
|
||||||
w.err = err
|
return err
|
||||||
w.c.writer = nil
|
}
|
||||||
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
@ -534,7 +553,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
|
||||||
// Check for invalid control frames.
|
// Check for invalid control frames.
|
||||||
if isControl(w.frameType) &&
|
if isControl(w.frameType) &&
|
||||||
(!final || length > maxControlFramePayloadSize) {
|
(!final || length > maxControlFramePayloadSize) {
|
||||||
return w.fatal(errInvalidControlFrame)
|
return w.endMessage(errInvalidControlFrame)
|
||||||
}
|
}
|
||||||
|
|
||||||
b0 := byte(w.frameType)
|
b0 := byte(w.frameType)
|
||||||
|
@ -579,7 +598,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
|
||||||
copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
|
copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
|
||||||
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
|
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
|
||||||
if len(extra) > 0 {
|
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
|
c.isWriting = false
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return w.fatal(err)
|
return w.endMessage(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if final {
|
if final {
|
||||||
c.writer = nil
|
w.endMessage(errWriteClosed)
|
||||||
if c.writePool != nil {
|
|
||||||
c.writePool.Put(writePoolData{buf: c.writeBuf})
|
|
||||||
c.writeBuf = nil
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,11 +721,7 @@ func (w *messageWriter) Close() error {
|
||||||
if w.err != nil {
|
if w.err != nil {
|
||||||
return w.err
|
return w.err
|
||||||
}
|
}
|
||||||
if err := w.flushFrame(true, nil); err != nil {
|
return w.flushFrame(true, nil)
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.err = errWriteClosed
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WritePreparedMessage writes prepared message into connection.
|
// 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) {
|
if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) {
|
||||||
// Fast path with no allocations and single frame.
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize}
|
|
||||||
n := copy(c.writeBuf[mw.pos:], data)
|
n := copy(c.writeBuf[mw.pos:], data)
|
||||||
mw.pos += n
|
mw.pos += n
|
||||||
data = data[n:]
|
data = data[n:]
|
||||||
|
@ -792,7 +803,7 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||||
final := p[0]&finalBit != 0
|
final := p[0]&finalBit != 0
|
||||||
frameType := int(p[0] & 0xf)
|
frameType := int(p[0] & 0xf)
|
||||||
mask := p[1]&maskBit != 0
|
mask := p[1]&maskBit != 0
|
||||||
c.readRemaining = int64(p[1] & 0x7f)
|
c.setReadRemaining(int64(p[1] & 0x7f))
|
||||||
|
|
||||||
c.readDecompress = false
|
c.readDecompress = false
|
||||||
if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
|
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))
|
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 {
|
switch c.readRemaining {
|
||||||
case 126:
|
case 126:
|
||||||
|
@ -834,13 +855,19 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return noFrame, err
|
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:
|
case 127:
|
||||||
p, err := c.read(8)
|
p, err := c.read(8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return noFrame, err
|
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.
|
// 4. Handle frame masking.
|
||||||
|
@ -863,6 +890,12 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||||
if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
|
if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
|
||||||
|
|
||||||
c.readLength += c.readRemaining
|
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 {
|
if c.readLimit > 0 && c.readLength > c.readLimit {
|
||||||
c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
|
c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
|
||||||
return noFrame, ErrReadLimit
|
return noFrame, ErrReadLimit
|
||||||
|
@ -876,7 +909,7 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||||
var payload []byte
|
var payload []byte
|
||||||
if c.readRemaining > 0 {
|
if c.readRemaining > 0 {
|
||||||
payload, err = c.read(int(c.readRemaining))
|
payload, err = c.read(int(c.readRemaining))
|
||||||
c.readRemaining = 0
|
c.setReadRemaining(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return noFrame, err
|
return noFrame, err
|
||||||
}
|
}
|
||||||
|
@ -949,6 +982,7 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
|
||||||
c.readErr = hideTempErr(err)
|
c.readErr = hideTempErr(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if frameType == TextMessage || frameType == BinaryMessage {
|
if frameType == TextMessage || frameType == BinaryMessage {
|
||||||
c.messageReader = &messageReader{c}
|
c.messageReader = &messageReader{c}
|
||||||
c.reader = c.messageReader
|
c.reader = c.messageReader
|
||||||
|
@ -989,7 +1023,9 @@ func (r *messageReader) Read(b []byte) (int, error) {
|
||||||
if c.isServer {
|
if c.isServer {
|
||||||
c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
|
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 {
|
if c.readRemaining > 0 && c.readErr == io.EOF {
|
||||||
c.readErr = errUnexpectedEOF
|
c.readErr = errUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
@ -1041,7 +1077,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||||
return c.conn.SetReadDeadline(t)
|
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
|
// message exceeds the limit, the connection sends a close message to the peer
|
||||||
// and returns ErrReadLimit to the application.
|
// and returns ErrReadLimit to the application.
|
||||||
func (c *Conn) SetReadLimit(limit int64) {
|
func (c *Conn) SetReadLimit(limit int64) {
|
||||||
|
|
|
@ -151,6 +151,53 @@
|
||||||
// checking. The application is responsible for checking the Origin header
|
// checking. The application is responsible for checking the Origin header
|
||||||
// before calling the Upgrade function.
|
// 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
|
||||||
|
// 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
|
// Compression EXPERIMENTAL
|
||||||
//
|
//
|
||||||
// Per message compression extensions (RFC 7692) are experimentally supported
|
// Per message compression extensions (RFC 7692) are experimentally supported
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/gorilla/websocket
|
||||||
|
|
||||||
|
go 1.12
|
|
@ -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
|
||||||
|
}
|
|
@ -73,8 +73,8 @@ func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
|
||||||
// Prepare a frame using a 'fake' connection.
|
// Prepare a frame using a 'fake' connection.
|
||||||
// TODO: Refactor code in conn.go to allow more direct construction of
|
// TODO: Refactor code in conn.go to allow more direct construction of
|
||||||
// the frame.
|
// the frame.
|
||||||
mu := make(chan bool, 1)
|
mu := make(chan struct{}, 1)
|
||||||
mu <- true
|
mu <- struct{}{}
|
||||||
var nc prepareConn
|
var nc prepareConn
|
||||||
c := &Conn{
|
c := &Conn{
|
||||||
conn: &nc,
|
conn: &nc,
|
||||||
|
|
|
@ -22,18 +22,18 @@ func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
|
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 {
|
type httpProxyDialer struct {
|
||||||
proxyURL *url.URL
|
proxyURL *url.URL
|
||||||
fowardDial func(network, addr string) (net.Conn, error)
|
forwardDial func(network, addr string) (net.Conn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
|
func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
|
||||||
hostPort, _ := hostPortNoPort(hpd.proxyURL)
|
hostPort, _ := hostPortNoPort(hpd.proxyURL)
|
||||||
conn, err := hpd.fowardDial(network, hostPort)
|
conn, err := hpd.forwardDial(network, hostPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ type Upgrader struct {
|
||||||
// HandshakeTimeout specifies the duration for the handshake to complete.
|
// HandshakeTimeout specifies the duration for the handshake to complete.
|
||||||
HandshakeTimeout time.Duration
|
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
|
// 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
|
// I/O buffer sizes do not limit the size of the messages that can be sent
|
||||||
// or received.
|
// or received.
|
||||||
|
@ -153,7 +153,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
||||||
|
|
||||||
challengeKey := r.Header.Get("Sec-Websocket-Key")
|
challengeKey := r.Header.Get("Sec-Websocket-Key")
|
||||||
if challengeKey == "" {
|
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)
|
subprotocol := u.selectSubprotocol(r, responseHeader)
|
||||||
|
|
|
@ -31,68 +31,113 @@ func generateChallengeKey() (string, error) {
|
||||||
return base64.StdEncoding.EncodeToString(p), nil
|
return base64.StdEncoding.EncodeToString(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Octet types from RFC 2616.
|
// Token octets per RFC 2616.
|
||||||
var octetTypes [256]byte
|
var isTokenOctet = [256]bool{
|
||||||
|
'!': true,
|
||||||
const (
|
'#': true,
|
||||||
isTokenOctet = 1 << iota
|
'$': true,
|
||||||
isSpaceOctet
|
'%': true,
|
||||||
)
|
'&': true,
|
||||||
|
'\'': true,
|
||||||
func init() {
|
'*': true,
|
||||||
// From RFC 2616
|
'+': true,
|
||||||
//
|
'-': true,
|
||||||
// OCTET = <any 8-bit sequence of data>
|
'.': true,
|
||||||
// CHAR = <any US-ASCII character (octets 0 - 127)>
|
'0': true,
|
||||||
// CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
|
'1': true,
|
||||||
// CR = <US-ASCII CR, carriage return (13)>
|
'2': true,
|
||||||
// LF = <US-ASCII LF, linefeed (10)>
|
'3': true,
|
||||||
// SP = <US-ASCII SP, space (32)>
|
'4': true,
|
||||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
'5': true,
|
||||||
// <"> = <US-ASCII double-quote mark (34)>
|
'6': true,
|
||||||
// CRLF = CR LF
|
'7': true,
|
||||||
// LWS = [CRLF] 1*( SP | HT )
|
'8': true,
|
||||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
'9': true,
|
||||||
// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
|
'A': true,
|
||||||
// | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
|
'B': true,
|
||||||
// token = 1*<any CHAR except CTLs or separators>
|
'C': true,
|
||||||
// qdtext = <any TEXT except <">>
|
'D': true,
|
||||||
|
'E': true,
|
||||||
for c := 0; c < 256; c++ {
|
'F': true,
|
||||||
var t byte
|
'G': true,
|
||||||
isCtl := c <= 31 || c == 127
|
'H': true,
|
||||||
isChar := 0 <= c && c <= 127
|
'I': true,
|
||||||
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
|
'J': true,
|
||||||
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
|
'K': true,
|
||||||
t |= isSpaceOctet
|
'L': true,
|
||||||
}
|
'M': true,
|
||||||
if isChar && !isCtl && !isSeparator {
|
'N': true,
|
||||||
t |= isTokenOctet
|
'O': true,
|
||||||
}
|
'P': true,
|
||||||
octetTypes[c] = t
|
'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) {
|
func skipSpace(s string) (rest string) {
|
||||||
i := 0
|
i := 0
|
||||||
for ; i < len(s); i++ {
|
for ; i < len(s); i++ {
|
||||||
if octetTypes[s[i]]&isSpaceOctet == 0 {
|
if b := s[i]; b != ' ' && b != '\t' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s[i:]
|
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) {
|
func nextToken(s string) (token, rest string) {
|
||||||
i := 0
|
i := 0
|
||||||
for ; i < len(s); i++ {
|
for ; i < len(s); i++ {
|
||||||
if octetTypes[s[i]]&isTokenOctet == 0 {
|
if !isTokenOctet[s[i]] {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s[:i], s[i:]
|
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) {
|
func nextTokenOrQuoted(s string) (value string, rest string) {
|
||||||
if !strings.HasPrefix(s, "\"") {
|
if !strings.HasPrefix(s, "\"") {
|
||||||
return nextToken(s)
|
return nextToken(s)
|
||||||
|
@ -128,7 +173,8 @@ func nextTokenOrQuoted(s string) (value string, rest string) {
|
||||||
return "", ""
|
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 {
|
func equalASCIIFold(s, t string) bool {
|
||||||
for s != "" && t != "" {
|
for s != "" && t != "" {
|
||||||
sr, size := utf8.DecodeRuneInString(s)
|
sr, size := utf8.DecodeRuneInString(s)
|
||||||
|
|
|
@ -78,8 +78,8 @@ type SpanningTransformer interface {
|
||||||
// considering the error err.
|
// considering the error err.
|
||||||
//
|
//
|
||||||
// A nil error means that all input bytes are known to be identical to the
|
// A nil error means that all input bytes are known to be identical to the
|
||||||
// output produced by the Transformer. A nil error can be be returned
|
// output produced by the Transformer. A nil error can be returned
|
||||||
// regardless of whether atEOF is true. If err is nil, then then n must
|
// regardless of whether atEOF is true. If err is nil, then n must
|
||||||
// equal len(src); the converse is not necessarily true.
|
// equal len(src); the converse is not necessarily true.
|
||||||
//
|
//
|
||||||
// ErrEndOfSpan means that the Transformer output may differ from the
|
// ErrEndOfSpan means that the Transformer output may differ from the
|
||||||
|
@ -493,7 +493,7 @@ func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err erro
|
||||||
return dstL.n, srcL.p, err
|
return dstL.n, srcL.p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: use runes.Remove instead.
|
// Deprecated: Use runes.Remove instead.
|
||||||
func RemoveFunc(f func(r rune) bool) Transformer {
|
func RemoveFunc(f func(r rune) bool) Transformer {
|
||||||
return removeF(f)
|
return removeF(f)
|
||||||
}
|
}
|
||||||
|
@ -648,7 +648,8 @@ func String(t Transformer, s string) (result string, n int, err error) {
|
||||||
// Transform the remaining input, growing dst and src buffers as necessary.
|
// Transform the remaining input, growing dst and src buffers as necessary.
|
||||||
for {
|
for {
|
||||||
n := copy(src, s[pSrc:])
|
n := copy(src, s[pSrc:])
|
||||||
nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], pSrc+n == len(s))
|
atEOF := pSrc+n == len(s)
|
||||||
|
nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], atEOF)
|
||||||
pDst += nDst
|
pDst += nDst
|
||||||
pSrc += nSrc
|
pSrc += nSrc
|
||||||
|
|
||||||
|
@ -659,6 +660,9 @@ func String(t Transformer, s string) (result string, n int, err error) {
|
||||||
dst = grow(dst, pDst)
|
dst = grow(dst, pDst)
|
||||||
}
|
}
|
||||||
} else if err == ErrShortSrc {
|
} else if err == ErrShortSrc {
|
||||||
|
if atEOF {
|
||||||
|
return string(dst[:pDst]), pSrc, err
|
||||||
|
}
|
||||||
if nSrc == 0 {
|
if nSrc == 0 {
|
||||||
src = grow(src, 0)
|
src = grow(src, 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
// Package bidi contains functionality for bidirectional text support.
|
// Package bidi contains functionality for bidirectional text support.
|
||||||
//
|
//
|
||||||
// See http://www.unicode.org/reports/tr9.
|
// See https://www.unicode.org/reports/tr9.
|
||||||
//
|
//
|
||||||
// NOTE: UNDER CONSTRUCTION. This API may change in backwards incompatible ways
|
// NOTE: UNDER CONSTRUCTION. This API may change in backwards incompatible ways
|
||||||
// and without notice.
|
// and without notice.
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
// This file contains a port of the reference implementation of the
|
// This file contains a port of the reference implementation of the
|
||||||
// Bidi Parentheses Algorithm:
|
// Bidi Parentheses Algorithm:
|
||||||
// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/BidiPBAReference.java
|
// https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/BidiPBAReference.java
|
||||||
//
|
//
|
||||||
// The implementation in this file covers definitions BD14-BD16 and rule N0
|
// The implementation in this file covers definitions BD14-BD16 and rule N0
|
||||||
// of UAX#9.
|
// of UAX#9.
|
||||||
|
@ -246,7 +246,7 @@ func (p *bracketPairer) getStrongTypeN0(index int) Class {
|
||||||
// assuming the given embedding direction.
|
// assuming the given embedding direction.
|
||||||
//
|
//
|
||||||
// It returns ON if no strong type is found. If a single strong type is found,
|
// It returns ON if no strong type is found. If a single strong type is found,
|
||||||
// it returns this this type. Otherwise it returns the embedding direction.
|
// it returns this type. Otherwise it returns the embedding direction.
|
||||||
//
|
//
|
||||||
// TODO: use separate type for "strong" directionality.
|
// TODO: use separate type for "strong" directionality.
|
||||||
func (p *bracketPairer) classifyPairContent(loc bracketPair, dirEmbed Class) Class {
|
func (p *bracketPairer) classifyPairContent(loc bracketPair, dirEmbed Class) Class {
|
||||||
|
|
|
@ -7,7 +7,7 @@ package bidi
|
||||||
import "log"
|
import "log"
|
||||||
|
|
||||||
// This implementation is a port based on the reference implementation found at:
|
// This implementation is a port based on the reference implementation found at:
|
||||||
// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/
|
// https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/
|
||||||
//
|
//
|
||||||
// described in Unicode Bidirectional Algorithm (UAX #9).
|
// described in Unicode Bidirectional Algorithm (UAX #9).
|
||||||
//
|
//
|
||||||
|
@ -480,15 +480,15 @@ func (s *isolatingRunSequence) resolveWeakTypes() {
|
||||||
|
|
||||||
// Rule W1.
|
// Rule W1.
|
||||||
// Changes all NSMs.
|
// Changes all NSMs.
|
||||||
preceedingCharacterType := s.sos
|
precedingCharacterType := s.sos
|
||||||
for i, t := range s.types {
|
for i, t := range s.types {
|
||||||
if t == NSM {
|
if t == NSM {
|
||||||
s.types[i] = preceedingCharacterType
|
s.types[i] = precedingCharacterType
|
||||||
} else {
|
} else {
|
||||||
if t.in(LRI, RLI, FSI, PDI) {
|
if t.in(LRI, RLI, FSI, PDI) {
|
||||||
preceedingCharacterType = ON
|
precedingCharacterType = ON
|
||||||
}
|
}
|
||||||
preceedingCharacterType = t
|
precedingCharacterType = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||||
|
|
||||||
// +build go1.10
|
// +build go1.10,!go1.13
|
||||||
|
|
||||||
package bidi
|
package bidi
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -407,7 +407,7 @@ func decomposeHangul(buf []byte, r rune) int {
|
||||||
|
|
||||||
// decomposeHangul algorithmically decomposes a Hangul rune into
|
// decomposeHangul algorithmically decomposes a Hangul rune into
|
||||||
// its Jamo components.
|
// its Jamo components.
|
||||||
// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
|
// See https://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
|
||||||
func (rb *reorderBuffer) decomposeHangul(r rune) {
|
func (rb *reorderBuffer) decomposeHangul(r rune) {
|
||||||
r -= hangulBase
|
r -= hangulBase
|
||||||
x := r % jamoTCount
|
x := r % jamoTCount
|
||||||
|
@ -420,7 +420,7 @@ func (rb *reorderBuffer) decomposeHangul(r rune) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// combineHangul algorithmically combines Jamo character components into Hangul.
|
// combineHangul algorithmically combines Jamo character components into Hangul.
|
||||||
// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
|
// See https://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
|
||||||
func (rb *reorderBuffer) combineHangul(s, i, k int) {
|
func (rb *reorderBuffer) combineHangul(s, i, k int) {
|
||||||
b := rb.rune[:]
|
b := rb.rune[:]
|
||||||
bn := rb.nrune
|
bn := rb.nrune
|
||||||
|
@ -461,6 +461,10 @@ func (rb *reorderBuffer) combineHangul(s, i, k int) {
|
||||||
// It should only be used to recompose a single segment, as it will not
|
// It should only be used to recompose a single segment, as it will not
|
||||||
// handle alternations between Hangul and non-Hangul characters correctly.
|
// handle alternations between Hangul and non-Hangul characters correctly.
|
||||||
func (rb *reorderBuffer) compose() {
|
func (rb *reorderBuffer) compose() {
|
||||||
|
// Lazily load the map used by the combine func below, but do
|
||||||
|
// it outside of the loop.
|
||||||
|
recompMapOnce.Do(buildRecompMap)
|
||||||
|
|
||||||
// UAX #15, section X5 , including Corrigendum #5
|
// UAX #15, section X5 , including Corrigendum #5
|
||||||
// "In any character sequence beginning with starter S, a character C is
|
// "In any character sequence beginning with starter S, a character C is
|
||||||
// blocked from S if and only if there is some character B between S
|
// blocked from S if and only if there is some character B between S
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package norm
|
package norm
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
// This file contains Form-specific logic and wrappers for data in tables.go.
|
// This file contains Form-specific logic and wrappers for data in tables.go.
|
||||||
|
|
||||||
// Rune info is stored in a separate trie per composing form. A composing form
|
// Rune info is stored in a separate trie per composing form. A composing form
|
||||||
|
@ -178,6 +180,17 @@ func (p Properties) TrailCCC() uint8 {
|
||||||
return ccc[p.tccc]
|
return ccc[p.tccc]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildRecompMap() {
|
||||||
|
recompMap = make(map[uint32]rune, len(recompMapPacked)/8)
|
||||||
|
var buf [8]byte
|
||||||
|
for i := 0; i < len(recompMapPacked); i += 8 {
|
||||||
|
copy(buf[:], recompMapPacked[i:i+8])
|
||||||
|
key := binary.BigEndian.Uint32(buf[:4])
|
||||||
|
val := binary.BigEndian.Uint32(buf[4:])
|
||||||
|
recompMap[key] = rune(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Recomposition
|
// Recomposition
|
||||||
// We use 32-bit keys instead of 64-bit for the two codepoint keys.
|
// We use 32-bit keys instead of 64-bit for the two codepoint keys.
|
||||||
// This clips off the bits of three entries, but we know this will not
|
// This clips off the bits of three entries, but we know this will not
|
||||||
|
@ -186,8 +199,14 @@ func (p Properties) TrailCCC() uint8 {
|
||||||
// Note that the recomposition map for NFC and NFKC are identical.
|
// Note that the recomposition map for NFC and NFKC are identical.
|
||||||
|
|
||||||
// combine returns the combined rune or 0 if it doesn't exist.
|
// combine returns the combined rune or 0 if it doesn't exist.
|
||||||
|
//
|
||||||
|
// The caller is responsible for calling
|
||||||
|
// recompMapOnce.Do(buildRecompMap) sometime before this is called.
|
||||||
func combine(a, b rune) rune {
|
func combine(a, b rune) rune {
|
||||||
key := uint32(uint16(a))<<16 + uint32(uint16(b))
|
key := uint32(uint16(a))<<16 + uint32(uint16(b))
|
||||||
|
if recompMap == nil {
|
||||||
|
panic("caller error") // see func comment
|
||||||
|
}
|
||||||
return recompMap[key]
|
return recompMap[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,8 +128,9 @@ func (i *Iter) Next() []byte {
|
||||||
func nextASCIIBytes(i *Iter) []byte {
|
func nextASCIIBytes(i *Iter) []byte {
|
||||||
p := i.p + 1
|
p := i.p + 1
|
||||||
if p >= i.rb.nsrc {
|
if p >= i.rb.nsrc {
|
||||||
|
p0 := i.p
|
||||||
i.setDone()
|
i.setDone()
|
||||||
return i.rb.src.bytes[i.p:p]
|
return i.rb.src.bytes[p0:p]
|
||||||
}
|
}
|
||||||
if i.rb.src.bytes[p] < utf8.RuneSelf {
|
if i.rb.src.bytes[p] < utf8.RuneSelf {
|
||||||
p0 := i.p
|
p0 := i.p
|
||||||
|
|
|
@ -29,8 +29,8 @@ import (
|
||||||
// proceed independently on both sides:
|
// proceed independently on both sides:
|
||||||
// f(x) == append(f(x[0:n]), f(x[n:])...)
|
// f(x) == append(f(x[0:n]), f(x[n:])...)
|
||||||
//
|
//
|
||||||
// References: http://unicode.org/reports/tr15/ and
|
// References: https://unicode.org/reports/tr15/ and
|
||||||
// http://unicode.org/notes/tn5/.
|
// https://unicode.org/notes/tn5/.
|
||||||
type Form int
|
type Form int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -60,8 +60,8 @@ func (w *normWriter) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writer returns a new writer that implements Write(b)
|
// Writer returns a new writer that implements Write(b)
|
||||||
// by writing f(b) to w. The returned writer may use an
|
// by writing f(b) to w. The returned writer may use an
|
||||||
// an internal buffer to maintain state across Write calls.
|
// internal buffer to maintain state across Write calls.
|
||||||
// Calling its Close method writes any buffered data to w.
|
// Calling its Close method writes any buffered data to w.
|
||||||
func (f Form) Writer(w io.Writer) io.WriteCloser {
|
func (f Form) Writer(w io.Writer) io.WriteCloser {
|
||||||
wr := &normWriter{rb: reorderBuffer{}, w: w}
|
wr := &normWriter{rb: reorderBuffer{}, w: w}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -18,7 +18,6 @@ func (Form) Reset() {}
|
||||||
// Users should either catch ErrShortDst and allow dst to grow or have dst be at
|
// Users should either catch ErrShortDst and allow dst to grow or have dst be at
|
||||||
// least of size MaxTransformChunkSize to be guaranteed of progress.
|
// least of size MaxTransformChunkSize to be guaranteed of progress.
|
||||||
func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||||
n := 0
|
|
||||||
// Cap the maximum number of src bytes to check.
|
// Cap the maximum number of src bytes to check.
|
||||||
b := src
|
b := src
|
||||||
eof := atEOF
|
eof := atEOF
|
||||||
|
@ -27,13 +26,14 @@ func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
|
||||||
eof = false
|
eof = false
|
||||||
b = b[:ns]
|
b = b[:ns]
|
||||||
}
|
}
|
||||||
i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof)
|
i, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), eof)
|
||||||
n += copy(dst[n:], b[n:i])
|
n := copy(dst, b[:i])
|
||||||
if !ok {
|
if !ok {
|
||||||
nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
|
nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
|
||||||
return nDst + n, nSrc + n, err
|
return nDst + n, nSrc + n, err
|
||||||
}
|
}
|
||||||
if n < len(src) && !atEOF {
|
|
||||||
|
if err == nil && n < len(src) && !atEOF {
|
||||||
err = transform.ErrShortSrc
|
err = transform.ErrShortSrc
|
||||||
}
|
}
|
||||||
return n, n, err
|
return n, n, err
|
||||||
|
@ -79,7 +79,7 @@ func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
|
||||||
nSrc += n
|
nSrc += n
|
||||||
nDst += n
|
nDst += n
|
||||||
if ok {
|
if ok {
|
||||||
if n < rb.nsrc && !atEOF {
|
if err == nil && n < rb.nsrc && !atEOF {
|
||||||
err = transform.ErrShortSrc
|
err = transform.ErrShortSrc
|
||||||
}
|
}
|
||||||
return nDst, nSrc, err
|
return nDst, nSrc, err
|
||||||
|
|
|
@ -131,7 +131,7 @@ github.com/golang/protobuf/ptypes/timestamp
|
||||||
github.com/google/uuid
|
github.com/google/uuid
|
||||||
# github.com/gorilla/mux v1.7.3
|
# github.com/gorilla/mux v1.7.3
|
||||||
github.com/gorilla/mux
|
github.com/gorilla/mux
|
||||||
# github.com/gorilla/websocket v1.4.0
|
# github.com/gorilla/websocket v1.4.2
|
||||||
github.com/gorilla/websocket
|
github.com/gorilla/websocket
|
||||||
# github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
|
# github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
|
||||||
github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc
|
github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc
|
||||||
|
@ -251,7 +251,7 @@ golang.org/x/sys/windows/registry
|
||||||
golang.org/x/sys/windows/svc
|
golang.org/x/sys/windows/svc
|
||||||
golang.org/x/sys/windows/svc/eventlog
|
golang.org/x/sys/windows/svc/eventlog
|
||||||
golang.org/x/sys/windows/svc/mgr
|
golang.org/x/sys/windows/svc/mgr
|
||||||
# golang.org/x/text v0.3.0
|
# golang.org/x/text v0.3.3
|
||||||
golang.org/x/text/secure/bidirule
|
golang.org/x/text/secure/bidirule
|
||||||
golang.org/x/text/transform
|
golang.org/x/text/transform
|
||||||
golang.org/x/text/unicode/bidi
|
golang.org/x/text/unicode/bidi
|
||||||
|
|
Loading…
Reference in New Issue