From 22a4006afea03e1b34bd14843b1752d5195f20dc Mon Sep 17 00:00:00 2001 From: Anmol Sethi <hi@nhooyr.io> Date: Sat, 15 Feb 2020 22:31:40 -0500 Subject: [PATCH] Remove dependency on golang.org/x/xerrors See https://github.com/nhooyr/websocket/issues/182 --- accept.go | 28 ++++++++++++++-------------- accept_js.go | 5 ++--- accept_test.go | 5 ++--- autobahn_test.go | 12 +++++------- close.go | 9 ++++----- close_notjs.go | 20 ++++++++++---------- conn_notjs.go | 18 +++++++++--------- conn_test.go | 5 ++--- dial.go | 32 ++++++++++++++++---------------- example_echo_test.go | 8 ++++---- frame.go | 5 ++--- go.mod | 3 +-- internal/errd/wrap.go | 32 ++------------------------------ internal/test/wstest/echo.go | 7 +++---- internal/test/wstest/pipe.go | 7 +++---- internal/xsync/go.go | 4 ++-- netconn.go | 5 ++--- read.go | 34 +++++++++++++++++----------------- write.go | 21 +++++++++++---------- ws_js.go | 36 ++++++++++++++++++------------------ wsjson/wsjson.go | 9 ++++----- wspb/wspb.go | 8 ++++---- 22 files changed, 137 insertions(+), 176 deletions(-) diff --git a/accept.go b/accept.go index 75d6d64..fda8cdc 100644 --- a/accept.go +++ b/accept.go @@ -6,14 +6,14 @@ import ( "bytes" "crypto/sha1" "encoding/base64" + "errors" + "fmt" "io" "net/http" "net/textproto" "net/url" "strings" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/errd" ) @@ -85,7 +85,7 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (_ *Con hj, ok := w.(http.Hijacker) if !ok { - err = xerrors.New("http.ResponseWriter does not implement http.Hijacker") + err = errors.New("http.ResponseWriter does not implement http.Hijacker") http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented) return nil, err } @@ -110,7 +110,7 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (_ *Con netConn, brw, err := hj.Hijack() if err != nil { - err = xerrors.Errorf("failed to hijack connection: %w", err) + err = fmt.Errorf("failed to hijack connection: %w", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return nil, err } @@ -133,32 +133,32 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (_ *Con func verifyClientRequest(w http.ResponseWriter, r *http.Request) (errCode int, _ error) { if !r.ProtoAtLeast(1, 1) { - return http.StatusUpgradeRequired, xerrors.Errorf("WebSocket protocol violation: handshake request must be at least HTTP/1.1: %q", r.Proto) + return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: handshake request must be at least HTTP/1.1: %q", r.Proto) } if !headerContainsToken(r.Header, "Connection", "Upgrade") { w.Header().Set("Connection", "Upgrade") w.Header().Set("Upgrade", "websocket") - return http.StatusUpgradeRequired, xerrors.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", r.Header.Get("Connection")) + return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", r.Header.Get("Connection")) } if !headerContainsToken(r.Header, "Upgrade", "websocket") { w.Header().Set("Connection", "Upgrade") w.Header().Set("Upgrade", "websocket") - return http.StatusUpgradeRequired, xerrors.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", r.Header.Get("Upgrade")) + return http.StatusUpgradeRequired, fmt.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", r.Header.Get("Upgrade")) } if r.Method != "GET" { - return http.StatusMethodNotAllowed, xerrors.Errorf("WebSocket protocol violation: handshake request method is not GET but %q", r.Method) + return http.StatusMethodNotAllowed, fmt.Errorf("WebSocket protocol violation: handshake request method is not GET but %q", r.Method) } if r.Header.Get("Sec-WebSocket-Version") != "13" { w.Header().Set("Sec-WebSocket-Version", "13") - return http.StatusBadRequest, xerrors.Errorf("unsupported WebSocket protocol version (only 13 is supported): %q", r.Header.Get("Sec-WebSocket-Version")) + return http.StatusBadRequest, fmt.Errorf("unsupported WebSocket protocol version (only 13 is supported): %q", r.Header.Get("Sec-WebSocket-Version")) } if r.Header.Get("Sec-WebSocket-Key") == "" { - return http.StatusBadRequest, xerrors.New("WebSocket protocol violation: missing Sec-WebSocket-Key") + return http.StatusBadRequest, errors.New("WebSocket protocol violation: missing Sec-WebSocket-Key") } return 0, nil @@ -169,10 +169,10 @@ func authenticateOrigin(r *http.Request) error { if origin != "" { u, err := url.Parse(origin) if err != nil { - return xerrors.Errorf("failed to parse Origin header %q: %w", origin, err) + return fmt.Errorf("failed to parse Origin header %q: %w", origin, err) } if !strings.EqualFold(u.Host, r.Host) { - return xerrors.Errorf("request Origin %q is not authorized for Host %q", origin, r.Host) + return fmt.Errorf("request Origin %q is not authorized for Host %q", origin, r.Host) } } return nil @@ -223,7 +223,7 @@ func acceptDeflate(w http.ResponseWriter, ext websocketExtension, mode Compressi continue } - err := xerrors.Errorf("unsupported permessage-deflate parameter: %q", p) + err := fmt.Errorf("unsupported permessage-deflate parameter: %q", p) http.Error(w, err.Error(), http.StatusBadRequest) return nil, err } @@ -253,7 +253,7 @@ func acceptWebkitDeflate(w http.ResponseWriter, ext websocketExtension, mode Com // // Either way, we're only implementing this for webkit which never sends the max_window_bits // parameter so we don't need to worry about it. - err := xerrors.Errorf("unsupported x-webkit-deflate-frame parameter: %q", p) + err := fmt.Errorf("unsupported x-webkit-deflate-frame parameter: %q", p) http.Error(w, err.Error(), http.StatusBadRequest) return nil, err } diff --git a/accept_js.go b/accept_js.go index 5db12d7..724b35b 100644 --- a/accept_js.go +++ b/accept_js.go @@ -1,9 +1,8 @@ package websocket import ( + "errors" "net/http" - - "golang.org/x/xerrors" ) // AcceptOptions represents Accept's options. @@ -16,5 +15,5 @@ type AcceptOptions struct { // Accept is stubbed out for Wasm. func Accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn, error) { - return nil, xerrors.New("unimplemented") + return nil, errors.New("unimplemented") } diff --git a/accept_test.go b/accept_test.go index 53338e1..523d468 100644 --- a/accept_test.go +++ b/accept_test.go @@ -4,14 +4,13 @@ package websocket import ( "bufio" + "errors" "net" "net/http" "net/http/httptest" "strings" "testing" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/test/assert" ) @@ -80,7 +79,7 @@ func TestAccept(t *testing.T) { w := mockHijacker{ ResponseWriter: httptest.NewRecorder(), hijack: func() (conn net.Conn, writer *bufio.ReadWriter, err error) { - return nil, nil, xerrors.New("haha") + return nil, nil, errors.New("haha") }, } diff --git a/autobahn_test.go b/autobahn_test.go index fb24a06..5047353 100644 --- a/autobahn_test.go +++ b/autobahn_test.go @@ -15,8 +15,6 @@ import ( "testing" "time" - "golang.org/x/xerrors" - "nhooyr.io/websocket" "nhooyr.io/websocket/internal/errd" "nhooyr.io/websocket/internal/test/assert" @@ -108,7 +106,7 @@ func wstestClientServer(ctx context.Context) (url string, closeFn func(), err er "exclude-cases": excludedAutobahnCases, }) if err != nil { - return "", nil, xerrors.Errorf("failed to write spec: %w", err) + return "", nil, fmt.Errorf("failed to write spec: %w", err) } ctx, cancel := context.WithTimeout(context.Background(), time.Minute*15) @@ -126,7 +124,7 @@ func wstestClientServer(ctx context.Context) (url string, closeFn func(), err er wstest := exec.CommandContext(ctx, "wstest", args...) err = wstest.Start() if err != nil { - return "", nil, xerrors.Errorf("failed to start wstest: %w", err) + return "", nil, fmt.Errorf("failed to start wstest: %w", err) } return url, func() { @@ -209,7 +207,7 @@ func unusedListenAddr() (_ string, err error) { func tempJSONFile(v interface{}) (string, error) { f, err := ioutil.TempFile("", "temp.json") if err != nil { - return "", xerrors.Errorf("temp file: %w", err) + return "", fmt.Errorf("temp file: %w", err) } defer f.Close() @@ -217,12 +215,12 @@ func tempJSONFile(v interface{}) (string, error) { e.SetIndent("", "\t") err = e.Encode(v) if err != nil { - return "", xerrors.Errorf("json encode: %w", err) + return "", fmt.Errorf("json encode: %w", err) } err = f.Close() if err != nil { - return "", xerrors.Errorf("close temp file: %w", err) + return "", fmt.Errorf("close temp file: %w", err) } return f.Name(), nil diff --git a/close.go b/close.go index 2007323..7cbc19e 100644 --- a/close.go +++ b/close.go @@ -1,9 +1,8 @@ package websocket import ( + "errors" "fmt" - - "golang.org/x/xerrors" ) // StatusCode represents a WebSocket status code. @@ -53,7 +52,7 @@ const ( // CloseError is returned when the connection is closed with a status and reason. // -// Use Go 1.13's xerrors.As to check for this error. +// Use Go 1.13's errors.As to check for this error. // Also see the CloseStatus helper. type CloseError struct { Code StatusCode @@ -64,13 +63,13 @@ func (ce CloseError) Error() string { return fmt.Sprintf("status = %v and reason = %q", ce.Code, ce.Reason) } -// CloseStatus is a convenience wrapper around Go 1.13's xerrors.As to grab +// CloseStatus is a convenience wrapper around Go 1.13's errors.As to grab // the status code from a CloseError. // // -1 will be returned if the passed error is nil or not a CloseError. func CloseStatus(err error) StatusCode { var ce CloseError - if xerrors.As(err, &ce) { + if errors.As(err, &ce) { return ce.Code } return -1 diff --git a/close_notjs.go b/close_notjs.go index 3367ea0..c25b088 100644 --- a/close_notjs.go +++ b/close_notjs.go @@ -5,11 +5,11 @@ package websocket import ( "context" "encoding/binary" + "errors" + "fmt" "log" "time" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/errd" ) @@ -46,7 +46,7 @@ func (c *Conn) closeHandshake(code StatusCode, reason string) (err error) { return nil } -var errAlreadyWroteClose = xerrors.New("already wrote close") +var errAlreadyWroteClose = errors.New("already wrote close") func (c *Conn) writeClose(code StatusCode, reason string) error { c.closeMu.Lock() @@ -62,7 +62,7 @@ func (c *Conn) writeClose(code StatusCode, reason string) error { Reason: reason, } - c.setCloseErr(xerrors.Errorf("sent close frame: %w", ce)) + c.setCloseErr(fmt.Errorf("sent close frame: %w", ce)) var p []byte var err error @@ -119,7 +119,7 @@ func parseClosePayload(p []byte) (CloseError, error) { } if len(p) < 2 { - return CloseError{}, xerrors.Errorf("close payload %q too small, cannot even contain the 2 byte status code", p) + return CloseError{}, fmt.Errorf("close payload %q too small, cannot even contain the 2 byte status code", p) } ce := CloseError{ @@ -128,7 +128,7 @@ func parseClosePayload(p []byte) (CloseError, error) { } if !validWireCloseCode(ce.Code) { - return CloseError{}, xerrors.Errorf("invalid status code %v", ce.Code) + return CloseError{}, fmt.Errorf("invalid status code %v", ce.Code) } return ce, nil @@ -155,7 +155,7 @@ func validWireCloseCode(code StatusCode) bool { func (ce CloseError) bytes() ([]byte, error) { p, err := ce.bytesErr() if err != nil { - err = xerrors.Errorf("failed to marshal close frame: %w", err) + err = fmt.Errorf("failed to marshal close frame: %w", err) ce = CloseError{ Code: StatusInternalError, } @@ -168,11 +168,11 @@ const maxCloseReason = maxControlPayload - 2 func (ce CloseError) bytesErr() ([]byte, error) { if len(ce.Reason) > maxCloseReason { - return nil, xerrors.Errorf("reason string max is %v but got %q with length %v", maxCloseReason, ce.Reason, len(ce.Reason)) + return nil, fmt.Errorf("reason string max is %v but got %q with length %v", maxCloseReason, ce.Reason, len(ce.Reason)) } if !validWireCloseCode(ce.Code) { - return nil, xerrors.Errorf("status code %v cannot be set", ce.Code) + return nil, fmt.Errorf("status code %v cannot be set", ce.Code) } buf := make([]byte, 2+len(ce.Reason)) @@ -189,7 +189,7 @@ func (c *Conn) setCloseErr(err error) { func (c *Conn) setCloseErrLocked(err error) { if c.closeErr == nil { - c.closeErr = xerrors.Errorf("WebSocket closed: %w", err) + c.closeErr = fmt.Errorf("WebSocket closed: %w", err) } } diff --git a/conn_notjs.go b/conn_notjs.go index 8598ded..7ee60fb 100644 --- a/conn_notjs.go +++ b/conn_notjs.go @@ -5,13 +5,13 @@ package websocket import ( "bufio" "context" + "errors" + "fmt" "io" "runtime" "strconv" "sync" "sync/atomic" - - "golang.org/x/xerrors" ) // Conn represents a WebSocket connection. @@ -108,7 +108,7 @@ func newConn(cfg connConfig) *Conn { } runtime.SetFinalizer(c, func(c *Conn) { - c.close(xerrors.New("connection garbage collected")) + c.close(errors.New("connection garbage collected")) }) go c.timeoutLoop() @@ -165,10 +165,10 @@ func (c *Conn) timeoutLoop() { case readCtx = <-c.readTimeout: case <-readCtx.Done(): - c.setCloseErr(xerrors.Errorf("read timed out: %w", readCtx.Err())) - go c.writeError(StatusPolicyViolation, xerrors.New("timed out")) + c.setCloseErr(fmt.Errorf("read timed out: %w", readCtx.Err())) + go c.writeError(StatusPolicyViolation, errors.New("timed out")) case <-writeCtx.Done(): - c.close(xerrors.Errorf("write timed out: %w", writeCtx.Err())) + c.close(fmt.Errorf("write timed out: %w", writeCtx.Err())) return } } @@ -190,7 +190,7 @@ func (c *Conn) Ping(ctx context.Context) error { err := c.ping(ctx, strconv.Itoa(int(p))) if err != nil { - return xerrors.Errorf("failed to ping: %w", err) + return fmt.Errorf("failed to ping: %w", err) } return nil } @@ -217,7 +217,7 @@ func (c *Conn) ping(ctx context.Context, p string) error { case <-c.closed: return c.closeErr case <-ctx.Done(): - err := xerrors.Errorf("failed to wait for pong: %w", ctx.Err()) + err := fmt.Errorf("failed to wait for pong: %w", ctx.Err()) c.close(err) return err case <-pong: @@ -242,7 +242,7 @@ func (m *mu) Lock(ctx context.Context) error { case <-m.c.closed: return m.c.closeErr case <-ctx.Done(): - err := xerrors.Errorf("failed to acquire lock: %w", ctx.Err()) + err := fmt.Errorf("failed to acquire lock: %w", ctx.Err()) m.c.close(err) return err case m.ch <- struct{}{}: diff --git a/conn_test.go b/conn_test.go index 7755048..c68a25f 100644 --- a/conn_test.go +++ b/conn_test.go @@ -19,7 +19,6 @@ import ( "github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes/duration" - "golang.org/x/xerrors" "nhooyr.io/websocket" "nhooyr.io/websocket/internal/test/assert" @@ -289,10 +288,10 @@ func TestWasm(t *testing.T) { func assertCloseStatus(exp websocket.StatusCode, err error) error { if websocket.CloseStatus(err) == -1 { - return xerrors.Errorf("expected websocket.CloseError: %T %v", err, err) + return fmt.Errorf("expected websocket.CloseError: %T %v", err, err) } if websocket.CloseStatus(err) != exp { - return xerrors.Errorf("expected close status %v but got ", exp, err) + return fmt.Errorf("expected close status %v but got %v", exp, err) } return nil } diff --git a/dial.go b/dial.go index 09546ac..6e37a58 100644 --- a/dial.go +++ b/dial.go @@ -8,6 +8,8 @@ import ( "context" "crypto/rand" "encoding/base64" + "errors" + "fmt" "io" "io/ioutil" "net/http" @@ -15,8 +17,6 @@ import ( "strings" "sync" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/errd" ) @@ -78,7 +78,7 @@ func dial(ctx context.Context, urls string, opts *DialOptions, rand io.Reader) ( secWebSocketKey, err := secWebSocketKey(rand) if err != nil { - return nil, nil, xerrors.Errorf("failed to generate Sec-WebSocket-Key: %w", err) + return nil, nil, fmt.Errorf("failed to generate Sec-WebSocket-Key: %w", err) } resp, err := handshakeRequest(ctx, urls, opts, secWebSocketKey) @@ -104,7 +104,7 @@ func dial(ctx context.Context, urls string, opts *DialOptions, rand io.Reader) ( rwc, ok := respBody.(io.ReadWriteCloser) if !ok { - return nil, resp, xerrors.Errorf("response body is not a io.ReadWriteCloser: %T", respBody) + return nil, resp, fmt.Errorf("response body is not a io.ReadWriteCloser: %T", respBody) } return newConn(connConfig{ @@ -120,12 +120,12 @@ func dial(ctx context.Context, urls string, opts *DialOptions, rand io.Reader) ( func handshakeRequest(ctx context.Context, urls string, opts *DialOptions, secWebSocketKey string) (*http.Response, error) { if opts.HTTPClient.Timeout > 0 { - return nil, xerrors.New("use context for cancellation instead of http.Client.Timeout; see https://github.com/nhooyr/websocket/issues/67") + return nil, errors.New("use context for cancellation instead of http.Client.Timeout; see https://github.com/nhooyr/websocket/issues/67") } u, err := url.Parse(urls) if err != nil { - return nil, xerrors.Errorf("failed to parse url: %w", err) + return nil, fmt.Errorf("failed to parse url: %w", err) } switch u.Scheme { @@ -134,7 +134,7 @@ func handshakeRequest(ctx context.Context, urls string, opts *DialOptions, secWe case "wss": u.Scheme = "https" default: - return nil, xerrors.Errorf("unexpected url scheme: %q", u.Scheme) + return nil, fmt.Errorf("unexpected url scheme: %q", u.Scheme) } req, _ := http.NewRequestWithContext(ctx, "GET", u.String(), nil) @@ -153,7 +153,7 @@ func handshakeRequest(ctx context.Context, urls string, opts *DialOptions, secWe resp, err := opts.HTTPClient.Do(req) if err != nil { - return nil, xerrors.Errorf("failed to send handshake request: %w", err) + return nil, fmt.Errorf("failed to send handshake request: %w", err) } return resp, nil } @@ -165,26 +165,26 @@ func secWebSocketKey(rr io.Reader) (string, error) { b := make([]byte, 16) _, err := io.ReadFull(rr, b) if err != nil { - return "", xerrors.Errorf("failed to read random data from rand.Reader: %w", err) + return "", fmt.Errorf("failed to read random data from rand.Reader: %w", err) } return base64.StdEncoding.EncodeToString(b), nil } func verifyServerResponse(opts *DialOptions, secWebSocketKey string, resp *http.Response) (*compressionOptions, error) { if resp.StatusCode != http.StatusSwitchingProtocols { - return nil, xerrors.Errorf("expected handshake response status code %v but got %v", http.StatusSwitchingProtocols, resp.StatusCode) + return nil, fmt.Errorf("expected handshake response status code %v but got %v", http.StatusSwitchingProtocols, resp.StatusCode) } if !headerContainsToken(resp.Header, "Connection", "Upgrade") { - return nil, xerrors.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", resp.Header.Get("Connection")) + return nil, fmt.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", resp.Header.Get("Connection")) } if !headerContainsToken(resp.Header, "Upgrade", "WebSocket") { - return nil, xerrors.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", resp.Header.Get("Upgrade")) + return nil, fmt.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", resp.Header.Get("Upgrade")) } if resp.Header.Get("Sec-WebSocket-Accept") != secWebSocketAccept(secWebSocketKey) { - return nil, xerrors.Errorf("WebSocket protocol violation: invalid Sec-WebSocket-Accept %q, key %q", + return nil, fmt.Errorf("WebSocket protocol violation: invalid Sec-WebSocket-Accept %q, key %q", resp.Header.Get("Sec-WebSocket-Accept"), secWebSocketKey, ) @@ -210,7 +210,7 @@ func verifySubprotocol(subprotos []string, resp *http.Response) error { } } - return xerrors.Errorf("WebSocket protocol violation: unexpected Sec-WebSocket-Protocol from server: %q", proto) + return fmt.Errorf("WebSocket protocol violation: unexpected Sec-WebSocket-Protocol from server: %q", proto) } func verifyServerExtensions(h http.Header) (*compressionOptions, error) { @@ -221,7 +221,7 @@ func verifyServerExtensions(h http.Header) (*compressionOptions, error) { ext := exts[0] if ext.name != "permessage-deflate" || len(exts) > 1 { - return nil, xerrors.Errorf("WebSocket protcol violation: unsupported extensions from server: %+v", exts[1:]) + return nil, fmt.Errorf("WebSocket protcol violation: unsupported extensions from server: %+v", exts[1:]) } copts := &compressionOptions{} @@ -232,7 +232,7 @@ func verifyServerExtensions(h http.Header) (*compressionOptions, error) { case "server_no_context_takeover": copts.serverNoContextTakeover = true default: - return nil, xerrors.Errorf("unsupported permessage-deflate parameter: %q", p) + return nil, fmt.Errorf("unsupported permessage-deflate parameter: %q", p) } } diff --git a/example_echo_test.go b/example_echo_test.go index 1daec8a..cd195d2 100644 --- a/example_echo_test.go +++ b/example_echo_test.go @@ -4,6 +4,7 @@ package websocket_test import ( "context" + "errors" "fmt" "io" "log" @@ -12,7 +13,6 @@ import ( "time" "golang.org/x/time/rate" - "golang.org/x/xerrors" "nhooyr.io/websocket" "nhooyr.io/websocket/wsjson" @@ -78,7 +78,7 @@ func echoServer(w http.ResponseWriter, r *http.Request) error { if c.Subprotocol() != "echo" { c.Close(websocket.StatusPolicyViolation, "client must speak the echo subprotocol") - return xerrors.New("client does not speak echo sub protocol") + return errors.New("client does not speak echo sub protocol") } l := rate.NewLimiter(rate.Every(time.Millisecond*100), 10) @@ -88,7 +88,7 @@ func echoServer(w http.ResponseWriter, r *http.Request) error { return nil } if err != nil { - return xerrors.Errorf("failed to echo with %v: %w", r.RemoteAddr, err) + return fmt.Errorf("failed to echo with %v: %w", r.RemoteAddr, err) } } } @@ -117,7 +117,7 @@ func echo(ctx context.Context, c *websocket.Conn, l *rate.Limiter) error { _, err = io.Copy(w, r) if err != nil { - return xerrors.Errorf("failed to io.Copy: %w", err) + return fmt.Errorf("failed to io.Copy: %w", err) } err = w.Close() diff --git a/frame.go b/frame.go index 4acaecf..2a036f9 100644 --- a/frame.go +++ b/frame.go @@ -3,12 +3,11 @@ package websocket import ( "bufio" "encoding/binary" + "fmt" "io" "math" "math/bits" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/errd" ) @@ -87,7 +86,7 @@ func readFrameHeader(r *bufio.Reader, readBuf []byte) (h header, err error) { } if h.payloadLength < 0 { - return header{}, xerrors.Errorf("received negative payload length: %v", h.payloadLength) + return header{}, fmt.Errorf("received negative payload length: %v", h.payloadLength) } if h.masked { diff --git a/go.mod b/go.mod index a10c7b1..801d6be 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module nhooyr.io/websocket -go 1.12 +go 1.13 require ( github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect @@ -11,5 +11,4 @@ require ( github.com/gorilla/websocket v1.4.1 github.com/klauspost/compress v1.10.0 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 - golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 ) diff --git a/internal/errd/wrap.go b/internal/errd/wrap.go index ed0b775..6e77913 100644 --- a/internal/errd/wrap.go +++ b/internal/errd/wrap.go @@ -2,41 +2,13 @@ package errd import ( "fmt" - - "golang.org/x/xerrors" ) -type wrapError struct { - msg string - err error - frame xerrors.Frame -} - -func (e *wrapError) Error() string { - return fmt.Sprint(e) -} - -func (e *wrapError) Format(s fmt.State, v rune) { xerrors.FormatError(e, s, v) } - -func (e *wrapError) FormatError(p xerrors.Printer) (next error) { - p.Print(e.msg) - e.frame.Format(p) - return e.err -} - -func (e *wrapError) Unwrap() error { - return e.err -} - -// Wrap wraps err with xerrors.Errorf if err is non nil. +// Wrap wraps err with fmt.Errorf if err is non nil. // Intended for use with defer and a named error return. // Inspired by https://github.com/golang/go/issues/32676. func Wrap(err *error, f string, v ...interface{}) { if *err != nil { - *err = &wrapError{ - msg: fmt.Sprintf(f, v...), - err: *err, - frame: xerrors.Caller(1), - } + *err = fmt.Errorf(f+": %w", append(v, *err)...) } } diff --git a/internal/test/wstest/echo.go b/internal/test/wstest/echo.go index 714767f..ab7bc25 100644 --- a/internal/test/wstest/echo.go +++ b/internal/test/wstest/echo.go @@ -3,11 +3,10 @@ package wstest import ( "bytes" "context" + "fmt" "io" "time" - "golang.org/x/xerrors" - "nhooyr.io/websocket" "nhooyr.io/websocket/internal/test/cmp" "nhooyr.io/websocket/internal/test/xrand" @@ -73,11 +72,11 @@ func Echo(ctx context.Context, c *websocket.Conn, max int) error { } if expType != actType { - return xerrors.Errorf("unexpected message typ (%v): %v", expType, actType) + return fmt.Errorf("unexpected message typ (%v): %v", expType, actType) } if !bytes.Equal(msg, act) { - return xerrors.Errorf("unexpected msg read: %v", cmp.Diff(msg, act)) + return fmt.Errorf("unexpected msg read: %v", cmp.Diff(msg, act)) } return nil diff --git a/internal/test/wstest/pipe.go b/internal/test/wstest/pipe.go index 81705a8..0a2899e 100644 --- a/internal/test/wstest/pipe.go +++ b/internal/test/wstest/pipe.go @@ -5,12 +5,11 @@ package wstest import ( "bufio" "context" + "fmt" "net" "net/http" "net/http/httptest" - "golang.org/x/xerrors" - "nhooyr.io/websocket" "nhooyr.io/websocket/internal/errd" "nhooyr.io/websocket/internal/test/xrand" @@ -39,11 +38,11 @@ func Pipe(dialOpts *websocket.DialOptions, acceptOpts *websocket.AcceptOptions) clientConn, _, err := websocket.Dial(context.Background(), "ws://example.com", dialOpts) if err != nil { - return nil, nil, xerrors.Errorf("failed to dial with fake transport: %w", err) + return nil, nil, fmt.Errorf("failed to dial with fake transport: %w", err) } if serverConn == nil { - return nil, nil, xerrors.Errorf("failed to get server conn from fake transport: %w", acceptErr) + return nil, nil, fmt.Errorf("failed to get server conn from fake transport: %w", acceptErr) } if xrand.Bool() { diff --git a/internal/xsync/go.go b/internal/xsync/go.go index 712739a..7a61f27 100644 --- a/internal/xsync/go.go +++ b/internal/xsync/go.go @@ -1,7 +1,7 @@ package xsync import ( - "golang.org/x/xerrors" + "fmt" ) // Go allows running a function in another goroutine @@ -13,7 +13,7 @@ func Go(fn func() error) <-chan error { r := recover() if r != nil { select { - case errs <- xerrors.Errorf("panic in go fn: %v", r): + case errs <- fmt.Errorf("panic in go fn: %v", r): default: } } diff --git a/netconn.go b/netconn.go index a2d8f4f..64aadf0 100644 --- a/netconn.go +++ b/netconn.go @@ -2,13 +2,12 @@ package websocket import ( "context" + "fmt" "io" "math" "net" "sync" "time" - - "golang.org/x/xerrors" ) // NetConn converts a *websocket.Conn into a net.Conn. @@ -108,7 +107,7 @@ func (c *netConn) Read(p []byte) (int, error) { return 0, err } if typ != c.msgType { - err := xerrors.Errorf("unexpected frame type read (expected %v): %v", c.msgType, typ) + err := fmt.Errorf("unexpected frame type read (expected %v): %v", c.msgType, typ) c.c.Close(StatusUnsupportedData, err.Error()) return 0, err } diff --git a/read.go b/read.go index bbad30d..a1efeca 100644 --- a/read.go +++ b/read.go @@ -5,13 +5,13 @@ package websocket import ( "bufio" "context" + "errors" + "fmt" "io" "io/ioutil" "strings" "time" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/errd" "nhooyr.io/websocket/internal/xsync" ) @@ -144,13 +144,13 @@ func (c *Conn) readLoop(ctx context.Context) (header, error) { } if h.rsv1 && c.readRSV1Illegal(h) || h.rsv2 || h.rsv3 { - err := xerrors.Errorf("received header with unexpected rsv bits set: %v:%v:%v", h.rsv1, h.rsv2, h.rsv3) + err := fmt.Errorf("received header with unexpected rsv bits set: %v:%v:%v", h.rsv1, h.rsv2, h.rsv3) c.writeError(StatusProtocolError, err) return header{}, err } if !c.client && !h.masked { - return header{}, xerrors.New("received unmasked frame from client") + return header{}, errors.New("received unmasked frame from client") } switch h.opcode { @@ -161,12 +161,12 @@ func (c *Conn) readLoop(ctx context.Context) (header, error) { if h.opcode == opClose && CloseStatus(err) != -1 { return header{}, err } - return header{}, xerrors.Errorf("failed to handle control frame %v: %w", h.opcode, err) + return header{}, fmt.Errorf("failed to handle control frame %v: %w", h.opcode, err) } case opContinuation, opText, opBinary: return h, nil default: - err := xerrors.Errorf("received unknown opcode %v", h.opcode) + err := fmt.Errorf("received unknown opcode %v", h.opcode) c.writeError(StatusProtocolError, err) return header{}, err } @@ -217,7 +217,7 @@ func (c *Conn) readFramePayload(ctx context.Context, p []byte) (int, error) { case <-ctx.Done(): return n, ctx.Err() default: - err = xerrors.Errorf("failed to read frame payload: %w", err) + err = fmt.Errorf("failed to read frame payload: %w", err) c.close(err) return n, err } @@ -234,13 +234,13 @@ func (c *Conn) readFramePayload(ctx context.Context, p []byte) (int, error) { func (c *Conn) handleControl(ctx context.Context, h header) (err error) { if h.payloadLength < 0 || h.payloadLength > maxControlPayload { - err := xerrors.Errorf("received control frame payload with invalid length: %d", h.payloadLength) + err := fmt.Errorf("received control frame payload with invalid length: %d", h.payloadLength) c.writeError(StatusProtocolError, err) return err } if !h.fin { - err := xerrors.New("received fragmented control frame") + err := errors.New("received fragmented control frame") c.writeError(StatusProtocolError, err) return err } @@ -277,12 +277,12 @@ func (c *Conn) handleControl(ctx context.Context, h header) (err error) { ce, err := parseClosePayload(b) if err != nil { - err = xerrors.Errorf("received invalid close payload: %w", err) + err = fmt.Errorf("received invalid close payload: %w", err) c.writeError(StatusProtocolError, err) return err } - err = xerrors.Errorf("received close frame: %w", ce) + err = fmt.Errorf("received close frame: %w", ce) c.setCloseErr(err) c.writeClose(ce.Code, ce.Reason) c.close(err) @@ -299,7 +299,7 @@ func (c *Conn) reader(ctx context.Context) (_ MessageType, _ io.Reader, err erro defer c.readMu.Unlock() if !c.msgReader.fin { - return 0, nil, xerrors.New("previous message not read to completion") + return 0, nil, errors.New("previous message not read to completion") } h, err := c.readLoop(ctx) @@ -308,7 +308,7 @@ func (c *Conn) reader(ctx context.Context) (_ MessageType, _ io.Reader, err erro } if h.opcode == opContinuation { - err := xerrors.New("received continuation frame without text or binary frame") + err := errors.New("received continuation frame without text or binary frame") c.writeError(StatusProtocolError, err) return 0, nil, err } @@ -357,10 +357,10 @@ func (mr *msgReader) setFrame(h header) { func (mr *msgReader) Read(p []byte) (n int, err error) { defer func() { - if xerrors.Is(err, io.ErrUnexpectedEOF) && mr.fin && mr.flate { + if errors.Is(err, io.ErrUnexpectedEOF) && mr.fin && mr.flate { err = io.EOF } - if xerrors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) { err = io.EOF mr.putFlateReader() return @@ -397,7 +397,7 @@ func (mr *msgReader) read(p []byte) (int, error) { return 0, err } if h.opcode != opContinuation { - err := xerrors.New("received new data message without finishing the previous message") + err := errors.New("received new data message without finishing the previous message") mr.c.writeError(StatusProtocolError, err) return 0, err } @@ -448,7 +448,7 @@ func (lr *limitReader) reset(r io.Reader) { func (lr *limitReader) Read(p []byte) (int, error) { if lr.n <= 0 { - err := xerrors.Errorf("read limited at %v bytes", lr.limit.Load()) + err := fmt.Errorf("read limited at %v bytes", lr.limit.Load()) lr.c.writeError(StatusMessageTooBig, err) return 0, err } diff --git a/write.go b/write.go index b560b44..81b9141 100644 --- a/write.go +++ b/write.go @@ -7,12 +7,13 @@ import ( "context" "crypto/rand" "encoding/binary" + "errors" + "fmt" "io" "sync" "time" "github.com/klauspost/compress/flate" - "golang.org/x/xerrors" "nhooyr.io/websocket/internal/errd" ) @@ -27,7 +28,7 @@ import ( func (c *Conn) Writer(ctx context.Context, typ MessageType) (io.WriteCloser, error) { w, err := c.writer(ctx, typ) if err != nil { - return nil, xerrors.Errorf("failed to get writer: %w", err) + return nil, fmt.Errorf("failed to get writer: %w", err) } return w, nil } @@ -41,7 +42,7 @@ func (c *Conn) Writer(ctx context.Context, typ MessageType) (io.WriteCloser, err func (c *Conn) Write(ctx context.Context, typ MessageType, p []byte) error { _, err := c.write(ctx, typ, p) if err != nil { - return xerrors.Errorf("failed to write msg: %w", err) + return fmt.Errorf("failed to write msg: %w", err) } return nil } @@ -53,14 +54,14 @@ type msgWriter struct { func (mw *msgWriter) Write(p []byte) (int, error) { if mw.closed { - return 0, xerrors.New("cannot use closed writer") + return 0, errors.New("cannot use closed writer") } return mw.mw.Write(p) } func (mw *msgWriter) Close() error { if mw.closed { - return xerrors.New("cannot use closed writer") + return errors.New("cannot use closed writer") } mw.closed = true return mw.mw.Close() @@ -182,7 +183,7 @@ func (mw *msgWriterState) Write(p []byte) (_ int, err error) { func (mw *msgWriterState) write(p []byte) (int, error) { n, err := mw.c.writeFrame(mw.ctx, false, mw.flate, mw.opcode, p) if err != nil { - return n, xerrors.Errorf("failed to write data frame: %w", err) + return n, fmt.Errorf("failed to write data frame: %w", err) } mw.opcode = opContinuation return n, nil @@ -197,7 +198,7 @@ func (mw *msgWriterState) Close() (err error) { _, err = mw.c.writeFrame(mw.ctx, true, mw.flate, mw.opcode, nil) if err != nil { - return xerrors.Errorf("failed to write fin frame: %w", err) + return fmt.Errorf("failed to write fin frame: %w", err) } if mw.flate && !mw.flateContextTakeover() { @@ -218,7 +219,7 @@ func (c *Conn) writeControl(ctx context.Context, opcode opcode, p []byte) error _, err := c.writeFrame(ctx, true, false, opcode, p) if err != nil { - return xerrors.Errorf("failed to write control frame %v: %w", opcode, err) + return fmt.Errorf("failed to write control frame %v: %w", opcode, err) } return nil } @@ -245,7 +246,7 @@ func (c *Conn) writeFrame(ctx context.Context, fin bool, flate bool, opcode opco c.writeHeader.masked = true _, err = io.ReadFull(rand.Reader, c.writeHeaderBuf[:4]) if err != nil { - return 0, xerrors.Errorf("failed to generate masking key: %w", err) + return 0, fmt.Errorf("failed to generate masking key: %w", err) } c.writeHeader.maskKey = binary.LittleEndian.Uint32(c.writeHeaderBuf[:]) } @@ -268,7 +269,7 @@ func (c *Conn) writeFrame(ctx context.Context, fin bool, flate bool, opcode opco if c.writeHeader.fin { err = c.bw.Flush() if err != nil { - return n, xerrors.Errorf("failed to flush: %w", err) + return n, fmt.Errorf("failed to flush: %w", err) } } diff --git a/ws_js.go b/ws_js.go index ecf3d78..2b560ce 100644 --- a/ws_js.go +++ b/ws_js.go @@ -3,6 +3,8 @@ package websocket // import "nhooyr.io/websocket" import ( "bytes" "context" + "errors" + "fmt" "io" "net/http" "reflect" @@ -10,8 +12,6 @@ import ( "sync" "syscall/js" - "golang.org/x/xerrors" - "nhooyr.io/websocket/internal/bpool" "nhooyr.io/websocket/internal/wsjs" "nhooyr.io/websocket/internal/xsync" @@ -45,7 +45,7 @@ func (c *Conn) close(err error, wasClean bool) { runtime.SetFinalizer(c, nil) if !wasClean { - err = xerrors.Errorf("unclean connection close: %w", err) + err = fmt.Errorf("unclean connection close: %w", err) } c.setCloseErr(err) c.closeWasClean = wasClean @@ -87,7 +87,7 @@ func (c *Conn) init() { }) runtime.SetFinalizer(c, func(c *Conn) { - c.setCloseErr(xerrors.New("connection garbage collected")) + c.setCloseErr(errors.New("connection garbage collected")) c.closeWithInternal() }) } @@ -100,15 +100,15 @@ func (c *Conn) closeWithInternal() { // The maximum time spent waiting is bounded by the context. func (c *Conn) Read(ctx context.Context) (MessageType, []byte, error) { if c.isReadClosed.Load() == 1 { - return 0, nil, xerrors.New("WebSocket connection read closed") + return 0, nil, errors.New("WebSocket connection read closed") } typ, p, err := c.read(ctx) if err != nil { - return 0, nil, xerrors.Errorf("failed to read: %w", err) + return 0, nil, fmt.Errorf("failed to read: %w", err) } if int64(len(p)) > c.msgReadLimit.Load() { - err := xerrors.Errorf("read limited at %v bytes", c.msgReadLimit.Load()) + err := fmt.Errorf("read limited at %v bytes", c.msgReadLimit.Load()) c.Close(StatusMessageTooBig, err.Error()) return 0, nil, err } @@ -166,7 +166,7 @@ func (c *Conn) Write(ctx context.Context, typ MessageType, p []byte) error { // to match the Go API. It can only error if the message type // is unexpected or the passed bytes contain invalid UTF-8 for // MessageText. - err := xerrors.Errorf("failed to write: %w", err) + err := fmt.Errorf("failed to write: %w", err) c.setCloseErr(err) c.closeWithInternal() return err @@ -184,7 +184,7 @@ func (c *Conn) write(ctx context.Context, typ MessageType, p []byte) error { case MessageText: return c.ws.SendText(string(p)) default: - return xerrors.Errorf("unexpected message type: %v", typ) + return fmt.Errorf("unexpected message type: %v", typ) } } @@ -195,7 +195,7 @@ func (c *Conn) write(ctx context.Context, typ MessageType, p []byte) error { func (c *Conn) Close(code StatusCode, reason string) error { err := c.exportedClose(code, reason) if err != nil { - return xerrors.Errorf("failed to close WebSocket: %w", err) + return fmt.Errorf("failed to close WebSocket: %w", err) } return nil } @@ -204,13 +204,13 @@ func (c *Conn) exportedClose(code StatusCode, reason string) error { c.closingMu.Lock() defer c.closingMu.Unlock() - ce := xerrors.Errorf("sent close: %w", CloseError{ + ce := fmt.Errorf("sent close: %w", CloseError{ Code: code, Reason: reason, }) if c.isClosed() { - return xerrors.Errorf("tried to close with %q but connection already closed: %w", ce, c.closeErr) + return fmt.Errorf("tried to close with %q but connection already closed: %w", ce, c.closeErr) } c.setCloseErr(ce) @@ -245,7 +245,7 @@ type DialOptions struct { func Dial(ctx context.Context, url string, opts *DialOptions) (*Conn, *http.Response, error) { c, resp, err := dial(ctx, url, opts) if err != nil { - return nil, nil, xerrors.Errorf("failed to WebSocket dial %q: %w", url, err) + return nil, nil, fmt.Errorf("failed to WebSocket dial %q: %w", url, err) } return c, resp, nil } @@ -318,25 +318,25 @@ type writer struct { func (w writer) Write(p []byte) (int, error) { if w.closed { - return 0, xerrors.New("cannot write to closed writer") + return 0, errors.New("cannot write to closed writer") } n, err := w.b.Write(p) if err != nil { - return n, xerrors.Errorf("failed to write message: %w", err) + return n, fmt.Errorf("failed to write message: %w", err) } return n, nil } func (w writer) Close() error { if w.closed { - return xerrors.New("cannot close closed writer") + return errors.New("cannot close closed writer") } w.closed = true defer bpool.Put(w.b) err := w.c.Write(w.ctx, w.typ, w.b.Bytes()) if err != nil { - return xerrors.Errorf("failed to close writer: %w", err) + return fmt.Errorf("failed to close writer: %w", err) } return nil } @@ -361,7 +361,7 @@ func (c *Conn) SetReadLimit(n int64) { func (c *Conn) setCloseErr(err error) { c.closeErrOnce.Do(func() { - c.closeErr = xerrors.Errorf("WebSocket closed: %w", err) + c.closeErr = fmt.Errorf("WebSocket closed: %w", err) }) } diff --git a/wsjson/wsjson.go b/wsjson/wsjson.go index e6f06a2..99996a6 100644 --- a/wsjson/wsjson.go +++ b/wsjson/wsjson.go @@ -4,8 +4,7 @@ package wsjson // import "nhooyr.io/websocket/wsjson" import ( "context" "encoding/json" - - "golang.org/x/xerrors" + "fmt" "nhooyr.io/websocket" "nhooyr.io/websocket/internal/bpool" @@ -28,7 +27,7 @@ func read(ctx context.Context, c *websocket.Conn, v interface{}) (err error) { if typ != websocket.MessageText { c.Close(websocket.StatusUnsupportedData, "expected text message") - return xerrors.Errorf("expected text message for JSON but got: %v", typ) + return fmt.Errorf("expected text message for JSON but got: %v", typ) } b := bpool.Get() @@ -42,7 +41,7 @@ func read(ctx context.Context, c *websocket.Conn, v interface{}) (err error) { err = json.Unmarshal(b.Bytes(), v) if err != nil { c.Close(websocket.StatusInvalidFramePayloadData, "failed to unmarshal JSON") - return xerrors.Errorf("failed to unmarshal JSON: %w", err) + return fmt.Errorf("failed to unmarshal JSON: %w", err) } return nil @@ -66,7 +65,7 @@ func write(ctx context.Context, c *websocket.Conn, v interface{}) (err error) { // a copy of the byte slice but Encoder does as it directly writes to w. err = json.NewEncoder(w).Encode(v) if err != nil { - return xerrors.Errorf("failed to marshal JSON: %w", err) + return fmt.Errorf("failed to marshal JSON: %w", err) } return w.Close() diff --git a/wspb/wspb.go b/wspb/wspb.go index 06ac336..e43042d 100644 --- a/wspb/wspb.go +++ b/wspb/wspb.go @@ -4,9 +4,9 @@ package wspb // import "nhooyr.io/websocket/wspb" import ( "bytes" "context" + "fmt" "github.com/golang/protobuf/proto" - "golang.org/x/xerrors" "nhooyr.io/websocket" "nhooyr.io/websocket/internal/bpool" @@ -29,7 +29,7 @@ func read(ctx context.Context, c *websocket.Conn, v proto.Message) (err error) { if typ != websocket.MessageBinary { c.Close(websocket.StatusUnsupportedData, "expected binary message") - return xerrors.Errorf("expected binary message for protobuf but got: %v", typ) + return fmt.Errorf("expected binary message for protobuf but got: %v", typ) } b := bpool.Get() @@ -43,7 +43,7 @@ func read(ctx context.Context, c *websocket.Conn, v proto.Message) (err error) { err = proto.Unmarshal(b.Bytes(), v) if err != nil { c.Close(websocket.StatusInvalidFramePayloadData, "failed to unmarshal protobuf") - return xerrors.Errorf("failed to unmarshal protobuf: %w", err) + return fmt.Errorf("failed to unmarshal protobuf: %w", err) } return nil @@ -66,7 +66,7 @@ func write(ctx context.Context, c *websocket.Conn, v proto.Message) (err error) err = pb.Marshal(v) if err != nil { - return xerrors.Errorf("failed to marshal protobuf: %w", err) + return fmt.Errorf("failed to marshal protobuf: %w", err) } return c.Write(ctx, websocket.MessageBinary, pb.Bytes()) -- GitLab