New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rfc7692 context-takeover implemention #342

Open
wants to merge 69 commits into
base: master
from
Open
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
8a8329b
modify: header option
smith-30 Jan 17, 2018
053a620
add: validation
smith-30 Jan 18, 2018
785fa70
add server header option
smith-30 Jan 21, 2018
9177fe8
mod: comment out
smith-30 Jan 21, 2018
a2b4877
Merge branch 'feature/add_extension_header' into feature/impl_decompr…
smith-30 Jan 21, 2018
e0da4e3
mod: .gitignore
smith-30 Jan 21, 2018
36c4397
impl: decompressContextTakeover
smith-30 Jan 24, 2018
a366cdf
impl: compressContextTakeover
smith-30 Jan 24, 2018
f7abc95
mod: method args name
smith-30 Jan 24, 2018
8ddcb40
Merge pull request #4 from smith-30/feature/impl_compressContextTakeover
smith-30 Jan 24, 2018
eec63bf
mod: split dict to rx and tx
smith-30 Jan 24, 2018
ad97036
Merge pull request #6 from smith-30/feature/split_dict
smith-30 Jan 24, 2018
dfe35b7
add: context-takeover option to client
smith-30 Jan 24, 2018
538a96d
Merge pull request #7 from smith-30/feature/client_context_takeover
smith-30 Jan 24, 2018
cecdf7c
mod: remove mutex.
smith-30 Jan 24, 2018
bf99740
Merge pull request #8 from smith-30/feature/remove_dict_lock
smith-30 Jan 24, 2018
80a8097
mod: add dict process
smith-30 Jan 25, 2018
67b9939
Merge pull request #10 from smith-30/feature/mod_add_dict
smith-30 Jan 25, 2018
70abf72
mod: .gitignore to ignore .test file
smith-30 Jan 25, 2018
e873eb1
mod: test and write compression
smith-30 Jan 26, 2018
d0e8769
Merge pull request #11 from smith-30/feature/add_test
smith-30 Jan 26, 2018
e2dd00d
mod: dict strategy
smith-30 Jan 29, 2018
a9475f2
mod: remove judge dict nil
smith-30 Jan 29, 2018
f2a68e2
add: call compress method test
smith-30 Jan 30, 2018
2472e6d
upgrade: use pool for writerdict
smith-30 Jan 30, 2018
b2e3d3e
Merge pull request #12 from smith-30/feature/upgrade_writer
smith-30 Jan 30, 2018
fededdd
mod: detach compressContextTakeover method and add debug comment.
smith-30 Jan 31, 2018
62df16a
mod: compressContextTakeover method.
smith-30 Jan 31, 2018
ee46f85
add: comment
smith-30 Jan 31, 2018
fb7d67a
mod: fmt variables of conn.go
smith-30 Feb 1, 2018
f8b4a0f
mod: flate.writer for context-takeover
smith-30 Feb 1, 2018
b822eaa
Merge pull request #13 from smith-30/feature/upgrade_writer
smith-30 Feb 1, 2018
3452ab8
mod: client & server setting for context-takeover
smith-30 Feb 1, 2018
ee5a233
Merge pull request #14 from smith-30/feature/upgrade_writer
smith-30 Feb 1, 2018
b9e2343
mod: set compressionLevel to conn, if EnabeleCompression
smith-30 Feb 1, 2018
aca4275
Merge branch 'feature/upgrade_writer' into feature/context-takeover
smith-30 Feb 1, 2018
e7575e2
upgrade: compressContextTakeover reader
smith-30 Feb 1, 2018
83a1338
mod: NextReader if compress
smith-30 Feb 1, 2018
7c6832c
mod: NextWriter if compress
smith-30 Feb 1, 2018
8e146c3
mod: remove unnecessary field
smith-30 Feb 1, 2018
c830889
upgrade: TestFraming
smith-30 Feb 2, 2018
e79bb70
upgrade: add context-takeover test to client_server_test
smith-30 Feb 2, 2018
4131adc
upgrade: remove readBench, it read blank data
smith-30 Feb 2, 2018
1bf0779
Merge branch 'master' into feature/context-takeover
smith-30 Feb 2, 2018
df2a0cc
mod: comment
smith-30 Feb 7, 2018
6282a7b
mod: doc.go
smith-30 Feb 7, 2018
e9a52af
mod: unnecessary format change
smith-30 Feb 9, 2018
f68770a
mod: unnecessary format change
smith-30 Feb 9, 2018
7fa60f8
mod: gitignore
smith-30 Mar 5, 2018
7ce5144
Merge branch 'master' of github.com:gorilla/websocket into upstream
smith-30 Mar 5, 2018
5241e53
Use latest patch releases of Go
AlekSi Feb 15, 2018
d0111e6
Simplify echo example client (#349)
Feb 19, 2018
3ab5e92
Travis config: add Go 1.10.x, revert 1.4.x to 1.4
garyburd Feb 19, 2018
c13439f
Modify http status code to variable
KimMachineGun Feb 26, 2018
416a1d5
add newline and remove extra space
carterjones Mar 4, 2018
af46d4f
mod: modification of review
smith-30 Mar 5, 2018
1727e34
resolve: conflict
smith-30 Mar 5, 2018
360a199
mod: doc.go
smith-30 Mar 5, 2018
658a2fb
temp: autobahn/server.go
smith-30 Apr 1, 2018
811803b
add: comment
smith-30 Apr 6, 2018
6caf089
mod: examples/autobahn/server.go to pass build go 1.4, 1.5
smith-30 Apr 6, 2018
cd973fd
mod: pointed out part
smith-30 Apr 20, 2018
b27407e
mod: no need to change line feed
smith-30 Apr 20, 2018
e82d2a9
mod: fmt
smith-30 Apr 23, 2018
6f489db
merge: v1.4.0
smith-30 Sep 11, 2018
89ee8d4
mod: test
smith-30 Sep 11, 2018
a8d45c1
merge: master
smith-30 Feb 2, 2019
62bb07b
add: comment
smith-30 Feb 3, 2019
985aed2
mod: doc
smith-30 Feb 3, 2019
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+328 −55
Diff settings

Always

Just for now

Copy path View file
@@ -6,6 +6,7 @@ package websocket

import (
"bytes"
"compress/flate"
"context"
"crypto/tls"
"errors"
@@ -89,16 +90,19 @@ type Dialer struct {
// Subprotocols specifies the client's requested subprotocols.
Subprotocols []string

// EnableCompression specifies if the client should attempt to negotiate
// per message compression (RFC 7692). Setting this value to true does not
// guarantee that compression will be supported. Currently only "no context
// takeover" modes are supported.
// EnableCompression specify if the server should attempt to negotiate per
// message compression (RFC 7692).
EnableCompression bool

// Jar specifies the cookie jar.
// If Jar is nil, cookies are not sent in requests and ignored
// in responses.
Jar http.CookieJar

// AllowClientContextTakeover specifies whether the server will negotiate client context
// takeover for per message compression. Context takeover improves compression at the
// the cost of using more memory.
AllowClientContextTakeover bool
}

// Dial creates a new client connection by calling DialContext with a background context.
@@ -224,8 +228,11 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
}
}

