From 7c372c0a0d859c51a706b2a9e6fe12b1c8c1a26d Mon Sep 17 00:00:00 2001 From: Oleg Kovalov Date: Thu, 6 Apr 2023 21:47:33 +0200 Subject: [PATCH] Fix linter suggestions (#165) --- autobahn/main.go | 10 +---- autobahn/main_go18.go | 1 + cipher_test.go | 22 +++++++--- dialer.go | 41 +++++++++--------- dialer_test.go | 53 +++++++++++++----------- dialer_tls_go18.go | 1 + doc.go | 80 ++++++++++++++++++------------------ example/autobahn/autobahn.go | 2 - frame.go | 6 +-- http.go | 27 ++++++------ nonce.go | 2 - read.go | 24 +++++------ rw_test.go | 2 +- server.go | 16 ++++---- server_test.go | 10 ++--- util.go | 6 +-- util_test.go | 54 +++--------------------- wsflate/cbuf.go | 2 +- wsflate/helper.go | 6 +-- wsflate/parameters.go | 9 ++-- wsutil/cipher.go | 4 +- wsutil/dialer.go | 1 + wsutil/dialer_test.go | 16 ++++---- wsutil/handler.go | 2 +- wsutil/helper.go | 4 +- wsutil/reader.go | 4 +- wsutil/reader_test.go | 3 +- wsutil/upgrader_test.go | 2 +- wsutil/utf8.go | 2 +- wsutil/writer_test.go | 6 +-- wsutil/wsutil.go | 76 +++++++++++++++++----------------- 31 files changed, 228 insertions(+), 266 deletions(-) diff --git a/autobahn/main.go b/autobahn/main.go index ffee1b8..b19ab3c 100644 --- a/autobahn/main.go +++ b/autobahn/main.go @@ -92,15 +92,13 @@ func main() { log.Fatal(err) } - var servers []string + servers := make([]string, 0, len(report)) for s := range report { servers = append(servers, s) } sort.Strings(servers) - var ( - failed bool - ) + var failed bool tw := tabwriter.NewWriter(os.Stderr, 0, 4, 1, ' ', 0) for _, server := range servers { var ( @@ -176,10 +174,6 @@ func main() { os.Exit(rc) } -type spec struct { - OutDir string `json:"outdir"` -} - type report map[string]server type server map[string]entry diff --git a/autobahn/main_go18.go b/autobahn/main_go18.go index 1209505..5db7f77 100644 --- a/autobahn/main_go18.go +++ b/autobahn/main_go18.go @@ -1,3 +1,4 @@ +//go:build go1.8 // +build go1.8 package main diff --git a/cipher_test.go b/cipher_test.go index 9c7bf8c..32e7912 100644 --- a/cipher_test.go +++ b/cipher_test.go @@ -169,15 +169,27 @@ func BenchmarkCipher(b *testing.B) { b.Fatal(err) } - //b.Run(fmt.Sprintf("naive_bytes=%d;offset=%d", bench.size, bench.offset), func(b *testing.B) { - // for i := 0; i < b.N; i++ { - // cipherNaiveNoCp(bts, mask, bench.offset) - // } - //}) + b.Run(fmt.Sprintf("naive_bytes=%d;offset=%d", bench.size, bench.offset), func(b *testing.B) { + var sink int64 + for i := 0; i < b.N; i++ { + r := cipherNaiveNoCp(bts, mask, bench.offset) + sink += int64(len(r)) + } + sinkValue(sink) + }) b.Run(fmt.Sprintf("bytes=%d;offset=%d", bench.size, bench.offset), func(b *testing.B) { + var sink int64 for i := 0; i < b.N; i++ { Cipher(bts, mask, bench.offset) + sink += int64(len(bts)) } + sinkValue(sink) }) } } + +func sinkValue(v int64) { + if r := rand.Float32(); r > 2 { + panic(fmt.Sprintf("impossible %g: %v", r, v)) + } +} diff --git a/dialer.go b/dialer.go index d35dc14..89e889b 100644 --- a/dialer.go +++ b/dialer.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "net" + "net/http" "net/url" "strconv" "strings" @@ -163,7 +164,7 @@ func (d Dialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *buf } } if conn, err = d.dial(dialctx, u); err != nil { - return + return conn, br, hs, err } defer func() { if err != nil { @@ -189,7 +190,7 @@ func (d Dialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *buf br, hs, err = d.Upgrade(conn, u) - return + return conn, br, hs, err } var ( @@ -204,7 +205,7 @@ func tlsDefaultConfig() *tls.Config { return &tlsEmptyConfig } -func hostport(host string, defaultPort string) (hostname, addr string) { +func hostport(host, defaultPort string) (hostname, addr string) { var ( colon = strings.LastIndexByte(host, ':') bracket = strings.IndexByte(host, ']') @@ -241,7 +242,7 @@ func (d Dialer) dial(ctx context.Context, u *url.URL) (conn net.Conn, err error) if wrap := d.WrapConn; wrap != nil { conn = wrap(conn) } - return + return conn, err } func (d Dialer) tlsClient(conn net.Conn, hostname string) net.Conn { @@ -310,29 +311,29 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha initNonce(nonce) httpWriteUpgradeRequest(bw, u, nonce, d.Protocols, d.Extensions, d.Header) - if err = bw.Flush(); err != nil { - return + if err := bw.Flush(); err != nil { + return br, hs, err } // Read HTTP status line like "HTTP/1.1 101 Switching Protocols". sl, err := readLine(br) if err != nil { - return + return br, hs, err } // Begin validation of the response. // See https://tools.ietf.org/html/rfc6455#section-4.2.2 // Parse request line data like HTTP version, uri and method. resp, err := httpParseResponseLine(sl) if err != nil { - return + return br, hs, err } // Even if RFC says "1.1 or higher" without mentioning the part of the // version, we apply it only to minor part. if resp.major != 1 || resp.minor < 1 { err = ErrHandshakeBadProtocol - return + return br, hs, err } - if resp.status != 101 { + if resp.status != http.StatusSwitchingProtocols { err = StatusError(resp.status) if onStatusError := d.OnStatusError; onStatusError != nil { // Invoke callback with multireader of status-line bytes br. @@ -344,7 +345,7 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha ), ) } - return + return br, hs, err } // If response status is 101 then we expect all technical headers to be // valid. If not, then we stop processing response without giving user @@ -355,7 +356,7 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha line, e := readLine(br) if e != nil { err = e - return + return br, hs, err } if len(line) == 0 { // Blank line, no more lines to read. @@ -365,7 +366,7 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha k, v, ok := httpParseHeaderLine(line) if !ok { err = ErrMalformedResponse - return + return br, hs, err } switch btsToString(k) { @@ -373,7 +374,7 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha headerSeen |= headerSeenUpgrade if !bytes.Equal(v, specHeaderValueUpgrade) && !bytes.EqualFold(v, specHeaderValueUpgrade) { err = ErrHandshakeBadUpgrade - return + return br, hs, err } case headerConnectionCanonical: @@ -384,14 +385,14 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha // multiple token. But in response it must contains exactly one. if !bytes.Equal(v, specHeaderValueConnection) && !bytes.EqualFold(v, specHeaderValueConnection) { err = ErrHandshakeBadConnection - return + return br, hs, err } case headerSecAcceptCanonical: headerSeen |= headerSeenSecAccept if !checkAcceptFromNonce(v, nonce) { err = ErrHandshakeBadSecAccept - return + return br, hs, err } case headerSecProtocolCanonical: @@ -409,20 +410,20 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha // Server echoed subprotocol that is not present in client // requested protocols. err = ErrHandshakeBadSubProtocol - return + return br, hs, err } case headerSecExtensionsCanonical: hs.Extensions, err = matchSelectedExtensions(v, d.Extensions, hs.Extensions) if err != nil { - return + return br, hs, err } default: if onHeader := d.OnHeader; onHeader != nil { if e := onHeader(k, v); e != nil { err = e - return + return br, hs, err } } } @@ -439,7 +440,7 @@ func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Ha panic("unknown headers state") } } - return + return br, hs, err } // PutReader returns bufio.Reader instance to the inner reuse pool. diff --git a/dialer_test.go b/dialer_test.go index 342a8f2..8dd258d 100644 --- a/dialer_test.go +++ b/dialer_test.go @@ -116,7 +116,7 @@ func makeAccept(nonce []byte) []byte { func BenchmarkPutAccept(b *testing.B) { nonce := make([]byte, nonceSize) - _, err := rand.Read(nonce[:]) + _, err := rand.Read(nonce) if err != nil { b.Fatal(err) } @@ -129,7 +129,7 @@ func BenchmarkPutAccept(b *testing.B) { func BenchmarkCheckNonce(b *testing.B) { nonce := make([]byte, nonceSize) - _, err := rand.Read(nonce[:]) + _, err := rand.Read(nonce) if err != nil { b.Fatal(err) } @@ -159,7 +159,7 @@ func TestDialerHandshake(t *testing.T) { }{ { res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -174,7 +174,7 @@ func TestDialerHandshake(t *testing.T) { Protocols: []string{"xml", "json", "soap"}, }, res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -190,7 +190,7 @@ func TestDialerHandshake(t *testing.T) { Protocols: []string{"xml", "json", "soap"}, }, res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -210,7 +210,7 @@ func TestDialerHandshake(t *testing.T) { }, }, res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -231,7 +231,7 @@ func TestDialerHandshake(t *testing.T) { }, }, res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -252,7 +252,7 @@ func TestDialerHandshake(t *testing.T) { }, }, res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -267,7 +267,7 @@ func TestDialerHandshake(t *testing.T) { { name: "resp with frames", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -284,7 +284,7 @@ func TestDialerHandshake(t *testing.T) { { name: "resp with body", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -303,7 +303,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad proto", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 2, ProtoMinor: 1, Header: make(http.Header), @@ -313,7 +313,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad status", res: &http.Response{ - StatusCode: 400, + StatusCode: http.StatusBadRequest, ProtoMajor: 1, ProtoMinor: 1, Header: make(http.Header), @@ -324,7 +324,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad status with body", res: &http.Response{ - StatusCode: 400, + StatusCode: http.StatusBadRequest, ProtoMajor: 1, ProtoMinor: 1, Header: make(http.Header), @@ -339,7 +339,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad upgrade", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -352,7 +352,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad upgrade", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -366,7 +366,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad connection", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -379,7 +379,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad connection", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -393,7 +393,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad accept", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -407,7 +407,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad accept", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -421,7 +421,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad subprotocol", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -436,7 +436,7 @@ func TestDialerHandshake(t *testing.T) { { name: "bad extensions", res: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -457,7 +457,7 @@ func TestDialerHandshake(t *testing.T) { // set in test case. req, err := http.ReadRequest(bufio.NewReader(client)) if err != nil { - t.Fatal(err) + panic(err) } switch test.accept { @@ -479,7 +479,7 @@ func TestDialerHandshake(t *testing.T) { var buf bytes.Buffer for _, f := range test.frames { if err := WriteFrame(&buf, f); err != nil { - t.Fatal(err) + panic(err) } bts = append(bts, buf.Bytes()...) buf.Reset() @@ -611,7 +611,7 @@ func TestDialerCancelation(t *testing.T) { if t.IsZero() { return nil } - d := t.Sub(time.Now()) + d := time.Until(t) if d < 0 { deadline <- ioErrDeadline } else { @@ -691,7 +691,7 @@ func BenchmarkDialer(b *testing.B) { rand.Seed(0) resp := &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{ @@ -827,18 +827,21 @@ func (s stubConn) Close() error { } return nil } + func (s stubConn) SetDeadline(t time.Time) error { if s.setDeadline != nil { return s.setDeadline(t) } return nil } + func (s stubConn) SetReadDeadline(t time.Time) error { if s.setReadDeadline != nil { return s.setReadDeadline(t) } return nil } + func (s stubConn) SetWriteDeadline(t time.Time) error { if s.setWriteDeadline != nil { return s.setWriteDeadline(t) diff --git a/dialer_tls_go18.go b/dialer_tls_go18.go index a6704d5..5589ee5 100644 --- a/dialer_tls_go18.go +++ b/dialer_tls_go18.go @@ -1,3 +1,4 @@ +//go:build go1.8 // +build go1.8 package ws diff --git a/doc.go b/doc.go index c9d5791..0118ce2 100644 --- a/doc.go +++ b/doc.go @@ -11,70 +11,70 @@ Upgrade to WebSocket (or WebSocket handshake) can be done in two ways. The first way is to use `net/http` server: - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - conn, _, _, err := ws.UpgradeHTTP(r, w) - }) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + conn, _, _, err := ws.UpgradeHTTP(r, w) + }) The second and much more efficient way is so-called "zero-copy upgrade". It avoids redundant allocations and copying of not used headers or other request data. User decides by himself which data should be copied. - ln, err := net.Listen("tcp", ":8080") - if err != nil { - // handle error - } + ln, err := net.Listen("tcp", ":8080") + if err != nil { + // handle error + } - conn, err := ln.Accept() - if err != nil { - // handle error - } + conn, err := ln.Accept() + if err != nil { + // handle error + } - handshake, err := ws.Upgrade(conn) - if err != nil { - // handle error - } + handshake, err := ws.Upgrade(conn) + if err != nil { + // handle error + } For customization details see `ws.Upgrader` documentation. After WebSocket handshake you can work with connection in multiple ways. That is, `ws` does not force the only one way of how to work with WebSocket: - header, err := ws.ReadHeader(conn) - if err != nil { - // handle err - } + header, err := ws.ReadHeader(conn) + if err != nil { + // handle err + } - buf := make([]byte, header.Length) - _, err := io.ReadFull(conn, buf) - if err != nil { - // handle err - } + buf := make([]byte, header.Length) + _, err := io.ReadFull(conn, buf) + if err != nil { + // handle err + } - resp := ws.NewBinaryFrame([]byte("hello, world!")) - if err := ws.WriteFrame(conn, frame); err != nil { - // handle err - } + resp := ws.NewBinaryFrame([]byte("hello, world!")) + if err := ws.WriteFrame(conn, frame); err != nil { + // handle err + } As you can see, it stream friendly: - const N = 42 + const N = 42 - ws.WriteHeader(ws.Header{ - Fin: true, - Length: N, - OpCode: ws.OpBinary, - }) + ws.WriteHeader(ws.Header{ + Fin: true, + Length: N, + OpCode: ws.OpBinary, + }) - io.CopyN(conn, rand.Reader, N) + io.CopyN(conn, rand.Reader, N) Or: - header, err := ws.ReadHeader(conn) - if err != nil { - // handle err - } + header, err := ws.ReadHeader(conn) + if err != nil { + // handle err + } - io.CopyN(ioutil.Discard, conn, header.Length) + io.CopyN(ioutil.Discard, conn, header.Length) For more info see the documentation. */ diff --git a/example/autobahn/autobahn.go b/example/autobahn/autobahn.go index a256c45..182f8b2 100644 --- a/example/autobahn/autobahn.go +++ b/example/autobahn/autobahn.go @@ -21,8 +21,6 @@ import ( "github.com/gobwas/ws/wsutil" ) -const dir = "./example/autobahn" - var addr = flag.String("listen", ":9001", "addr to listen") func main() { diff --git a/frame.go b/frame.go index a4b9ddb..ae10144 100644 --- a/frame.go +++ b/frame.go @@ -225,7 +225,7 @@ func RsvBits(rsv byte) (r1, r2, r3 bool) { r1 = rsv&bit5 != 0 r2 = rsv&bit6 != 0 r3 = rsv&bit7 != 0 - return + return r1, r2, r3 } // Frame represents websocket frame. @@ -378,7 +378,7 @@ func MaskFrameInPlaceWith(f Frame, m [4]byte) Frame { // NewMask creates new random mask. func NewMask() (ret [4]byte) { binary.BigEndian.PutUint32(ret[:], rand.Uint32()) - return + return ret } // CompileFrame returns byte representation of given frame. @@ -388,7 +388,7 @@ func CompileFrame(f Frame) (bts []byte, err error) { buf := bytes.NewBuffer(make([]byte, 0, 16)) err = WriteFrame(buf, f) bts = buf.Bytes() - return + return bts, err } // MustCompileFrame is like CompileFrame but panics if frame can not be diff --git a/http.go b/http.go index 7d7175a..d020bac 100644 --- a/http.go +++ b/http.go @@ -5,7 +5,6 @@ import ( "bytes" "io" "net/http" - "net/textproto" "net/url" "strconv" @@ -48,14 +47,14 @@ var ( headerSecKey = "Sec-WebSocket-Key" headerSecAccept = "Sec-WebSocket-Accept" - headerHostCanonical = textproto.CanonicalMIMEHeaderKey(headerHost) - headerUpgradeCanonical = textproto.CanonicalMIMEHeaderKey(headerUpgrade) - headerConnectionCanonical = textproto.CanonicalMIMEHeaderKey(headerConnection) - headerSecVersionCanonical = textproto.CanonicalMIMEHeaderKey(headerSecVersion) - headerSecProtocolCanonical = textproto.CanonicalMIMEHeaderKey(headerSecProtocol) - headerSecExtensionsCanonical = textproto.CanonicalMIMEHeaderKey(headerSecExtensions) - headerSecKeyCanonical = textproto.CanonicalMIMEHeaderKey(headerSecKey) - headerSecAcceptCanonical = textproto.CanonicalMIMEHeaderKey(headerSecAccept) + headerHostCanonical = headerHost + headerUpgradeCanonical = headerUpgrade + headerConnectionCanonical = headerConnection + headerSecVersionCanonical = "Sec-Websocket-Version" + headerSecProtocolCanonical = "Sec-Websocket-Protocol" + headerSecExtensionsCanonical = "Sec-Websocket-Extensions" + headerSecKeyCanonical = "Sec-Websocket-Key" + headerSecAcceptCanonical = "Sec-Websocket-Accept" ) var ( @@ -91,10 +90,9 @@ func httpParseRequestLine(line []byte) (req httpRequestLine, err error) { req.major, req.minor, ok = httpParseVersion(proto) if !ok { err = ErrMalformedRequest - return + return req, err } - - return + return req, err } func httpParseResponseLine(line []byte) (resp httpResponseLine, err error) { @@ -198,8 +196,9 @@ func strSelectProtocol(h string, check func(string) bool) (ret string, ok bool) } return true }) - return + return ret, ok } + func btsSelectProtocol(h []byte, check func([]byte) bool) (ret string, ok bool) { var selected []byte ok = httphead.ScanTokens(h, func(v []byte) bool { @@ -212,7 +211,7 @@ func btsSelectProtocol(h []byte, check func([]byte) bool) (ret string, ok bool) if ok && selected != nil { return string(selected), true } - return + return ret, ok } func btsSelectExtensions(h []byte, selected []httphead.Option, check func(httphead.Option) bool) ([]httphead.Option, bool) { diff --git a/nonce.go b/nonce.go index e694da7..7b0edd9 100644 --- a/nonce.go +++ b/nonce.go @@ -65,8 +65,6 @@ func initAcceptFromNonce(accept, nonce []byte) { sum := sha1.Sum(p) base64.StdEncoding.Encode(accept, sum[:]) - - return } func writeAccept(bw *bufio.Writer, nonce []byte) (int, error) { diff --git a/read.go b/read.go index bc653e4..966cf8d 100644 --- a/read.go +++ b/read.go @@ -24,7 +24,7 @@ func ReadHeader(r io.Reader) (h Header, err error) { // Prepare to hold first 2 bytes to choose size of next read. _, err = io.ReadFull(r, bts) if err != nil { - return + return h, err } h.Fin = bts[0]&bit0 != 0 @@ -51,11 +51,11 @@ func ReadHeader(r io.Reader) (h Header, err error) { default: err = ErrHeaderLengthUnexpected - return + return h, err } if extra == 0 { - return + return h, err } // Increase len of bts to extra bytes need to read. @@ -63,7 +63,7 @@ func ReadHeader(r io.Reader) (h Header, err error) { bts = bts[:extra] _, err = io.ReadFull(r, bts) if err != nil { - return + return h, err } switch { @@ -74,7 +74,7 @@ func ReadHeader(r io.Reader) (h Header, err error) { case length == 127: if bts[0]&0x80 != 0 { err = ErrHeaderLengthMSB - return + return h, err } h.Length = int64(binary.BigEndian.Uint64(bts[:8])) bts = bts[8:] @@ -84,7 +84,7 @@ func ReadHeader(r io.Reader) (h Header, err error) { copy(h.Mask[:], bts) } - return + return h, err } // ReadFrame reads a frame from r. @@ -95,7 +95,7 @@ func ReadHeader(r io.Reader) (h Header, err error) { func ReadFrame(r io.Reader) (f Frame, err error) { f.Header, err = ReadHeader(r) if err != nil { - return + return f, err } if f.Header.Length > 0 { @@ -105,7 +105,7 @@ func ReadFrame(r io.Reader) (f Frame, err error) { _, err = io.ReadFull(r, f.Payload) } - return + return f, err } // MustReadFrame is like ReadFrame but panics if frame can not be read. @@ -128,20 +128,20 @@ func ParseCloseFrameData(payload []byte) (code StatusCode, reason string) { // In other words, we ignoring this rule [RFC6455:7.1.5]: // If this Close control frame contains no status code, _The WebSocket // Connection Close Code_ is considered to be 1005. - return + return code, reason } code = StatusCode(binary.BigEndian.Uint16(payload)) reason = string(payload[2:]) - return + return code, reason } // ParseCloseFrameDataUnsafe is like ParseCloseFrameData except the thing // that it does not copies payload bytes into reason, but prepares unsafe cast. func ParseCloseFrameDataUnsafe(payload []byte) (code StatusCode, reason string) { if len(payload) < 2 { - return + return code, reason } code = StatusCode(binary.BigEndian.Uint16(payload)) reason = btsToString(payload[2:]) - return + return code, reason } diff --git a/rw_test.go b/rw_test.go index 797e3ba..400803e 100644 --- a/rw_test.go +++ b/rw_test.go @@ -117,7 +117,7 @@ var RWTestCases = []RWTestCase{ } func bits(s string) []byte { - s = strings.Replace(s, " ", "", -1) + s = strings.ReplaceAll(s, " ", "") bts := make([]byte, len(s)/8) for i, j := 0, 0; i < len(s); i, j = i+8, j+1 { diff --git a/server.go b/server.go index ce530ae..1b710d5 100644 --- a/server.go +++ b/server.go @@ -24,11 +24,11 @@ const ( var ( ErrHandshakeBadProtocol = RejectConnectionError( RejectionStatus(http.StatusHTTPVersionNotSupported), - RejectionReason(fmt.Sprintf("handshake error: bad HTTP protocol version")), + RejectionReason("handshake error: bad HTTP protocol version"), ) ErrHandshakeBadMethod = RejectConnectionError( RejectionStatus(http.StatusMethodNotAllowed), - RejectionReason(fmt.Sprintf("handshake error: bad HTTP request method")), + RejectionReason("handshake error: bad HTTP request method"), ) ErrHandshakeBadHost = RejectConnectionError( RejectionStatus(http.StatusBadRequest), @@ -130,7 +130,7 @@ type HTTPUpgrader struct { // 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. + // Deprecated: use Negotiate instead. Extension func(httphead.Option) bool // Negotiate is the callback that is used to negotiate extensions from @@ -163,7 +163,7 @@ func (u HTTPUpgrader) Upgrade(r *http.Request, w http.ResponseWriter) (conn net. } if err != nil { httpError(w, err.Error(), http.StatusInternalServerError) - return + return conn, rw, hs, err } // See https://tools.ietf.org/html/rfc6455#section-4.1 @@ -262,7 +262,7 @@ func (u HTTPUpgrader) Upgrade(r *http.Request, w http.ResponseWriter) (conn net. // Do not store Flush() error to not override already existing one. _ = rw.Writer.Flush() } - return + return conn, rw, hs, err } // Upgrader contains options for upgrading connection to websocket. @@ -311,7 +311,7 @@ type Upgrader struct { // header fields it wishes to use, with the first options listed being most // preferable." // - // DEPRECATED. Use Negotiate instead. + // Deprecated: use Negotiate instead. Extension func(httphead.Option) bool // ExtensionCustom allow user to parse Sec-WebSocket-Extensions header @@ -549,7 +549,7 @@ func (u Upgrader) Upgrade(conn io.ReadWriter) (hs Handshake, err error) { if len(v) != nonceSize { err = ErrHandshakeBadSecKey } else { - copy(nonce[:], v) + copy(nonce, v) } case headerSecProtocolCanonical: @@ -646,7 +646,7 @@ func (u Upgrader) Upgrade(conn io.ReadWriter) (hs Handshake, err error) { httpWriteResponseUpgrade(bw, nonce, hs, header.WriteTo) err = bw.Flush() - return + return hs, err } type handshakeHeader [2]HandshakeHeader diff --git a/server_test.go b/server_test.go index d7fe3c5..42cf002 100644 --- a/server_test.go +++ b/server_test.go @@ -668,7 +668,7 @@ func dumpResponse(res *http.Response) []byte { panic(err) } if !res.Close { - bts = bytes.Replace(bts, []byte("Connection: close\r\n"), nil, -1) + bts = bytes.ReplaceAll(bts, []byte("Connection: close\r\n"), nil) } return bts @@ -744,7 +744,7 @@ func (r *recorder) Bytes() []byte { func (r *recorder) Hijack() (conn net.Conn, brw *bufio.ReadWriter, err error) { if r.hijacked { err = fmt.Errorf("already hijacked") - return + return conn, brw, err } r.hijacked = true @@ -771,11 +771,11 @@ func (r *recorder) Hijack() (conn net.Conn, brw *bufio.ReadWriter, err error) { brw = bufio.NewReadWriter(br, bw) - return + return conn, brw, err } func mustMakeRequest(method, url string, headers http.Header) *http.Request { - req, err := http.NewRequest(method, url, nil) + req, err := http.NewRequest(method, url, http.NoBody) if err != nil { panic(err) } @@ -837,5 +837,5 @@ func mustMakeErrResponse(code int, err error, headers http.Header) *http.Respons func mustMakeNonce() (ret []byte) { ret = make([]byte, nonceSize) initNonce(ret) - return + return ret } diff --git a/util.go b/util.go index 67ad906..9a5be51 100644 --- a/util.go +++ b/util.go @@ -47,7 +47,7 @@ func strToBytes(str string) (bts []byte) { b.Data = s.Data b.Len = s.Len b.Cap = s.Len - return + return bts } func btsToString(bts []byte) (str string) { @@ -73,7 +73,7 @@ func asciiToInt(bts []byte) (ret int, err error) { } // pow for integers implementation. -// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3 +// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3. func pow(a, b int) int { p := 1 for b > 0 { @@ -116,7 +116,7 @@ func btsHasToken(header, token []byte) (has bool) { has = bytes.EqualFold(v, token) return !has }) - return + return has } const ( diff --git a/util_test.go b/util_test.go index e2a3f66..67ade59 100644 --- a/util_test.go +++ b/util_test.go @@ -6,7 +6,6 @@ import ( "context" "fmt" "io" - "math/rand" "net" "net/http" "net/textproto" @@ -337,18 +336,6 @@ func BenchmarkHasToken(b *testing.B) { } } -type equalFoldCase struct { - label string - a, b string -} - -var equalFoldCases = []equalFoldCase{ - {"websocket", "WebSocket", "websocket"}, - {"upgrade", "Upgrade", "upgrade"}, - randomEqualLetters(512), - inequalAt(randomEqualLetters(512), 256), -} - func TestAsciiToInt(t *testing.T) { for _, test := range []struct { bts []byte @@ -361,7 +348,7 @@ func TestAsciiToInt(t *testing.T) { {[]byte("420"), 420, false}, {[]byte("010050042"), 10050042, false}, } { - t.Run(fmt.Sprintf("%s", string(test.bts)), func(t *testing.T) { + t.Run(string(test.bts), func(t *testing.T) { act, err := asciiToInt(test.bts) if (test.err && err == nil) || (!test.err && err != nil) { t.Errorf("unexpected error: %v", err) @@ -383,7 +370,7 @@ func TestBtrim(t *testing.T) { {[]byte("abc "), []byte("abc")}, {[]byte(" abc "), []byte("abc")}, } { - t.Run(fmt.Sprintf("%s", string(test.bts)), func(t *testing.T) { + t.Run(string(test.bts), func(t *testing.T) { if act := btrim(test.bts); !bytes.Equal(act, test.exp) { t.Errorf("btrim(%v) = %v; want %v", test.bts, act, test.exp) } @@ -402,7 +389,7 @@ func TestBSplit3(t *testing.T) { {[]byte(""), ' ', []byte{}, nil, nil}, {[]byte("GET / HTTP/1.1"), ' ', []byte("GET"), []byte("/"), []byte("HTTP/1.1")}, } { - t.Run(fmt.Sprintf("%s", string(test.bts)), func(t *testing.T) { + t.Run(string(test.bts), func(t *testing.T) { b1, b2, b3 := bsplit3(test.bts, test.sep) if !bytes.Equal(b1, test.exp1) || !bytes.Equal(b2, test.exp2) || !bytes.Equal(b3, test.exp3) { t.Errorf( @@ -428,7 +415,7 @@ var canonicalHeaderCases = [][]byte{ func TestCanonicalizeHeaderKey(t *testing.T) { for _, bts := range canonicalHeaderCases { - t.Run(fmt.Sprintf("%s", string(bts)), func(t *testing.T) { + t.Run(string(bts), func(t *testing.T) { act := append([]byte(nil), bts...) canonicalizeHeaderKey(act) @@ -446,41 +433,10 @@ func TestCanonicalizeHeaderKey(t *testing.T) { func BenchmarkCanonicalizeHeaderKey(b *testing.B) { for _, bts := range canonicalHeaderCases { - b.Run(fmt.Sprintf("%s", string(bts)), func(b *testing.B) { + b.Run(string(bts), func(b *testing.B) { for i := 0; i < b.N; i++ { canonicalizeHeaderKey(bts) } }) } } - -func randomEqualLetters(n int) (c equalFoldCase) { - c.label = fmt.Sprintf("rnd_eq_%d", n) - - a, b := make([]byte, n), make([]byte, n) - - for i := 0; i < n; i++ { - c := byte(rand.Intn('Z'-'A'+1) + 'A') // Random character from 'A' to 'Z'. - a[i] = c - b[i] = c | ('a' - 'A') // Swap fold. - } - - c.a = string(a) - c.b = string(b) - - return -} - -func inequalAt(c equalFoldCase, i int) equalFoldCase { - bts := make([]byte, len(c.a)) - copy(bts, c.a) - for { - b := byte(rand.Intn('z'-'a'+1) + 'a') - if bts[i] != b { - bts[i] = b - c.a = string(bts) - c.label = fmt.Sprintf("rnd_ineq_%d_%d", len(c.a), i) - return c - } - } -} diff --git a/wsflate/cbuf.go b/wsflate/cbuf.go index 2c10332..f1d0fb4 100644 --- a/wsflate/cbuf.go +++ b/wsflate/cbuf.go @@ -117,7 +117,7 @@ func (r *suffixedReader) ReadByte() (b byte, err error) { return 0, io.EOF } b = r.suffix[r.pos] - r.pos += 1 + r.pos++ return b, nil } diff --git a/wsflate/helper.go b/wsflate/helper.go index bfb4b69..eae94d7 100644 --- a/wsflate/helper.go +++ b/wsflate/helper.go @@ -172,10 +172,10 @@ func (h *Helper) CompressTo(w io.Writer, p []byte) (err error) { if _, err = c.Write(p); err != nil { return err } - if err = c.Flush(); err != nil { + if err := c.Flush(); err != nil { return err } - if err = c.Close(); err != nil { + if err := c.Close(); err != nil { return err } return nil @@ -188,7 +188,7 @@ func (h *Helper) DecompressTo(w io.Writer, p []byte) (err error) { if _, err = io.Copy(w, fr); err != nil { return err } - if err = fr.Close(); err != nil { + if err := fr.Close(); err != nil { return err } return nil diff --git a/wsflate/parameters.go b/wsflate/parameters.go index 2b70eab..3f2691c 100644 --- a/wsflate/parameters.go +++ b/wsflate/parameters.go @@ -63,12 +63,11 @@ const ( // // It returns non-nil error at least in these cases: // - The negotiation offer contains an extension parameter not defined for -// use in an offer/response. +// use in an offer/response. // - The negotiation offer/response contains an extension parameter with an -// invalid value. +// invalid value. // - The negotiation offer/response contains multiple extension parameters -// with -// the same name. +// with the same name. func (p *Parameters) Parse(opt httphead.Option) (err error) { const ( clientMaxWindowBitsSeen = 1 << iota @@ -143,7 +142,7 @@ func (p *Parameters) Parse(opt httphead.Option) (err error) { } return true }) - return + return err } // Option encodes parameters into HTTP header option. diff --git a/wsutil/cipher.go b/wsutil/cipher.go index f234be7..bc25064 100644 --- a/wsutil/cipher.go +++ b/wsutil/cipher.go @@ -34,7 +34,7 @@ func (c *CipherReader) Read(p []byte) (n int, err error) { n, err = c.r.Read(p) ws.Cipher(p[:n], c.mask, c.pos) c.pos += n - return + return n, err } // CipherWriter implements io.Writer that applies xor-cipher to the bytes @@ -68,5 +68,5 @@ func (c *CipherWriter) Write(p []byte) (n int, err error) { n, err = c.w.Write(cp) c.pos += n - return + return n, err } diff --git a/wsutil/dialer.go b/wsutil/dialer.go index 91c03d5..4f8788f 100644 --- a/wsutil/dialer.go +++ b/wsutil/dialer.go @@ -113,6 +113,7 @@ type rwConn struct { func (rwc rwConn) Read(p []byte) (int, error) { return rwc.r.Read(p) } + func (rwc rwConn) Write(p []byte) (int, error) { return rwc.w.Write(p) } diff --git a/wsutil/dialer_test.go b/wsutil/dialer_test.go index 216d9d6..885f05b 100644 --- a/wsutil/dialer_test.go +++ b/wsutil/dialer_test.go @@ -32,7 +32,7 @@ func TestDebugDialer(t *testing.T) { { name: "fail", resp: &http.Response{ - StatusCode: 101, + StatusCode: http.StatusSwitchingProtocols, ProtoMajor: 1, ProtoMinor: 1, }, @@ -41,7 +41,7 @@ func TestDebugDialer(t *testing.T) { { name: "fail", resp: &http.Response{ - StatusCode: 400, + StatusCode: http.StatusBadRequest, ProtoMajor: 42, ProtoMinor: 1, }, @@ -50,7 +50,7 @@ func TestDebugDialer(t *testing.T) { { name: "fail", resp: &http.Response{ - StatusCode: 400, + StatusCode: http.StatusBadRequest, ProtoMajor: 1, ProtoMinor: 1, }, @@ -59,7 +59,7 @@ func TestDebugDialer(t *testing.T) { { name: "fail footer", resp: &http.Response{ - StatusCode: 400, + StatusCode: http.StatusBadRequest, ProtoMajor: 1, ProtoMinor: 1, }, @@ -72,7 +72,7 @@ func TestDebugDialer(t *testing.T) { // response with body that does not fit to Dialer read buffer, // OnResponse will still be called with full response bytes. resp: &http.Response{ - StatusCode: 200, + StatusCode: http.StatusOK, ProtoMajor: 1, ProtoMinor: 1, Body: ioutil.NopCloser(bytes.NewReader( @@ -121,14 +121,14 @@ func TestDebugDialer(t *testing.T) { if test.resp == nil { _, err := ws.Upgrade(conn) if err != nil { - t.Fatal(err) + panic(err) } } else { if _, err := http.ReadRequest(bufio.NewReader(conn)); err != nil { - t.Fatal(err) + panic(err) } if err := test.resp.Write(conn); err != nil { - t.Fatal(err) + panic(err) } } diff --git a/wsutil/handler.go b/wsutil/handler.go index abb7cb7..44fd360 100644 --- a/wsutil/handler.go +++ b/wsutil/handler.go @@ -199,7 +199,7 @@ func (c ControlHandler) HandleClose(h ws.Header) error { if err != nil { return err } - if err = w.Flush(); err != nil { + if err := w.Flush(); err != nil { return err } return ClosedError{ diff --git a/wsutil/helper.go b/wsutil/helper.go index 411d68d..231760b 100644 --- a/wsutil/helper.go +++ b/wsutil/helper.go @@ -64,14 +64,14 @@ func ReadMessage(r io.Reader, s ws.State, m []Message) ([]Message, error) { // ReadClientMessage reads next message from r, considering that caller // represents server side. -// It is a shortcut for ReadMessage(r, ws.StateServerSide, m) +// It is a shortcut for ReadMessage(r, ws.StateServerSide, m). func ReadClientMessage(r io.Reader, m []Message) ([]Message, error) { return ReadMessage(r, ws.StateServerSide, m) } // ReadServerMessage reads next message from r, considering that caller // represents client side. -// It is a shortcut for ReadMessage(r, ws.StateClientSide, m) +// It is a shortcut for ReadMessage(r, ws.StateClientSide, m). func ReadServerMessage(r io.Reader, m []Message) ([]Message, error) { return ReadMessage(r, ws.StateClientSide, m) } diff --git a/wsutil/reader.go b/wsutil/reader.go index 33a2291..a40418f 100644 --- a/wsutil/reader.go +++ b/wsutil/reader.go @@ -137,7 +137,7 @@ func (r *Reader) Read(p []byte) (n int, err error) { err = io.EOF } - return + return n, err } // Discard discards current message unread bytes. @@ -240,7 +240,7 @@ func (r *Reader) NextFrame() (hdr ws.Header, err error) { r.State = r.State.Set(ws.StateFragmented) } - return + return hdr, err } func (r *Reader) fragmented() bool { diff --git a/wsutil/reader_test.go b/wsutil/reader_test.go index a20c034..b0676c1 100644 --- a/wsutil/reader_test.go +++ b/wsutil/reader_test.go @@ -34,7 +34,7 @@ func TestReadFromWithIntermediateControl(t *testing.T) { } intermediate = append( intermediate, - append(([]byte)(nil), bts...), + append([]byte(nil), bts...), ) return nil }, @@ -165,7 +165,6 @@ func TestReaderNextFrameAndReadEOF(t *testing.T) { } }) } - } func TestMaxFrameSize(t *testing.T) { diff --git a/wsutil/upgrader_test.go b/wsutil/upgrader_test.go index a1bad17..6262892 100644 --- a/wsutil/upgrader_test.go +++ b/wsutil/upgrader_test.go @@ -90,7 +90,7 @@ func TestDebugUpgrader(t *testing.T) { type falseReader struct{} -func (f falseReader) Read(p []byte) (int, error) { +func (f falseReader) Read([]byte) (int, error) { return 0, fmt.Errorf("falsy read") } diff --git a/wsutil/utf8.go b/wsutil/utf8.go index d877be0..b8dc726 100644 --- a/wsutil/utf8.go +++ b/wsutil/utf8.go @@ -65,7 +65,7 @@ func (u *UTF8Reader) Read(p []byte) (n int, err error) { u.state, u.codep = s, c u.accepted = accepted - return + return n, err } // Valid checks current reader state. It returns true if all read bytes are diff --git a/wsutil/writer_test.go b/wsutil/writer_test.go index 3a96a7f..d069d09 100644 --- a/wsutil/writer_test.go +++ b/wsutil/writer_test.go @@ -362,7 +362,7 @@ func TestWriterLargeWrite(t *testing.T) { w := NewWriterSize(&dest, 0, 0, 16) // Test that even for big writes extensions set their bits. - var rsv = [3]bool{true, true, false} + rsv := [3]bool{true, true, false} w.SetExtensions(SendExtensionFunc(func(h ws.Header) (ws.Header, error) { h.Rsv = ws.Rsv(rsv[0], rsv[1], rsv[2]) return h, nil @@ -426,7 +426,7 @@ func TestWriterGrow(t *testing.T) { w.DisableFlush() // Test that even for big writes extensions set their bits. - var rsv = [3]bool{true, true, false} + rsv := [3]bool{true, true, false} w.SetExtensions(SendExtensionFunc(func(h ws.Header) (ws.Header, error) { h.Rsv = ws.Rsv(rsv[0], rsv[1], rsv[2]) return h, nil @@ -615,7 +615,7 @@ func frames(p []byte) (ret []ws.Frame) { } ret = append(ret, f) } - return + return ret } func pretty(f ...ws.Frame) string { diff --git a/wsutil/wsutil.go b/wsutil/wsutil.go index ffd4336..86211f3 100644 --- a/wsutil/wsutil.go +++ b/wsutil/wsutil.go @@ -3,54 +3,54 @@ Package wsutil provides utilities for working with WebSocket protocol. Overview: - // Read masked text message from peer and check utf8 encoding. - header, err := ws.ReadHeader(conn) - if err != nil { - // handle err - } - - // Prepare to read payload. - r := io.LimitReader(conn, header.Length) - r = wsutil.NewCipherReader(r, header.Mask) - r = wsutil.NewUTF8Reader(r) - - payload, err := ioutil.ReadAll(r) - if err != nil { - // handle err - } + // Read masked text message from peer and check utf8 encoding. + header, err := ws.ReadHeader(conn) + if err != nil { + // handle err + } + + // Prepare to read payload. + r := io.LimitReader(conn, header.Length) + r = wsutil.NewCipherReader(r, header.Mask) + r = wsutil.NewUTF8Reader(r) + + payload, err := ioutil.ReadAll(r) + if err != nil { + // handle err + } You could get the same behavior using just `wsutil.Reader`: - r := wsutil.Reader{ - Source: conn, - CheckUTF8: true, - } + r := wsutil.Reader{ + Source: conn, + CheckUTF8: true, + } - payload, err := ioutil.ReadAll(r) - if err != nil { - // handle err - } + payload, err := ioutil.ReadAll(r) + if err != nil { + // handle err + } Or even simplest: - payload, err := wsutil.ReadClientText(conn) - if err != nil { - // handle err - } + payload, err := wsutil.ReadClientText(conn) + if err != nil { + // handle err + } Package is also exports tools for buffered writing: - // Create buffered writer, that will buffer output bytes and send them as - // 128-length fragments (with exception on large writes, see the doc). - writer := wsutil.NewWriterSize(conn, ws.StateServerSide, ws.OpText, 128) - - _, err := io.CopyN(writer, rand.Reader, 100) - if err == nil { - err = writer.Flush() - } - if err != nil { - // handle error - } + // Create buffered writer, that will buffer output bytes and send them as + // 128-length fragments (with exception on large writes, see the doc). + writer := wsutil.NewWriterSize(conn, ws.StateServerSide, ws.OpText, 128) + + _, err := io.CopyN(writer, rand.Reader, 100) + if err == nil { + err = writer.Flush() + } + if err != nil { + // handle error + } For more utils and helpers see the documentation. */