Skip to content

Commit 1bc100d

Browse files
committed
Update docs and random little issues
1 parent d57b253 commit 1bc100d

File tree

11 files changed

+61
-57
lines changed

11 files changed

+61
-57
lines changed

.github/workflows/ci.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
1313
restore-keys: |
1414
${{ runner.os }}-go-
15-
- name: make fmt
15+
- name: Run make fmt
1616
uses: ./ci/image
1717
with:
1818
args: make fmt
@@ -27,7 +27,7 @@ jobs:
2727
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
2828
restore-keys: |
2929
${{ runner.os }}-go-
30-
- name: make lint
30+
- name: Run make lint
3131
uses: ./ci/image
3232
with:
3333
args: make lint
@@ -42,7 +42,7 @@ jobs:
4242
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
4343
restore-keys: |
4444
${{ runner.os }}-go-
45-
- name: make test
45+
- name: Run make test
4646
uses: ./ci/image
4747
with:
4848
args: make test

README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ go get nhooyr.io/websocket
1717

1818
- Minimal and idiomatic API
1919
- First class [context.Context](https://blog.golang.org/context) support
20-
- Thorough tests, fully passes the [autobahn-testsuite](https://github.com/crossbario/autobahn-testsuite)
21-
- [Zero dependencies](https://godoc.org/nhooyr.io/websocket?imports)
20+
- Thorough tests, fully passes the WebSocket [autobahn-testsuite](https://github.com/crossbario/autobahn-testsuite)
21+
- [Minimal dependencies](https://godoc.org/nhooyr.io/websocket?imports)
2222
- JSON and protobuf helpers in the [wsjson](https://godoc.org/nhooyr.io/websocket/wsjson) and [wspb](https://godoc.org/nhooyr.io/websocket/wspb) subpackages
2323
- Zero alloc reads and writes
2424
- Concurrent writes
@@ -34,7 +34,7 @@ go get nhooyr.io/websocket
3434

3535
## Examples
3636

37-
For a production quality example that demonstrates the full API, see the [echo example](https://godoc.org/nhooyr.io/websocket#example-package--Echo).
37+
For a production quality example that demonstrates the complete API, see the [echo example](https://godoc.org/nhooyr.io/websocket#example-package--Echo).
3838

3939
### Server
4040

@@ -111,6 +111,8 @@ Advantages of nhooyr.io/websocket:
111111
- Gorilla's implementation is slower and uses [unsafe](https://golang.org/pkg/unsafe/).
112112
- Full [permessage-deflate](https://tools.ietf.org/html/rfc7692) compression extension support
113113
- Gorilla only supports no context takeover mode
114+
- Uses [klauspost/compress](https://github.com/klauspost/compress) for optimized compression
115+
- See [gorilla/websocket#203](https://github.com/gorilla/websocket/issues/203)
114116
- [CloseRead](https://godoc.org/nhooyr.io/websocket#Conn.CloseRead) helper ([gorilla/websocket#492](https://github.com/gorilla/websocket/issues/492))
115117
- Actively maintained ([gorilla/websocket#370](https://github.com/gorilla/websocket/issues/370))
116118

accept.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,17 @@ type AcceptOptions struct {
3737
// If used incorrectly your WebSocket server will be open to CSRF attacks.
3838
InsecureSkipVerify bool
3939

40-
// CompressionOptions controls the compression options.
41-
// See docs on the CompressionOptions type.
42-
CompressionOptions *CompressionOptions
40+
// CompressionMode controls the compression mode.
41+
// Defaults to CompressionNoContextTakeover.
42+
//
43+
// See docs on CompressionMode for details.
44+
CompressionMode CompressionMode
45+
46+
// CompressionThreshold controls the minimum size of a message before compression is applied.
47+
//
48+
// Defaults to 512 bytes for CompressionNoContextTakeover and 128 bytes
49+
// for CompressionContextTakeover.
50+
CompressionThreshold int
4351
}
4452

4553
// Accept accepts a WebSocket handshake from a client and upgrades the
@@ -61,10 +69,6 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (_ *Con
6169
}
6270
opts = &*opts
6371

64-
if opts.CompressionOptions == nil {
65-
opts.CompressionOptions = &CompressionOptions{}
66-
}
67-
6872
errCode, err := verifyClientRequest(w, r)
6973
if err != nil {
7074
http.Error(w, err.Error(), errCode)
@@ -97,7 +101,7 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (_ *Con
97101
w.Header().Set("Sec-WebSocket-Protocol", subproto)
98102
}
99103

100-
copts, err := acceptCompression(r, w, opts.CompressionOptions.Mode)
104+
copts, err := acceptCompression(r, w, opts.CompressionMode)
101105
if err != nil {
102106
return nil, err
103107
}
@@ -120,7 +124,7 @@ func accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (_ *Con
120124
rwc: netConn,
121125
client: false,
122126
copts: copts,
123-
flateThreshold: opts.CompressionOptions.Threshold,
127+
flateThreshold: opts.CompressionThreshold,
124128

125129
br: brw.Reader,
126130
bw: brw.Writer,

accept_js.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import (
88

99
// AcceptOptions represents Accept's options.
1010
type AcceptOptions struct {
11-
Subprotocols []string
12-
InsecureSkipVerify bool
13-
CompressionOptions *CompressionOptions
11+
Subprotocols []string
12+
InsecureSkipVerify bool
13+
CompressionMode CompressionMode
14+
CompressionThreshold int
1415
}
1516

1617
// Accept is stubbed out for Wasm.

close_notjs.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func (c *Conn) closeHandshake(code StatusCode, reason string) (err error) {
3535
defer errd.Wrap(&err, "failed to close WebSocket")
3636

3737
err = c.writeClose(code, reason)
38-
if err != nil && CloseStatus(err) == -1 {
38+
if err != nil && CloseStatus(err) == -1 && err != errAlreadyWroteClose {
3939
return err
4040
}
4141

@@ -46,13 +46,15 @@ func (c *Conn) closeHandshake(code StatusCode, reason string) (err error) {
4646
return nil
4747
}
4848

49+
var errAlreadyWroteClose = xerrors.New("already wrote close")
50+
4951
func (c *Conn) writeClose(code StatusCode, reason string) error {
5052
c.closeMu.Lock()
5153
closing := c.wroteClose
5254
c.wroteClose = true
5355
c.closeMu.Unlock()
5456
if closing {
55-
return xerrors.New("already wrote close")
57+
return errAlreadyWroteClose
5658
}
5759

5860
ce := CloseError{

compress.go

+1-16
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,5 @@
11
package websocket
22

3-
// CompressionOptions represents the available deflate extension options.
4-
// See https://tools.ietf.org/html/rfc7692
5-
type CompressionOptions struct {
6-
// Mode controls the compression mode.
7-
//
8-
// See docs on CompressionMode.
9-
Mode CompressionMode
10-
11-
// Threshold controls the minimum size of a message before compression is applied.
12-
//
13-
// Defaults to 512 bytes for CompressionNoContextTakeover and 256 bytes
14-
// for CompressionContextTakeover.
15-
Threshold int
16-
}
17-
183
// CompressionMode represents the modes available to the deflate extension.
194
// See https://tools.ietf.org/html/rfc7692
205
//
@@ -38,7 +23,7 @@ const (
3823
// CompressionContextTakeover uses a flate.Reader and flate.Writer per connection.
3924
// This enables reusing the sliding window from previous messages.
4025
// As most WebSocket protocols are repetitive, this can be very efficient.
41-
// It carries an overhead of 64 kB for every connection compared to CompressionNoContextTakeover.
26+
// It carries an overhead of 8 kB for every connection compared to CompressionNoContextTakeover.
4227
//
4328
// If the peer negotiates NoContextTakeover on the client or server side, it will be
4429
// used instead as this is required by the RFC.

conn_notjs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func newConn(cfg connConfig) *Conn {
101101
}
102102

103103
if c.flate() && c.flateThreshold == 0 {
104-
c.flateThreshold = 256
104+
c.flateThreshold = 128
105105
if !c.msgWriterState.flateContextTakeover() {
106106
c.flateThreshold = 512
107107
}

conn_test.go

+8-9
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,18 @@ func TestConn(t *testing.T) {
3636
t.Run("fuzzData", func(t *testing.T) {
3737
t.Parallel()
3838

39-
copts := func() *websocket.CompressionOptions {
40-
return &websocket.CompressionOptions{
41-
Mode: websocket.CompressionMode(xrand.Int(int(websocket.CompressionDisabled) + 1)),
42-
Threshold: xrand.Int(9999),
43-
}
39+
compressionMode := func() websocket.CompressionMode {
40+
return websocket.CompressionMode(xrand.Int(int(websocket.CompressionDisabled) + 1))
4441
}
4542

4643
for i := 0; i < 5; i++ {
4744
t.Run("", func(t *testing.T) {
4845
tt, c1, c2 := newConnTest(t, &websocket.DialOptions{
49-
CompressionOptions: copts(),
46+
CompressionMode: compressionMode(),
47+
CompressionThreshold: xrand.Int(9999),
5048
}, &websocket.AcceptOptions{
51-
CompressionOptions: copts(),
49+
CompressionMode: compressionMode(),
50+
CompressionThreshold: xrand.Int(9999),
5251
})
5352
defer tt.cleanup()
5453

@@ -394,9 +393,9 @@ func BenchmarkConn(b *testing.B) {
394393
for _, bc := range benchCases {
395394
b.Run(bc.name, func(b *testing.B) {
396395
bb, c1, c2 := newConnTest(b, &websocket.DialOptions{
397-
CompressionOptions: &websocket.CompressionOptions{Mode: bc.mode},
396+
CompressionMode: bc.mode,
398397
}, &websocket.AcceptOptions{
399-
CompressionOptions: &websocket.CompressionOptions{Mode: bc.mode},
398+
CompressionMode: bc.mode,
400399
})
401400
defer bb.cleanup()
402401

dial.go

+14-9
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,17 @@ type DialOptions struct {
3333
// Subprotocols lists the WebSocket subprotocols to negotiate with the server.
3434
Subprotocols []string
3535

36-
// CompressionOptions controls the compression options.
37-
// See docs on the CompressionOptions type.
38-
CompressionOptions *CompressionOptions
36+
// CompressionMode controls the compression mode.
37+
// Defaults to CompressionNoContextTakeover.
38+
//
39+
// See docs on CompressionMode for details.
40+
CompressionMode CompressionMode
41+
42+
// CompressionThreshold controls the minimum size of a message before compression is applied.
43+
//
44+
// Defaults to 512 bytes for CompressionNoContextTakeover and 128 bytes
45+
// for CompressionContextTakeover.
46+
CompressionThreshold int
3947
}
4048

4149
// Dial performs a WebSocket handshake on url.
@@ -67,9 +75,6 @@ func dial(ctx context.Context, urls string, opts *DialOptions, rand io.Reader) (
6775
if opts.HTTPHeader == nil {
6876
opts.HTTPHeader = http.Header{}
6977
}
70-
if opts.CompressionOptions == nil {
71-
opts.CompressionOptions = &CompressionOptions{}
72-
}
7378

7479
secWebSocketKey, err := secWebSocketKey(rand)
7580
if err != nil {
@@ -107,7 +112,7 @@ func dial(ctx context.Context, urls string, opts *DialOptions, rand io.Reader) (
107112
rwc: rwc,
108113
client: true,
109114
copts: copts,
110-
flateThreshold: opts.CompressionOptions.Threshold,
115+
flateThreshold: opts.CompressionThreshold,
111116
br: getBufioReader(rwc),
112117
bw: getBufioWriter(rwc),
113118
}), resp, nil
@@ -141,8 +146,8 @@ func handshakeRequest(ctx context.Context, urls string, opts *DialOptions, secWe
141146
if len(opts.Subprotocols) > 0 {
142147
req.Header.Set("Sec-WebSocket-Protocol", strings.Join(opts.Subprotocols, ","))
143148
}
144-
if opts.CompressionOptions.Mode != CompressionDisabled {
145-
copts := opts.CompressionOptions.Mode.opts()
149+
if opts.CompressionMode != CompressionDisabled {
150+
copts := opts.CompressionMode.opts()
146151
copts.setHeader(req.Header)
147152
}
148153

doc.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77
// Use Dial to dial a WebSocket server.
88
//
9-
// Accept to accept a WebSocket client.
9+
// Use Accept to accept a WebSocket client.
1010
//
1111
// Conn represents the resulting WebSocket connection.
1212
//
@@ -25,7 +25,8 @@
2525
//
2626
// Some important caveats to be aware of:
2727
//
28+
// - Accept always errors out
2829
// - Conn.Ping is no-op
2930
// - HTTPClient, HTTPHeader and CompressionMode in DialOptions are no-op
30-
// - *http.Response from Dial is &http.Response{} on success
31+
// - *http.Response from Dial is &http.Response{} with a 101 status code on success
3132
package websocket // import "nhooyr.io/websocket"

ws_js.go

+5
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ func (c *Conn) read(ctx context.Context) (MessageType, []byte, error) {
152152
}
153153
}
154154

155+
// Ping is mocked out for Wasm.
156+
func (c *Conn) Ping(ctx context.Context) error {
157+
return nil
158+
}
159+
155160
// Write writes a message of the given type to the connection.
156161
// Always non blocking.
157162
func (c *Conn) Write(ctx context.Context, typ MessageType, p []byte) error {

0 commit comments

Comments
 (0)