if d.EnableCompression {
req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"}
switch {
case d.EnableCompression && d.AllowClientContextTakeover:
req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_max_window_bits=15; client_max_window_bits=15")
case d.EnableCompression:
req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
}

if d.HandshakeTimeout != 0 {
@@ -364,13 +371,24 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
if ext[""] != "permessage-deflate" {
continue
}
_, snct := ext["server_no_context_takeover"]
_, cnct := ext["client_no_context_takeover"]
if !snct || !cnct {
return nil, resp, errInvalidCompression

_, cmwb := ext["client_max_window_bits"]
_, smwb := ext["server_max_window_bits"]

switch {
case cmwb && smwb:
var wf contextTakeoverWriterFactory
conn.newCompressionWriter = wf.newCompressionWriter

var rf contextTakeoverReaderFactory
fr := flate.NewReader(nil)
rf.fr = fr
conn.newDecompressionReader = rf.newDeCompressionReader
default:
conn.newCompressionWriter = compressNoContextTakeover
conn.newDecompressionReader = decompressNoContextTakeover
}
conn.newCompressionWriter = compressNoContextTakeover
conn.newDecompressionReader = decompressNoContextTakeover

break
}

Copy path View file
@@ -44,7 +44,14 @@ var cstDialer = Dialer{
HandshakeTimeout: 30 * time.Second,
}

type cstHandler struct{ *testing.T }
type cstHandlerConfig struct {
contextTakeover bool
}

type cstHandler struct {
*testing.T
cstHandlerConfig
}

type cstServer struct {
*httptest.Server
@@ -58,17 +65,17 @@ const (
cstRequestURI = cstPath + "?" + cstRawQuery
)

func newServer(t *testing.T) *cstServer {
func newServer(t *testing.T, c cstHandlerConfig) *cstServer {
var s cstServer
s.Server = httptest.NewServer(cstHandler{t})
s.Server = httptest.NewServer(cstHandler{t, c})
s.Server.URL += cstRequestURI
s.URL = makeWsProto(s.Server.URL)
return &s
}

func newTLSServer(t *testing.T) *cstServer {
func newTLSServer(t *testing.T, c cstHandlerConfig) *cstServer {
var s cstServer
s.Server = httptest.NewTLSServer(cstHandler{t})
s.Server = httptest.NewTLSServer(cstHandler{t, c})
s.Server.URL += cstRequestURI
s.URL = makeWsProto(s.Server.URL)
return &s
@@ -91,6 +98,9 @@ func (t cstHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "bad protocol", http.StatusBadRequest)
return
}
if t.contextTakeover {
cstUpgrader.AllowServerContextTakeover = true
}
ws, err := cstUpgrader.Upgrade(w, r, http.Header{"Set-Cookie": {"sessionID=1234"}})
if err != nil {
t.Logf("Upgrade: %v", err)
@@ -121,6 +131,28 @@ func (t cstHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t.Logf("Close: %v", err)
return
}

// for multipleSendRecv when context takeover.
if t.contextTakeover {
op, rd, err := ws.NextReader()
if err != nil {
t.Logf("NextReader: %v", err)
return
}
wr, err := ws.NextWriter(op)
if err != nil {
t.Logf("NextWriter: %v", err)
return
}
if _, err = io.Copy(wr, rd); err != nil {
t.Logf("NextWriter: %v", err)
return
}
if err := wr.Close(); err != nil {
t.Logf("Close: %v", err)
return
}
}
}

func makeWsProto(s string) string {
@@ -147,9 +179,30 @@ func sendRecv(t *testing.T, ws *Conn) {
}
}

func multipleSendRecv(t *testing.T, ws *Conn) {
for _, message := range []string{"Hello World", "Can you read message?"} {
if err := ws.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
t.Fatalf("SetWriteDeadline: %v", err)
}
if err := ws.WriteMessage(TextMessage, []byte(message)); err != nil {
t.Fatalf("WriteMessage: %v", err)
}
if err := ws.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
t.Fatalf("SetReadDeadline: %v", err)
}
_, p, err := ws.ReadMessage()
if err != nil {
t.Fatalf("ReadMessage: %v", err)
}
if string(p) != message {
t.Fatalf("message=%s, want %s", p, message)
}
}
}

func TestProxyDial(t *testing.T) {

s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

surl, _ := url.Parse(s.Server.URL)
@@ -186,7 +239,7 @@ func TestProxyDial(t *testing.T) {
}

func TestProxyAuthorizationDial(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

surl, _ := url.Parse(s.Server.URL)
@@ -226,7 +279,7 @@ func TestProxyAuthorizationDial(t *testing.T) {
}

func TestDial(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

ws, _, err := cstDialer.Dial(s.URL, nil)
@@ -238,7 +291,7 @@ func TestDial(t *testing.T) {
}

func TestDialCookieJar(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

jar, _ := cookiejar.New(nil)
@@ -300,7 +353,7 @@ func rootCAs(t *testing.T, s *httptest.Server) *x509.CertPool {
}

func TestDialTLS(t *testing.T) {
s := newTLSServer(t)
s := newTLSServer(t, cstHandlerConfig{})
defer s.Close()

d := cstDialer
@@ -314,7 +367,7 @@ func TestDialTLS(t *testing.T) {
}

func TestDialTimeout(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

d := cstDialer
@@ -370,7 +423,7 @@ func (c *requireDeadlineNetConn) LocalAddr() net.Addr { return c.c.LocalAddr()
func (c *requireDeadlineNetConn) RemoteAddr() net.Addr { return c.c.RemoteAddr() }

func TestHandshakeTimeout(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

d := cstDialer
@@ -386,7 +439,7 @@ func TestHandshakeTimeout(t *testing.T) {
}

func TestHandshakeTimeoutInContext(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

d := cstDialer
@@ -407,7 +460,7 @@ func TestHandshakeTimeoutInContext(t *testing.T) {
}

func TestDialBadScheme(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

ws, _, err := cstDialer.Dial(s.Server.URL, nil)
@@ -418,7 +471,7 @@ func TestDialBadScheme(t *testing.T) {
}

func TestDialBadOrigin(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {"bad"}})
@@ -435,7 +488,7 @@ func TestDialBadOrigin(t *testing.T) {
}

func TestDialBadHeader(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

for _, k := range []string{"Upgrade",
@@ -482,7 +535,7 @@ func TestBadMethod(t *testing.T) {
}

func TestHandshake(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {s.URL}})
@@ -733,7 +786,7 @@ func TestHost(t *testing.T) {
}

func TestDialCompression(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

dialer := cstDialer
@@ -746,8 +799,24 @@ func TestDialCompression(t *testing.T) {
sendRecv(t, ws)
}

func TestDialCompressionOfContextTakeover(t *testing.T) {
s := newServer(t, cstHandlerConfig{true})
defer s.Close()

dialer := cstDialer
dialer.EnableCompression = true
dialer.AllowClientContextTakeover = true
ws, _, err := dialer.Dial(s.URL, nil)
if err != nil {
t.Fatalf("Dial: %v", err)
}
defer ws.Close()

multipleSendRecv(t, ws)
}

func TestSocksProxyDial(t *testing.T) {
s := newServer(t)
s := newServer(t, cstHandlerConfig{})
defer s.Close()

proxyListener, err := net.Listen("tcp", "127.0.0.1:0")
@@ -850,7 +919,7 @@ func TestTracingDialWithContext(t *testing.T) {
}
ctx := httptrace.WithClientTrace(context.Background(), trace)

s := newTLSServer(t)
s := newTLSServer(t, cstHandlerConfig{})
defer s.Close()

d := cstDialer
@@ -889,7 +958,7 @@ func TestEmptyTracingDialWithContext(t *testing.T) {
trace := &httptrace.ClientTrace{}
ctx := httptrace.WithClientTrace(context.Background(), trace)

s := newTLSServer(t)
s := newTLSServer(t, cstHandlerConfig{})
defer s.Close()

d := cstDialer
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.