forked from gorilla/websocket
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add hooks to support RFC 7692 (per-message compression extension)
Add newCompressionWriter and newDecompressionReader fields to Conn. When not nil, these functions are used to create a compression/decompression wrapper around an underlying message writer/reader. Add code to set and check for RSV1 frame header bit. Add functions compressNoContextTakeover and decompressNoContextTakeover for creating no context takeover wrappers around an underlying message writer/reader. Work remaining: - Add fields to Dialer and Upgrader for specifying compression options. - Add compression negotiation to Dialer and Upgrader. - Add function to enable/disable write compression: // EnableWriteCompression enables and disables write compression of // subsequent text and binary messages. This function is a noop if // compression was not negotiated with the peer. func (c *Conn) EnableWriteCompression(enable bool) { c.enableWriteCompression = enable }
- Loading branch information
Showing
3 changed files
with
191 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package websocket | ||
|
||
import ( | ||
"compress/flate" | ||
"errors" | ||
"io" | ||
"strings" | ||
) | ||
|
||
func decompressNoContextTakeover(r io.Reader) io.Reader { | ||
const tail = | ||
// Add four bytes as specified in RFC | ||
"\x00\x00\xff\xff" + | ||
// Add final block to squelch unexpected EOF error from flate reader. | ||
"\x01\x00\x00\xff\xff" | ||
|
||
return flate.NewReader(io.MultiReader(r, strings.NewReader(tail))) | ||
} | ||
|
||
func compressNoContextTakeover(w io.WriteCloser) (io.WriteCloser, error) { | ||
tw := &truncWriter{w: w} | ||
fw, err := flate.NewWriter(tw, 3) | ||
return &flateWrapper{fw: fw, tw: tw}, err | ||
} | ||
|
||
// truncWriter is an io.Writer that writes all but the last four bytes of the | ||
// stream to another io.Writer. | ||
type truncWriter struct { | ||
w io.WriteCloser | ||
n int | ||
p [4]byte | ||
} | ||
|
||
func (w *truncWriter) Write(p []byte) (int, error) { | ||
n := 0 | ||
|
||
// fill buffer first for simplicity. | ||
if w.n < len(w.p) { | ||
n = copy(w.p[w.n:], p) | ||
p = p[n:] | ||
w.n += n | ||
if len(p) == 0 { | ||
return n, nil | ||
} | ||
} | ||
|
||
m := len(p) | ||
if m > len(w.p) { | ||
m = len(w.p) | ||
} | ||
|
||
if nn, err := w.w.Write(w.p[:m]); err != nil { | ||
return n + nn, err | ||
} | ||
|
||
copy(w.p[:], w.p[m:]) | ||
copy(w.p[len(w.p)-m:], p[len(p)-m:]) | ||
nn, err := w.w.Write(p[:len(p)-m]) | ||
return n + nn, err | ||
} | ||
|
||
type flateWrapper struct { | ||
fw *flate.Writer | ||
tw *truncWriter | ||
} | ||
|
||
func (w *flateWrapper) Write(p []byte) (int, error) { | ||
return w.fw.Write(p) | ||
} | ||
|
||
func (w *flateWrapper) Close() error { | ||
err1 := w.fw.Flush() | ||
if w.tw.p != [4]byte{0, 0, 0xff, 0xff} { | ||
return errors.New("websocket: internal error, unexpected bytes at end of flate stream") | ||
} | ||
err2 := w.tw.w.Close() | ||
if err1 != nil { | ||
return err1 | ||
} | ||
return err2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package websocket | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"testing" | ||
) | ||
|
||
type nopCloser struct{ io.Writer } | ||
|
||
func (nopCloser) Close() error { return nil } | ||
|
||
func TestTruncWriter(t *testing.T) { | ||
const data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijlkmnopqrstuvwxyz987654321" | ||
for n := 1; n <= 10; n++ { | ||
var b bytes.Buffer | ||
w := &truncWriter{w: nopCloser{&b}} | ||
p := []byte(data) | ||
for len(p) > 0 { | ||
m := len(p) | ||
if m > n { | ||
m = n | ||
} | ||
w.Write(p[:m]) | ||
p = p[m:] | ||
} | ||
if b.String() != data[:len(data)-len(w.p)] { | ||
t.Errorf("%d: %q", n, b.String()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters