diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 9c062320831..a8e5f859efe 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -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", diff --git a/Godeps/_workspace/src/golang.org/x/net/context/context.go b/Godeps/_workspace/src/golang.org/x/net/context/context.go index 66aff7cb4a0..ef2f3e86fec 100644 --- a/Godeps/_workspace/src/golang.org/x/net/context/context.go +++ b/Godeps/_workspace/src/golang.org/x/net/context/context.go @@ -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) diff --git a/Godeps/_workspace/src/golang.org/x/net/context/context_test.go b/Godeps/_workspace/src/golang.org/x/net/context/context_test.go index 82d2494a492..e64afa64c66 100644 --- a/Godeps/_workspace/src/golang.org/x/net/context/context_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/context/context_test.go @@ -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) +} diff --git a/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq.go b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq.go new file mode 100644 index 00000000000..48610e36277 --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq.go @@ -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) + } +} diff --git a/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq_go14.go b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq_go14.go new file mode 100644 index 00000000000..56bcbadb85f --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/cancelreq_go14.go @@ -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) + } +} diff --git a/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp.go b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp.go new file mode 100644 index 00000000000..9f34888132e --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp.go @@ -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())) +} diff --git a/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp_test.go b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp_test.go new file mode 100644 index 00000000000..47b53d7f18c --- /dev/null +++ b/Godeps/_workspace/src/golang.org/x/net/context/ctxhttp/ctxhttp_test.go @@ -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) +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/atom/gen.go b/Godeps/_workspace/src/golang.org/x/net/html/atom/gen.go index 9958a718842..6bfa8660198 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/atom/gen.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/atom/gen.go @@ -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", diff --git a/Godeps/_workspace/src/golang.org/x/net/html/atom/table.go b/Godeps/_workspace/src/golang.org/x/net/html/atom/table.go index 20b8b8a5903..2605ba3102f 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/atom/table.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/atom/table.go @@ -3,692 +3,711 @@ package atom const ( - A Atom = 0x1 - Abbr Atom = 0x4 - Accept Atom = 0x2106 - AcceptCharset Atom = 0x210e - Accesskey Atom = 0x3309 - Action Atom = 0x21b06 - Address Atom = 0x5d507 - Align Atom = 0x1105 - Alt Atom = 0x4503 - Annotation Atom = 0x18d0a - AnnotationXml Atom = 0x18d0e - Applet Atom = 0x2d106 - Area Atom = 0x31804 - Article Atom = 0x39907 - Aside Atom = 0x4f05 - Async Atom = 0x9305 - Audio Atom = 0xaf05 - Autocomplete Atom = 0xd50c - Autofocus Atom = 0xe109 - Autoplay Atom = 0x10c08 - B Atom = 0x101 - Base Atom = 0x11404 - Basefont Atom = 0x11408 - Bdi Atom = 0x1a03 - Bdo Atom = 0x12503 - Bgsound Atom = 0x13807 - Big Atom = 0x14403 - Blink Atom = 0x14705 - Blockquote Atom = 0x14c0a - Body Atom = 0x2f04 - Border Atom = 0x15606 - Br Atom = 0x202 - Button Atom = 0x15c06 - Canvas Atom = 0x4b06 - Caption Atom = 0x1e007 - Center Atom = 0x2df06 - Challenge Atom = 0x23e09 - Charset Atom = 0x2807 - Checked Atom = 0x33f07 - Cite Atom = 0x9704 - Class Atom = 0x3d905 - Code Atom = 0x16f04 - Col Atom = 0x17603 - Colgroup Atom = 0x17608 - Color Atom = 0x18305 - Cols Atom = 0x18804 - Colspan Atom = 0x18807 - Command Atom = 0x19b07 - Content Atom = 0x42c07 - Contenteditable Atom = 0x42c0f - Contextmenu Atom = 0x3480b - Controls Atom = 0x1ae08 - Coords Atom = 0x1ba06 - Crossorigin Atom = 0x1c40b - Data Atom = 0x44304 - Datalist Atom = 0x44308 - Datetime Atom = 0x25b08 - Dd Atom = 0x28802 - Default Atom = 0x5207 - Defer Atom = 0x17105 - Del Atom = 0x4d603 - Desc Atom = 0x4804 - Details Atom = 0x6507 - Dfn Atom = 0x8303 - Dialog Atom = 0x1b06 - Dir Atom = 0x9d03 - Dirname Atom = 0x9d07 - Disabled Atom = 0x10008 - Div Atom = 0x10703 - Dl Atom = 0x13e02 - Download Atom = 0x40908 - Draggable Atom = 0x1a109 - Dropzone Atom = 0x3a208 - Dt Atom = 0x4e402 - Em Atom = 0x7f02 - Embed Atom = 0x7f05 - Enctype Atom = 0x23007 - Face Atom = 0x2dd04 - Fieldset Atom = 0x1d508 - Figcaption Atom = 0x1dd0a - Figure Atom = 0x1f106 - Font Atom = 0x11804 - Footer Atom = 0x5906 - For Atom = 0x1fd03 - ForeignObject Atom = 0x1fd0d - Foreignobject Atom = 0x20a0d - Form Atom = 0x21704 - Formaction Atom = 0x2170a - Formenctype Atom = 0x22c0b - Formmethod Atom = 0x2470a - Formnovalidate Atom = 0x2510e - Formtarget Atom = 0x2660a - Frame Atom = 0x8705 - Frameset Atom = 0x8708 - H1 Atom = 0x13602 - H2 Atom = 0x29602 - H3 Atom = 0x2c502 - H4 Atom = 0x30e02 - H5 Atom = 0x4e602 - H6 Atom = 0x27002 - Head Atom = 0x2fa04 - Header Atom = 0x2fa06 - Headers Atom = 0x2fa07 - Height Atom = 0x27206 - Hgroup Atom = 0x27a06 - Hidden Atom = 0x28606 - High Atom = 0x29304 - Hr Atom = 0x13102 - Href Atom = 0x29804 - Hreflang Atom = 0x29808 - Html Atom = 0x27604 - HttpEquiv Atom = 0x2a00a - I Atom = 0x601 - Icon Atom = 0x42b04 - Id Atom = 0x5102 - Iframe Atom = 0x2b406 - Image Atom = 0x2ba05 - Img Atom = 0x2bf03 - Inert Atom = 0x4c105 - Input Atom = 0x3f605 - Ins Atom = 0x1cd03 - Isindex Atom = 0x2c707 - Ismap Atom = 0x2ce05 - Itemid Atom = 0x9806 - Itemprop Atom = 0x57e08 - Itemref Atom = 0x2d707 - Itemscope Atom = 0x2e509 - Itemtype Atom = 0x2ef08 - Kbd Atom = 0x1903 - Keygen Atom = 0x3906 - Keytype Atom = 0x51207 - Kind Atom = 0xfd04 - Label Atom = 0xba05 - Lang Atom = 0x29c04 - Legend Atom = 0x1a806 - Li Atom = 0x1202 - Link Atom = 0x14804 - List Atom = 0x44704 - Listing Atom = 0x44707 - Loop Atom = 0xbe04 - Low Atom = 0x13f03 - Malignmark Atom = 0x100a - Manifest Atom = 0x5b608 - Map Atom = 0x2d003 - Mark Atom = 0x1604 - Marquee Atom = 0x5f207 - Math Atom = 0x2f704 - Max Atom = 0x30603 - Maxlength Atom = 0x30609 - Media Atom = 0xa205 - Mediagroup Atom = 0xa20a - Menu Atom = 0x34f04 - Meta Atom = 0x45604 - Meter Atom = 0x26105 - Method Atom = 0x24b06 - Mglyph Atom = 0x2c006 - Mi Atom = 0x9b02 - Min Atom = 0x31003 - Mn Atom = 0x25402 - Mo Atom = 0x47a02 - Ms Atom = 0x2e802 - Mtext Atom = 0x31305 - Multiple Atom = 0x32108 - Muted Atom = 0x32905 - Name Atom = 0xa004 - Nav Atom = 0x3e03 - Nobr Atom = 0x7404 - Noembed Atom = 0x7d07 - Noframes Atom = 0x8508 - Noscript Atom = 0x28b08 - Novalidate Atom = 0x2550a - Object Atom = 0x21106 - Ol Atom = 0xcd02 - Onabort Atom = 0x16007 - Onafterprint Atom = 0x1e50c - Onbeforeprint Atom = 0x21f0d - Onbeforeunload Atom = 0x5c90e - Onblur Atom = 0x3e206 - Oncancel Atom = 0xb308 - Oncanplay Atom = 0x12709 - Oncanplaythrough Atom = 0x12710 - Onchange Atom = 0x3b808 - Onclick Atom = 0x2ad07 - Onclose Atom = 0x32e07 - Oncontextmenu Atom = 0x3460d - Oncuechange Atom = 0x3530b - Ondblclick Atom = 0x35e0a - Ondrag Atom = 0x36806 - Ondragend Atom = 0x36809 - Ondragenter Atom = 0x3710b - Ondragleave Atom = 0x37c0b - Ondragover Atom = 0x3870a - Ondragstart Atom = 0x3910b - Ondrop Atom = 0x3a006 - Ondurationchange Atom = 0x3b010 - Onemptied Atom = 0x3a709 - Onended Atom = 0x3c007 - Onerror Atom = 0x3c707 - Onfocus Atom = 0x3ce07 - Onhashchange Atom = 0x3e80c - Oninput Atom = 0x3f407 - Oninvalid Atom = 0x3fb09 - Onkeydown Atom = 0x40409 - Onkeypress Atom = 0x4110a - Onkeyup Atom = 0x42107 - Onload Atom = 0x43b06 - Onloadeddata Atom = 0x43b0c - Onloadedmetadata Atom = 0x44e10 - Onloadstart Atom = 0x4640b - Onmessage Atom = 0x46f09 - Onmousedown Atom = 0x4780b - Onmousemove Atom = 0x4830b - Onmouseout Atom = 0x48e0a - Onmouseover Atom = 0x49b0b - Onmouseup Atom = 0x4a609 - Onmousewheel Atom = 0x4af0c - Onoffline Atom = 0x4bb09 - Ononline Atom = 0x4c608 - Onpagehide Atom = 0x4ce0a - Onpageshow Atom = 0x4d90a - Onpause Atom = 0x4e807 - Onplay Atom = 0x4f206 - Onplaying Atom = 0x4f209 - Onpopstate Atom = 0x4fb0a - Onprogress Atom = 0x5050a - Onratechange Atom = 0x5190c - Onreset Atom = 0x52507 - Onresize Atom = 0x52c08 - Onscroll Atom = 0x53a08 - Onseeked Atom = 0x54208 - Onseeking Atom = 0x54a09 - Onselect Atom = 0x55308 - Onshow Atom = 0x55d06 - Onstalled Atom = 0x56609 - Onstorage Atom = 0x56f09 - Onsubmit Atom = 0x57808 - Onsuspend Atom = 0x58809 - Ontimeupdate Atom = 0x1190c - Onunload Atom = 0x59108 - Onvolumechange Atom = 0x5990e - Onwaiting Atom = 0x5a709 - Open Atom = 0x58404 - Optgroup Atom = 0xc008 - Optimum Atom = 0x5b007 - Option Atom = 0x5c506 - Output Atom = 0x49506 - P Atom = 0xc01 - Param Atom = 0xc05 - Pattern Atom = 0x6e07 - Ping Atom = 0xab04 - Placeholder Atom = 0xc70b - Plaintext Atom = 0xf109 - Poster Atom = 0x17d06 - Pre Atom = 0x27f03 - Preload Atom = 0x27f07 - Progress Atom = 0x50708 - Prompt Atom = 0x5bf06 - Public Atom = 0x42706 - Q Atom = 0x15101 - Radiogroup Atom = 0x30a - Readonly Atom = 0x31908 - Rel Atom = 0x28003 - Required Atom = 0x1f508 - Reversed Atom = 0x5e08 - Rows Atom = 0x7704 - Rowspan Atom = 0x7707 - Rp Atom = 0x1eb02 - Rt Atom = 0x16502 - Ruby Atom = 0xd104 - S Atom = 0x2c01 - Samp Atom = 0x6b04 - Sandbox Atom = 0xe907 - Scope Atom = 0x2e905 - Scoped Atom = 0x2e906 - Script Atom = 0x28d06 - Seamless Atom = 0x33308 - Section Atom = 0x3dd07 - Select Atom = 0x55506 - Selected Atom = 0x55508 - Shape Atom = 0x1b505 - Size Atom = 0x53004 - Sizes Atom = 0x53005 - Small Atom = 0x1bf05 - Source Atom = 0x1cf06 - Spacer Atom = 0x30006 - Span Atom = 0x7a04 - Spellcheck Atom = 0x33a0a - Src Atom = 0x3d403 - Srcdoc Atom = 0x3d406 - Srclang Atom = 0x41a07 - Start Atom = 0x39705 - Step Atom = 0x5bc04 - Strike Atom = 0x50e06 - Strong Atom = 0x53406 - Style Atom = 0x5db05 - Sub Atom = 0x57a03 - Summary Atom = 0x5e007 - Sup Atom = 0x5e703 - Svg Atom = 0x5ea03 - System Atom = 0x5ed06 - Tabindex Atom = 0x45c08 - Table Atom = 0x43605 - Target Atom = 0x26a06 - Tbody Atom = 0x2e05 - Td Atom = 0x4702 - Textarea Atom = 0x31408 - Tfoot Atom = 0x5805 - Th Atom = 0x13002 - Thead Atom = 0x2f905 - Time Atom = 0x11b04 - Title Atom = 0x8e05 - Tr Atom = 0xf902 - Track Atom = 0xf905 - Translate Atom = 0x16609 - Tt Atom = 0x7002 - Type Atom = 0x23304 - Typemustmatch Atom = 0x2330d - U Atom = 0xb01 - Ul Atom = 0x5602 - Usemap Atom = 0x4ec06 - Value Atom = 0x4005 - Var Atom = 0x10903 - Video Atom = 0x2a905 - Wbr Atom = 0x14103 - Width Atom = 0x4e205 - Wrap Atom = 0x56204 - Xmp Atom = 0xef03 + A Atom = 0x1 + Abbr Atom = 0x4 + Accept Atom = 0x2106 + AcceptCharset Atom = 0x210e + Accesskey Atom = 0x3309 + Action Atom = 0x1f606 + Address Atom = 0x4f307 + Align Atom = 0x1105 + Alt Atom = 0x4503 + Annotation Atom = 0x1670a + AnnotationXml Atom = 0x1670e + Applet Atom = 0x2b306 + Area Atom = 0x2fa04 + Article Atom = 0x38807 + Aside Atom = 0x8305 + Async Atom = 0x7b05 + Audio Atom = 0xa605 + Autocomplete Atom = 0x1fc0c + Autofocus Atom = 0xb309 + Autoplay Atom = 0xce08 + B Atom = 0x101 + Base Atom = 0xd604 + Basefont Atom = 0xd608 + Bdi Atom = 0x1a03 + Bdo Atom = 0xe703 + Bgsound Atom = 0x11807 + Big Atom = 0x12403 + Blink Atom = 0x12705 + Blockquote Atom = 0x12c0a + Body Atom = 0x2f04 + Br Atom = 0x202 + Button Atom = 0x13606 + Canvas Atom = 0x7f06 + Caption Atom = 0x1bb07 + Center Atom = 0x5b506 + Challenge Atom = 0x21f09 + Charset Atom = 0x2807 + Checked Atom = 0x32807 + Cite Atom = 0x3c804 + Class Atom = 0x4de05 + Code Atom = 0x14904 + Col Atom = 0x15003 + Colgroup Atom = 0x15008 + Color Atom = 0x15d05 + Cols Atom = 0x16204 + Colspan Atom = 0x16207 + Command Atom = 0x17507 + Content Atom = 0x42307 + Contenteditable Atom = 0x4230f + Contextmenu Atom = 0x3310b + Controls Atom = 0x18808 + Coords Atom = 0x19406 + Crossorigin Atom = 0x19f0b + Data Atom = 0x44a04 + Datalist Atom = 0x44a08 + Datetime Atom = 0x23c08 + Dd Atom = 0x26702 + Default Atom = 0x8607 + Defer Atom = 0x14b05 + Del Atom = 0x3ef03 + Desc Atom = 0x4db04 + Details Atom = 0x4807 + Dfn Atom = 0x6103 + Dialog Atom = 0x1b06 + Dir Atom = 0x6903 + Dirname Atom = 0x6907 + Disabled Atom = 0x10c08 + Div Atom = 0x11303 + Dl Atom = 0x11e02 + Download Atom = 0x40008 + Draggable Atom = 0x17b09 + Dropzone Atom = 0x39108 + Dt Atom = 0x50902 + Em Atom = 0x6502 + Embed Atom = 0x6505 + Enctype Atom = 0x21107 + Face Atom = 0x5b304 + Fieldset Atom = 0x1b008 + Figcaption Atom = 0x1b80a + Figure Atom = 0x1cc06 + Font Atom = 0xda04 + Footer Atom = 0x8d06 + For Atom = 0x1d803 + ForeignObject Atom = 0x1d80d + Foreignobject Atom = 0x1e50d + Form Atom = 0x1f204 + Formaction Atom = 0x1f20a + Formenctype Atom = 0x20d0b + Formmethod Atom = 0x2280a + Formnovalidate Atom = 0x2320e + Formtarget Atom = 0x2470a + Frame Atom = 0x9a05 + Frameset Atom = 0x9a08 + H1 Atom = 0x26e02 + H2 Atom = 0x29402 + H3 Atom = 0x2a702 + H4 Atom = 0x2e902 + H5 Atom = 0x2f302 + H6 Atom = 0x50b02 + Head Atom = 0x2d504 + Header Atom = 0x2d506 + Headers Atom = 0x2d507 + Height Atom = 0x25106 + Hgroup Atom = 0x25906 + Hidden Atom = 0x26506 + High Atom = 0x26b04 + Hr Atom = 0x27002 + Href Atom = 0x27004 + Hreflang Atom = 0x27008 + Html Atom = 0x25504 + HttpEquiv Atom = 0x2780a + I Atom = 0x601 + Icon Atom = 0x42204 + Id Atom = 0x8502 + Iframe Atom = 0x29606 + Image Atom = 0x29c05 + Img Atom = 0x2a103 + Input Atom = 0x3e805 + Inputmode Atom = 0x3e809 + Ins Atom = 0x1a803 + Isindex Atom = 0x2a907 + Ismap Atom = 0x2b005 + Itemid Atom = 0x33c06 + Itemprop Atom = 0x3c908 + Itemref Atom = 0x5ad07 + Itemscope Atom = 0x2b909 + Itemtype Atom = 0x2c308 + Kbd Atom = 0x1903 + Keygen Atom = 0x3906 + Keytype Atom = 0x53707 + Kind Atom = 0x10904 + Label Atom = 0xf005 + Lang Atom = 0x27404 + Legend Atom = 0x18206 + Li Atom = 0x1202 + Link Atom = 0x12804 + List Atom = 0x44e04 + Listing Atom = 0x44e07 + Loop Atom = 0xf404 + Low Atom = 0x11f03 + Malignmark Atom = 0x100a + Manifest Atom = 0x5f108 + Map Atom = 0x2b203 + Mark Atom = 0x1604 + Marquee Atom = 0x2cb07 + Math Atom = 0x2d204 + Max Atom = 0x2e103 + Maxlength Atom = 0x2e109 + Media Atom = 0x6e05 + Mediagroup Atom = 0x6e0a + Menu Atom = 0x33804 + Menuitem Atom = 0x33808 + Meta Atom = 0x45d04 + Meter Atom = 0x24205 + Method Atom = 0x22c06 + Mglyph Atom = 0x2a206 + Mi Atom = 0x2eb02 + Min Atom = 0x2eb03 + Minlength Atom = 0x2eb09 + Mn Atom = 0x23502 + Mo Atom = 0x3ed02 + Ms Atom = 0x2bc02 + Mtext Atom = 0x2f505 + Multiple Atom = 0x30308 + Muted Atom = 0x30b05 + Name Atom = 0x6c04 + Nav Atom = 0x3e03 + Nobr Atom = 0x5704 + Noembed Atom = 0x6307 + Noframes Atom = 0x9808 + Noscript Atom = 0x3d208 + Novalidate Atom = 0x2360a + Object Atom = 0x1ec06 + Ol Atom = 0xc902 + Onabort Atom = 0x13a07 + Onafterprint Atom = 0x1c00c + Onautocomplete Atom = 0x1fa0e + Onautocompleteerror Atom = 0x1fa13 + Onbeforeprint Atom = 0x6040d + Onbeforeunload Atom = 0x4e70e + Onblur Atom = 0xaa06 + Oncancel Atom = 0xe908 + Oncanplay Atom = 0x28509 + Oncanplaythrough Atom = 0x28510 + Onchange Atom = 0x3a708 + Onclick Atom = 0x31007 + Onclose Atom = 0x31707 + Oncontextmenu Atom = 0x32f0d + Oncuechange Atom = 0x3420b + Ondblclick Atom = 0x34d0a + Ondrag Atom = 0x35706 + Ondragend Atom = 0x35709 + Ondragenter Atom = 0x3600b + Ondragleave Atom = 0x36b0b + Ondragover Atom = 0x3760a + Ondragstart Atom = 0x3800b + Ondrop Atom = 0x38f06 + Ondurationchange Atom = 0x39f10 + Onemptied Atom = 0x39609 + Onended Atom = 0x3af07 + Onerror Atom = 0x3b607 + Onfocus Atom = 0x3bd07 + Onhashchange Atom = 0x3da0c + Oninput Atom = 0x3e607 + Oninvalid Atom = 0x3f209 + Onkeydown Atom = 0x3fb09 + Onkeypress Atom = 0x4080a + Onkeyup Atom = 0x41807 + Onlanguagechange Atom = 0x43210 + Onload Atom = 0x44206 + Onloadeddata Atom = 0x4420c + Onloadedmetadata Atom = 0x45510 + Onloadstart Atom = 0x46b0b + Onmessage Atom = 0x47609 + Onmousedown Atom = 0x47f0b + Onmousemove Atom = 0x48a0b + Onmouseout Atom = 0x4950a + Onmouseover Atom = 0x4a20b + Onmouseup Atom = 0x4ad09 + Onmousewheel Atom = 0x4b60c + Onoffline Atom = 0x4c209 + Ononline Atom = 0x4cb08 + Onpagehide Atom = 0x4d30a + Onpageshow Atom = 0x4fe0a + Onpause Atom = 0x50d07 + Onplay Atom = 0x51706 + Onplaying Atom = 0x51709 + Onpopstate Atom = 0x5200a + Onprogress Atom = 0x52a0a + Onratechange Atom = 0x53e0c + Onreset Atom = 0x54a07 + Onresize Atom = 0x55108 + Onscroll Atom = 0x55f08 + Onseeked Atom = 0x56708 + Onseeking Atom = 0x56f09 + Onselect Atom = 0x57808 + Onshow Atom = 0x58206 + Onsort Atom = 0x58b06 + Onstalled Atom = 0x59509 + Onstorage Atom = 0x59e09 + Onsubmit Atom = 0x5a708 + Onsuspend Atom = 0x5bb09 + Ontimeupdate Atom = 0xdb0c + Ontoggle Atom = 0x5c408 + Onunload Atom = 0x5cc08 + Onvolumechange Atom = 0x5d40e + Onwaiting Atom = 0x5e209 + Open Atom = 0x3cf04 + Optgroup Atom = 0xf608 + Optimum Atom = 0x5eb07 + Option Atom = 0x60006 + Output Atom = 0x49c06 + P Atom = 0xc01 + Param Atom = 0xc05 + Pattern Atom = 0x5107 + Ping Atom = 0x7704 + Placeholder Atom = 0xc30b + Plaintext Atom = 0xfd09 + Poster Atom = 0x15706 + Pre Atom = 0x25e03 + Preload Atom = 0x25e07 + Progress Atom = 0x52c08 + Prompt Atom = 0x5fa06 + Public Atom = 0x41e06 + Q Atom = 0x13101 + Radiogroup Atom = 0x30a + Readonly Atom = 0x2fb08 + Rel Atom = 0x25f03 + Required Atom = 0x1d008 + Reversed Atom = 0x5a08 + Rows Atom = 0x9204 + Rowspan Atom = 0x9207 + Rp Atom = 0x1c602 + Rt Atom = 0x13f02 + Ruby Atom = 0xaf04 + S Atom = 0x2c01 + Samp Atom = 0x4e04 + Sandbox Atom = 0xbb07 + Scope Atom = 0x2bd05 + Scoped Atom = 0x2bd06 + Script Atom = 0x3d406 + Seamless Atom = 0x31c08 + Section Atom = 0x4e207 + Select Atom = 0x57a06 + Selected Atom = 0x57a08 + Shape Atom = 0x4f905 + Size Atom = 0x55504 + Sizes Atom = 0x55505 + Small Atom = 0x18f05 + Sortable Atom = 0x58d08 + Sorted Atom = 0x19906 + Source Atom = 0x1aa06 + Spacer Atom = 0x2db06 + Span Atom = 0x9504 + Spellcheck Atom = 0x3230a + Src Atom = 0x3c303 + Srcdoc Atom = 0x3c306 + Srclang Atom = 0x41107 + Start Atom = 0x38605 + Step Atom = 0x5f704 + Strike Atom = 0x53306 + Strong Atom = 0x55906 + Style Atom = 0x61105 + Sub Atom = 0x5a903 + Summary Atom = 0x61607 + Sup Atom = 0x61d03 + Svg Atom = 0x62003 + System Atom = 0x62306 + Tabindex Atom = 0x46308 + Table Atom = 0x42d05 + Target Atom = 0x24b06 + Tbody Atom = 0x2e05 + Td Atom = 0x4702 + Template Atom = 0x62608 + Textarea Atom = 0x2f608 + Tfoot Atom = 0x8c05 + Th Atom = 0x22e02 + Thead Atom = 0x2d405 + Time Atom = 0xdd04 + Title Atom = 0xa105 + Tr Atom = 0x10502 + Track Atom = 0x10505 + Translate Atom = 0x14009 + Tt Atom = 0x5302 + Type Atom = 0x21404 + Typemustmatch Atom = 0x2140d + U Atom = 0xb01 + Ul Atom = 0x8a02 + Usemap Atom = 0x51106 + Value Atom = 0x4005 + Var Atom = 0x11503 + Video Atom = 0x28105 + Wbr Atom = 0x12103 + Width Atom = 0x50705 + Wrap Atom = 0x58704 + Xmp Atom = 0xc103 ) const hash0 = 0xc17da63e -const maxAtomLen = 16 +const maxAtomLen = 19 var table = [1 << 9]Atom{ - 0x1: 0x4830b, // onmousemove - 0x2: 0x5a709, // onwaiting - 0x4: 0x5bf06, // prompt - 0x7: 0x5b007, // optimum + 0x1: 0x48a0b, // onmousemove + 0x2: 0x5e209, // onwaiting + 0x3: 0x1fa13, // onautocompleteerror + 0x4: 0x5fa06, // prompt + 0x7: 0x5eb07, // optimum 0x8: 0x1604, // mark - 0xa: 0x2d707, // itemref - 0xb: 0x4d90a, // onpageshow - 0xc: 0x55506, // select - 0xd: 0x1a109, // draggable + 0xa: 0x5ad07, // itemref + 0xb: 0x4fe0a, // onpageshow + 0xc: 0x57a06, // select + 0xd: 0x17b09, // draggable 0xe: 0x3e03, // nav - 0xf: 0x19b07, // command + 0xf: 0x17507, // command 0x11: 0xb01, // u - 0x14: 0x2fa07, // headers - 0x15: 0x44308, // datalist - 0x17: 0x6b04, // samp - 0x1a: 0x40409, // onkeydown - 0x1b: 0x53a08, // onscroll - 0x1c: 0x17603, // col - 0x20: 0x57e08, // itemprop - 0x21: 0x2a00a, // http-equiv - 0x22: 0x5e703, // sup - 0x24: 0x1f508, // required - 0x2b: 0x27f07, // preload - 0x2c: 0x21f0d, // onbeforeprint - 0x2d: 0x3710b, // ondragenter - 0x2e: 0x4e402, // dt - 0x2f: 0x57808, // onsubmit - 0x30: 0x13102, // hr - 0x31: 0x3460d, // oncontextmenu - 0x33: 0x2ba05, // image - 0x34: 0x4e807, // onpause - 0x35: 0x27a06, // hgroup - 0x36: 0xab04, // ping - 0x37: 0x55308, // onselect - 0x3a: 0x10703, // div - 0x40: 0x9b02, // mi - 0x41: 0x33308, // seamless + 0x14: 0x2d507, // headers + 0x15: 0x44a08, // datalist + 0x17: 0x4e04, // samp + 0x1a: 0x3fb09, // onkeydown + 0x1b: 0x55f08, // onscroll + 0x1c: 0x15003, // col + 0x20: 0x3c908, // itemprop + 0x21: 0x2780a, // http-equiv + 0x22: 0x61d03, // sup + 0x24: 0x1d008, // required + 0x2b: 0x25e07, // preload + 0x2c: 0x6040d, // onbeforeprint + 0x2d: 0x3600b, // ondragenter + 0x2e: 0x50902, // dt + 0x2f: 0x5a708, // onsubmit + 0x30: 0x27002, // hr + 0x31: 0x32f0d, // oncontextmenu + 0x33: 0x29c05, // image + 0x34: 0x50d07, // onpause + 0x35: 0x25906, // hgroup + 0x36: 0x7704, // ping + 0x37: 0x57808, // onselect + 0x3a: 0x11303, // div + 0x3b: 0x1fa0e, // onautocomplete + 0x40: 0x2eb02, // mi + 0x41: 0x31c08, // seamless 0x42: 0x2807, // charset - 0x43: 0x5102, // id - 0x44: 0x4fb0a, // onpopstate - 0x45: 0x4d603, // del - 0x46: 0x5f207, // marquee + 0x43: 0x8502, // id + 0x44: 0x5200a, // onpopstate + 0x45: 0x3ef03, // del + 0x46: 0x2cb07, // marquee 0x47: 0x3309, // accesskey - 0x49: 0x5906, // footer - 0x4a: 0x2d106, // applet - 0x4b: 0x2ce05, // ismap - 0x51: 0x34f04, // menu + 0x49: 0x8d06, // footer + 0x4a: 0x44e04, // list + 0x4b: 0x2b005, // ismap + 0x51: 0x33804, // menu 0x52: 0x2f04, // body - 0x55: 0x8708, // frameset - 0x56: 0x52507, // onreset - 0x57: 0x14705, // blink - 0x58: 0x8e05, // title - 0x59: 0x39907, // article - 0x5b: 0x13002, // th - 0x5d: 0x15101, // q - 0x5e: 0x58404, // open - 0x5f: 0x31804, // area - 0x61: 0x43b06, // onload - 0x62: 0x3f605, // input - 0x63: 0x11404, // base - 0x64: 0x18807, // colspan - 0x65: 0x51207, // keytype - 0x66: 0x13e02, // dl - 0x68: 0x1d508, // fieldset - 0x6a: 0x31003, // min - 0x6b: 0x10903, // var - 0x6f: 0x2fa06, // header - 0x70: 0x16502, // rt - 0x71: 0x17608, // colgroup - 0x72: 0x25402, // mn - 0x74: 0x16007, // onabort + 0x55: 0x9a08, // frameset + 0x56: 0x54a07, // onreset + 0x57: 0x12705, // blink + 0x58: 0xa105, // title + 0x59: 0x38807, // article + 0x5b: 0x22e02, // th + 0x5d: 0x13101, // q + 0x5e: 0x3cf04, // open + 0x5f: 0x2fa04, // area + 0x61: 0x44206, // onload + 0x62: 0xda04, // font + 0x63: 0xd604, // base + 0x64: 0x16207, // colspan + 0x65: 0x53707, // keytype + 0x66: 0x11e02, // dl + 0x68: 0x1b008, // fieldset + 0x6a: 0x2eb03, // min + 0x6b: 0x11503, // var + 0x6f: 0x2d506, // header + 0x70: 0x13f02, // rt + 0x71: 0x15008, // colgroup + 0x72: 0x23502, // mn + 0x74: 0x13a07, // onabort 0x75: 0x3906, // keygen - 0x76: 0x4bb09, // onoffline - 0x77: 0x23e09, // challenge - 0x78: 0x2d003, // map - 0x7a: 0x30e02, // h4 - 0x7b: 0x3c707, // onerror - 0x7c: 0x30609, // maxlength - 0x7d: 0x31305, // mtext - 0x7e: 0x5805, // tfoot - 0x7f: 0x11804, // font + 0x76: 0x4c209, // onoffline + 0x77: 0x21f09, // challenge + 0x78: 0x2b203, // map + 0x7a: 0x2e902, // h4 + 0x7b: 0x3b607, // onerror + 0x7c: 0x2e109, // maxlength + 0x7d: 0x2f505, // mtext + 0x7e: 0xbb07, // sandbox + 0x7f: 0x58b06, // onsort 0x80: 0x100a, // malignmark - 0x81: 0x45604, // meta - 0x82: 0x9305, // async - 0x83: 0x2c502, // h3 - 0x84: 0x28802, // dd - 0x85: 0x29804, // href - 0x86: 0xa20a, // mediagroup - 0x87: 0x1ba06, // coords - 0x88: 0x41a07, // srclang - 0x89: 0x35e0a, // ondblclick + 0x81: 0x45d04, // meta + 0x82: 0x7b05, // async + 0x83: 0x2a702, // h3 + 0x84: 0x26702, // dd + 0x85: 0x27004, // href + 0x86: 0x6e0a, // mediagroup + 0x87: 0x19406, // coords + 0x88: 0x41107, // srclang + 0x89: 0x34d0a, // ondblclick 0x8a: 0x4005, // value - 0x8c: 0xb308, // oncancel - 0x8e: 0x33a0a, // spellcheck - 0x8f: 0x8705, // frame - 0x91: 0x14403, // big - 0x94: 0x21b06, // action - 0x95: 0x9d03, // dir - 0x97: 0x31908, // readonly - 0x99: 0x43605, // table - 0x9a: 0x5e007, // summary - 0x9b: 0x14103, // wbr + 0x8c: 0xe908, // oncancel + 0x8e: 0x3230a, // spellcheck + 0x8f: 0x9a05, // frame + 0x91: 0x12403, // big + 0x94: 0x1f606, // action + 0x95: 0x6903, // dir + 0x97: 0x2fb08, // readonly + 0x99: 0x42d05, // table + 0x9a: 0x61607, // summary + 0x9b: 0x12103, // wbr 0x9c: 0x30a, // radiogroup - 0x9d: 0xa004, // name - 0x9f: 0x5ed06, // system - 0xa1: 0x18305, // color - 0xa2: 0x4b06, // canvas - 0xa3: 0x27604, // html - 0xa5: 0x54a09, // onseeking - 0xac: 0x1b505, // shape - 0xad: 0x28003, // rel - 0xae: 0x12710, // oncanplaythrough - 0xaf: 0x3870a, // ondragover - 0xb1: 0x1fd0d, // foreignObject - 0xb3: 0x7704, // rows - 0xb6: 0x44707, // listing - 0xb7: 0x49506, // output - 0xb9: 0x3480b, // contextmenu - 0xbb: 0x13f03, // low - 0xbc: 0x1eb02, // rp - 0xbd: 0x58809, // onsuspend - 0xbe: 0x15c06, // button - 0xbf: 0x4804, // desc - 0xc1: 0x3dd07, // section - 0xc2: 0x5050a, // onprogress - 0xc3: 0x56f09, // onstorage - 0xc4: 0x2f704, // math - 0xc5: 0x4f206, // onplay - 0xc7: 0x5602, // ul - 0xc8: 0x6e07, // pattern - 0xc9: 0x4af0c, // onmousewheel - 0xca: 0x36809, // ondragend - 0xcb: 0xd104, // ruby + 0x9d: 0x6c04, // name + 0x9f: 0x62306, // system + 0xa1: 0x15d05, // color + 0xa2: 0x7f06, // canvas + 0xa3: 0x25504, // html + 0xa5: 0x56f09, // onseeking + 0xac: 0x4f905, // shape + 0xad: 0x25f03, // rel + 0xae: 0x28510, // oncanplaythrough + 0xaf: 0x3760a, // ondragover + 0xb0: 0x62608, // template + 0xb1: 0x1d80d, // foreignObject + 0xb3: 0x9204, // rows + 0xb6: 0x44e07, // listing + 0xb7: 0x49c06, // output + 0xb9: 0x3310b, // contextmenu + 0xbb: 0x11f03, // low + 0xbc: 0x1c602, // rp + 0xbd: 0x5bb09, // onsuspend + 0xbe: 0x13606, // button + 0xbf: 0x4db04, // desc + 0xc1: 0x4e207, // section + 0xc2: 0x52a0a, // onprogress + 0xc3: 0x59e09, // onstorage + 0xc4: 0x2d204, // math + 0xc5: 0x4503, // alt + 0xc7: 0x8a02, // ul + 0xc8: 0x5107, // pattern + 0xc9: 0x4b60c, // onmousewheel + 0xca: 0x35709, // ondragend + 0xcb: 0xaf04, // ruby 0xcc: 0xc01, // p - 0xcd: 0x32e07, // onclose - 0xce: 0x26105, // meter - 0xcf: 0x13807, // bgsound - 0xd2: 0x27206, // height + 0xcd: 0x31707, // onclose + 0xce: 0x24205, // meter + 0xcf: 0x11807, // bgsound + 0xd2: 0x25106, // height 0xd4: 0x101, // b - 0xd5: 0x2ef08, // itemtype - 0xd8: 0x1e007, // caption - 0xd9: 0x10008, // disabled - 0xdc: 0x5ea03, // svg - 0xdd: 0x1bf05, // small - 0xde: 0x44304, // data - 0xe0: 0x4c608, // ononline - 0xe1: 0x2c006, // mglyph - 0xe3: 0x7f05, // embed - 0xe4: 0xf902, // tr - 0xe5: 0x4640b, // onloadstart - 0xe7: 0x3b010, // ondurationchange - 0xed: 0x12503, // bdo + 0xd5: 0x2c308, // itemtype + 0xd8: 0x1bb07, // caption + 0xd9: 0x10c08, // disabled + 0xdb: 0x33808, // menuitem + 0xdc: 0x62003, // svg + 0xdd: 0x18f05, // small + 0xde: 0x44a04, // data + 0xe0: 0x4cb08, // ononline + 0xe1: 0x2a206, // mglyph + 0xe3: 0x6505, // embed + 0xe4: 0x10502, // tr + 0xe5: 0x46b0b, // onloadstart + 0xe7: 0x3c306, // srcdoc + 0xeb: 0x5c408, // ontoggle + 0xed: 0xe703, // bdo 0xee: 0x4702, // td - 0xef: 0x4f05, // aside - 0xf0: 0x29602, // h2 - 0xf1: 0x50708, // progress - 0xf2: 0x14c0a, // blockquote - 0xf4: 0xba05, // label + 0xef: 0x8305, // aside + 0xf0: 0x29402, // h2 + 0xf1: 0x52c08, // progress + 0xf2: 0x12c0a, // blockquote + 0xf4: 0xf005, // label 0xf5: 0x601, // i - 0xf7: 0x7707, // rowspan - 0xfb: 0x4f209, // onplaying - 0xfd: 0x2bf03, // img - 0xfe: 0xc008, // optgroup - 0xff: 0x42c07, // content - 0x101: 0x5190c, // onratechange - 0x103: 0x3e80c, // onhashchange - 0x104: 0x6507, // details - 0x106: 0x40908, // download - 0x109: 0xe907, // sandbox - 0x10b: 0x42c0f, // contenteditable - 0x10d: 0x37c0b, // ondragleave + 0xf7: 0x9207, // rowspan + 0xfb: 0x51709, // onplaying + 0xfd: 0x2a103, // img + 0xfe: 0xf608, // optgroup + 0xff: 0x42307, // content + 0x101: 0x53e0c, // onratechange + 0x103: 0x3da0c, // onhashchange + 0x104: 0x4807, // details + 0x106: 0x40008, // download + 0x109: 0x14009, // translate + 0x10b: 0x4230f, // contenteditable + 0x10d: 0x36b0b, // ondragleave 0x10e: 0x2106, // accept - 0x10f: 0x55508, // selected - 0x112: 0x2170a, // formaction - 0x113: 0x2df06, // center - 0x115: 0x44e10, // onloadedmetadata - 0x116: 0x14804, // link - 0x117: 0x11b04, // time - 0x118: 0x1c40b, // crossorigin - 0x119: 0x3ce07, // onfocus - 0x11a: 0x56204, // wrap - 0x11b: 0x42b04, // icon - 0x11d: 0x2a905, // video - 0x11e: 0x3d905, // class - 0x121: 0x5990e, // onvolumechange - 0x122: 0x3e206, // onblur - 0x123: 0x2e509, // itemscope - 0x124: 0x5db05, // style - 0x127: 0x42706, // public - 0x129: 0x2510e, // formnovalidate - 0x12a: 0x55d06, // onshow - 0x12c: 0x16609, // translate - 0x12d: 0x9704, // cite - 0x12e: 0x2e802, // ms - 0x12f: 0x1190c, // ontimeupdate - 0x130: 0xfd04, // kind - 0x131: 0x2660a, // formtarget - 0x135: 0x3c007, // onended - 0x136: 0x28606, // hidden + 0x10f: 0x57a08, // selected + 0x112: 0x1f20a, // formaction + 0x113: 0x5b506, // center + 0x115: 0x45510, // onloadedmetadata + 0x116: 0x12804, // link + 0x117: 0xdd04, // time + 0x118: 0x19f0b, // crossorigin + 0x119: 0x3bd07, // onfocus + 0x11a: 0x58704, // wrap + 0x11b: 0x42204, // icon + 0x11d: 0x28105, // video + 0x11e: 0x4de05, // class + 0x121: 0x5d40e, // onvolumechange + 0x122: 0xaa06, // onblur + 0x123: 0x2b909, // itemscope + 0x124: 0x61105, // style + 0x127: 0x41e06, // public + 0x129: 0x2320e, // formnovalidate + 0x12a: 0x58206, // onshow + 0x12c: 0x51706, // onplay + 0x12d: 0x3c804, // cite + 0x12e: 0x2bc02, // ms + 0x12f: 0xdb0c, // ontimeupdate + 0x130: 0x10904, // kind + 0x131: 0x2470a, // formtarget + 0x135: 0x3af07, // onended + 0x136: 0x26506, // hidden 0x137: 0x2c01, // s - 0x139: 0x2470a, // formmethod - 0x13a: 0x44704, // list - 0x13c: 0x27002, // h6 - 0x13d: 0xcd02, // ol - 0x13e: 0x3530b, // oncuechange - 0x13f: 0x20a0d, // foreignobject - 0x143: 0x5c90e, // onbeforeunload - 0x145: 0x3a709, // onemptied - 0x146: 0x17105, // defer - 0x147: 0xef03, // xmp - 0x148: 0xaf05, // audio + 0x139: 0x2280a, // formmethod + 0x13a: 0x3e805, // input + 0x13c: 0x50b02, // h6 + 0x13d: 0xc902, // ol + 0x13e: 0x3420b, // oncuechange + 0x13f: 0x1e50d, // foreignobject + 0x143: 0x4e70e, // onbeforeunload + 0x144: 0x2bd05, // scope + 0x145: 0x39609, // onemptied + 0x146: 0x14b05, // defer + 0x147: 0xc103, // xmp + 0x148: 0x39f10, // ondurationchange 0x149: 0x1903, // kbd - 0x14c: 0x46f09, // onmessage - 0x14d: 0x5c506, // option - 0x14e: 0x4503, // alt - 0x14f: 0x33f07, // checked - 0x150: 0x10c08, // autoplay + 0x14c: 0x47609, // onmessage + 0x14d: 0x60006, // option + 0x14e: 0x2eb09, // minlength + 0x14f: 0x32807, // checked + 0x150: 0xce08, // autoplay 0x152: 0x202, // br - 0x153: 0x2550a, // novalidate - 0x156: 0x7d07, // noembed - 0x159: 0x2ad07, // onclick - 0x15a: 0x4780b, // onmousedown - 0x15b: 0x3b808, // onchange - 0x15e: 0x3fb09, // oninvalid - 0x15f: 0x2e906, // scoped - 0x160: 0x1ae08, // controls - 0x161: 0x32905, // muted - 0x163: 0x4ec06, // usemap - 0x164: 0x1dd0a, // figcaption - 0x165: 0x36806, // ondrag - 0x166: 0x29304, // high - 0x168: 0x3d403, // src - 0x169: 0x17d06, // poster - 0x16b: 0x18d0e, // annotation-xml - 0x16c: 0x5bc04, // step + 0x153: 0x2360a, // novalidate + 0x156: 0x6307, // noembed + 0x159: 0x31007, // onclick + 0x15a: 0x47f0b, // onmousedown + 0x15b: 0x3a708, // onchange + 0x15e: 0x3f209, // oninvalid + 0x15f: 0x2bd06, // scoped + 0x160: 0x18808, // controls + 0x161: 0x30b05, // muted + 0x162: 0x58d08, // sortable + 0x163: 0x51106, // usemap + 0x164: 0x1b80a, // figcaption + 0x165: 0x35706, // ondrag + 0x166: 0x26b04, // high + 0x168: 0x3c303, // src + 0x169: 0x15706, // poster + 0x16b: 0x1670e, // annotation-xml + 0x16c: 0x5f704, // step 0x16d: 0x4, // abbr 0x16e: 0x1b06, // dialog 0x170: 0x1202, // li - 0x172: 0x47a02, // mo - 0x175: 0x1fd03, // for - 0x176: 0x1cd03, // ins - 0x178: 0x53004, // size - 0x17a: 0x5207, // default + 0x172: 0x3ed02, // mo + 0x175: 0x1d803, // for + 0x176: 0x1a803, // ins + 0x178: 0x55504, // size + 0x179: 0x43210, // onlanguagechange + 0x17a: 0x8607, // default 0x17b: 0x1a03, // bdi - 0x17c: 0x4ce0a, // onpagehide - 0x17d: 0x9d07, // dirname - 0x17e: 0x23304, // type - 0x17f: 0x21704, // form - 0x180: 0x4c105, // inert - 0x181: 0x12709, // oncanplay - 0x182: 0x8303, // dfn - 0x183: 0x45c08, // tabindex - 0x186: 0x7f02, // em - 0x187: 0x29c04, // lang - 0x189: 0x3a208, // dropzone - 0x18a: 0x4110a, // onkeypress - 0x18b: 0x25b08, // datetime - 0x18c: 0x18804, // cols + 0x17c: 0x4d30a, // onpagehide + 0x17d: 0x6907, // dirname + 0x17e: 0x21404, // type + 0x17f: 0x1f204, // form + 0x181: 0x28509, // oncanplay + 0x182: 0x6103, // dfn + 0x183: 0x46308, // tabindex + 0x186: 0x6502, // em + 0x187: 0x27404, // lang + 0x189: 0x39108, // dropzone + 0x18a: 0x4080a, // onkeypress + 0x18b: 0x23c08, // datetime + 0x18c: 0x16204, // cols 0x18d: 0x1, // a - 0x18e: 0x43b0c, // onloadeddata - 0x191: 0x15606, // border + 0x18e: 0x4420c, // onloadeddata + 0x190: 0xa605, // audio 0x192: 0x2e05, // tbody - 0x193: 0x24b06, // method - 0x195: 0xbe04, // loop - 0x196: 0x2b406, // iframe - 0x198: 0x2fa04, // head - 0x19e: 0x5b608, // manifest - 0x19f: 0xe109, // autofocus - 0x1a0: 0x16f04, // code - 0x1a1: 0x53406, // strong - 0x1a2: 0x32108, // multiple + 0x193: 0x22c06, // method + 0x195: 0xf404, // loop + 0x196: 0x29606, // iframe + 0x198: 0x2d504, // head + 0x19e: 0x5f108, // manifest + 0x19f: 0xb309, // autofocus + 0x1a0: 0x14904, // code + 0x1a1: 0x55906, // strong + 0x1a2: 0x30308, // multiple 0x1a3: 0xc05, // param - 0x1a6: 0x23007, // enctype - 0x1a7: 0x2dd04, // face - 0x1a8: 0xf109, // plaintext - 0x1a9: 0x13602, // h1 - 0x1aa: 0x56609, // onstalled - 0x1ad: 0x28d06, // script - 0x1ae: 0x30006, // spacer - 0x1af: 0x52c08, // onresize - 0x1b0: 0x49b0b, // onmouseover - 0x1b1: 0x59108, // onunload - 0x1b2: 0x54208, // onseeked - 0x1b4: 0x2330d, // typemustmatch - 0x1b5: 0x1f106, // figure - 0x1b6: 0x48e0a, // onmouseout - 0x1b7: 0x27f03, // pre - 0x1b8: 0x4e205, // width - 0x1bb: 0x7404, // nobr - 0x1be: 0x7002, // tt + 0x1a6: 0x21107, // enctype + 0x1a7: 0x5b304, // face + 0x1a8: 0xfd09, // plaintext + 0x1a9: 0x26e02, // h1 + 0x1aa: 0x59509, // onstalled + 0x1ad: 0x3d406, // script + 0x1ae: 0x2db06, // spacer + 0x1af: 0x55108, // onresize + 0x1b0: 0x4a20b, // onmouseover + 0x1b1: 0x5cc08, // onunload + 0x1b2: 0x56708, // onseeked + 0x1b4: 0x2140d, // typemustmatch + 0x1b5: 0x1cc06, // figure + 0x1b6: 0x4950a, // onmouseout + 0x1b7: 0x25e03, // pre + 0x1b8: 0x50705, // width + 0x1b9: 0x19906, // sorted + 0x1bb: 0x5704, // nobr + 0x1be: 0x5302, // tt 0x1bf: 0x1105, // align - 0x1c0: 0x3f407, // oninput - 0x1c3: 0x42107, // onkeyup - 0x1c6: 0x1e50c, // onafterprint + 0x1c0: 0x3e607, // oninput + 0x1c3: 0x41807, // onkeyup + 0x1c6: 0x1c00c, // onafterprint 0x1c7: 0x210e, // accept-charset - 0x1c8: 0x9806, // itemid - 0x1cb: 0x50e06, // strike - 0x1cc: 0x57a03, // sub - 0x1cd: 0xf905, // track - 0x1ce: 0x39705, // start - 0x1d0: 0x11408, // basefont - 0x1d6: 0x1cf06, // source - 0x1d7: 0x1a806, // legend - 0x1d8: 0x2f905, // thead - 0x1da: 0x2e905, // scope - 0x1dd: 0x21106, // object - 0x1de: 0xa205, // media - 0x1df: 0x18d0a, // annotation - 0x1e0: 0x22c0b, // formenctype - 0x1e2: 0x28b08, // noscript - 0x1e4: 0x53005, // sizes - 0x1e5: 0xd50c, // autocomplete - 0x1e6: 0x7a04, // span - 0x1e7: 0x8508, // noframes - 0x1e8: 0x26a06, // target - 0x1e9: 0x3a006, // ondrop - 0x1ea: 0x3d406, // srcdoc - 0x1ec: 0x5e08, // reversed - 0x1f0: 0x2c707, // isindex - 0x1f3: 0x29808, // hreflang - 0x1f5: 0x4e602, // h5 - 0x1f6: 0x5d507, // address - 0x1fa: 0x30603, // max - 0x1fb: 0xc70b, // placeholder - 0x1fc: 0x31408, // textarea - 0x1fe: 0x4a609, // onmouseup - 0x1ff: 0x3910b, // ondragstart + 0x1c8: 0x33c06, // itemid + 0x1c9: 0x3e809, // inputmode + 0x1cb: 0x53306, // strike + 0x1cc: 0x5a903, // sub + 0x1cd: 0x10505, // track + 0x1ce: 0x38605, // start + 0x1d0: 0xd608, // basefont + 0x1d6: 0x1aa06, // source + 0x1d7: 0x18206, // legend + 0x1d8: 0x2d405, // thead + 0x1da: 0x8c05, // tfoot + 0x1dd: 0x1ec06, // object + 0x1de: 0x6e05, // media + 0x1df: 0x1670a, // annotation + 0x1e0: 0x20d0b, // formenctype + 0x1e2: 0x3d208, // noscript + 0x1e4: 0x55505, // sizes + 0x1e5: 0x1fc0c, // autocomplete + 0x1e6: 0x9504, // span + 0x1e7: 0x9808, // noframes + 0x1e8: 0x24b06, // target + 0x1e9: 0x38f06, // ondrop + 0x1ea: 0x2b306, // applet + 0x1ec: 0x5a08, // reversed + 0x1f0: 0x2a907, // isindex + 0x1f3: 0x27008, // hreflang + 0x1f5: 0x2f302, // h5 + 0x1f6: 0x4f307, // address + 0x1fa: 0x2e103, // max + 0x1fb: 0xc30b, // placeholder + 0x1fc: 0x2f608, // textarea + 0x1fe: 0x4ad09, // onmouseup + 0x1ff: 0x3800b, // ondragstart } const atomText = "abbradiogrouparamalignmarkbdialogaccept-charsetbodyaccesskey" + - "genavaluealtdescanvasidefaultfootereversedetailsampatternobr" + - "owspanoembedfnoframesetitleasyncitemidirnamediagroupingaudio" + - "ncancelabelooptgrouplaceholderubyautocompleteautofocusandbox" + - "mplaintextrackindisabledivarautoplaybasefontimeupdatebdoncan" + - "playthrough1bgsoundlowbrbigblinkblockquoteborderbuttonabortr" + - "anslatecodefercolgroupostercolorcolspannotation-xmlcommandra" + - "ggablegendcontrolshapecoordsmallcrossoriginsourcefieldsetfig" + - "captionafterprintfigurequiredforeignObjectforeignobjectforma" + - "ctionbeforeprintformenctypemustmatchallengeformmethodformnov" + - "alidatetimeterformtargeth6heightmlhgroupreloadhiddenoscripth" + - "igh2hreflanghttp-equivideonclickiframeimageimglyph3isindexis" + - "mappletitemrefacenteritemscopeditemtypematheaderspacermaxlen" + - "gth4minmtextareadonlymultiplemutedoncloseamlesspellcheckedon" + - "contextmenuoncuechangeondblclickondragendondragenterondragle" + - "aveondragoverondragstarticleondropzonemptiedondurationchange" + - "onendedonerroronfocusrcdoclassectionbluronhashchangeoninputo" + - "ninvalidonkeydownloadonkeypressrclangonkeyupublicontentedita" + - "bleonloadeddatalistingonloadedmetadatabindexonloadstartonmes" + - "sageonmousedownonmousemoveonmouseoutputonmouseoveronmouseupo" + - "nmousewheelonofflinertononlineonpagehidelonpageshowidth5onpa" + - "usemaponplayingonpopstateonprogresstrikeytypeonratechangeonr" + - "esetonresizestrongonscrollonseekedonseekingonselectedonshowr" + - "aponstalledonstorageonsubmitempropenonsuspendonunloadonvolum" + - "echangeonwaitingoptimumanifestepromptoptionbeforeunloaddress" + - "tylesummarysupsvgsystemarquee" + "genavaluealtdetailsampatternobreversedfnoembedirnamediagroup" + + "ingasyncanvasidefaultfooterowspanoframesetitleaudionblurubya" + + "utofocusandboxmplaceholderautoplaybasefontimeupdatebdoncance" + + "labelooptgrouplaintextrackindisabledivarbgsoundlowbrbigblink" + + "blockquotebuttonabortranslatecodefercolgroupostercolorcolspa" + + "nnotation-xmlcommandraggablegendcontrolsmallcoordsortedcross" + + "originsourcefieldsetfigcaptionafterprintfigurequiredforeignO" + + "bjectforeignobjectformactionautocompleteerrorformenctypemust" + + "matchallengeformmethodformnovalidatetimeterformtargetheightm" + + "lhgroupreloadhiddenhigh1hreflanghttp-equivideoncanplaythroug" + + "h2iframeimageimglyph3isindexismappletitemscopeditemtypemarqu" + + "eematheaderspacermaxlength4minlength5mtextareadonlymultiplem" + + "utedonclickoncloseamlesspellcheckedoncontextmenuitemidoncuec" + + "hangeondblclickondragendondragenterondragleaveondragoverondr" + + "agstarticleondropzonemptiedondurationchangeonendedonerroronf" + + "ocusrcdocitempropenoscriptonhashchangeoninputmodeloninvalido" + + "nkeydownloadonkeypressrclangonkeyupublicontenteditableonlang" + + "uagechangeonloadeddatalistingonloadedmetadatabindexonloadsta" + + "rtonmessageonmousedownonmousemoveonmouseoutputonmouseoveronm" + + "ouseuponmousewheelonofflineononlineonpagehidesclassectionbef" + + "oreunloaddresshapeonpageshowidth6onpausemaponplayingonpopsta" + + "teonprogresstrikeytypeonratechangeonresetonresizestrongonscr" + + "ollonseekedonseekingonselectedonshowraponsortableonstalledon" + + "storageonsubmitemrefacenteronsuspendontoggleonunloadonvolume" + + "changeonwaitingoptimumanifestepromptoptionbeforeprintstylesu" + + "mmarysupsvgsystemplate" diff --git a/Godeps/_workspace/src/golang.org/x/net/html/atom/table_test.go b/Godeps/_workspace/src/golang.org/x/net/html/atom/table_test.go index db016a1c01c..0f2ecce4fd4 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/atom/table_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/atom/table_test.go @@ -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", diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/charset.go b/Godeps/_workspace/src/golang.org/x/net/html/charset/charset.go index b19f83b7276..fd7eb585d82 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/charset/charset.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/charset.go @@ -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 { diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/charset_test.go b/Godeps/_workspace/src/golang.org/x/net/html/charset/charset_test.go index d309f75c621..8b10399d3d7 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/charset/charset_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/charset_test.go @@ -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 = "r\xe9sum\xe9" + + 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) + } +} diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/gen.go b/Godeps/_workspace/src/golang.org/x/net/html/charset/gen.go index 8b769099662..828347f4aec 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/charset/gen.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/gen.go @@ -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) diff --git a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README index a8e1fa471f1..38ef0f9f121 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README +++ b/Godeps/_workspace/src/golang.org/x/net/html/charset/testdata/README @@ -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). diff --git a/Godeps/_workspace/src/golang.org/x/net/html/const.go b/Godeps/_workspace/src/golang.org/x/net/html/const.go index d7cc8bb9a99..52f651ff6db 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/const.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/const.go @@ -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, diff --git a/Godeps/_workspace/src/golang.org/x/net/html/doc.go b/Godeps/_workspace/src/golang.org/x/net/html/doc.go index fac0f54e78a..b453fe1e4c2 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/doc.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/doc.go @@ -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 diff --git a/Godeps/_workspace/src/golang.org/x/net/html/entity.go b/Godeps/_workspace/src/golang.org/x/net/html/entity.go index af8a007ed04..a50c04c60e9 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/entity.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/entity.go @@ -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 diff --git a/Godeps/_workspace/src/golang.org/x/net/html/escape.go b/Godeps/_workspace/src/golang.org/x/net/html/escape.go index 75bddff094f..d8561396200 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/escape.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/escape.go @@ -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:] diff --git a/Godeps/_workspace/src/golang.org/x/net/html/parse.go b/Godeps/_workspace/src/golang.org/x/net/html/parse.go index b42a3238fff..be4b2bf5aa9 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/parse.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/parse.go @@ -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 { diff --git a/Godeps/_workspace/src/golang.org/x/net/html/render.go b/Godeps/_workspace/src/golang.org/x/net/html/render.go index 4a833b44012..d34564f49dd 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/render.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/render.go @@ -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) } diff --git a/Godeps/_workspace/src/golang.org/x/net/html/token_test.go b/Godeps/_workspace/src/golang.org/x/net/html/token_test.go index f6988a88968..20221c32840 100644 --- a/Godeps/_workspace/src/golang.org/x/net/html/token_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/html/token_test.go @@ -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", ``, diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/client.go b/Godeps/_workspace/src/golang.org/x/net/websocket/client.go index a861bb92c6c..20d1e1e38eb 100644 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/client.go +++ b/Godeps/_workspace/src/golang.org/x/net/websocket/client.go @@ -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 diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go b/Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go index f8c0b2e2994..60bbc841890 100644 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go +++ b/Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go @@ -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) diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go b/Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go index d6a19108a6d..9504aa2d30b 100644 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go @@ -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) diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/server.go b/Godeps/_workspace/src/golang.org/x/net/websocket/server.go index 70322133c49..0895dea1905 100644 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/server.go +++ b/Godeps/_workspace/src/golang.org/x/net/websocket/server.go @@ -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) { diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go b/Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go index 0f4917bf7e6..da0dd964c37 100644 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go +++ b/Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go @@ -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 } diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go b/Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go index 48f14b696fa..05b7e5356e4 100644 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go @@ -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) + } + } +}