Update chromedp to fix console errors (#1521)

This commit is contained in:
peolic
2021-06-23 01:05:58 +03:00
committed by GitHub
parent ae3400a9b1
commit be2fe1de26
526 changed files with 55061 additions and 30300 deletions

3
vendor/github.com/gobwas/httphead/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/gobwas/httphead
go 1.15

View File

@@ -25,6 +25,12 @@ func (opt Option) Copy(p []byte) Option {
return opt
}
// Clone is a shorthand for making slice of opt.Size() sequenced with Copy()
// call.
func (opt Option) Clone() Option {
return opt.Copy(make([]byte, opt.Size()))
}
// String represents option as a string.
func (opt Option) String() string {
return "{" + string(opt.Name) + " " + opt.Parameters.String() + "}"

21
vendor/github.com/gobwas/pool/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017-2019 Sergey Kamardin <gobwas@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,25 +0,0 @@
sudo: required
language: go
services:
- docker
os:
- linux
- windows
go:
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.x
install:
- go get github.com/gobwas/pool
- go get github.com/gobwas/httphead
script:
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then go test ./...; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then make test autobahn; fi

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017-2018 Sergey Kamardin <gobwas@gmail.com>
Copyright (c) 2017-2021 Sergey Kamardin <gobwas@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

11
vendor/github.com/gobwas/ws/Makefile generated vendored
View File

@@ -13,15 +13,22 @@ bin/gocovmerge:
.PHONY: autobahn
autobahn: clean bin/reporter
./autobahn/script/test.sh --build
./autobahn/script/test.sh --build --follow-logs
bin/reporter $(PWD)/autobahn/report/index.json
.PHONY: autobahn/report
autobahn/report: bin/reporter
./bin/reporter -http localhost:5555 ./autobahn/report/index.json
test:
go test -coverprofile=ws.coverage .
go test -coverprofile=wsutil.coverage ./wsutil
go test -coverprofile=wsfalte.coverage ./wsflate
# No statemenets to cover in ./tests (there are only tests).
go test ./tests
cover: bin/gocovmerge test autobahn
bin/gocovmerge ws.coverage wsutil.coverage autobahn/report/server.coverage > total.coverage
bin/gocovmerge ws.coverage wsutil.coverage wsflate.coverage autobahn/report/server.coverage > total.coverage
benchcmp: BENCH_BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
benchcmp: BENCH_OLD:=$(shell mktemp -t old.XXXX)

109
vendor/github.com/gobwas/ws/README.md generated vendored
View File

@@ -1,7 +1,7 @@
# ws
[![GoDoc][godoc-image]][godoc-url]
[![Travis][travis-image]][travis-url]
[![CI][ci-badge]][ci-url]
> [RFC6455][rfc-url] WebSocket implementation in Go.
@@ -351,10 +351,113 @@ func main() {
}
```
# Compression
There is a `ws/wsflate` package to support [Permessage-Deflate Compression
Extension][rfc-pmce].
It provides minimalistic I/O wrappers to be used in conjunction with any
deflate implementation (for example, the standard library's
[compress/flate][compress/flate].
It is also compatible with `wsutil`'s reader and writer by providing
`wsflate.MessageState` type, which implements `wsutil.SendExtension` and
`wsutil.RecvExtension` interfaces.
```go
package main
import (
"bytes"
"log"
"net"
"github.com/gobwas/ws"
"github.com/gobwas/ws/wsflate"
)
func main() {
ln, err := net.Listen("tcp", "localhost:8080")
if err != nil {
// handle error
}
e := wsflate.Extension{
// We are using default parameters here since we use
// wsflate.{Compress,Decompress}Frame helpers below in the code.
// This assumes that we use standard compress/flate package as flate
// implementation.
Parameters: wsflate.DefaultParameters,
}
u := ws.Upgrader{
Negotiate: e.Negotiate,
}
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
// Reset extension after previous upgrades.
e.Reset()
_, err = u.Upgrade(conn)
if err != nil {
log.Printf("upgrade error: %s", err)
continue
}
if _, ok := e.Accepted(); !ok {
log.Printf("didn't negotiate compression for %s", conn.RemoteAddr())
conn.Close()
continue
}
go func() {
defer conn.Close()
for {
frame, err := ws.ReadFrame(conn)
if err != nil {
// Handle error.
return
}
frame = ws.UnmaskFrameInPlace(frame)
if wsflate.IsCompressed(frame.Header) {
// Note that even after successful negotiation of
// compression extension, both sides are able to send
// non-compressed messages.
frame, err = wsflate.DecompressFrame(frame)
if err != nil {
// Handle error.
return
}
}
// Do something with frame...
ack := ws.NewTextFrame([]byte("this is an acknowledgement"))
// Compress response unconditionally.
ack, err = wsflate.CompressFrame(ack)
if err != nil {
// Handle error.
return
}
if err = ws.WriteFrame(conn, ack); err != nil {
// Handle error.
return
}
}
}()
}
}
```
[rfc-url]: https://tools.ietf.org/html/rfc6455
[rfc-pmce]: https://tools.ietf.org/html/rfc7692#section-7
[godoc-image]: https://godoc.org/github.com/gobwas/ws?status.svg
[godoc-url]: https://godoc.org/github.com/gobwas/ws
[travis-image]: https://travis-ci.org/gobwas/ws.svg?branch=master
[travis-url]: https://travis-ci.org/gobwas/ws
[compress/flate]: https://golang.org/pkg/compress/flate/
[ci-badge]: https://github.com/gobwas/ws/workflows/CI/badge.svg
[ci-url]: https://github.com/gobwas/ws/actions?query=workflow%3ACI

View File

@@ -109,9 +109,10 @@ func CheckHeader(h Header, s State) error {
return ErrProtocolContinuationExpected
case !s.Fragmented() && h.OpCode == OpContinuation:
return ErrProtocolContinuationUnexpected
}
return nil
default:
return nil
}
}
// CheckCloseFrameData checks received close information

View File

@@ -1,7 +1,7 @@
package ws
import (
"unsafe"
"encoding/binary"
)
// Cipher applies XOR cipher to the payload using mask.
@@ -35,19 +35,24 @@ func Cipher(payload []byte, mask [4]byte, offset int) {
payload[i] ^= mask[(mpos+i)%4]
}
// We should cast mask to uint32 with unsafe instead of encoding.BigEndian
// to avoid care of os dependent byte order. That is, on any endianess mask
// and payload will be presented with the same order. In other words, we
// could not use encoding.BigEndian on xoring payload as uint64.
m := *(*uint32)(unsafe.Pointer(&mask))
m2 := uint64(m)<<32 | uint64(m)
// NOTE: we use here binary.LittleEndian regardless of what is real
// endianness on machine is. To do so, we have to use binary.LittleEndian in
// the masking loop below as well.
var (
m = binary.LittleEndian.Uint32(mask[:])
m2 = uint64(m)<<32 | uint64(m)
)
// Skip already processed right part.
// Get number of uint64 parts remaining to process.
n = (n - ln - rn) >> 3
for i := 0; i < n; i++ {
v := (*uint64)(unsafe.Pointer(&payload[ln+(i<<3)]))
*v = *v ^ m2
var (
j = ln + (i << 3)
chunk = payload[j : j+8]
)
p := binary.LittleEndian.Uint64(chunk)
p = p ^ m2
binary.LittleEndian.PutUint64(chunk, p)
}
}

View File

@@ -371,7 +371,7 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha
switch btsToString(k) {
case headerUpgradeCanonical:
headerSeen |= headerSeenUpgrade
if !bytes.Equal(v, specHeaderValueUpgrade) && !btsEqualFold(v, specHeaderValueUpgrade) {
if !bytes.Equal(v, specHeaderValueUpgrade) && !bytes.EqualFold(v, specHeaderValueUpgrade) {
err = ErrHandshakeBadUpgrade
return
}
@@ -382,7 +382,7 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha
// > A |Connection| header field with value "Upgrade".
// That is, in server side, "Connection" header could contain
// multiple token. But in response it must contains exactly one.
if !bytes.Equal(v, specHeaderValueConnection) && !btsEqualFold(v, specHeaderValueConnection) {
if !bytes.Equal(v, specHeaderValueConnection) && !bytes.EqualFold(v, specHeaderValueConnection) {
err = ErrHandshakeBadConnection
return
}
@@ -474,11 +474,18 @@ func matchSelectedExtensions(selected []byte, wanted, received []httphead.Option
index = -1
match := func() (ok bool) {
for _, want := range wanted {
if option.Equal(want) {
// A server accepts one or more extensions by including a
// |Sec-WebSocket-Extensions| header field containing one or more
// extensions that were requested by the client.
//
// The interpretation of any extension parameters, and what
// constitutes a valid response by a server to a requested set of
// parameters by a client, will be defined by each such extension.
if bytes.Equal(option.Name, want.Name) {
// Check parsed extension to be present in client
// requested extensions. We move matched extension
// from client list to avoid allocation.
received = append(received, want)
received = append(received, option)
return true
}
}

87
vendor/github.com/gobwas/ws/frame.go generated vendored
View File

@@ -206,6 +206,28 @@ func (h Header) Rsv2() bool { return h.Rsv&bit6 != 0 }
// Rsv3 reports whether the header has third rsv bit set.
func (h Header) Rsv3() bool { return h.Rsv&bit7 != 0 }
// Rsv creates rsv byte representation from bits.
func Rsv(r1, r2, r3 bool) (rsv byte) {
if r1 {
rsv |= bit5
}
if r2 {
rsv |= bit6
}
if r3 {
rsv |= bit7
}
return rsv
}
// RsvBits returns rsv bits from bytes representation.
func RsvBits(rsv byte) (r1, r2, r3 bool) {
r1 = rsv&bit5 != 0
r2 = rsv&bit6 != 0
r3 = rsv&bit7 != 0
return
}
// Frame represents websocket frame.
// See https://tools.ietf.org/html/rfc6455#section-5.2
type Frame struct {
@@ -319,6 +341,29 @@ func MaskFrameInPlace(f Frame) Frame {
return MaskFrameInPlaceWith(f, NewMask())
}
var zeroMask [4]byte
// UnmaskFrame unmasks frame and returns frame with unmasked payload and Mask
// header's field cleared.
// Note that it copies f payload.
func UnmaskFrame(f Frame) Frame {
p := make([]byte, len(f.Payload))
copy(p, f.Payload)
f.Payload = p
return UnmaskFrameInPlace(f)
}
// UnmaskFrameInPlace unmasks frame and returns frame with unmasked payload and
// Mask header's field cleared.
// Note that it applies xor cipher to f.Payload without copying, that is, it
// modifies f.Payload inplace.
func UnmaskFrameInPlace(f Frame) Frame {
Cipher(f.Payload, f.Header.Mask, 0)
f.Header.Masked = false
f.Header.Mask = zeroMask
return f
}
// MaskFrameInPlaceWith masks frame with given mask and returns frame
// with masked payload and Mask header's field set.
// Note that it applies xor cipher to f.Payload without copying, that is, it
@@ -356,36 +401,20 @@ func MustCompileFrame(f Frame) []byte {
return bts
}
// Rsv creates rsv byte representation.
func Rsv(r1, r2, r3 bool) (rsv byte) {
if r1 {
rsv |= bit5
}
if r2 {
rsv |= bit6
}
if r3 {
rsv |= bit7
}
return rsv
}
func makeCloseFrame(code StatusCode, reason string) Frame {
return NewCloseFrame(NewCloseFrameBody(
code, reason,
))
func makeCloseFrame(code StatusCode) Frame {
return NewCloseFrame(NewCloseFrameBody(code, ""))
}
var (
closeFrameNormalClosure = makeCloseFrame(StatusNormalClosure, "")
closeFrameGoingAway = makeCloseFrame(StatusGoingAway, "")
closeFrameProtocolError = makeCloseFrame(StatusProtocolError, "")
closeFrameUnsupportedData = makeCloseFrame(StatusUnsupportedData, "")
closeFrameNoMeaningYet = makeCloseFrame(StatusNoMeaningYet, "")
closeFrameInvalidFramePayloadData = makeCloseFrame(StatusInvalidFramePayloadData, "")
closeFramePolicyViolation = makeCloseFrame(StatusPolicyViolation, "")
closeFrameMessageTooBig = makeCloseFrame(StatusMessageTooBig, "")
closeFrameMandatoryExt = makeCloseFrame(StatusMandatoryExt, "")
closeFrameInternalServerError = makeCloseFrame(StatusInternalServerError, "")
closeFrameTLSHandshake = makeCloseFrame(StatusTLSHandshake, "")
closeFrameNormalClosure = makeCloseFrame(StatusNormalClosure)
closeFrameGoingAway = makeCloseFrame(StatusGoingAway)
closeFrameProtocolError = makeCloseFrame(StatusProtocolError)
closeFrameUnsupportedData = makeCloseFrame(StatusUnsupportedData)
closeFrameNoMeaningYet = makeCloseFrame(StatusNoMeaningYet)
closeFrameInvalidFramePayloadData = makeCloseFrame(StatusInvalidFramePayloadData)
closeFramePolicyViolation = makeCloseFrame(StatusPolicyViolation)
closeFrameMessageTooBig = makeCloseFrame(StatusMessageTooBig)
closeFrameMandatoryExt = makeCloseFrame(StatusMandatoryExt)
closeFrameInternalServerError = makeCloseFrame(StatusInternalServerError)
closeFrameTLSHandshake = makeCloseFrame(StatusTLSHandshake)
)

9
vendor/github.com/gobwas/ws/go.mod generated vendored Normal file
View File

@@ -0,0 +1,9 @@
module github.com/gobwas/ws
go 1.15
require (
github.com/gobwas/httphead v0.1.0
github.com/gobwas/pool v0.2.1
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d // indirect
)

6
vendor/github.com/gobwas/ws/go.sum generated vendored Normal file
View File

@@ -0,0 +1,6 @@
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

46
vendor/github.com/gobwas/ws/http.go generated vendored
View File

@@ -215,18 +215,54 @@ func btsSelectProtocol(h []byte, check func([]byte) bool) (ret string, ok bool)
return
}
func strSelectExtensions(h string, selected []httphead.Option, check func(httphead.Option) bool) ([]httphead.Option, bool) {
return btsSelectExtensions(strToBytes(h), selected, check)
}
func btsSelectExtensions(h []byte, selected []httphead.Option, check func(httphead.Option) bool) ([]httphead.Option, bool) {
s := httphead.OptionSelector{
Flags: httphead.SelectUnique | httphead.SelectCopy,
Flags: httphead.SelectCopy,
Check: check,
}
return s.Select(h, selected)
}
func negotiateMaybe(in httphead.Option, dest []httphead.Option, f func(httphead.Option) (httphead.Option, error)) ([]httphead.Option, error) {
if in.Size() == 0 {
return dest, nil
}
opt, err := f(in)
if err != nil {
return nil, err
}
if opt.Size() > 0 {
dest = append(dest, opt)
}
return dest, nil
}
func negotiateExtensions(
h []byte, dest []httphead.Option,
f func(httphead.Option) (httphead.Option, error),
) (_ []httphead.Option, err error) {
index := -1
var current httphead.Option
ok := httphead.ScanOptions(h, func(i int, name, attr, val []byte) httphead.Control {
if i != index {
dest, err = negotiateMaybe(current, dest, f)
if err != nil {
return httphead.ControlBreak
}
index = i
current = httphead.Option{Name: name}
}
if attr != nil {
current.Parameters.Set(attr, val)
}
return httphead.ControlContinue
})
if !ok {
return nil, ErrMalformedRequest
}
return negotiateMaybe(current, dest, f)
}
func httpWriteHeader(bw *bufio.Writer, key, value string) {
httpWriteHeaderKey(bw, key)
bw.WriteString(value)

View File

@@ -7,6 +7,7 @@ import (
"io"
"net"
"net/http"
"strings"
"time"
"github.com/gobwas/httphead"
@@ -128,7 +129,22 @@ type HTTPUpgrader struct {
// Extension is the select function that is used to select extensions from
// list requested by client. If this field is set, then the all matched
// extensions are sent to a client as negotiated.
//
// DEPRECATED. Use Negotiate instead.
Extension func(httphead.Option) bool
// Negotiate is the callback that is used to negotiate extensions from
// the client's offer. If this field is set, then the returned non-zero
// extensions are sent to the client as accepted extensions in the
// response.
//
// The argument is only valid until the Negotiate callback returns.
//
// If returned error is non-nil then connection is rejected and response is
// sent with appropriate HTTP error code and body set to error message.
//
// RejectConnectionError could be used to get more control on response.
Negotiate func(httphead.Option) (httphead.Option, error)
}
// Upgrade upgrades http connection to the websocket connection.
@@ -159,7 +175,7 @@ func (u HTTPUpgrader) Upgrade(r *http.Request, w http.ResponseWriter) (conn net.
err = ErrHandshakeBadProtocol
} else if r.Host == "" {
err = ErrHandshakeBadHost
} else if u := httpGetHeader(r.Header, headerUpgradeCanonical); u != "websocket" && !strEqualFold(u, "websocket") {
} else if u := httpGetHeader(r.Header, headerUpgradeCanonical); u != "websocket" && !strings.EqualFold(u, "websocket") {
err = ErrHandshakeBadUpgrade
} else if c := httpGetHeader(r.Header, headerConnectionCanonical); c != "Upgrade" && !strHasToken(c, "upgrade") {
err = ErrHandshakeBadConnection
@@ -199,11 +215,20 @@ func (u HTTPUpgrader) Upgrade(r *http.Request, w http.ResponseWriter) (conn net.
}
}
}
if check := u.Extension; err == nil && check != nil {
if f := u.Negotiate; err == nil && f != nil {
for _, h := range r.Header[headerSecExtensionsCanonical] {
hs.Extensions, err = negotiateExtensions(strToBytes(h), hs.Extensions, f)
if err != nil {
break
}
}
}
// DEPRECATED path.
if check := u.Extension; err == nil && check != nil && u.Negotiate == nil {
xs := r.Header[headerSecExtensionsCanonical]
for i := 0; i < len(xs) && err == nil; i++ {
var ok bool
hs.Extensions, ok = strSelectExtensions(xs[i], hs.Extensions, check)
hs.Extensions, ok = btsSelectExtensions(strToBytes(xs[i]), hs.Extensions, check)
if !ok {
err = ErrMalformedRequest
}
@@ -270,6 +295,9 @@ type Upgrader struct {
// from list requested by client. If this field is set, then the all matched
// extensions are sent to a client as negotiated.
//
// Note that Extension may be called multiple times and implementations
// must track uniqueness of accepted extensions manually.
//
// The argument is only valid until the callback returns.
//
// According to the RFC6455 order of extensions passed by a client is
@@ -282,13 +310,38 @@ type Upgrader struct {
// fields listed by the client in its request represent a preference of the
// header fields it wishes to use, with the first options listed being most
// preferable."
//
// DEPRECATED. Use Negotiate instead.
Extension func(httphead.Option) bool
// ExtensionCustorm allow user to parse Sec-WebSocket-Extensions header manually.
// ExtensionCustom allow user to parse Sec-WebSocket-Extensions header
// manually.
//
// If ExtensionCustom() decides to accept received extension, it must
// append appropriate option to the given slice of httphead.Option.
// It returns results of append() to the given slice and a flag that
// reports whether given header value is wellformed or not.
//
// Note that ExtensionCustom may be called multiple times and
// implementations must track uniqueness of accepted extensions manually.
//
// Note that returned options should be valid until Upgrade returns.
// If ExtensionCustom is set, it used instead of Extension function.
ExtensionCustom func([]byte, []httphead.Option) ([]httphead.Option, bool)
// Negotiate is the callback that is used to negotiate extensions from
// the client's offer. If this field is set, then the returned non-zero
// extensions are sent to the client as accepted extensions in the
// response.
//
// The argument is only valid until the Negotiate callback returns.
//
// If returned error is non-nil then connection is rejected and response is
// sent with appropriate HTTP error code and body set to error message.
//
// RejectConnectionError could be used to get more control on response.
Negotiate func(httphead.Option) (httphead.Option, error)
// Header is an optional HandshakeHeader instance that could be used to
// write additional headers to the handshake response.
//
@@ -475,7 +528,7 @@ func (u Upgrader) Upgrade(conn io.ReadWriter) (hs Handshake, err error) {
case headerUpgradeCanonical:
headerSeen |= headerSeenUpgrade
if !bytes.Equal(v, specHeaderValueUpgrade) && !btsEqualFold(v, specHeaderValueUpgrade) {
if !bytes.Equal(v, specHeaderValueUpgrade) && !bytes.EqualFold(v, specHeaderValueUpgrade) {
err = ErrHandshakeBadUpgrade
}
@@ -513,7 +566,11 @@ func (u Upgrader) Upgrade(conn io.ReadWriter) (hs Handshake, err error) {
}
case headerSecExtensionsCanonical:
if custom, check := u.ExtensionCustom, u.Extension; custom != nil || check != nil {
if f := u.Negotiate; err == nil && f != nil {
hs.Extensions, err = negotiateExtensions(v, hs.Extensions, f)
}
// DEPRECATED path.
if custom, check := u.ExtensionCustom, u.Extension; u.Negotiate == nil && (custom != nil || check != nil) {
var ok bool
if custom != nil {
hs.Extensions, ok = custom(v, hs.Extensions)

43
vendor/github.com/gobwas/ws/util.go generated vendored
View File

@@ -113,7 +113,7 @@ func strHasToken(header, token string) (has bool) {
func btsHasToken(header, token []byte) (has bool) {
httphead.ScanTokens(header, func(v []byte) bool {
has = btsEqualFold(v, token)
has = bytes.EqualFold(v, token)
return !has
})
return
@@ -199,47 +199,6 @@ func readLine(br *bufio.Reader) ([]byte, error) {
}
}
// strEqualFold checks s to be case insensitive equal to p.
// Note that p must be only ascii letters. That is, every byte in p belongs to
// range ['a','z'] or ['A','Z'].
func strEqualFold(s, p string) bool {
return btsEqualFold(strToBytes(s), strToBytes(p))
}
// btsEqualFold checks s to be case insensitive equal to p.
// Note that p must be only ascii letters. That is, every byte in p belongs to
// range ['a','z'] or ['A','Z'].
func btsEqualFold(s, p []byte) bool {
if len(s) != len(p) {
return false
}
n := len(s)
// Prepare manual conversion on bytes that not lay in uint64.
m := n % 8
for i := 0; i < m; i++ {
if s[i]|toLower != p[i]|toLower {
return false
}
}
// Iterate over uint64 parts of s.
n = (n - m) >> 3
if n == 0 {
// There are no more bytes to compare.
return true
}
for i := 0; i < n; i++ {
x := m + (i << 3)
av := *(*uint64)(unsafe.Pointer(&s[x]))
bv := *(*uint64)(unsafe.Pointer(&p[x]))
if av|toLower8 != bv|toLower8 {
return false
}
}
return true
}
func min(a, b int) int {
if a < b {
return a

31
vendor/github.com/gobwas/ws/wsutil/extenstion.go generated vendored Normal file
View File

@@ -0,0 +1,31 @@
package wsutil
import "github.com/gobwas/ws"
// RecvExtension is an interface for clearing fragment header RSV bits.
type RecvExtension interface {
UnsetBits(ws.Header) (ws.Header, error)
}
// RecvExtensionFunc is an adapter to allow the use of ordinary functions as
// RecvExtension.
type RecvExtensionFunc func(ws.Header) (ws.Header, error)
// BitsRecv implements RecvExtension.
func (fn RecvExtensionFunc) UnsetBits(h ws.Header) (ws.Header, error) {
return fn(h)
}
// SendExtension is an interface for setting fragment header RSV bits.
type SendExtension interface {
SetBits(ws.Header) (ws.Header, error)
}
// SendExtensionFunc is an adapter to allow the use of ordinary functions as
// SendExtension.
type SendExtensionFunc func(ws.Header) (ws.Header, error)
// BitsSend implements SendExtension.
func (fn SendExtensionFunc) SetBits(h ws.Header) (ws.Header, error) {
return fn(h)
}

View File

@@ -194,7 +194,7 @@ func (c ControlHandler) HandleClose(h ws.Header) error {
// If an endpoint receives a Close frame and did not previously
// send a Close frame, the endpoint MUST send a Close frame in
// response. (When sending a Close frame in response, the endpoint
// typically echos the status code it received.)
// typically echoes the status code it received.)
_, err := w.Write(p[:2])
if err != nil {
return err

View File

@@ -113,7 +113,7 @@ func ReadClientText(rw io.ReadWriter) ([]byte, error) {
// It discards received text messages.
//
// Note this may handle and write control frames into the writer part of a given
// io.ReadWriter.
// io.ReadWriter.
func ReadClientBinary(rw io.ReadWriter) ([]byte, error) {
p, _, err := readData(rw, ws.StateServerSide, ws.OpBinary)
return p, err
@@ -133,7 +133,7 @@ func ReadServerData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
// It discards received binary messages.
//
// Note this may handle and write control frames into the writer part of a given
// io.ReadWriter.
// io.ReadWriter.
func ReadServerText(rw io.ReadWriter) ([]byte, error) {
p, _, err := readData(rw, ws.StateClientSide, ws.OpText)
return p, err
@@ -152,7 +152,7 @@ func ReadServerBinary(rw io.ReadWriter) ([]byte, error) {
// WriteMessage is a helper function that writes message to the w. It
// constructs single frame with given operation code and payload.
// It uses given state to prepare side-dependtend things, like cipher
// It uses given state to prepare side-dependent things, like cipher
// payload bytes from client to server. It will not mutate p bytes if
// cipher must be made.
//

View File

@@ -12,7 +12,11 @@ import (
// preceding NextFrame() call.
var ErrNoFrameAdvance = errors.New("no frame advance")
// FrameHandlerFunc handles parsed frame header and its body represetned by
// ErrFrameTooLarge indicates that a message of length higher than
// MaxFrameSize was being read.
var ErrFrameTooLarge = errors.New("frame too large")
// FrameHandlerFunc handles parsed frame header and its body represented by
// io.Reader.
//
// Note that reader represents already unmasked body.
@@ -37,7 +41,17 @@ type Reader struct {
// bytes are not valid UTF-8 sequence, ErrInvalidUTF8 returned.
CheckUTF8 bool
// TODO(gobwas): add max frame size limit here.
// Extensions is a list of negotiated extensions for reader Source.
// It is used to meet the specs and clear appropriate bits in fragment
// header RSV segment.
Extensions []RecvExtension
// MaxFrameSize controls the maximum frame size in bytes
// that can be read. A message exceeding that size will return
// a ErrFrameTooLarge to the application.
//
// Not setting this field means there is no limit.
MaxFrameSize int64
OnContinuation FrameHandlerFunc
OnIntermediate FrameHandlerFunc
@@ -100,9 +114,10 @@ func (r *Reader) Read(p []byte) (n int, err error) {
return
}
if err == nil && r.raw.N != 0 {
return
return n, nil
}
// EOF condition (either err is io.EOF or r.raw.N is zero).
switch {
case r.raw.N != 0:
err = io.ErrUnexpectedEOF
@@ -112,6 +127,8 @@ func (r *Reader) Read(p []byte) (n int, err error) {
r.resetFragment()
case r.CheckUTF8 && !r.utf8.Valid():
// NOTE: check utf8 only when full message received, since partial
// reads may be invalid.
n = r.utf8.Accepted()
err = ErrInvalidUTF8
@@ -166,14 +183,29 @@ func (r *Reader) NextFrame() (hdr ws.Header, err error) {
return hdr, err
}
if n := r.MaxFrameSize; n > 0 && hdr.Length > n {
return hdr, ErrFrameTooLarge
}
// Save raw reader to use it on discarding frame without ciphering and
// other streaming checks.
r.raw = io.LimitedReader{r.Source, hdr.Length}
r.raw = io.LimitedReader{
R: r.Source,
N: hdr.Length,
}
frame := io.Reader(&r.raw)
if hdr.Masked {
frame = NewCipherReader(frame, hdr.Mask)
}
for _, x := range r.Extensions {
hdr, err = x.UnsetBits(hdr)
if err != nil {
return hdr, err
}
}
if r.fragmented() {
if hdr.OpCode.IsControl() {
if cb := r.OnIntermediate; cb != nil {

View File

@@ -84,38 +84,6 @@ func (c *ControlWriter) Flush() error {
return c.w.Flush()
}
// Writer contains logic of buffering output data into a WebSocket fragments.
// It is much the same as bufio.Writer, except the thing that it works with
// WebSocket frames, not the raw data.
//
// Writer writes frames with specified OpCode.
// It uses ws.State to decide whether the output frames must be masked.
//
// Note that it does not check control frame size or other RFC rules.
// That is, it must be used with special care to write control frames without
// violation of RFC. You could use ControlWriter that wraps Writer and contains
// some guards for writing control frames.
//
// If an error occurs writing to a Writer, no more data will be accepted and
// all subsequent writes will return the error.
// After all data has been written, the client should call the Flush() method
// to guarantee all data has been forwarded to the underlying io.Writer.
type Writer struct {
dest io.Writer
n int // Buffered bytes counter.
raw []byte // Raw representation of buffer, including reserved header bytes.
buf []byte // Writeable part of buffer, without reserved header bytes.
op ws.OpCode
state ws.State
dirty bool
fragmented bool
err error
}
var writers = pool.New(128, 65536)
// GetWriter tries to reuse Writer getting it from the pool.
@@ -145,6 +113,58 @@ func PutWriter(w *Writer) {
writers.Put(w, w.Size())
}
// Writer contains logic of buffering output data into a WebSocket fragments.
// It is much the same as bufio.Writer, except the thing that it works with
// WebSocket frames, not the raw data.
//
// Writer writes frames with specified OpCode.
// It uses ws.State to decide whether the output frames must be masked.
//
// Note that it does not check control frame size or other RFC rules.
// That is, it must be used with special care to write control frames without
// violation of RFC. You could use ControlWriter that wraps Writer and contains
// some guards for writing control frames.
//
// If an error occurs writing to a Writer, no more data will be accepted and
// all subsequent writes will return the error.
//
// After all data has been written, the client should call the Flush() method
// to guarantee all data has been forwarded to the underlying io.Writer.
type Writer struct {
// dest specifies a destination of buffer flushes.
dest io.Writer
// op specifies the WebSocket operation code used in flushed frames.
op ws.OpCode
// state specifies the state of the Writer.
state ws.State
// extensions is a list of negotiated extensions for writer Dest.
// It is used to meet the specs and set appropriate bits in fragment
// header RSV segment.
extensions []SendExtension
// noFlush reports whether buffer must grow instead of being flushed.
noFlush bool
// Raw representation of the buffer, including reserved header bytes.
raw []byte
// Writeable part of buffer, without reserved header bytes.
// Resetting this to nil will not result in reallocation if raw is not nil.
// And vice versa: if buf is not nil, then Writer is assumed as ready and
// initialized.
buf []byte
// Buffered bytes counter.
n int
dirty bool
fseq int
err error
}
// NewWriter returns a new Writer whose buffer has the DefaultWriteBuffer size.
func NewWriter(dest io.Writer, state ws.State, op ws.OpCode) *Writer {
return NewWriterBufferSize(dest, state, op, 0)
@@ -186,57 +206,63 @@ func NewWriterBufferSize(dest io.Writer, state ws.State, op ws.OpCode, n int) *W
//
// It panics if len(buf) is too small to fit header and payload data.
func NewWriterBuffer(dest io.Writer, state ws.State, op ws.OpCode, buf []byte) *Writer {
offset := reserve(state, len(buf))
if len(buf) <= offset {
panic("buffer too small")
}
return &Writer{
w := &Writer{
dest: dest,
raw: buf,
buf: buf[offset:],
state: state,
op: op,
raw: buf,
}
w.initBuf()
return w
}
func reserve(state ws.State, n int) (offset int) {
var mask int
if state.ClientSide() {
mask = 4
}
switch {
case n <= int(len7)+mask+2:
return mask + 2
case n <= int(len16)+mask+4:
return mask + 4
default:
return mask + 10
func (w *Writer) initBuf() {
offset := reserve(w.state, len(w.raw))
if len(w.raw) <= offset {
panic("wsutil: writer buffer is too small")
}
w.buf = w.raw[offset:]
}
// headerSize returns number of bytes needed to encode header of a frame with
// given state and length.
func headerSize(s ws.State, n int) int {
return ws.HeaderSize(ws.Header{
Length: int64(n),
Masked: s.ClientSide(),
})
}
// Reset discards any buffered data, clears error, and resets w to have given
// state and write frames with given OpCode to dest.
// Reset resets Writer as it was created by New() methods.
// Note that Reset does reset extensions and other options was set after
// Writer initialization.
func (w *Writer) Reset(dest io.Writer, state ws.State, op ws.OpCode) {
w.n = 0
w.dirty = false
w.fragmented = false
w.dest = dest
w.state = state
w.op = op
w.initBuf()
w.n = 0
w.dirty = false
w.fseq = 0
w.extensions = w.extensions[:0]
w.noFlush = false
}
// Size returns the size of the underlying buffer in bytes.
// ResetOp is an quick version of Reset().
// ResetOp does reset unwritten fragments and does not reset results of
// SetExtensions() or DisableFlush() methods.
func (w *Writer) ResetOp(op ws.OpCode) {
w.op = op
w.n = 0
w.dirty = false
w.fseq = 0
}
// SetExtensions adds xs as extensions to be used during writes.
func (w *Writer) SetExtensions(xs ...SendExtension) {
w.extensions = xs
}
// DisableFlush denies Writer to write fragments.
func (w *Writer) DisableFlush() {
w.noFlush = true
}
// Size returns the size of the underlying buffer in bytes (not including
// WebSocket header bytes).
func (w *Writer) Size() int {
return len(w.buf)
}
@@ -263,6 +289,10 @@ func (w *Writer) Write(p []byte) (n int, err error) {
var nn int
for len(p) > w.Available() && w.err == nil {
if w.noFlush {
w.Grow(len(p) - w.Available())
continue
}
if w.Buffered() == 0 {
// Large write, empty buffer. Write directly from p to avoid copy.
// Trade off here is that we make additional Write() to underlying
@@ -295,6 +325,31 @@ func (w *Writer) Write(p []byte) (n int, err error) {
return n, w.err
}
func ceilPowerOfTwo(n int) int {
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
n |= n >> 32
n++
return n
}
func (w *Writer) Grow(n int) {
var (
offset = len(w.raw) - len(w.buf)
size = ceilPowerOfTwo(offset + w.n + n)
)
if size <= len(w.raw) {
panic("wsutil: buffer grow leads to its reduce")
}
p := make([]byte, size)
copy(p, w.raw[:offset+w.n])
w.raw = p
w.buf = w.raw[offset:]
}
// WriteThrough writes data bypassing the buffer.
// Note that Writer's buffer must be empty before calling WriteThrough().
func (w *Writer) WriteThrough(p []byte) (n int, err error) {
@@ -305,13 +360,37 @@ func (w *Writer) WriteThrough(p []byte) (n int, err error) {
return 0, ErrNotEmpty
}
w.err = writeFrame(w.dest, w.state, w.opCode(), false, p)
var frame ws.Frame
frame.Header = ws.Header{
OpCode: w.opCode(),
Fin: false,
Length: int64(len(p)),
}
for _, x := range w.extensions {
frame.Header, err = x.SetBits(frame.Header)
if err != nil {
return 0, err
}
}
if w.state.ClientSide() {
// Should copy bytes to prevent corruption of caller data.
payload := pbytes.GetLen(len(p))
defer pbytes.Put(payload)
copy(payload, p)
frame.Payload = payload
frame = ws.MaskFrameInPlace(frame)
} else {
frame.Payload = p
}
w.err = ws.WriteFrame(w.dest, frame)
if w.err == nil {
n = len(p)
}
w.dirty = true
w.fragmented = true
w.fseq++
return n, w.err
}
@@ -321,7 +400,11 @@ func (w *Writer) ReadFrom(src io.Reader) (n int64, err error) {
var nn int
for err == nil {
if w.Available() == 0 {
err = w.FlushFragment()
if w.noFlush {
w.Grow(w.Buffered()) // Twice bigger.
} else {
err = w.FlushFragment()
}
continue
}
@@ -367,7 +450,7 @@ func (w *Writer) Flush() error {
w.err = w.flushFragment(true)
w.n = 0
w.dirty = false
w.fragmented = false
w.fseq = 0
return w.err
}
@@ -381,35 +464,49 @@ func (w *Writer) FlushFragment() error {
w.err = w.flushFragment(false)
w.n = 0
w.fragmented = true
w.fseq++
return w.err
}
func (w *Writer) flushFragment(fin bool) error {
frame := ws.NewFrame(w.opCode(), fin, w.buf[:w.n])
func (w *Writer) flushFragment(fin bool) (err error) {
var (
payload = w.buf[:w.n]
header = ws.Header{
OpCode: w.opCode(),
Fin: fin,
Length: int64(len(payload)),
}
)
for _, ext := range w.extensions {
header, err = ext.SetBits(header)
if err != nil {
return err
}
}
if w.state.ClientSide() {
frame = ws.MaskFrameInPlace(frame)
header.Masked = true
header.Mask = ws.NewMask()
ws.Cipher(payload, header.Mask, 0)
}
// Write header to the header segment of the raw buffer.
head := len(w.raw) - len(w.buf)
offset := head - ws.HeaderSize(frame.Header)
var (
offset = len(w.raw) - len(w.buf)
skip = offset - ws.HeaderSize(header)
)
buf := bytesWriter{
buf: w.raw[offset:head],
buf: w.raw[skip:offset],
}
if err := ws.WriteHeader(&buf, frame.Header); err != nil {
if err := ws.WriteHeader(&buf, header); err != nil {
// Must never be reached.
panic("dump header error: " + err.Error())
}
_, err := w.dest.Write(w.raw[offset : head+w.n])
_, err = w.dest.Write(w.raw[skip : offset+w.n])
return err
}
func (w *Writer) opCode() ws.OpCode {
if w.fragmented {
if w.fseq > 0 {
return ws.OpContinuation
}
return w.op
@@ -448,3 +545,28 @@ func writeFrame(w io.Writer, s ws.State, op ws.OpCode, fin bool, p []byte) error
return ws.WriteFrame(w, frame)
}
func reserve(state ws.State, n int) (offset int) {
var mask int
if state.ClientSide() {
mask = 4
}
switch {
case n <= int(len7)+mask+2:
return mask + 2
case n <= int(len16)+mask+4:
return mask + 4
default:
return mask + 10
}
}
// headerSize returns number of bytes needed to encode header of a frame with
// given state and length.
func headerSize(s ws.State, n int) int {
return ws.HeaderSize(ws.Header{
Length: int64(n),
Masked: s.ClientSide(),
})
}