mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #14747 from eparis/update-golang-x-net
Update golang.org/x/net to fix godep reproducability problem
This commit is contained in:
commit
26c51881ca
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