good morning!!!!

Skip to content
Snippets Groups Projects
Unverified Commit 989ba2f7 authored by Anmol Sethi's avatar Anmol Sethi
Browse files

Change websocket to WebSocket in docs/errors

parent 6b782a33
Branches
Tags
No related merge requests found
......@@ -170,4 +170,4 @@ See the gorilla/websocket comparison for more performance details.
If your company or project is using this library, feel free to open an issue or PR to amend this list.
- [Coder](https://github.com/cdr)
- [Tatsu Works](https://github.com/tatsuworks) - Ingresses 20 TB in websocket data every month on their Discord bot.
- [Tatsu Works](https://github.com/tatsuworks) - Ingresses 20 TB in WebSocket data every month on their Discord bot.
......@@ -10,68 +10,56 @@ import (
"net/http"
"net/textproto"
"net/url"
"nhooyr.io/websocket/internal/errd"
"strings"
)
// AcceptOptions represents the options available to pass to Accept.
type AcceptOptions struct {
// Subprotocols lists the websocket subprotocols that Accept will negotiate with a client.
// Subprotocols lists the WebSocket subprotocols that Accept will negotiate with the client.
// The empty subprotocol will always be negotiated as per RFC 6455. If you would like to
// reject it, close the connection if c.Subprotocol() == "".
// reject it, close the connection when c.Subprotocol() == "".
Subprotocols []string
// InsecureSkipVerify disables Accept's origin verification
// behaviour. By default Accept only allows the handshake to
// succeed if the javascript that is initiating the handshake
// is on the same domain as the server. This is to prevent CSRF
// attacks when secure data is stored in a cookie as there is no same
// origin policy for WebSockets. In other words, javascript from
// any domain can perform a WebSocket dial on an arbitrary server.
// This dial will include cookies which means the arbitrary javascript
// can perform actions as the authenticated user.
// InsecureSkipVerify disables Accept's origin verification behaviour. By default,
// the connection will only be accepted if the request origin is equal to the request
// host.
//
// This is only required if you want javascript served from a different domain
// to access your WebSocket server.
//
// See https://stackoverflow.com/a/37837709/4283659
//
// The only time you need this is if your javascript is running on a different domain
// than your WebSocket server.
// Think carefully about whether you really need this option before you use it.
// If you do, remember that if you store secure data in cookies, you wil need to verify the
// Origin header yourself otherwise you are exposing yourself to a CSRF attack.
// Please ensure you understand the ramifications of enabling this.
// If used incorrectly your WebSocket server will be open to CSRF attacks.
InsecureSkipVerify bool
// CompressionMode sets the compression mode.
// See docs on the CompressionMode type and defined constants.
// See docs on the CompressionMode type.
CompressionMode CompressionMode
}
// Accept accepts a WebSocket HTTP handshake from a client and upgrades the
// Accept accepts a WebSocket handshake from a client and upgrades the
// the connection to a WebSocket.
//
// Accept will reject the handshake if the Origin domain is not the same as the Host unless
// the InsecureSkipVerify option is set. In other words, by default it does not allow
// cross origin requests.
// Accept will not allow cross origin requests by default.
// See the InsecureSkipVerify option to allow cross origin requests.
//
// If an error occurs, Accept will write a response with a safe error message to w.
// Accept will write a response to w on all errors.
func Accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn, error) {
c, err := accept(w, r, opts)
if err != nil {
return nil, fmt.Errorf("failed to accept websocket connection: %w", err)
}
return c, nil
return accept(w, r, opts)
}
func (opts *AcceptOptions) ensure() *AcceptOptions {
func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (_ *Conn, err error) {
defer errd.Wrap(&err, "failed to accept WebSocket connection")
if opts == nil {
return &AcceptOptions{}
opts = &AcceptOptions{}
}
return opts
}
func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn, error) {
opts = opts.ensure()
err := verifyClientRequest(w, r)
err = verifyClientRequest(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return nil, err
}
......@@ -85,7 +73,7 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn,
hj, ok := w.(http.Hijacker)
if !ok {
err = errors.New("passed 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
}
......@@ -93,7 +81,8 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn,
w.Header().Set("Upgrade", "websocket")
w.Header().Set("Connection", "Upgrade")
handleSecWebSocketKey(w, r)
key := r.Header.Get("Sec-WebSocket-Key")
w.Header().Set("Sec-WebSocket-Accept", secWebSocketAccept(key))
subproto := selectSubprotocol(r, opts.Subprotocols)
if subproto != "" {
......@@ -102,7 +91,6 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn,
copts, err := acceptCompression(r, w, opts.CompressionMode)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return nil, err
}
......@@ -129,41 +117,29 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn,
}), nil
}
func verifyClientRequest(w http.ResponseWriter, r *http.Request) error {
func verifyClientRequest(r *http.Request) error {
if !r.ProtoAtLeast(1, 1) {
err := fmt.Errorf("websocket protocol violation: handshake request must be at least HTTP/1.1: %q", r.Proto)
http.Error(w, err.Error(), http.StatusBadRequest)
return err
return fmt.Errorf("WebSocket protocol violation: handshake request must be at least HTTP/1.1: %q", r.Proto)
}
if !headerContainsToken(r.Header, "Connection", "Upgrade") {
err := fmt.Errorf("websocket protocol violation: Connection header %q does not contain Upgrade", r.Header.Get("Connection"))
http.Error(w, err.Error(), http.StatusBadRequest)
return err
return fmt.Errorf("WebSocket protocol violation: Connection header %q does not contain Upgrade", r.Header.Get("Connection"))
}
if !headerContainsToken(r.Header, "Upgrade", "WebSocket") {
err := fmt.Errorf("websocket protocol violation: Upgrade header %q does not contain websocket", r.Header.Get("Upgrade"))
http.Error(w, err.Error(), http.StatusBadRequest)
return err
if !headerContainsToken(r.Header, "Upgrade", "websocket") {
return fmt.Errorf("WebSocket protocol violation: Upgrade header %q does not contain websocket", r.Header.Get("Upgrade"))
}
if r.Method != "GET" {
err := fmt.Errorf("websocket protocol violation: handshake request method is not GET but %q", r.Method)
http.Error(w, err.Error(), http.StatusBadRequest)
return err
return fmt.Errorf("WebSocket protocol violation: handshake request method is not GET but %q", r.Method)
}
if r.Header.Get("Sec-WebSocket-Version") != "13" {
err := fmt.Errorf("unsupported websocket protocol version (only 13 is supported): %q", r.Header.Get("Sec-WebSocket-Version"))
http.Error(w, err.Error(), http.StatusBadRequest)
return err
return fmt.Errorf("unsupported WebSocket protocol version (only 13 is supported): %q", r.Header.Get("Sec-WebSocket-Version"))
}
if r.Header.Get("Sec-WebSocket-Key") == "" {
err := errors.New("websocket protocol violation: missing Sec-WebSocket-Key")
http.Error(w, err.Error(), http.StatusBadRequest)
return err
return errors.New("WebSocket protocol violation: missing Sec-WebSocket-Key")
}
return nil
......@@ -171,9 +147,7 @@ func verifyClientRequest(w http.ResponseWriter, r *http.Request) error {
func authenticateOrigin(r *http.Request) error {
origin := r.Header.Get("Origin")
if origin == "" {
return nil
}
if origin != "" {
u, err := url.Parse(origin)
if err != nil {
return fmt.Errorf("failed to parse Origin header %q: %w", origin, err)
......@@ -181,20 +155,12 @@ func authenticateOrigin(r *http.Request) error {
if !strings.EqualFold(u.Host, r.Host) {
return fmt.Errorf("request Origin %q is not authorized for Host %q", origin, r.Host)
}
return nil
}
func handleSecWebSocketKey(w http.ResponseWriter, r *http.Request) {
key := r.Header.Get("Sec-WebSocket-Key")
w.Header().Set("Sec-WebSocket-Accept", secWebSocketAccept(key))
return nil
}
func selectSubprotocol(r *http.Request, subprotocols []string) string {
cps := headerTokens(r.Header, "Sec-WebSocket-Protocol")
if len(cps) == 0 {
return ""
}
for _, sp := range subprotocols {
for _, cp := range cps {
if strings.EqualFold(sp, cp) {
......@@ -236,7 +202,9 @@ func acceptDeflate(w http.ResponseWriter, ext websocketExtension, mode Compressi
continue
}
return nil, fmt.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
}
copts.setHeader(w.Header())
......@@ -264,7 +232,9 @@ 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.
return nil, fmt.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
}
s := "x-webkit-deflate-frame"
......
......@@ -114,7 +114,6 @@ func Test_verifyClientHandshake(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r := httptest.NewRequest(tc.method, "/", nil)
r.ProtoMajor = 1
......@@ -127,7 +126,7 @@ func Test_verifyClientHandshake(t *testing.T) {
r.Header.Set(k, v)
}
err := verifyClientRequest(w, r)
err := verifyClientRequest(r)
if (err == nil) != tc.success {
t.Fatalf("unexpected error value: %+v", err)
}
......
......@@ -22,4 +22,4 @@ prettier:
prettier --write --print-width=120 --no-semi --trailing-comma=all --loglevel=warn $$(git ls-files "*.yml" "*.md")
gen:
stringer -type=opcode,MessageType,StatusCode -output=websocket_stringer.go
stringer -type=opcode,MessageType,StatusCode -output=stringer.go
......@@ -19,5 +19,5 @@ coveralls: gotest
gotest:
go test -covermode=count -coverprofile=ci/out/coverage.prof -coverpkg=./... $${GOTESTFLAGS-} ./...
sed -i '/_stringer\.go/d' ci/out/coverage.prof
sed -i '/stringer\.go/d' ci/out/coverage.prof
sed -i '/assert/d' ci/out/coverage.prof
......@@ -97,7 +97,7 @@ func CloseStatus(err error) StatusCode {
func (c *Conn) Close(code StatusCode, reason string) error {
err := c.closeHandshake(code, reason)
if err != nil {
return fmt.Errorf("failed to close websocket: %w", err)
return fmt.Errorf("failed to close WebSocket: %w", err)
}
return nil
}
......@@ -236,7 +236,7 @@ func (c *Conn) setCloseErr(err error) {
func (c *Conn) setCloseErrNoLock(err error) {
if c.closeErr == nil {
c.closeErr = fmt.Errorf("websocket closed: %w", err)
c.closeErr = fmt.Errorf("WebSocket closed: %w", err)
}
}
......
......@@ -47,7 +47,7 @@ type DialOptions struct {
func Dial(ctx context.Context, u string, opts *DialOptions) (*Conn, *http.Response, error) {
c, r, err := dial(ctx, u, opts)
if err != nil {
return nil, r, fmt.Errorf("failed to websocket dial: %w", err)
return nil, r, fmt.Errorf("failed to WebSocket dial: %w", err)
}
return c, r, nil
}
......@@ -158,22 +158,22 @@ func verifyServerResponse(r *http.Request, resp *http.Response) (*compressionOpt
}
if !headerContainsToken(resp.Header, "Connection", "Upgrade") {
return nil, fmt.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, fmt.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(r.Header.Get("Sec-WebSocket-Key")) {
return nil, fmt.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"),
r.Header.Get("Sec-WebSocket-Key"),
)
}
if proto := resp.Header.Get("Sec-WebSocket-Protocol"); proto != "" && !headerContainsToken(r.Header, "Sec-WebSocket-Protocol", proto) {
return nil, fmt.Errorf("websocket protocol violation: unexpected Sec-WebSocket-Protocol from server: %q", proto)
return nil, fmt.Errorf("WebSocket protocol violation: unexpected Sec-WebSocket-Protocol from server: %q", proto)
}
copts, err := verifyServerExtensions(resp.Header)
......
......@@ -93,7 +93,7 @@ func echoServer(w http.ResponseWriter, r *http.Request) error {
}
}
// echo reads from the websocket connection and then writes
// echo reads from the WebSocket connection and then writes
// the received message back to it.
// The entire function has 10s to complete.
func echo(ctx context.Context, c *websocket.Conn, l *rate.Limiter) error {
......
......@@ -102,7 +102,7 @@ type MessageEvent struct {
// See https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent
}
// OnMessage registers a function to be called when the websocket receives a message.
// OnMessage registers a function to be called when the WebSocket receives a message.
func (c WebSocket) OnMessage(fn func(m MessageEvent)) (remove func()) {
return c.addEventListener("message", func(e js.Value) {
var data interface{}
......@@ -128,7 +128,7 @@ func (c WebSocket) Subprotocol() string {
return c.v.Get("protocol").String()
}
// OnOpen registers a function to be called when the websocket is opened.
// OnOpen registers a function to be called when the WebSocket is opened.
func (c WebSocket) OnOpen(fn func(e js.Value)) (remove func()) {
return c.addEventListener("open", fn)
}
......
// Code generated by "stringer -type=opcode,MessageType,StatusCode -output=websocket_stringer.go"; DO NOT EDIT.
// Code generated by "stringer -type=opcode,MessageType,StatusCode -output=stringer.go"; DO NOT EDIT.
package websocket
......
......@@ -105,7 +105,7 @@ 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, errors.New("websocket connection read closed")
return 0, nil, errors.New("WebSocket connection read closed")
}
typ, p, err := c.read(ctx)
......@@ -188,14 +188,14 @@ func (c *Conn) write(ctx context.Context, typ MessageType, p []byte) error {
}
}
// Close closes the websocket with the given code and reason.
// Close closes the WebSocket with the given code and reason.
// It will wait until the peer responds with a close frame
// or the connection is closed.
// It thus performs the full WebSocket close handshake.
func (c *Conn) Close(code StatusCode, reason string) error {
err := c.exportedClose(code, reason)
if err != nil {
return fmt.Errorf("failed to close websocket: %w", err)
return fmt.Errorf("failed to close WebSocket: %w", err)
}
return nil
}
......@@ -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, resp, fmt.Errorf("failed to websocket dial %q: %w", url, err)
return nil, resp, fmt.Errorf("failed to WebSocket dial %q: %w", url, err)
}
return c, resp, nil
}
......@@ -359,7 +359,7 @@ func (c *Conn) SetReadLimit(n int64) {
func (c *Conn) setCloseErr(err error) {
c.closeErrOnce.Do(func() {
c.closeErr = fmt.Errorf("websocket closed: %w", err)
c.closeErr = fmt.Errorf("WebSocket closed: %w", err)
})
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment