mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-11 21:12:07 +00:00
Update golang.org/x/net to fix godep reproducability problem
We are debugging why in #14677 but basically godep restore is ending up on master and no the commit specified in godeps. (reproducable with just go get, so don't blame godep right off) To unbreak things this updates golang.org/x/net while we continue to dig deeping into the core problem...
This commit is contained in:
parent
7b428d8bcd
commit
17d54f42fe
6
Godeps/Godeps.json
generated
6
Godeps/Godeps.json
generated
@ -578,15 +578,15 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/context",
|
||||
"Rev": "cbcac7bb8415db9b6cb4d1ebab1dc9afbd688b97"
|
||||
"Rev": "c2528b2dd8352441850638a8bb678c2ad056fd3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html",
|
||||
"Rev": "cbcac7bb8415db9b6cb4d1ebab1dc9afbd688b97"
|
||||
"Rev": "c2528b2dd8352441850638a8bb678c2ad056fd3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/websocket",
|
||||
"Rev": "cbcac7bb8415db9b6cb4d1ebab1dc9afbd688b97"
|
||||
"Rev": "c2528b2dd8352441850638a8bb678c2ad056fd3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/oauth2",
|
||||
|
67
Godeps/_workspace/src/golang.org/x/net/context/context.go
generated
vendored
67
Godeps/_workspace/src/golang.org/x/net/context/context.go
generated
vendored
@ -64,18 +64,21 @@ type Context interface {
|
||||
//
|
||||
// Done is provided for use in select statements:
|
||||
//
|
||||
// // DoSomething calls DoSomethingSlow and returns as soon as
|
||||
// // it returns or ctx.Done is closed.
|
||||
// func DoSomething(ctx context.Context) (Result, error) {
|
||||
// c := make(chan Result, 1)
|
||||
// go func() { c <- DoSomethingSlow(ctx) }()
|
||||
// select {
|
||||
// case res := <-c:
|
||||
// return res, nil
|
||||
// case <-ctx.Done():
|
||||
// return nil, ctx.Err()
|
||||
// }
|
||||
// }
|
||||
// // Stream generates values with DoSomething and sends them to out
|
||||
// // until DoSomething returns an error or ctx.Done is closed.
|
||||
// func Stream(ctx context.Context, out <-chan Value) error {
|
||||
// for {
|
||||
// v, err := DoSomething(ctx)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return ctx.Err()
|
||||
// case out <- v:
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// See http://blog.golang.org/pipelines for more examples of how to use
|
||||
// a Done channel for cancelation.
|
||||
@ -202,6 +205,9 @@ type CancelFunc func()
|
||||
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||
// context's Done channel is closed when the returned cancel function is called
|
||||
// or when the parent context's Done channel is closed, whichever happens first.
|
||||
//
|
||||
// Canceling this context releases resources associated with it, so code should
|
||||
// call cancel as soon as the operations running in this Context complete.
|
||||
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||
c := newCancelCtx(parent)
|
||||
propagateCancel(parent, &c)
|
||||
@ -262,6 +268,19 @@ func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// removeChild removes a context from its parent.
|
||||
func removeChild(parent Context, child canceler) {
|
||||
p, ok := parentCancelCtx(parent)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
p.mu.Lock()
|
||||
if p.children != nil {
|
||||
delete(p.children, child)
|
||||
}
|
||||
p.mu.Unlock()
|
||||
}
|
||||
|
||||
// A canceler is a context type that can be canceled directly. The
|
||||
// implementations are *cancelCtx and *timerCtx.
|
||||
type canceler interface {
|
||||
@ -316,13 +335,7 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||
c.mu.Unlock()
|
||||
|
||||
if removeFromParent {
|
||||
if p, ok := parentCancelCtx(c.Context); ok {
|
||||
p.mu.Lock()
|
||||
if p.children != nil {
|
||||
delete(p.children, c)
|
||||
}
|
||||
p.mu.Unlock()
|
||||
}
|
||||
removeChild(c.Context, c)
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,9 +346,8 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||
// cancel function is called, or when the parent context's Done channel is
|
||||
// closed, whichever happens first.
|
||||
//
|
||||
// Canceling this context releases resources associated with the deadline
|
||||
// timer, so code should call cancel as soon as the operations running in this
|
||||
// Context complete.
|
||||
// Canceling this context releases resources associated with it, so code should
|
||||
// call cancel as soon as the operations running in this Context complete.
|
||||
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||
if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
|
||||
// The current deadline is already sooner than the new one.
|
||||
@ -380,7 +392,11 @@ func (c *timerCtx) String() string {
|
||||
}
|
||||
|
||||
func (c *timerCtx) cancel(removeFromParent bool, err error) {
|
||||
c.cancelCtx.cancel(removeFromParent, err)
|
||||
c.cancelCtx.cancel(false, err)
|
||||
if removeFromParent {
|
||||
// Remove this timerCtx from its parent cancelCtx's children.
|
||||
removeChild(c.cancelCtx.Context, c)
|
||||
}
|
||||
c.mu.Lock()
|
||||
if c.timer != nil {
|
||||
c.timer.Stop()
|
||||
@ -391,9 +407,8 @@ func (c *timerCtx) cancel(removeFromParent bool, err error) {
|
||||
|
||||
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
|
||||
//
|
||||
// Canceling this context releases resources associated with the deadline
|
||||
// timer, so code should call cancel as soon as the operations running in this
|
||||
// Context complete:
|
||||
// Canceling this context releases resources associated with it, so code should
|
||||
// call cancel as soon as the operations running in this Context complete:
|
||||
//
|
||||
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
|
||||
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||
|
24
Godeps/_workspace/src/golang.org/x/net/context/context_test.go
generated
vendored
24
Godeps/_workspace/src/golang.org/x/net/context/context_test.go
generated
vendored
@ -375,7 +375,7 @@ func TestAllocs(t *testing.T) {
|
||||
<-c.Done()
|
||||
},
|
||||
limit: 8,
|
||||
gccgoLimit: 13,
|
||||
gccgoLimit: 15,
|
||||
},
|
||||
{
|
||||
desc: "WithCancel(bg)",
|
||||
@ -551,3 +551,25 @@ func testLayers(t *testing.T, seed int64, testTimeout bool) {
|
||||
checkValues("after cancel")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelRemoves(t *testing.T) {
|
||||
checkChildren := func(when string, ctx Context, want int) {
|
||||
if got := len(ctx.(*cancelCtx).children); got != want {
|
||||
t.Errorf("%s: context has %d children, want %d", when, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, _ := WithCancel(Background())
|
||||
checkChildren("after creation", ctx, 0)
|
||||
_, cancel := WithCancel(ctx)
|
||||
checkChildren("with WithCancel child ", ctx, 1)
|
||||
cancel()
|
||||
checkChildren("after cancelling WithCancel child", ctx, 0)
|
||||
|
||||
ctx, _ = WithCancel(Background())
|
||||
checkChildren("after creation", ctx, 0)
|
||||
_, cancel = WithTimeout(ctx, 60*time.Minute)
|
||||
checkChildren("with WithTimeout child ", ctx, 1)
|
||||
cancel()
|
||||
checkChildren("after cancelling WithTimeout child", ctx, 0)
|
||||
}
|
||||
|
18
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq.go
generated
vendored
Normal file
18
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.5
|
||||
|
||||
package ctxhttp
|
||||
|
||||
import "net/http"
|
||||
|
||||
func canceler(client *http.Client, req *http.Request) func() {
|
||||
ch := make(chan struct{})
|
||||
req.Cancel = ch
|
||||
|
||||
return func() {
|
||||
close(ch)
|
||||
}
|
||||
}
|
23
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
generated
vendored
Normal file
23
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.5
|
||||
|
||||
package ctxhttp
|
||||
|
||||
import "net/http"
|
||||
|
||||
type requestCanceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
|
||||
func canceler(client *http.Client, req *http.Request) func() {
|
||||
rc, ok := client.Transport.(requestCanceler)
|
||||
if !ok {
|
||||
return func() {}
|
||||
}
|
||||
return func() {
|
||||
rc.CancelRequest(req)
|
||||
}
|
||||
}
|
79
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
79
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2015 The Go 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 ctxhttp provides helper functions for performing context-aware HTTP requests.
|
||||
package ctxhttp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
|
||||
// If the client is nil, http.DefaultClient is used.
|
||||
// If the context is canceled or times out, ctx.Err() will be returned.
|
||||
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
|
||||
// Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go.
|
||||
cancel := canceler(client, req)
|
||||
|
||||
type responseAndError struct {
|
||||
resp *http.Response
|
||||
err error
|
||||
}
|
||||
result := make(chan responseAndError, 1)
|
||||
|
||||
go func() {
|
||||
resp, err := client.Do(req)
|
||||
result <- responseAndError{resp, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
cancel()
|
||||
return nil, ctx.Err()
|
||||
case r := <-result:
|
||||
return r.resp, r.err
|
||||
}
|
||||
}
|
||||
|
||||
// Get issues a GET request via the Do function.
|
||||
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// Head issues a HEAD request via the Do function.
|
||||
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("HEAD", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// Post issues a POST request via the Do function.
|
||||
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", bodyType)
|
||||
return Do(ctx, client, req)
|
||||
}
|
||||
|
||||
// PostForm issues a POST request via the Do function.
|
||||
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
||||
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||
}
|
72
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
generated
vendored
Normal file
72
Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2015 The Go 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 ctxhttp
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
requestDuration = 100 * time.Millisecond
|
||||
requestBody = "ok"
|
||||
)
|
||||
|
||||
func TestNoTimeout(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
resp, err := doRequest(ctx)
|
||||
|
||||
if resp == nil || err != nil {
|
||||
t.Fatalf("error received from client: %v %v", err, resp)
|
||||
}
|
||||
}
|
||||
func TestCancel(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
time.Sleep(requestDuration / 2)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
resp, err := doRequest(ctx)
|
||||
|
||||
if resp != nil || err == nil {
|
||||
t.Fatalf("expected error, didn't get one. resp: %v", resp)
|
||||
}
|
||||
if err != ctx.Err() {
|
||||
t.Fatalf("expected error from context but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAfterRequest(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
resp, err := doRequest(ctx)
|
||||
|
||||
// Cancel before reading the body.
|
||||
// Request.Body should still be readable after the context is canceled.
|
||||
cancel()
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil || string(b) != requestBody {
|
||||
t.Fatalf("could not read body: %q %v", b, err)
|
||||
}
|
||||
}
|
||||
|
||||
func doRequest(ctx context.Context) (*http.Response, error) {
|
||||
var okHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
time.Sleep(requestDuration)
|
||||
w.Write([]byte(requestBody))
|
||||
})
|
||||
|
||||
serv := httptest.NewServer(okHandler)
|
||||
defer serv.Close()
|
||||
|
||||
return Get(ctx, nil, serv.URL)
|
||||
}
|
20
Godeps/_workspace/src/golang.org/x/net/html/atom/gen.go
generated
vendored
20
Godeps/_workspace/src/golang.org/x/net/html/atom/gen.go
generated
vendored
@ -284,8 +284,8 @@ func (t *table) push(i uint32, depth int) bool {
|
||||
}
|
||||
|
||||
// The lists of element names and attribute keys were taken from
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/section-index.html
|
||||
// as of the "HTML Living Standard - Last Updated 30 May 2012" version.
|
||||
// https://html.spec.whatwg.org/multipage/indices.html#index
|
||||
// as of the "HTML Living Standard - Last Updated 21 February 2015" version.
|
||||
|
||||
var elements = []string{
|
||||
"a",
|
||||
@ -352,6 +352,7 @@ var elements = []string{
|
||||
"map",
|
||||
"mark",
|
||||
"menu",
|
||||
"menuitem",
|
||||
"meta",
|
||||
"meter",
|
||||
"nav",
|
||||
@ -385,6 +386,7 @@ var elements = []string{
|
||||
"table",
|
||||
"tbody",
|
||||
"td",
|
||||
"template",
|
||||
"textarea",
|
||||
"tfoot",
|
||||
"th",
|
||||
@ -400,7 +402,10 @@ var elements = []string{
|
||||
"wbr",
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/indices.html#attributes-3
|
||||
|
||||
var attributes = []string{
|
||||
"abbr",
|
||||
"accept",
|
||||
"accept-charset",
|
||||
"accesskey",
|
||||
@ -410,7 +415,6 @@ var attributes = []string{
|
||||
"autocomplete",
|
||||
"autofocus",
|
||||
"autoplay",
|
||||
"border",
|
||||
"challenge",
|
||||
"charset",
|
||||
"checked",
|
||||
@ -452,7 +456,7 @@ var attributes = []string{
|
||||
"http-equiv",
|
||||
"icon",
|
||||
"id",
|
||||
"inert",
|
||||
"inputmode",
|
||||
"ismap",
|
||||
"itemid",
|
||||
"itemprop",
|
||||
@ -473,6 +477,7 @@ var attributes = []string{
|
||||
"mediagroup",
|
||||
"method",
|
||||
"min",
|
||||
"minlength",
|
||||
"multiple",
|
||||
"muted",
|
||||
"name",
|
||||
@ -500,6 +505,8 @@ var attributes = []string{
|
||||
"shape",
|
||||
"size",
|
||||
"sizes",
|
||||
"sortable",
|
||||
"sorted",
|
||||
"span",
|
||||
"src",
|
||||
"srcdoc",
|
||||
@ -521,6 +528,8 @@ var attributes = []string{
|
||||
|
||||
var eventHandlers = []string{
|
||||
"onabort",
|
||||
"onautocomplete",
|
||||
"onautocompleteerror",
|
||||
"onafterprint",
|
||||
"onbeforeprint",
|
||||
"onbeforeunload",
|
||||
@ -552,6 +561,7 @@ var eventHandlers = []string{
|
||||
"onkeydown",
|
||||
"onkeypress",
|
||||
"onkeyup",
|
||||
"onlanguagechange",
|
||||
"onload",
|
||||
"onloadeddata",
|
||||
"onloadedmetadata",
|
||||
@ -580,11 +590,13 @@ var eventHandlers = []string{
|
||||
"onseeking",
|
||||
"onselect",
|
||||
"onshow",
|
||||
"onsort",
|
||||
"onstalled",
|
||||
"onstorage",
|
||||
"onsubmit",
|
||||
"onsuspend",
|
||||
"ontimeupdate",
|
||||
"ontoggle",
|
||||
"onunload",
|
||||
"onvolumechange",
|
||||
"onwaiting",
|
||||
|
1325
Godeps/_workspace/src/golang.org/x/net/html/atom/table.go
generated
vendored
1325
Godeps/_workspace/src/golang.org/x/net/html/atom/table.go
generated
vendored
File diff suppressed because it is too large
Load Diff
14
Godeps/_workspace/src/golang.org/x/net/html/atom/table_test.go
generated
vendored
14
Godeps/_workspace/src/golang.org/x/net/html/atom/table_test.go
generated
vendored
@ -5,6 +5,7 @@ package atom
|
||||
var testAtomList = []string{
|
||||
"a",
|
||||
"abbr",
|
||||
"abbr",
|
||||
"accept",
|
||||
"accept-charset",
|
||||
"accesskey",
|
||||
@ -33,7 +34,6 @@ var testAtomList = []string{
|
||||
"blink",
|
||||
"blockquote",
|
||||
"body",
|
||||
"border",
|
||||
"br",
|
||||
"button",
|
||||
"canvas",
|
||||
@ -125,8 +125,8 @@ var testAtomList = []string{
|
||||
"iframe",
|
||||
"image",
|
||||
"img",
|
||||
"inert",
|
||||
"input",
|
||||
"inputmode",
|
||||
"ins",
|
||||
"isindex",
|
||||
"ismap",
|
||||
@ -160,12 +160,14 @@ var testAtomList = []string{
|
||||
"media",
|
||||
"mediagroup",
|
||||
"menu",
|
||||
"menuitem",
|
||||
"meta",
|
||||
"meter",
|
||||
"method",
|
||||
"mglyph",
|
||||
"mi",
|
||||
"min",
|
||||
"minlength",
|
||||
"mn",
|
||||
"mo",
|
||||
"ms",
|
||||
@ -183,6 +185,8 @@ var testAtomList = []string{
|
||||
"ol",
|
||||
"onabort",
|
||||
"onafterprint",
|
||||
"onautocomplete",
|
||||
"onautocompleteerror",
|
||||
"onbeforeprint",
|
||||
"onbeforeunload",
|
||||
"onblur",
|
||||
@ -213,6 +217,7 @@ var testAtomList = []string{
|
||||
"onkeydown",
|
||||
"onkeypress",
|
||||
"onkeyup",
|
||||
"onlanguagechange",
|
||||
"onload",
|
||||
"onloadeddata",
|
||||
"onloadedmetadata",
|
||||
@ -241,11 +246,13 @@ var testAtomList = []string{
|
||||
"onseeking",
|
||||
"onselect",
|
||||
"onshow",
|
||||
"onsort",
|
||||
"onstalled",
|
||||
"onstorage",
|
||||
"onsubmit",
|
||||
"onsuspend",
|
||||
"ontimeupdate",
|
||||
"ontoggle",
|
||||
"onunload",
|
||||
"onvolumechange",
|
||||
"onwaiting",
|
||||
@ -291,6 +298,8 @@ var testAtomList = []string{
|
||||
"size",
|
||||
"sizes",
|
||||
"small",
|
||||
"sortable",
|
||||
"sorted",
|
||||
"source",
|
||||
"spacer",
|
||||
"span",
|
||||
@ -315,6 +324,7 @@ var testAtomList = []string{
|
||||
"target",
|
||||
"tbody",
|
||||
"td",
|
||||
"template",
|
||||
"textarea",
|
||||
"tfoot",
|
||||
"th",
|
||||
|
15
Godeps/_workspace/src/golang.org/x/net/html/charset/charset.go
generated
vendored
15
Godeps/_workspace/src/golang.org/x/net/html/charset/charset.go
generated
vendored
@ -5,11 +5,12 @@
|
||||
// Package charset provides common text encodings for HTML documents.
|
||||
//
|
||||
// The mapping from encoding labels to encodings is defined at
|
||||
// http://encoding.spec.whatwg.org.
|
||||
// https://encoding.spec.whatwg.org/.
|
||||
package charset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"strings"
|
||||
@ -110,6 +111,18 @@ func NewReader(r io.Reader, contentType string) (io.Reader, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// NewReaderLabel returns a reader that converts from the specified charset to
|
||||
// UTF-8. It uses Lookup to find the encoding that corresponds to label, and
|
||||
// returns an error if Lookup returns nil. It is suitable for use as
|
||||
// encoding/xml.Decoder's CharsetReader function.
|
||||
func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
|
||||
e, _ := Lookup(label)
|
||||
if e == nil {
|
||||
return nil, fmt.Errorf("unsupported charset: %q", label)
|
||||
}
|
||||
return transform.NewReader(input, e.NewDecoder()), nil
|
||||
}
|
||||
|
||||
func prescan(content []byte) (e encoding.Encoding, name string) {
|
||||
z := html.NewTokenizer(bytes.NewReader(content))
|
||||
for {
|
||||
|
21
Godeps/_workspace/src/golang.org/x/net/html/charset/charset_test.go
generated
vendored
21
Godeps/_workspace/src/golang.org/x/net/html/charset/charset_test.go
generated
vendored
@ -6,6 +6,7 @@ package charset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strings"
|
||||
@ -213,3 +214,23 @@ func TestFromMeta(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestXML(t *testing.T) {
|
||||
const s = "<?xml version=\"1.0\" encoding=\"windows-1252\"?><a><Word>r\xe9sum\xe9</Word></a>"
|
||||
|
||||
d := xml.NewDecoder(strings.NewReader(s))
|
||||
d.CharsetReader = NewReaderLabel
|
||||
|
||||
var a struct {
|
||||
Word string
|
||||
}
|
||||
err := d.Decode(&a)
|
||||
if err != nil {
|
||||
t.Fatalf("Decode: %v", err)
|
||||
}
|
||||
|
||||
want := "résumé"
|
||||
if a.Word != want {
|
||||
t.Errorf("got %q, want %q", a.Word, want)
|
||||
}
|
||||
}
|
||||
|
4
Godeps/_workspace/src/golang.org/x/net/html/charset/gen.go
generated
vendored
4
Godeps/_workspace/src/golang.org/x/net/html/charset/gen.go
generated
vendored
@ -6,7 +6,7 @@
|
||||
|
||||
package main
|
||||
|
||||
// Download http://encoding.spec.whatwg.org/encodings.json and use it to
|
||||
// Download https://encoding.spec.whatwg.org/encodings.json and use it to
|
||||
// generate table.go.
|
||||
|
||||
import (
|
||||
@ -27,7 +27,7 @@ type group struct {
|
||||
Heading string
|
||||
}
|
||||
|
||||
const specURL = "http://encoding.spec.whatwg.org/encodings.json"
|
||||
const specURL = "https://encoding.spec.whatwg.org/encodings.json"
|
||||
|
||||
func main() {
|
||||
resp, err := http.Get(specURL)
|
||||
|
10
Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README
generated
vendored
10
Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README
generated
vendored
@ -1 +1,9 @@
|
||||
These test cases come from http://www.w3.org/International/tests/html5/the-input-byte-stream/results-basics
|
||||
These test cases come from
|
||||
http://www.w3.org/International/tests/repository/html5/the-input-byte-stream/results-basics
|
||||
|
||||
Distributed under both the W3C Test Suite License
|
||||
(http://www.w3.org/Consortium/Legal/2008/04-testsuite-license)
|
||||
and the W3C 3-clause BSD License
|
||||
(http://www.w3.org/Consortium/Legal/2008/03-bsd-license).
|
||||
To contribute to a W3C Test Suite, see the policies and contribution
|
||||
forms (http://www.w3.org/2004/10/27-testcases).
|
||||
|
6
Godeps/_workspace/src/golang.org/x/net/html/const.go
generated
vendored
6
Godeps/_workspace/src/golang.org/x/net/html/const.go
generated
vendored
@ -6,7 +6,7 @@ package html
|
||||
|
||||
// Section 12.2.3.2 of the HTML5 specification says "The following elements
|
||||
// have varying levels of special parsing rules".
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
|
||||
var isSpecialElementMap = map[string]bool{
|
||||
"address": true,
|
||||
"applet": true,
|
||||
@ -24,7 +24,6 @@ var isSpecialElementMap = map[string]bool{
|
||||
"center": true,
|
||||
"col": true,
|
||||
"colgroup": true,
|
||||
"command": true,
|
||||
"dd": true,
|
||||
"details": true,
|
||||
"dir": true,
|
||||
@ -73,17 +72,20 @@ var isSpecialElementMap = map[string]bool{
|
||||
"script": true,
|
||||
"section": true,
|
||||
"select": true,
|
||||
"source": true,
|
||||
"style": true,
|
||||
"summary": true,
|
||||
"table": true,
|
||||
"tbody": true,
|
||||
"td": true,
|
||||
"template": true,
|
||||
"textarea": true,
|
||||
"tfoot": true,
|
||||
"th": true,
|
||||
"thead": true,
|
||||
"title": true,
|
||||
"tr": true,
|
||||
"track": true,
|
||||
"ul": true,
|
||||
"wbr": true,
|
||||
"xmp": true,
|
||||
|
4
Godeps/_workspace/src/golang.org/x/net/html/doc.go
generated
vendored
4
Godeps/_workspace/src/golang.org/x/net/html/doc.go
generated
vendored
@ -90,8 +90,8 @@ example, to process each anchor node in depth-first order:
|
||||
f(doc)
|
||||
|
||||
The relevant specifications include:
|
||||
http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html and
|
||||
http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
|
||||
https://html.spec.whatwg.org/multipage/syntax.html and
|
||||
https://html.spec.whatwg.org/multipage/syntax.html#tokenization
|
||||
*/
|
||||
package html
|
||||
|
||||
|
2
Godeps/_workspace/src/golang.org/x/net/html/entity.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/net/html/entity.go
generated
vendored
@ -8,7 +8,7 @@ package html
|
||||
const longestEntityWithoutSemicolon = 6
|
||||
|
||||
// entity is a map from HTML entity names to their values. The semicolon matters:
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references
|
||||
// lists both "amp" and "amp;" as two separate entries.
|
||||
//
|
||||
// Note that the HTML5 list is larger than the HTML4 list at
|
||||
|
4
Godeps/_workspace/src/golang.org/x/net/html/escape.go
generated
vendored
4
Godeps/_workspace/src/golang.org/x/net/html/escape.go
generated
vendored
@ -12,7 +12,7 @@ import (
|
||||
|
||||
// These replacements permit compatibility with old numeric entities that
|
||||
// assumed Windows-1252 encoding.
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
|
||||
var replacementTable = [...]rune{
|
||||
'\u20AC', // First entry is what 0x80 should be replaced with.
|
||||
'\u0081',
|
||||
@ -55,7 +55,7 @@ var replacementTable = [...]rune{
|
||||
// Precondition: b[src] == '&' && dst <= src.
|
||||
// attribute should be true if parsing an attribute value.
|
||||
func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
|
||||
|
||||
// i starts at 1 because we already know that s[0] == '&'.
|
||||
i, s := 1, b[src:]
|
||||
|
42
Godeps/_workspace/src/golang.org/x/net/html/parse.go
generated
vendored
42
Godeps/_workspace/src/golang.org/x/net/html/parse.go
generated
vendored
@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
// A parser implements the HTML5 parsing algorithm:
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#tree-construction
|
||||
type parser struct {
|
||||
// tokenizer provides the tokens for the parser.
|
||||
tokenizer *Tokenizer
|
||||
@ -59,7 +59,7 @@ func (p *parser) top() *Node {
|
||||
// Stop tags for use in popUntil. These come from section 12.2.3.2.
|
||||
var (
|
||||
defaultScopeStopTags = map[string][]a.Atom{
|
||||
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object},
|
||||
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
|
||||
"math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
|
||||
"svg": {a.Desc, a.ForeignObject, a.Title},
|
||||
}
|
||||
@ -1037,15 +1037,15 @@ func inBodyIM(p *parser) bool {
|
||||
|
||||
func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
||||
// This is the "adoption agency" algorithm, described at
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
|
||||
|
||||
// TODO: this is a fairly literal line-by-line translation of that algorithm.
|
||||
// Once the code successfully parses the comprehensive test suite, we should
|
||||
// refactor this code to be more idiomatic.
|
||||
|
||||
// Steps 1-3. The outer loop.
|
||||
// Steps 1-4. The outer loop.
|
||||
for i := 0; i < 8; i++ {
|
||||
// Step 4. Find the formatting element.
|
||||
// Step 5. Find the formatting element.
|
||||
var formattingElement *Node
|
||||
for j := len(p.afe) - 1; j >= 0; j-- {
|
||||
if p.afe[j].Type == scopeMarkerNode {
|
||||
@ -1070,7 +1070,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
||||
return
|
||||
}
|
||||
|
||||
// Steps 5-6. Find the furthest block.
|
||||
// Steps 9-10. Find the furthest block.
|
||||
var furthestBlock *Node
|
||||
for _, e := range p.oe[feIndex:] {
|
||||
if isSpecialElement(e) {
|
||||
@ -1087,47 +1087,47 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
||||
return
|
||||
}
|
||||
|
||||
// Steps 7-8. Find the common ancestor and bookmark node.
|
||||
// Steps 11-12. Find the common ancestor and bookmark node.
|
||||
commonAncestor := p.oe[feIndex-1]
|
||||
bookmark := p.afe.index(formattingElement)
|
||||
|
||||
// Step 9. The inner loop. Find the lastNode to reparent.
|
||||
// Step 13. The inner loop. Find the lastNode to reparent.
|
||||
lastNode := furthestBlock
|
||||
node := furthestBlock
|
||||
x := p.oe.index(node)
|
||||
// Steps 9.1-9.3.
|
||||
// Steps 13.1-13.2
|
||||
for j := 0; j < 3; j++ {
|
||||
// Step 9.4.
|
||||
// Step 13.3.
|
||||
x--
|
||||
node = p.oe[x]
|
||||
// Step 9.5.
|
||||
// Step 13.4 - 13.5.
|
||||
if p.afe.index(node) == -1 {
|
||||
p.oe.remove(node)
|
||||
continue
|
||||
}
|
||||
// Step 9.6.
|
||||
// Step 13.6.
|
||||
if node == formattingElement {
|
||||
break
|
||||
}
|
||||
// Step 9.7.
|
||||
// Step 13.7.
|
||||
clone := node.clone()
|
||||
p.afe[p.afe.index(node)] = clone
|
||||
p.oe[p.oe.index(node)] = clone
|
||||
node = clone
|
||||
// Step 9.8.
|
||||
// Step 13.8.
|
||||
if lastNode == furthestBlock {
|
||||
bookmark = p.afe.index(node) + 1
|
||||
}
|
||||
// Step 9.9.
|
||||
// Step 13.9.
|
||||
if lastNode.Parent != nil {
|
||||
lastNode.Parent.RemoveChild(lastNode)
|
||||
}
|
||||
node.AppendChild(lastNode)
|
||||
// Step 9.10.
|
||||
// Step 13.10.
|
||||
lastNode = node
|
||||
}
|
||||
|
||||
// Step 10. Reparent lastNode to the common ancestor,
|
||||
// Step 14. Reparent lastNode to the common ancestor,
|
||||
// or for misnested table nodes, to the foster parent.
|
||||
if lastNode.Parent != nil {
|
||||
lastNode.Parent.RemoveChild(lastNode)
|
||||
@ -1139,13 +1139,13 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
||||
commonAncestor.AppendChild(lastNode)
|
||||
}
|
||||
|
||||
// Steps 11-13. Reparent nodes from the furthest block's children
|
||||
// Steps 15-17. Reparent nodes from the furthest block's children
|
||||
// to a clone of the formatting element.
|
||||
clone := formattingElement.clone()
|
||||
reparentChildren(clone, furthestBlock)
|
||||
furthestBlock.AppendChild(clone)
|
||||
|
||||
// Step 14. Fix up the list of active formatting elements.
|
||||
// Step 18. Fix up the list of active formatting elements.
|
||||
if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
|
||||
// Move the bookmark with the rest of the list.
|
||||
bookmark--
|
||||
@ -1153,13 +1153,15 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
||||
p.afe.remove(formattingElement)
|
||||
p.afe.insert(bookmark, clone)
|
||||
|
||||
// Step 15. Fix up the stack of open elements.
|
||||
// Step 19. Fix up the stack of open elements.
|
||||
p.oe.remove(formattingElement)
|
||||
p.oe.insert(p.oe.index(furthestBlock)+1, clone)
|
||||
}
|
||||
}
|
||||
|
||||
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
|
||||
// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
|
||||
func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
|
||||
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||
if p.oe[i].DataAtom == tagAtom {
|
||||
|
2
Godeps/_workspace/src/golang.org/x/net/html/render.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/net/html/render.go
generated
vendored
@ -14,7 +14,7 @@ import (
|
||||
|
||||
type writer interface {
|
||||
io.Writer
|
||||
WriteByte(c byte) error // in Go 1.1, use io.ByteWriter
|
||||
io.ByteWriter
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
|
2
Godeps/_workspace/src/golang.org/x/net/html/token_test.go
generated
vendored
2
Godeps/_workspace/src/golang.org/x/net/html/token_test.go
generated
vendored
@ -392,7 +392,7 @@ var tokenTests = []tokenTest{
|
||||
"½",
|
||||
},
|
||||
// Attribute tests:
|
||||
// http://dev.w3.org/html5/spec/Overview.html#attributes-0
|
||||
// http://dev.w3.org/html5/pf-summary/Overview.html#attributes
|
||||
{
|
||||
"Empty attribute",
|
||||
`<input disabled FOO>`,
|
||||
|
19
Godeps/_workspace/src/golang.org/x/net/websocket/client.go
generated
vendored
19
Godeps/_workspace/src/golang.org/x/net/websocket/client.go
generated
vendored
@ -64,6 +64,20 @@ func Dial(url_, protocol, origin string) (ws *Conn, err error) {
|
||||
return DialConfig(config)
|
||||
}
|
||||
|
||||
var portMap = map[string]string{
|
||||
"ws": "80",
|
||||
"wss": "443",
|
||||
}
|
||||
|
||||
func parseAuthority(location *url.URL) string {
|
||||
if _, ok := portMap[location.Scheme]; ok {
|
||||
if _, _, err := net.SplitHostPort(location.Host); err != nil {
|
||||
return net.JoinHostPort(location.Host, portMap[location.Scheme])
|
||||
}
|
||||
}
|
||||
return location.Host
|
||||
}
|
||||
|
||||
// DialConfig opens a new client connection to a WebSocket with a config.
|
||||
func DialConfig(config *Config) (ws *Conn, err error) {
|
||||
var client net.Conn
|
||||
@ -75,10 +89,10 @@ func DialConfig(config *Config) (ws *Conn, err error) {
|
||||
}
|
||||
switch config.Location.Scheme {
|
||||
case "ws":
|
||||
client, err = net.Dial("tcp", config.Location.Host)
|
||||
client, err = net.Dial("tcp", parseAuthority(config.Location))
|
||||
|
||||
case "wss":
|
||||
client, err = tls.Dial("tcp", config.Location.Host, config.TlsConfig)
|
||||
client, err = tls.Dial("tcp", parseAuthority(config.Location), config.TlsConfig)
|
||||
|
||||
default:
|
||||
err = ErrBadScheme
|
||||
@ -89,6 +103,7 @@ func DialConfig(config *Config) (ws *Conn, err error) {
|
||||
|
||||
ws, err = NewClient(config, client)
|
||||
if err != nil {
|
||||
client.Close()
|
||||
goto Error
|
||||
}
|
||||
return
|
||||
|
50
Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go
generated
vendored
50
Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go
generated
vendored
@ -157,6 +157,9 @@ func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits
|
||||
b &= 0x7f
|
||||
}
|
||||
header = append(header, b)
|
||||
hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
|
||||
}
|
||||
@ -264,7 +267,7 @@ type hybiFrameHandler struct {
|
||||
payloadType byte
|
||||
}
|
||||
|
||||
func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) {
|
||||
func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) {
|
||||
if handler.conn.IsServerConn() {
|
||||
// The client MUST mask all frames sent to the server.
|
||||
if frame.(*hybiFrameReader).header.MaskingKey == nil {
|
||||
@ -288,20 +291,19 @@ func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader,
|
||||
handler.payloadType = frame.PayloadType()
|
||||
case CloseFrame:
|
||||
return nil, io.EOF
|
||||
case PingFrame:
|
||||
pingMsg := make([]byte, maxControlFramePayloadLength)
|
||||
n, err := io.ReadFull(frame, pingMsg)
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
case PingFrame, PongFrame:
|
||||
b := make([]byte, maxControlFramePayloadLength)
|
||||
n, err := io.ReadFull(frame, b)
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
return nil, err
|
||||
}
|
||||
io.Copy(ioutil.Discard, frame)
|
||||
n, err = handler.WritePong(pingMsg[:n])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if frame.PayloadType() == PingFrame {
|
||||
if _, err := handler.WritePong(b[:n]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
case PongFrame:
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
return frame, nil
|
||||
}
|
||||
@ -370,6 +372,23 @@ func generateNonce() (nonce []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
// removeZone removes IPv6 zone identifer from host.
|
||||
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
|
||||
func removeZone(host string) string {
|
||||
if !strings.HasPrefix(host, "[") {
|
||||
return host
|
||||
}
|
||||
i := strings.LastIndex(host, "]")
|
||||
if i < 0 {
|
||||
return host
|
||||
}
|
||||
j := strings.LastIndex(host[:i], "%")
|
||||
if j < 0 {
|
||||
return host
|
||||
}
|
||||
return host[:j] + host[i:]
|
||||
}
|
||||
|
||||
// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
|
||||
// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
|
||||
func getNonceAccept(nonce []byte) (expected []byte, err error) {
|
||||
@ -389,7 +408,10 @@ func getNonceAccept(nonce []byte) (expected []byte, err error) {
|
||||
func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
|
||||
bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
|
||||
|
||||
bw.WriteString("Host: " + config.Location.Host + "\r\n")
|
||||
// According to RFC 6874, an HTTP client, proxy, or other
|
||||
// intermediary must remove any IPv6 zone identifier attached
|
||||
// to an outgoing URI.
|
||||
bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n")
|
||||
bw.WriteString("Upgrade: websocket\r\n")
|
||||
bw.WriteString("Connection: Upgrade\r\n")
|
||||
nonce := generateNonce()
|
||||
@ -515,15 +537,15 @@ func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Reques
|
||||
return http.StatusSwitchingProtocols, nil
|
||||
}
|
||||
|
||||
// Origin parses Origin header in "req".
|
||||
// If origin is "null", returns (nil, nil).
|
||||
// Origin parses the Origin header in req.
|
||||
// If the Origin header is not set, it returns nil and nil.
|
||||
func Origin(config *Config, req *http.Request) (*url.URL, error) {
|
||||
var origin string
|
||||
switch config.Version {
|
||||
case ProtocolVersionHybi13:
|
||||
origin = req.Header.Get("Origin")
|
||||
}
|
||||
if origin == "null" {
|
||||
if origin == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return url.ParseRequestURI(origin)
|
||||
|
124
Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go
generated
vendored
124
Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go
generated
vendored
@ -31,63 +31,74 @@ func TestSecWebSocketAccept(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHybiClientHandshake(t *testing.T) {
|
||||
b := bytes.NewBuffer([]byte{})
|
||||
bw := bufio.NewWriter(b)
|
||||
br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
|
||||
type test struct {
|
||||
url, host string
|
||||
}
|
||||
tests := []test{
|
||||
{"ws://server.example.com/chat", "server.example.com"},
|
||||
{"ws://127.0.0.1/chat", "127.0.0.1"},
|
||||
}
|
||||
if _, err := url.ParseRequestURI("http://[fe80::1%25lo0]"); err == nil {
|
||||
tests = append(tests, test{"ws://[fe80::1%25lo0]/chat", "[fe80::1]"})
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
var b bytes.Buffer
|
||||
bw := bufio.NewWriter(&b)
|
||||
br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
|
||||
Upgrade: websocket
|
||||
Connection: Upgrade
|
||||
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
||||
Sec-WebSocket-Protocol: chat
|
||||
|
||||
`))
|
||||
var err error
|
||||
config := new(Config)
|
||||
config.Location, err = url.ParseRequestURI("ws://server.example.com/chat")
|
||||
if err != nil {
|
||||
t.Fatal("location url", err)
|
||||
}
|
||||
config.Origin, err = url.ParseRequestURI("http://example.com")
|
||||
if err != nil {
|
||||
t.Fatal("origin url", err)
|
||||
}
|
||||
config.Protocol = append(config.Protocol, "chat")
|
||||
config.Protocol = append(config.Protocol, "superchat")
|
||||
config.Version = ProtocolVersionHybi13
|
||||
|
||||
config.handshakeData = map[string]string{
|
||||
"key": "dGhlIHNhbXBsZSBub25jZQ==",
|
||||
}
|
||||
err = hybiClientHandshake(config, br, bw)
|
||||
if err != nil {
|
||||
t.Errorf("handshake failed: %v", err)
|
||||
}
|
||||
req, err := http.ReadRequest(bufio.NewReader(b))
|
||||
if err != nil {
|
||||
t.Fatalf("read request: %v", err)
|
||||
}
|
||||
if req.Method != "GET" {
|
||||
t.Errorf("request method expected GET, but got %q", req.Method)
|
||||
}
|
||||
if req.URL.Path != "/chat" {
|
||||
t.Errorf("request path expected /chat, but got %q", req.URL.Path)
|
||||
}
|
||||
if req.Proto != "HTTP/1.1" {
|
||||
t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
|
||||
}
|
||||
if req.Host != "server.example.com" {
|
||||
t.Errorf("request Host expected server.example.com, but got %v", req.Host)
|
||||
}
|
||||
var expectedHeader = map[string]string{
|
||||
"Connection": "Upgrade",
|
||||
"Upgrade": "websocket",
|
||||
"Sec-Websocket-Key": config.handshakeData["key"],
|
||||
"Origin": config.Origin.String(),
|
||||
"Sec-Websocket-Protocol": "chat, superchat",
|
||||
"Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi13),
|
||||
}
|
||||
for k, v := range expectedHeader {
|
||||
if req.Header.Get(k) != v {
|
||||
t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
|
||||
var err error
|
||||
var config Config
|
||||
config.Location, err = url.ParseRequestURI(tt.url)
|
||||
if err != nil {
|
||||
t.Fatal("location url", err)
|
||||
}
|
||||
config.Origin, err = url.ParseRequestURI("http://example.com")
|
||||
if err != nil {
|
||||
t.Fatal("origin url", err)
|
||||
}
|
||||
config.Protocol = append(config.Protocol, "chat")
|
||||
config.Protocol = append(config.Protocol, "superchat")
|
||||
config.Version = ProtocolVersionHybi13
|
||||
config.handshakeData = map[string]string{
|
||||
"key": "dGhlIHNhbXBsZSBub25jZQ==",
|
||||
}
|
||||
if err := hybiClientHandshake(&config, br, bw); err != nil {
|
||||
t.Fatal("handshake", err)
|
||||
}
|
||||
req, err := http.ReadRequest(bufio.NewReader(&b))
|
||||
if err != nil {
|
||||
t.Fatal("read request", err)
|
||||
}
|
||||
if req.Method != "GET" {
|
||||
t.Errorf("request method expected GET, but got %s", req.Method)
|
||||
}
|
||||
if req.URL.Path != "/chat" {
|
||||
t.Errorf("request path expected /chat, but got %s", req.URL.Path)
|
||||
}
|
||||
if req.Proto != "HTTP/1.1" {
|
||||
t.Errorf("request proto expected HTTP/1.1, but got %s", req.Proto)
|
||||
}
|
||||
if req.Host != tt.host {
|
||||
t.Errorf("request host expected %s, but got %s", tt.host, req.Host)
|
||||
}
|
||||
var expectedHeader = map[string]string{
|
||||
"Connection": "Upgrade",
|
||||
"Upgrade": "websocket",
|
||||
"Sec-Websocket-Key": config.handshakeData["key"],
|
||||
"Origin": config.Origin.String(),
|
||||
"Sec-Websocket-Protocol": "chat, superchat",
|
||||
"Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi13),
|
||||
}
|
||||
for k, v := range expectedHeader {
|
||||
if req.Header.Get(k) != v {
|
||||
t.Errorf("%s expected %s, but got %v", k, v, req.Header.Get(k))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -326,7 +337,7 @@ func testHybiFrame(t *testing.T, testHeader, testPayload, testMaskedPayload []by
|
||||
}
|
||||
payload := make([]byte, len(testPayload))
|
||||
_, err = r.Read(payload)
|
||||
if err != nil {
|
||||
if err != nil && err != io.EOF {
|
||||
t.Errorf("read %v", err)
|
||||
}
|
||||
if !bytes.Equal(testPayload, payload) {
|
||||
@ -363,13 +374,20 @@ func TestHybiShortBinaryFrame(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHybiControlFrame(t *testing.T) {
|
||||
frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame}
|
||||
payload := []byte("hello")
|
||||
|
||||
frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame}
|
||||
testHybiFrame(t, []byte{0x89, 0x05}, payload, payload, frameHeader)
|
||||
|
||||
frameHeader = &hybiFrameHeader{Fin: true, OpCode: PingFrame}
|
||||
testHybiFrame(t, []byte{0x89, 0x00}, nil, nil, frameHeader)
|
||||
|
||||
frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame}
|
||||
testHybiFrame(t, []byte{0x8A, 0x05}, payload, payload, frameHeader)
|
||||
|
||||
frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame}
|
||||
testHybiFrame(t, []byte{0x8A, 0x00}, nil, nil, frameHeader)
|
||||
|
||||
frameHeader = &hybiFrameHeader{Fin: true, OpCode: CloseFrame}
|
||||
payload = []byte{0x03, 0xe8} // 1000
|
||||
testHybiFrame(t, []byte{0x88, 0x02}, payload, payload, frameHeader)
|
||||
|
5
Godeps/_workspace/src/golang.org/x/net/websocket/server.go
generated
vendored
5
Godeps/_workspace/src/golang.org/x/net/websocket/server.go
generated
vendored
@ -74,7 +74,6 @@ func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
|
||||
rwc, buf, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
panic("Hijack failed: " + err.Error())
|
||||
return
|
||||
}
|
||||
// The server should abort the WebSocket connection if it finds
|
||||
// the client did not send a handshake that matches with protocol
|
||||
@ -95,8 +94,8 @@ func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
|
||||
// You might want to verify websocket.Conn.Config().Origin in the func.
|
||||
// If you use Server instead of Handler, you could call websocket.Origin and
|
||||
// check the origin in your Handshake func. So, if you want to accept
|
||||
// non-browser client, which doesn't send Origin header, you could use Server
|
||||
//. that doesn't check origin in its Handshake.
|
||||
// non-browser clients, which do not send an Origin header, set a
|
||||
// Server.Handshake that does not check the origin.
|
||||
type Handler func(*Conn)
|
||||
|
||||
func checkOrigin(config *Config, req *http.Request) (err error) {
|
||||
|
3
Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go
generated
vendored
3
Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go
generated
vendored
@ -216,10 +216,11 @@ func (ws *Conn) Write(msg []byte) (n int, err error) {
|
||||
// Close implements the io.Closer interface.
|
||||
func (ws *Conn) Close() error {
|
||||
err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
|
||||
err1 := ws.rwc.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ws.rwc.Close()
|
||||
return err1
|
||||
}
|
||||
|
||||
func (ws *Conn) IsClientConn() bool { return ws.request == nil }
|
||||
|
248
Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go
generated
vendored
248
Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go
generated
vendored
@ -13,15 +13,21 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var serverAddr string
|
||||
var once sync.Once
|
||||
|
||||
func echoServer(ws *Conn) { io.Copy(ws, ws) }
|
||||
func echoServer(ws *Conn) {
|
||||
defer ws.Close()
|
||||
io.Copy(ws, ws)
|
||||
}
|
||||
|
||||
type Count struct {
|
||||
S string
|
||||
@ -29,6 +35,7 @@ type Count struct {
|
||||
}
|
||||
|
||||
func countServer(ws *Conn) {
|
||||
defer ws.Close()
|
||||
for {
|
||||
var count Count
|
||||
err := JSON.Receive(ws, &count)
|
||||
@ -44,6 +51,55 @@ func countServer(ws *Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
type testCtrlAndDataHandler struct {
|
||||
hybiFrameHandler
|
||||
}
|
||||
|
||||
func (h *testCtrlAndDataHandler) WritePing(b []byte) (int, error) {
|
||||
h.hybiFrameHandler.conn.wio.Lock()
|
||||
defer h.hybiFrameHandler.conn.wio.Unlock()
|
||||
w, err := h.hybiFrameHandler.conn.frameWriterFactory.NewFrameWriter(PingFrame)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, err := w.Write(b)
|
||||
w.Close()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func ctrlAndDataServer(ws *Conn) {
|
||||
defer ws.Close()
|
||||
h := &testCtrlAndDataHandler{hybiFrameHandler: hybiFrameHandler{conn: ws}}
|
||||
ws.frameHandler = h
|
||||
|
||||
go func() {
|
||||
for i := 0; ; i++ {
|
||||
var b []byte
|
||||
if i%2 != 0 { // with or without payload
|
||||
b = []byte(fmt.Sprintf("#%d-CONTROL-FRAME-FROM-SERVER", i))
|
||||
}
|
||||
if _, err := h.WritePing(b); err != nil {
|
||||
break
|
||||
}
|
||||
if _, err := h.WritePong(b); err != nil { // unsolicited pong
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
b := make([]byte, 128)
|
||||
for {
|
||||
n, err := ws.Read(b)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if _, err := ws.Write(b[:n]); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func subProtocolHandshake(config *Config, req *http.Request) error {
|
||||
for _, proto := range config.Protocol {
|
||||
if proto == "chat" {
|
||||
@ -63,6 +119,7 @@ func subProtoServer(ws *Conn) {
|
||||
func startServer() {
|
||||
http.Handle("/echo", Handler(echoServer))
|
||||
http.Handle("/count", Handler(countServer))
|
||||
http.Handle("/ctrldata", Handler(ctrlAndDataServer))
|
||||
subproto := Server{
|
||||
Handshake: subProtocolHandshake,
|
||||
Handler: Handler(subProtoServer),
|
||||
@ -339,3 +396,192 @@ func TestSmallBuffer(t *testing.T) {
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
var parseAuthorityTests = []struct {
|
||||
in *url.URL
|
||||
out string
|
||||
}{
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "ws",
|
||||
Host: "www.google.com",
|
||||
},
|
||||
"www.google.com:80",
|
||||
},
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "wss",
|
||||
Host: "www.google.com",
|
||||
},
|
||||
"www.google.com:443",
|
||||
},
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "ws",
|
||||
Host: "www.google.com:80",
|
||||
},
|
||||
"www.google.com:80",
|
||||
},
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "wss",
|
||||
Host: "www.google.com:443",
|
||||
},
|
||||
"www.google.com:443",
|
||||
},
|
||||
// some invalid ones for parseAuthority. parseAuthority doesn't
|
||||
// concern itself with the scheme unless it actually knows about it
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "http",
|
||||
Host: "www.google.com",
|
||||
},
|
||||
"www.google.com",
|
||||
},
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "http",
|
||||
Host: "www.google.com:80",
|
||||
},
|
||||
"www.google.com:80",
|
||||
},
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "asdf",
|
||||
Host: "127.0.0.1",
|
||||
},
|
||||
"127.0.0.1",
|
||||
},
|
||||
{
|
||||
&url.URL{
|
||||
Scheme: "asdf",
|
||||
Host: "www.google.com",
|
||||
},
|
||||
"www.google.com",
|
||||
},
|
||||
}
|
||||
|
||||
func TestParseAuthority(t *testing.T) {
|
||||
for _, tt := range parseAuthorityTests {
|
||||
out := parseAuthority(tt.in)
|
||||
if out != tt.out {
|
||||
t.Errorf("got %v; want %v", out, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type closerConn struct {
|
||||
net.Conn
|
||||
closed int // count of the number of times Close was called
|
||||
}
|
||||
|
||||
func (c *closerConn) Close() error {
|
||||
c.closed++
|
||||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
if runtime.GOOS == "plan9" {
|
||||
t.Skip("see golang.org/issue/11454")
|
||||
}
|
||||
|
||||
once.Do(startServer)
|
||||
|
||||
conn, err := net.Dial("tcp", serverAddr)
|
||||
if err != nil {
|
||||
t.Fatal("dialing", err)
|
||||
}
|
||||
|
||||
cc := closerConn{Conn: conn}
|
||||
|
||||
client, err := NewClient(newConfig(t, "/echo"), &cc)
|
||||
if err != nil {
|
||||
t.Fatalf("WebSocket handshake: %v", err)
|
||||
}
|
||||
|
||||
// set the deadline to ten minutes ago, which will have expired by the time
|
||||
// client.Close sends the close status frame.
|
||||
conn.SetDeadline(time.Now().Add(-10 * time.Minute))
|
||||
|
||||
if err := client.Close(); err == nil {
|
||||
t.Errorf("ws.Close(): expected error, got %v", err)
|
||||
}
|
||||
if cc.closed < 1 {
|
||||
t.Fatalf("ws.Close(): expected underlying ws.rwc.Close to be called > 0 times, got: %v", cc.closed)
|
||||
}
|
||||
}
|
||||
|
||||
var originTests = []struct {
|
||||
req *http.Request
|
||||
origin *url.URL
|
||||
}{
|
||||
{
|
||||
req: &http.Request{
|
||||
Header: http.Header{
|
||||
"Origin": []string{"http://www.example.com"},
|
||||
},
|
||||
},
|
||||
origin: &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "www.example.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
req: &http.Request{},
|
||||
},
|
||||
}
|
||||
|
||||
func TestOrigin(t *testing.T) {
|
||||
conf := newConfig(t, "/echo")
|
||||
conf.Version = ProtocolVersionHybi13
|
||||
for i, tt := range originTests {
|
||||
origin, err := Origin(conf, tt.req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(origin, tt.origin) {
|
||||
t.Errorf("#%d: got origin %v; want %v", i, origin, tt.origin)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtrlAndData(t *testing.T) {
|
||||
once.Do(startServer)
|
||||
|
||||
c, err := net.Dial("tcp", serverAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ws, err := NewClient(newConfig(t, "/ctrldata"), c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
h := &testCtrlAndDataHandler{hybiFrameHandler: hybiFrameHandler{conn: ws}}
|
||||
ws.frameHandler = h
|
||||
|
||||
b := make([]byte, 128)
|
||||
for i := 0; i < 2; i++ {
|
||||
data := []byte(fmt.Sprintf("#%d-DATA-FRAME-FROM-CLIENT", i))
|
||||
if _, err := ws.Write(data); err != nil {
|
||||
t.Fatalf("#%d: %v", i, err)
|
||||
}
|
||||
var ctrl []byte
|
||||
if i%2 != 0 { // with or without payload
|
||||
ctrl = []byte(fmt.Sprintf("#%d-CONTROL-FRAME-FROM-CLIENT", i))
|
||||
}
|
||||
if _, err := h.WritePing(ctrl); err != nil {
|
||||
t.Fatalf("#%d: %v", i, err)
|
||||
}
|
||||
n, err := ws.Read(b)
|
||||
if err != nil {
|
||||
t.Fatalf("#%d: %v", i, err)
|
||||
}
|
||||
if !bytes.Equal(b[:n], data) {
|
||||
t.Fatalf("#%d: got %v; want %v", i, b[:n], data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user