Update x/net (#5169)

This commit is contained in:
Antoine GIRARD 2018-10-27 01:05:56 +02:00 committed by techknowlogick
parent f887085ee0
commit 2af57c7820
16 changed files with 3452 additions and 3034 deletions

5
Gopkg.lock generated
View File

@ -746,7 +746,8 @@
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e" revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
[[projects]] [[projects]]
digest = "1:47ea747d07fae720d749d06ac5dc5ded0df70c57e328b6549cf2d9c64698757e" branch = "master"
digest = "1:6d5ed712653ea5321fe3e3475ab2188cf362a4e0d31e9fd3acbd4dfbbca0d680"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"context", "context",
@ -755,7 +756,7 @@
"html/charset", "html/charset",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d" revision = "9b4f9f5ad5197c79fd623a3638e70d8b26cef344"
[[projects]] [[projects]]
digest = "1:8159a9cda4b8810aaaeb0d60e2fa68e2fd86d8af4ec8f5059830839e3c8d93d5" digest = "1:8159a9cda4b8810aaaeb0d60e2fa68e2fd86d8af4ec8f5059830839e3c8d93d5"

View File

@ -27,7 +27,7 @@ ignored = ["google.golang.org/appengine*"]
name = "golang.org/x/text" name = "golang.org/x/text"
[[constraint]] [[constraint]]
revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d" branch = "master"
name = "golang.org/x/net" name = "golang.org/x/net"
[[override]] [[override]]

View File

@ -5,9 +5,11 @@
// Package context defines the Context type, which carries deadlines, // Package context defines the Context type, which carries deadlines,
// cancelation signals, and other request-scoped values across API boundaries // cancelation signals, and other request-scoped values across API boundaries
// and between processes. // and between processes.
// As of Go 1.7 this package is available in the standard library under the
// name context. https://golang.org/pkg/context.
// //
// Incoming requests to a server should create a Context, and outgoing calls to // Incoming requests to a server should create a Context, and outgoing calls to
// servers should accept a Context. The chain of function calls between must // servers should accept a Context. The chain of function calls between must
// propagate the Context, optionally replacing it with a modified copy created // propagate the Context, optionally replacing it with a modified copy created
// using WithDeadline, WithTimeout, WithCancel, or WithValue. // using WithDeadline, WithTimeout, WithCancel, or WithValue.
// //
@ -16,14 +18,14 @@
// propagation: // propagation:
// //
// Do not store Contexts inside a struct type; instead, pass a Context // Do not store Contexts inside a struct type; instead, pass a Context
// explicitly to each function that needs it. The Context should be the first // explicitly to each function that needs it. The Context should be the first
// parameter, typically named ctx: // parameter, typically named ctx:
// //
// func DoSomething(ctx context.Context, arg Arg) error { // func DoSomething(ctx context.Context, arg Arg) error {
// // ... use ctx ... // // ... use ctx ...
// } // }
// //
// Do not pass a nil Context, even if a function permits it. Pass context.TODO // Do not pass a nil Context, even if a function permits it. Pass context.TODO
// if you are unsure about which Context to use. // if you are unsure about which Context to use.
// //
// Use context Values only for request-scoped data that transits processes and // Use context Values only for request-scoped data that transits processes and
@ -36,112 +38,15 @@
// Contexts. // Contexts.
package context // import "golang.org/x/net/context" package context // import "golang.org/x/net/context"
import "time"
// A Context carries a deadline, a cancelation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
//
// WithCancel arranges for Done to be closed when cancel is called;
// WithDeadline arranges for Done to be closed when the deadline
// expires; WithTimeout arranges for Done to be closed when the timeout
// elapses.
//
// Done is provided for use in select statements:
//
// // 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.
Done() <-chan struct{}
// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
Err() error
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
//
// Use context values only for request-scoped data that transits
// processes and API boundaries, not for passing optional parameters to
// functions.
//
// A key identifies a specific value in a Context. Functions that wish
// to store values in Context typically allocate a key in a global
// variable then use that key as the argument to context.WithValue and
// Context.Value. A key can be any type that supports equality;
// packages should define keys as an unexported type to avoid
// collisions.
//
// Packages that define a Context key should provide type-safe accessors
// for the values stores using that key:
//
// // Package user defines a User type that's stored in Contexts.
// package user
//
// import "golang.org/x/net/context"
//
// // User is the type of value stored in the Contexts.
// type User struct {...}
//
// // key is an unexported type for keys defined in this package.
// // This prevents collisions with keys defined in other packages.
// type key int
//
// // userKey is the key for user.User values in Contexts. It is
// // unexported; clients use user.NewContext and user.FromContext
// // instead of using this key directly.
// var userKey key = 0
//
// // NewContext returns a new Context that carries value u.
// func NewContext(ctx context.Context, u *User) context.Context {
// return context.WithValue(ctx, userKey, u)
// }
//
// // FromContext returns the User value stored in ctx, if any.
// func FromContext(ctx context.Context) (*User, bool) {
// u, ok := ctx.Value(userKey).(*User)
// return u, ok
// }
Value(key interface{}) interface{}
}
// Background returns a non-nil, empty Context. It is never canceled, has no // Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function, // values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming // initialization, and tests, and as the top-level Context for incoming
// requests. // requests.
func Background() Context { func Background() Context {
return background return background
} }
// TODO returns a non-nil, empty Context. Code should use context.TODO when // TODO returns a non-nil, empty Context. Code should use context.TODO when
// it's unclear which Context to use or it is not yet available (because the // it's unclear which Context to use or it is not yet available (because the
// surrounding function has not yet been extended to accept a Context // surrounding function has not yet been extended to accept a Context
// parameter). TODO is recognized by static analysis tools that determine // parameter). TODO is recognized by static analysis tools that determine
@ -149,8 +54,3 @@ func Background() Context {
func TODO() Context { func TODO() Context {
return todo return todo
} }
// A CancelFunc tells an operation to abandon its work.
// A CancelFunc does not wait for the work to stop.
// After the first call, subsequent calls to a CancelFunc do nothing.
type CancelFunc func()

View File

@ -35,8 +35,8 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
} }
// WithDeadline returns a copy of the parent context with the deadline adjusted // WithDeadline returns a copy of the parent context with the deadline adjusted
// to be no later than d. If the parent's deadline is already earlier than d, // to be no later than d. If the parent's deadline is already earlier than d,
// WithDeadline(parent, d) is semantically equivalent to parent. The returned // WithDeadline(parent, d) is semantically equivalent to parent. The returned
// context's Done channel is closed when the deadline expires, when the returned // context's Done channel is closed when the deadline expires, when the returned
// cancel function is called, or when the parent context's Done channel is // cancel function is called, or when the parent context's Done channel is
// closed, whichever happens first. // closed, whichever happens first.

20
vendor/golang.org/x/net/context/go19.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2017 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.9
package context
import "context" // standard library's context, as of Go 1.7
// A Context carries a deadline, a cancelation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
type Context = context.Context
// A CancelFunc tells an operation to abandon its work.
// A CancelFunc does not wait for the work to stop.
// After the first call, subsequent calls to a CancelFunc do nothing.
type CancelFunc = context.CancelFunc

View File

@ -13,7 +13,7 @@ import (
"time" "time"
) )
// An emptyCtx is never canceled, has no values, and has no deadline. It is not // An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses. // struct{}, since vars of this type must have distinct addresses.
type emptyCtx int type emptyCtx int
@ -104,7 +104,7 @@ func propagateCancel(parent Context, child canceler) {
} }
// parentCancelCtx follows a chain of parent references until it finds a // parentCancelCtx follows a chain of parent references until it finds a
// *cancelCtx. This function understands how each of the concrete types in this // *cancelCtx. This function understands how each of the concrete types in this
// package represents its parent. // package represents its parent.
func parentCancelCtx(parent Context) (*cancelCtx, bool) { func parentCancelCtx(parent Context) (*cancelCtx, bool) {
for { for {
@ -134,14 +134,14 @@ func removeChild(parent Context, child canceler) {
p.mu.Unlock() p.mu.Unlock()
} }
// A canceler is a context type that can be canceled directly. The // A canceler is a context type that can be canceled directly. The
// implementations are *cancelCtx and *timerCtx. // implementations are *cancelCtx and *timerCtx.
type canceler interface { type canceler interface {
cancel(removeFromParent bool, err error) cancel(removeFromParent bool, err error)
Done() <-chan struct{} Done() <-chan struct{}
} }
// A cancelCtx can be canceled. When canceled, it also cancels any children // A cancelCtx can be canceled. When canceled, it also cancels any children
// that implement canceler. // that implement canceler.
type cancelCtx struct { type cancelCtx struct {
Context Context
@ -193,8 +193,8 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
} }
// WithDeadline returns a copy of the parent context with the deadline adjusted // WithDeadline returns a copy of the parent context with the deadline adjusted
// to be no later than d. If the parent's deadline is already earlier than d, // to be no later than d. If the parent's deadline is already earlier than d,
// WithDeadline(parent, d) is semantically equivalent to parent. The returned // WithDeadline(parent, d) is semantically equivalent to parent. The returned
// context's Done channel is closed when the deadline expires, when the returned // context's Done channel is closed when the deadline expires, when the returned
// cancel function is called, or when the parent context's Done channel is // cancel function is called, or when the parent context's Done channel is
// closed, whichever happens first. // closed, whichever happens first.
@ -226,8 +226,8 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
return c, func() { c.cancel(true, Canceled) } return c, func() { c.cancel(true, Canceled) }
} }
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
// implement Done and Err. It implements cancel by stopping its timer then // implement Done and Err. It implements cancel by stopping its timer then
// delegating to cancelCtx.cancel. // delegating to cancelCtx.cancel.
type timerCtx struct { type timerCtx struct {
*cancelCtx *cancelCtx
@ -281,7 +281,7 @@ func WithValue(parent Context, key interface{}, val interface{}) Context {
return &valueCtx{parent, key, val} return &valueCtx{parent, key, val}
} }
// A valueCtx carries a key-value pair. It implements Value for that key and // A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context. // delegates all other calls to the embedded Context.
type valueCtx struct { type valueCtx struct {
Context Context

109
vendor/golang.org/x/net/context/pre_go19.go generated vendored Normal file
View File

@ -0,0 +1,109 @@
// Copyright 2014 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.9
package context
import "time"
// A Context carries a deadline, a cancelation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
//
// WithCancel arranges for Done to be closed when cancel is called;
// WithDeadline arranges for Done to be closed when the deadline
// expires; WithTimeout arranges for Done to be closed when the timeout
// elapses.
//
// Done is provided for use in select statements:
//
// // 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.
Done() <-chan struct{}
// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
Err() error
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
//
// Use context values only for request-scoped data that transits
// processes and API boundaries, not for passing optional parameters to
// functions.
//
// A key identifies a specific value in a Context. Functions that wish
// to store values in Context typically allocate a key in a global
// variable then use that key as the argument to context.WithValue and
// Context.Value. A key can be any type that supports equality;
// packages should define keys as an unexported type to avoid
// collisions.
//
// Packages that define a Context key should provide type-safe accessors
// for the values stores using that key:
//
// // Package user defines a User type that's stored in Contexts.
// package user
//
// import "golang.org/x/net/context"
//
// // User is the type of value stored in the Contexts.
// type User struct {...}
//
// // key is an unexported type for keys defined in this package.
// // This prevents collisions with keys defined in other packages.
// type key int
//
// // userKey is the key for user.User values in Contexts. It is
// // unexported; clients use user.NewContext and user.FromContext
// // instead of using this key directly.
// var userKey key = 0
//
// // NewContext returns a new Context that carries value u.
// func NewContext(ctx context.Context, u *User) context.Context {
// return context.WithValue(ctx, userKey, u)
// }
//
// // FromContext returns the User value stored in ctx, if any.
// func FromContext(ctx context.Context) (*User, bool) {
// u, ok := ctx.Value(userKey).(*User)
// return u, ok
// }
Value(key interface{}) interface{}
}
// A CancelFunc tells an operation to abandon its work.
// A CancelFunc does not wait for the work to stop.
// After the first call, subsequent calls to a CancelFunc do nothing.
type CancelFunc func()

View File

@ -4,17 +4,17 @@
// +build ignore // +build ignore
//go:generate go run gen.go
//go:generate go run gen.go -test
package main package main
// This program generates table.go and table_test.go.
// Invoke as
//
// go run gen.go |gofmt >table.go
// go run gen.go -test |gofmt >table_test.go
import ( import (
"bytes"
"flag" "flag"
"fmt" "fmt"
"go/format"
"io/ioutil"
"math/rand" "math/rand"
"os" "os"
"sort" "sort"
@ -42,6 +42,18 @@ func identifier(s string) string {
var test = flag.Bool("test", false, "generate table_test.go") var test = flag.Bool("test", false, "generate table_test.go")
func genFile(name string, buf *bytes.Buffer) {
b, err := format.Source(buf.Bytes())
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if err := ioutil.WriteFile(name, b, 0644); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func main() { func main() {
flag.Parse() flag.Parse()
@ -52,32 +64,31 @@ func main() {
all = append(all, extra...) all = append(all, extra...)
sort.Strings(all) sort.Strings(all)
if *test {
fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n")
fmt.Printf("package atom\n\n")
fmt.Printf("var testAtomList = []string{\n")
for _, s := range all {
fmt.Printf("\t%q,\n", s)
}
fmt.Printf("}\n")
return
}
// uniq - lists have dups // uniq - lists have dups
// compute max len too
maxLen := 0
w := 0 w := 0
for _, s := range all { for _, s := range all {
if w == 0 || all[w-1] != s { if w == 0 || all[w-1] != s {
if maxLen < len(s) {
maxLen = len(s)
}
all[w] = s all[w] = s
w++ w++
} }
} }
all = all[:w] all = all[:w]
if *test {
var buf bytes.Buffer
fmt.Fprintln(&buf, "// Code generated by go generate gen.go; DO NOT EDIT.\n")
fmt.Fprintln(&buf, "//go:generate go run gen.go -test\n")
fmt.Fprintln(&buf, "package atom\n")
fmt.Fprintln(&buf, "var testAtomList = []string{")
for _, s := range all {
fmt.Fprintf(&buf, "\t%q,\n", s)
}
fmt.Fprintln(&buf, "}")
genFile("table_test.go", &buf)
return
}
// Find hash that minimizes table size. // Find hash that minimizes table size.
var best *table var best *table
for i := 0; i < 1000000; i++ { for i := 0; i < 1000000; i++ {
@ -163,36 +174,46 @@ func main() {
atom[s] = uint32(off<<8 | len(s)) atom[s] = uint32(off<<8 | len(s))
} }
var buf bytes.Buffer
// Generate the Go code. // Generate the Go code.
fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n") fmt.Fprintln(&buf, "// Code generated by go generate gen.go; DO NOT EDIT.\n")
fmt.Printf("package atom\n\nconst (\n") fmt.Fprintln(&buf, "//go:generate go run gen.go\n")
fmt.Fprintln(&buf, "package atom\n\nconst (")
// compute max len
maxLen := 0
for _, s := range all { for _, s := range all {
fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s]) if maxLen < len(s) {
maxLen = len(s)
}
fmt.Fprintf(&buf, "\t%s Atom = %#x\n", identifier(s), atom[s])
} }
fmt.Printf(")\n\n") fmt.Fprintln(&buf, ")\n")
fmt.Printf("const hash0 = %#x\n\n", best.h0) fmt.Fprintf(&buf, "const hash0 = %#x\n\n", best.h0)
fmt.Printf("const maxAtomLen = %d\n\n", maxLen) fmt.Fprintf(&buf, "const maxAtomLen = %d\n\n", maxLen)
fmt.Printf("var table = [1<<%d]Atom{\n", best.k) fmt.Fprintf(&buf, "var table = [1<<%d]Atom{\n", best.k)
for i, s := range best.tab { for i, s := range best.tab {
if s == "" { if s == "" {
continue continue
} }
fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s) fmt.Fprintf(&buf, "\t%#x: %#x, // %s\n", i, atom[s], s)
} }
fmt.Printf("}\n") fmt.Fprintf(&buf, "}\n")
datasize := (1 << best.k) * 4 datasize := (1 << best.k) * 4
fmt.Printf("const atomText =\n") fmt.Fprintln(&buf, "const atomText =")
textsize := len(text) textsize := len(text)
for len(text) > 60 { for len(text) > 60 {
fmt.Printf("\t%q +\n", text[:60]) fmt.Fprintf(&buf, "\t%q +\n", text[:60])
text = text[60:] text = text[60:]
} }
fmt.Printf("\t%q\n\n", text) fmt.Fprintf(&buf, "\t%q\n\n", text)
fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize) genFile("table.go", &buf)
fmt.Fprintf(os.Stdout, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
} }
type byLen []string type byLen []string
@ -285,8 +306,10 @@ func (t *table) push(i uint32, depth int) bool {
// The lists of element names and attribute keys were taken from // The lists of element names and attribute keys were taken from
// https://html.spec.whatwg.org/multipage/indices.html#index // https://html.spec.whatwg.org/multipage/indices.html#index
// as of the "HTML Living Standard - Last Updated 21 February 2015" version. // as of the "HTML Living Standard - Last Updated 16 April 2018" version.
// "command", "keygen" and "menuitem" have been removed from the spec,
// but are kept here for backwards compatibility.
var elements = []string{ var elements = []string{
"a", "a",
"abbr", "abbr",
@ -349,6 +372,7 @@ var elements = []string{
"legend", "legend",
"li", "li",
"link", "link",
"main",
"map", "map",
"mark", "mark",
"menu", "menu",
@ -364,6 +388,7 @@ var elements = []string{
"output", "output",
"p", "p",
"param", "param",
"picture",
"pre", "pre",
"progress", "progress",
"q", "q",
@ -375,6 +400,7 @@ var elements = []string{
"script", "script",
"section", "section",
"select", "select",
"slot",
"small", "small",
"source", "source",
"span", "span",
@ -403,14 +429,21 @@ var elements = []string{
} }
// https://html.spec.whatwg.org/multipage/indices.html#attributes-3 // https://html.spec.whatwg.org/multipage/indices.html#attributes-3
//
// "challenge", "command", "contextmenu", "dropzone", "icon", "keytype", "mediagroup",
// "radiogroup", "spellcheck", "scoped", "seamless", "sortable" and "sorted" have been removed from the spec,
// but are kept here for backwards compatibility.
var attributes = []string{ var attributes = []string{
"abbr", "abbr",
"accept", "accept",
"accept-charset", "accept-charset",
"accesskey", "accesskey",
"action", "action",
"allowfullscreen",
"allowpaymentrequest",
"allowusermedia",
"alt", "alt",
"as",
"async", "async",
"autocomplete", "autocomplete",
"autofocus", "autofocus",
@ -420,6 +453,7 @@ var attributes = []string{
"checked", "checked",
"cite", "cite",
"class", "class",
"color",
"cols", "cols",
"colspan", "colspan",
"command", "command",
@ -457,6 +491,8 @@ var attributes = []string{
"icon", "icon",
"id", "id",
"inputmode", "inputmode",
"integrity",
"is",
"ismap", "ismap",
"itemid", "itemid",
"itemprop", "itemprop",
@ -481,16 +517,20 @@ var attributes = []string{
"multiple", "multiple",
"muted", "muted",
"name", "name",
"nomodule",
"nonce",
"novalidate", "novalidate",
"open", "open",
"optimum", "optimum",
"pattern", "pattern",
"ping", "ping",
"placeholder", "placeholder",
"playsinline",
"poster", "poster",
"preload", "preload",
"radiogroup", "radiogroup",
"readonly", "readonly",
"referrerpolicy",
"rel", "rel",
"required", "required",
"reversed", "reversed",
@ -507,10 +547,13 @@ var attributes = []string{
"sizes", "sizes",
"sortable", "sortable",
"sorted", "sorted",
"slot",
"span", "span",
"spellcheck",
"src", "src",
"srcdoc", "srcdoc",
"srclang", "srclang",
"srcset",
"start", "start",
"step", "step",
"style", "style",
@ -520,16 +563,22 @@ var attributes = []string{
"translate", "translate",
"type", "type",
"typemustmatch", "typemustmatch",
"updateviacache",
"usemap", "usemap",
"value", "value",
"width", "width",
"workertype",
"wrap", "wrap",
} }
// "onautocomplete", "onautocompleteerror", "onmousewheel",
// "onshow" and "onsort" have been removed from the spec,
// but are kept here for backwards compatibility.
var eventHandlers = []string{ var eventHandlers = []string{
"onabort", "onabort",
"onautocomplete", "onautocomplete",
"onautocompleteerror", "onautocompleteerror",
"onauxclick",
"onafterprint", "onafterprint",
"onbeforeprint", "onbeforeprint",
"onbeforeunload", "onbeforeunload",
@ -541,11 +590,14 @@ var eventHandlers = []string{
"onclick", "onclick",
"onclose", "onclose",
"oncontextmenu", "oncontextmenu",
"oncopy",
"oncuechange", "oncuechange",
"oncut",
"ondblclick", "ondblclick",
"ondrag", "ondrag",
"ondragend", "ondragend",
"ondragenter", "ondragenter",
"ondragexit",
"ondragleave", "ondragleave",
"ondragover", "ondragover",
"ondragstart", "ondragstart",
@ -565,18 +617,24 @@ var eventHandlers = []string{
"onload", "onload",
"onloadeddata", "onloadeddata",
"onloadedmetadata", "onloadedmetadata",
"onloadend",
"onloadstart", "onloadstart",
"onmessage", "onmessage",
"onmessageerror",
"onmousedown", "onmousedown",
"onmouseenter",
"onmouseleave",
"onmousemove", "onmousemove",
"onmouseout", "onmouseout",
"onmouseover", "onmouseover",
"onmouseup", "onmouseup",
"onmousewheel", "onmousewheel",
"onwheel",
"onoffline", "onoffline",
"ononline", "ononline",
"onpagehide", "onpagehide",
"onpageshow", "onpageshow",
"onpaste",
"onpause", "onpause",
"onplay", "onplay",
"onplaying", "onplaying",
@ -585,7 +643,9 @@ var eventHandlers = []string{
"onratechange", "onratechange",
"onreset", "onreset",
"onresize", "onresize",
"onrejectionhandled",
"onscroll", "onscroll",
"onsecuritypolicyviolation",
"onseeked", "onseeked",
"onseeking", "onseeking",
"onselect", "onselect",
@ -597,6 +657,7 @@ var eventHandlers = []string{
"onsuspend", "onsuspend",
"ontimeupdate", "ontimeupdate",
"ontoggle", "ontoggle",
"onunhandledrejection",
"onunload", "onunload",
"onvolumechange", "onvolumechange",
"onwaiting", "onwaiting",
@ -604,6 +665,7 @@ var eventHandlers = []string{
// extra are ad-hoc values not covered by any of the lists above. // extra are ad-hoc values not covered by any of the lists above.
var extra = []string{ var extra = []string{
"acronym",
"align", "align",
"annotation", "annotation",
"annotation-xml", "annotation-xml",
@ -639,6 +701,8 @@ var extra = []string{
"plaintext", "plaintext",
"prompt", "prompt",
"public", "public",
"rb",
"rtc",
"spacer", "spacer",
"strike", "strike",
"svg", "svg",

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
package html package html
// Section 12.2.3.2 of the HTML5 specification says "The following elements // Section 12.2.4.2 of the HTML5 specification says "The following elements
// have varying levels of special parsing rules". // have varying levels of special parsing rules".
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements // https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
var isSpecialElementMap = map[string]bool{ var isSpecialElementMap = map[string]bool{
@ -52,10 +52,12 @@ var isSpecialElementMap = map[string]bool{
"iframe": true, "iframe": true,
"img": true, "img": true,
"input": true, "input": true,
"isindex": true, "isindex": true, // The 'isindex' element has been removed, but keep it for backwards compatibility.
"keygen": true,
"li": true, "li": true,
"link": true, "link": true,
"listing": true, "listing": true,
"main": true,
"marquee": true, "marquee": true,
"menu": true, "menu": true,
"meta": true, "meta": true,
@ -95,8 +97,16 @@ func isSpecialElement(element *Node) bool {
switch element.Namespace { switch element.Namespace {
case "", "html": case "", "html":
return isSpecialElementMap[element.Data] return isSpecialElementMap[element.Data]
case "math":
switch element.Data {
case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
return true
}
case "svg": case "svg":
return element.Data == "foreignObject" switch element.Data {
case "foreignObject", "desc", "title":
return true
}
} }
return false return false
} }

View File

@ -49,18 +49,18 @@ call to Next. For example, to extract an HTML page's anchor text:
for { for {
tt := z.Next() tt := z.Next()
switch tt { switch tt {
case ErrorToken: case html.ErrorToken:
return z.Err() return z.Err()
case TextToken: case html.TextToken:
if depth > 0 { if depth > 0 {
// emitBytes should copy the []byte it receives, // emitBytes should copy the []byte it receives,
// if it doesn't process it immediately. // if it doesn't process it immediately.
emitBytes(z.Text()) emitBytes(z.Text())
} }
case StartTagToken, EndTagToken: case html.StartTagToken, html.EndTagToken:
tn, _ := z.TagName() tn, _ := z.TagName()
if len(tn) == 1 && tn[0] == 'a' { if len(tn) == 1 && tn[0] == 'a' {
if tt == StartTagToken { if tt == html.StartTagToken {
depth++ depth++
} else { } else {
depth-- depth--

4154
vendor/golang.org/x/net/html/entity.go generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,7 @@ func mathMLTextIntegrationPoint(n *Node) bool {
return false return false
} }
// Section 12.2.5.5. // Section 12.2.6.5.
var breakout = map[string]bool{ var breakout = map[string]bool{
"b": true, "b": true,
"big": true, "big": true,
@ -115,7 +115,7 @@ var breakout = map[string]bool{
"var": true, "var": true,
} }
// Section 12.2.5.5. // Section 12.2.6.5.
var svgTagNameAdjustments = map[string]string{ var svgTagNameAdjustments = map[string]string{
"altglyph": "altGlyph", "altglyph": "altGlyph",
"altglyphdef": "altGlyphDef", "altglyphdef": "altGlyphDef",
@ -155,7 +155,7 @@ var svgTagNameAdjustments = map[string]string{
"textpath": "textPath", "textpath": "textPath",
} }
// Section 12.2.5.1 // Section 12.2.6.1
var mathMLAttributeAdjustments = map[string]string{ var mathMLAttributeAdjustments = map[string]string{
"definitionurl": "definitionURL", "definitionurl": "definitionURL",
} }

33
vendor/golang.org/x/net/html/node.go generated vendored
View File

@ -21,9 +21,10 @@ const (
scopeMarkerNode scopeMarkerNode
) )
// Section 12.2.3.3 says "scope markers are inserted when entering applet // Section 12.2.4.3 says "The markers are inserted when entering applet,
// elements, buttons, object elements, marquees, table cells, and table // object, marquee, template, td, th, and caption elements, and are used
// captions, and are used to prevent formatting from 'leaking'". // to prevent formatting from "leaking" into applet, object, marquee,
// template, td, th, and caption elements".
var scopeMarker = Node{Type: scopeMarkerNode} var scopeMarker = Node{Type: scopeMarkerNode}
// A Node consists of a NodeType and some Data (tag name for element nodes, // A Node consists of a NodeType and some Data (tag name for element nodes,
@ -173,6 +174,16 @@ func (s *nodeStack) index(n *Node) int {
return -1 return -1
} }
// contains returns whether a is within s.
func (s *nodeStack) contains(a atom.Atom) bool {
for _, n := range *s {
if n.DataAtom == a {
return true
}
}
return false
}
// insert inserts a node at the given index. // insert inserts a node at the given index.
func (s *nodeStack) insert(i int, n *Node) { func (s *nodeStack) insert(i int, n *Node) {
(*s) = append(*s, nil) (*s) = append(*s, nil)
@ -191,3 +202,19 @@ func (s *nodeStack) remove(n *Node) {
(*s)[j] = nil (*s)[j] = nil
*s = (*s)[:j] *s = (*s)[:j]
} }
type insertionModeStack []insertionMode
func (s *insertionModeStack) pop() (im insertionMode) {
i := len(*s)
im = (*s)[i-1]
*s = (*s)[:i-1]
return im
}
func (s *insertionModeStack) top() insertionMode {
if i := len(*s); i > 0 {
return (*s)[i-1]
}
return nil
}

381
vendor/golang.org/x/net/html/parse.go generated vendored
View File

@ -25,20 +25,22 @@ type parser struct {
hasSelfClosingToken bool hasSelfClosingToken bool
// doc is the document root element. // doc is the document root element.
doc *Node doc *Node
// The stack of open elements (section 12.2.3.2) and active formatting // The stack of open elements (section 12.2.4.2) and active formatting
// elements (section 12.2.3.3). // elements (section 12.2.4.3).
oe, afe nodeStack oe, afe nodeStack
// Element pointers (section 12.2.3.4). // Element pointers (section 12.2.4.4).
head, form *Node head, form *Node
// Other parsing state flags (section 12.2.3.5). // Other parsing state flags (section 12.2.4.5).
scripting, framesetOK bool scripting, framesetOK bool
// The stack of template insertion modes
templateStack insertionModeStack
// im is the current insertion mode. // im is the current insertion mode.
im insertionMode im insertionMode
// originalIM is the insertion mode to go back to after completing a text // originalIM is the insertion mode to go back to after completing a text
// or inTableText insertion mode. // or inTableText insertion mode.
originalIM insertionMode originalIM insertionMode
// fosterParenting is whether new elements should be inserted according to // fosterParenting is whether new elements should be inserted according to
// the foster parenting rules (section 12.2.5.3). // the foster parenting rules (section 12.2.6.1).
fosterParenting bool fosterParenting bool
// quirks is whether the parser is operating in "quirks mode." // quirks is whether the parser is operating in "quirks mode."
quirks bool quirks bool
@ -56,7 +58,7 @@ func (p *parser) top() *Node {
return p.doc return p.doc
} }
// Stop tags for use in popUntil. These come from section 12.2.3.2. // Stop tags for use in popUntil. These come from section 12.2.4.2.
var ( var (
defaultScopeStopTags = map[string][]a.Atom{ defaultScopeStopTags = map[string][]a.Atom{
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
@ -79,7 +81,7 @@ const (
// popUntil pops the stack of open elements at the highest element whose tag // popUntil pops the stack of open elements at the highest element whose tag
// is in matchTags, provided there is no higher element in the scope's stop // is in matchTags, provided there is no higher element in the scope's stop
// tags (as defined in section 12.2.3.2). It returns whether or not there was // tags (as defined in section 12.2.4.2). It returns whether or not there was
// such an element. If there was not, popUntil leaves the stack unchanged. // such an element. If there was not, popUntil leaves the stack unchanged.
// //
// For example, the set of stop tags for table scope is: "html", "table". If // For example, the set of stop tags for table scope is: "html", "table". If
@ -126,7 +128,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
return -1 return -1
} }
case tableScope: case tableScope:
if tagAtom == a.Html || tagAtom == a.Table { if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
return -1 return -1
} }
case selectScope: case selectScope:
@ -162,17 +164,17 @@ func (p *parser) clearStackToContext(s scope) {
tagAtom := p.oe[i].DataAtom tagAtom := p.oe[i].DataAtom
switch s { switch s {
case tableScope: case tableScope:
if tagAtom == a.Html || tagAtom == a.Table { if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
p.oe = p.oe[:i+1] p.oe = p.oe[:i+1]
return return
} }
case tableRowScope: case tableRowScope:
if tagAtom == a.Html || tagAtom == a.Tr { if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
p.oe = p.oe[:i+1] p.oe = p.oe[:i+1]
return return
} }
case tableBodyScope: case tableBodyScope:
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead { if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
p.oe = p.oe[:i+1] p.oe = p.oe[:i+1]
return return
} }
@ -183,7 +185,7 @@ func (p *parser) clearStackToContext(s scope) {
} }
// generateImpliedEndTags pops nodes off the stack of open elements as long as // generateImpliedEndTags pops nodes off the stack of open elements as long as
// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt. // the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc.
// If exceptions are specified, nodes with that name will not be popped off. // If exceptions are specified, nodes with that name will not be popped off.
func (p *parser) generateImpliedEndTags(exceptions ...string) { func (p *parser) generateImpliedEndTags(exceptions ...string) {
var i int var i int
@ -192,7 +194,7 @@ loop:
n := p.oe[i] n := p.oe[i]
if n.Type == ElementNode { if n.Type == ElementNode {
switch n.DataAtom { switch n.DataAtom {
case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt: case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc:
for _, except := range exceptions { for _, except := range exceptions {
if n.Data == except { if n.Data == except {
break loop break loop
@ -234,9 +236,9 @@ func (p *parser) shouldFosterParent() bool {
} }
// fosterParent adds a child node according to the foster parenting rules. // fosterParent adds a child node according to the foster parenting rules.
// Section 12.2.5.3, "foster parenting". // Section 12.2.6.1, "foster parenting".
func (p *parser) fosterParent(n *Node) { func (p *parser) fosterParent(n *Node) {
var table, parent, prev *Node var table, parent, prev, template *Node
var i int var i int
for i = len(p.oe) - 1; i >= 0; i-- { for i = len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].DataAtom == a.Table { if p.oe[i].DataAtom == a.Table {
@ -245,6 +247,19 @@ func (p *parser) fosterParent(n *Node) {
} }
} }
var j int
for j = len(p.oe) - 1; j >= 0; j-- {
if p.oe[j].DataAtom == a.Template {
template = p.oe[j]
break
}
}
if template != nil && (table == nil || j > i) {
template.AppendChild(n)
return
}
if table == nil { if table == nil {
// The foster parent is the html element. // The foster parent is the html element.
parent = p.oe[0] parent = p.oe[0]
@ -304,7 +319,7 @@ func (p *parser) addElement() {
}) })
} }
// Section 12.2.3.3. // Section 12.2.4.3.
func (p *parser) addFormattingElement() { func (p *parser) addFormattingElement() {
tagAtom, attr := p.tok.DataAtom, p.tok.Attr tagAtom, attr := p.tok.DataAtom, p.tok.Attr
p.addElement() p.addElement()
@ -351,7 +366,7 @@ findIdenticalElements:
p.afe = append(p.afe, p.top()) p.afe = append(p.afe, p.top())
} }
// Section 12.2.3.3. // Section 12.2.4.3.
func (p *parser) clearActiveFormattingElements() { func (p *parser) clearActiveFormattingElements() {
for { for {
n := p.afe.pop() n := p.afe.pop()
@ -361,7 +376,7 @@ func (p *parser) clearActiveFormattingElements() {
} }
} }
// Section 12.2.3.3. // Section 12.2.4.3.
func (p *parser) reconstructActiveFormattingElements() { func (p *parser) reconstructActiveFormattingElements() {
n := p.afe.top() n := p.afe.top()
if n == nil { if n == nil {
@ -390,12 +405,12 @@ func (p *parser) reconstructActiveFormattingElements() {
} }
} }
// Section 12.2.4. // Section 12.2.5.
func (p *parser) acknowledgeSelfClosingTag() { func (p *parser) acknowledgeSelfClosingTag() {
p.hasSelfClosingToken = false p.hasSelfClosingToken = false
} }
// An insertion mode (section 12.2.3.1) is the state transition function from // An insertion mode (section 12.2.4.1) is the state transition function from
// a particular state in the HTML5 parser's state machine. It updates the // a particular state in the HTML5 parser's state machine. It updates the
// parser's fields depending on parser.tok (where ErrorToken means EOF). // parser's fields depending on parser.tok (where ErrorToken means EOF).
// It returns whether the token was consumed. // It returns whether the token was consumed.
@ -403,7 +418,7 @@ type insertionMode func(*parser) bool
// setOriginalIM sets the insertion mode to return to after completing a text or // setOriginalIM sets the insertion mode to return to after completing a text or
// inTableText insertion mode. // inTableText insertion mode.
// Section 12.2.3.1, "using the rules for". // Section 12.2.4.1, "using the rules for".
func (p *parser) setOriginalIM() { func (p *parser) setOriginalIM() {
if p.originalIM != nil { if p.originalIM != nil {
panic("html: bad parser state: originalIM was set twice") panic("html: bad parser state: originalIM was set twice")
@ -411,18 +426,38 @@ func (p *parser) setOriginalIM() {
p.originalIM = p.im p.originalIM = p.im
} }
// Section 12.2.3.1, "reset the insertion mode". // Section 12.2.4.1, "reset the insertion mode".
func (p *parser) resetInsertionMode() { func (p *parser) resetInsertionMode() {
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i] n := p.oe[i]
if i == 0 && p.context != nil { last := i == 0
if last && p.context != nil {
n = p.context n = p.context
} }
switch n.DataAtom { switch n.DataAtom {
case a.Select: case a.Select:
if !last {
for ancestor, first := n, p.oe[0]; ancestor != first; {
if ancestor == first {
break
}
ancestor = p.oe[p.oe.index(ancestor)-1]
switch ancestor.DataAtom {
case a.Template:
p.im = inSelectIM
return
case a.Table:
p.im = inSelectInTableIM
return
}
}
}
p.im = inSelectIM p.im = inSelectIM
case a.Td, a.Th: case a.Td, a.Th:
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inCellIM p.im = inCellIM
case a.Tr: case a.Tr:
p.im = inRowIM p.im = inRowIM
@ -434,25 +469,41 @@ func (p *parser) resetInsertionMode() {
p.im = inColumnGroupIM p.im = inColumnGroupIM
case a.Table: case a.Table:
p.im = inTableIM p.im = inTableIM
case a.Template:
// TODO: remove this divergence from the HTML5 spec.
if n.Namespace != "" {
continue
}
p.im = p.templateStack.top()
case a.Head: case a.Head:
p.im = inBodyIM // TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inHeadIM
case a.Body: case a.Body:
p.im = inBodyIM p.im = inBodyIM
case a.Frameset: case a.Frameset:
p.im = inFramesetIM p.im = inFramesetIM
case a.Html: case a.Html:
p.im = beforeHeadIM if p.head == nil {
p.im = beforeHeadIM
} else {
p.im = afterHeadIM
}
default: default:
if last {
p.im = inBodyIM
return
}
continue continue
} }
return return
} }
p.im = inBodyIM
} }
const whitespace = " \t\r\n\f" const whitespace = " \t\r\n\f"
// Section 12.2.5.4.1. // Section 12.2.6.4.1.
func initialIM(p *parser) bool { func initialIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@ -479,7 +530,7 @@ func initialIM(p *parser) bool {
return false return false
} }
// Section 12.2.5.4.2. // Section 12.2.6.4.2.
func beforeHTMLIM(p *parser) bool { func beforeHTMLIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case DoctypeToken: case DoctypeToken:
@ -517,7 +568,7 @@ func beforeHTMLIM(p *parser) bool {
return false return false
} }
// Section 12.2.5.4.3. // Section 12.2.6.4.3.
func beforeHeadIM(p *parser) bool { func beforeHeadIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@ -560,7 +611,7 @@ func beforeHeadIM(p *parser) bool {
return false return false
} }
// Section 12.2.5.4.4. // Section 12.2.6.4.4.
func inHeadIM(p *parser) bool { func inHeadIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@ -590,19 +641,41 @@ func inHeadIM(p *parser) bool {
case a.Head: case a.Head:
// Ignore the token. // Ignore the token.
return true return true
case a.Template:
p.addElement()
p.afe = append(p.afe, &scopeMarker)
p.framesetOK = false
p.im = inTemplateIM
p.templateStack = append(p.templateStack, inTemplateIM)
return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.DataAtom { switch p.tok.DataAtom {
case a.Head: case a.Head:
n := p.oe.pop() p.oe.pop()
if n.DataAtom != a.Head {
panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
}
p.im = afterHeadIM p.im = afterHeadIM
return true return true
case a.Body, a.Html, a.Br: case a.Body, a.Html, a.Br:
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
return false return false
case a.Template:
if !p.oe.contains(a.Template) {
return true
}
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.generateImpliedEndTags()
for i := len(p.oe) - 1; i >= 0; i-- {
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
p.oe = p.oe[:i]
break
}
}
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return true
default: default:
// Ignore the token. // Ignore the token.
return true return true
@ -622,7 +695,7 @@ func inHeadIM(p *parser) bool {
return false return false
} }
// Section 12.2.5.4.6. // Section 12.2.6.4.6.
func afterHeadIM(p *parser) bool { func afterHeadIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@ -648,7 +721,7 @@ func afterHeadIM(p *parser) bool {
p.addElement() p.addElement()
p.im = inFramesetIM p.im = inFramesetIM
return true return true
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
p.oe = append(p.oe, p.head) p.oe = append(p.oe, p.head)
defer p.oe.remove(p.head) defer p.oe.remove(p.head)
return inHeadIM(p) return inHeadIM(p)
@ -660,6 +733,8 @@ func afterHeadIM(p *parser) bool {
switch p.tok.DataAtom { switch p.tok.DataAtom {
case a.Body, a.Html, a.Br: case a.Body, a.Html, a.Br:
// Drop down to creating an implied <body> tag. // Drop down to creating an implied <body> tag.
case a.Template:
return inHeadIM(p)
default: default:
// Ignore the token. // Ignore the token.
return true return true
@ -697,7 +772,7 @@ func copyAttributes(dst *Node, src Token) {
} }
} }
// Section 12.2.5.4.7. // Section 12.2.6.4.7.
func inBodyIM(p *parser) bool { func inBodyIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@ -727,10 +802,16 @@ func inBodyIM(p *parser) bool {
case StartTagToken: case StartTagToken:
switch p.tok.DataAtom { switch p.tok.DataAtom {
case a.Html: case a.Html:
if p.oe.contains(a.Template) {
return true
}
copyAttributes(p.oe[0], p.tok) copyAttributes(p.oe[0], p.tok)
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p) return inHeadIM(p)
case a.Body: case a.Body:
if p.oe.contains(a.Template) {
return true
}
if len(p.oe) >= 2 { if len(p.oe) >= 2 {
body := p.oe[1] body := p.oe[1]
if body.Type == ElementNode && body.DataAtom == a.Body { if body.Type == ElementNode && body.DataAtom == a.Body {
@ -767,9 +848,13 @@ func inBodyIM(p *parser) bool {
// The newline, if any, will be dealt with by the TextToken case. // The newline, if any, will be dealt with by the TextToken case.
p.framesetOK = false p.framesetOK = false
case a.Form: case a.Form:
if p.form == nil { if p.form != nil && !p.oe.contains(a.Template) {
p.popUntil(buttonScope, a.P) // Ignore the token
p.addElement() return true
}
p.popUntil(buttonScope, a.P)
p.addElement()
if !p.oe.contains(a.Template) {
p.form = p.top() p.form = p.top()
} }
case a.Li: case a.Li:
@ -903,6 +988,14 @@ func inBodyIM(p *parser) bool {
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
p.popUntil(buttonScope, a.P) p.popUntil(buttonScope, a.P)
p.parseImpliedToken(StartTagToken, a.Form, a.Form.String()) p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
if p.form == nil {
// NOTE: The 'isindex' element has been removed,
// and the 'template' element has not been designed to be
// collaborative with the index element.
//
// Ignore the token.
return true
}
if action != "" { if action != "" {
p.form.Attr = []Attribute{{Key: "action", Val: action}} p.form.Attr = []Attribute{{Key: "action", Val: action}}
} }
@ -952,11 +1045,16 @@ func inBodyIM(p *parser) bool {
} }
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement() p.addElement()
case a.Rp, a.Rt: case a.Rb, a.Rtc:
if p.elementInScope(defaultScope, a.Ruby) { if p.elementInScope(defaultScope, a.Ruby) {
p.generateImpliedEndTags() p.generateImpliedEndTags()
} }
p.addElement() p.addElement()
case a.Rp, a.Rt:
if p.elementInScope(defaultScope, a.Ruby) {
p.generateImpliedEndTags("rtc")
}
p.addElement()
case a.Math, a.Svg: case a.Math, a.Svg:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
if p.tok.DataAtom == a.Math { if p.tok.DataAtom == a.Math {
@ -993,15 +1091,29 @@ func inBodyIM(p *parser) bool {
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul: case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
p.popUntil(defaultScope, p.tok.DataAtom) p.popUntil(defaultScope, p.tok.DataAtom)
case a.Form: case a.Form:
node := p.form if p.oe.contains(a.Template) {
p.form = nil i := p.indexOfElementInScope(defaultScope, a.Form)
i := p.indexOfElementInScope(defaultScope, a.Form) if i == -1 {
if node == nil || i == -1 || p.oe[i] != node { // Ignore the token.
// Ignore the token. return true
return true }
p.generateImpliedEndTags()
if p.oe[i].DataAtom != a.Form {
// Ignore the token.
return true
}
p.popUntil(defaultScope, a.Form)
} else {
node := p.form
p.form = nil
i := p.indexOfElementInScope(defaultScope, a.Form)
if node == nil || i == -1 || p.oe[i] != node {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
p.oe.remove(node)
} }
p.generateImpliedEndTags()
p.oe.remove(node)
case a.P: case a.P:
if !p.elementInScope(buttonScope, a.P) { if !p.elementInScope(buttonScope, a.P) {
p.parseImpliedToken(StartTagToken, a.P, a.P.String()) p.parseImpliedToken(StartTagToken, a.P, a.P.String())
@ -1022,6 +1134,8 @@ func inBodyIM(p *parser) bool {
case a.Br: case a.Br:
p.tok.Type = StartTagToken p.tok.Type = StartTagToken
return false return false
case a.Template:
return inHeadIM(p)
default: default:
p.inBodyEndTagOther(p.tok.DataAtom) p.inBodyEndTagOther(p.tok.DataAtom)
} }
@ -1030,6 +1144,21 @@ func inBodyIM(p *parser) bool {
Type: CommentNode, Type: CommentNode,
Data: p.tok.Data, Data: p.tok.Data,
}) })
case ErrorToken:
// TODO: remove this divergence from the HTML5 spec.
if len(p.templateStack) > 0 {
p.im = inTemplateIM
return false
} else {
for _, e := range p.oe {
switch e.DataAtom {
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th,
a.Thead, a.Tr, a.Body, a.Html:
default:
return true
}
}
}
} }
return true return true
@ -1160,7 +1289,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
} }
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. // 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 // "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
func (p *parser) inBodyEndTagOther(tagAtom a.Atom) { func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
@ -1174,7 +1303,7 @@ func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
} }
} }
// Section 12.2.5.4.8. // Section 12.2.6.4.8.
func textIM(p *parser) bool { func textIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case ErrorToken: case ErrorToken:
@ -1203,12 +1332,9 @@ func textIM(p *parser) bool {
return p.tok.Type == EndTagToken return p.tok.Type == EndTagToken
} }
// Section 12.2.5.4.9. // Section 12.2.6.4.9.
func inTableIM(p *parser) bool { func inTableIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case ErrorToken:
// Stop parsing.
return true
case TextToken: case TextToken:
p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1) p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
switch p.oe.top().DataAtom { switch p.oe.top().DataAtom {
@ -1249,7 +1375,7 @@ func inTableIM(p *parser) bool {
} }
// Ignore the token. // Ignore the token.
return true return true
case a.Style, a.Script: case a.Style, a.Script, a.Template:
return inHeadIM(p) return inHeadIM(p)
case a.Input: case a.Input:
for _, t := range p.tok.Attr { for _, t := range p.tok.Attr {
@ -1261,7 +1387,7 @@ func inTableIM(p *parser) bool {
} }
// Otherwise drop down to the default action. // Otherwise drop down to the default action.
case a.Form: case a.Form:
if p.form != nil { if p.oe.contains(a.Template) || p.form != nil {
// Ignore the token. // Ignore the token.
return true return true
} }
@ -1291,6 +1417,8 @@ func inTableIM(p *parser) bool {
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr: case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token. // Ignore the token.
return true return true
case a.Template:
return inHeadIM(p)
} }
case CommentToken: case CommentToken:
p.addChild(&Node{ p.addChild(&Node{
@ -1301,6 +1429,8 @@ func inTableIM(p *parser) bool {
case DoctypeToken: case DoctypeToken:
// Ignore the token. // Ignore the token.
return true return true
case ErrorToken:
return inBodyIM(p)
} }
p.fosterParenting = true p.fosterParenting = true
@ -1309,7 +1439,7 @@ func inTableIM(p *parser) bool {
return inBodyIM(p) return inBodyIM(p)
} }
// Section 12.2.5.4.11. // Section 12.2.6.4.11.
func inCaptionIM(p *parser) bool { func inCaptionIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
@ -1355,7 +1485,7 @@ func inCaptionIM(p *parser) bool {
return inBodyIM(p) return inBodyIM(p)
} }
// Section 12.2.5.4.12. // Section 12.2.6.4.12.
func inColumnGroupIM(p *parser) bool { func inColumnGroupIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@ -1386,11 +1516,13 @@ func inColumnGroupIM(p *parser) bool {
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
return true return true
case a.Template:
return inHeadIM(p)
} }
case EndTagToken: case EndTagToken:
switch p.tok.DataAtom { switch p.tok.DataAtom {
case a.Colgroup: case a.Colgroup:
if p.oe.top().DataAtom != a.Html { if p.oe.top().DataAtom == a.Colgroup {
p.oe.pop() p.oe.pop()
p.im = inTableIM p.im = inTableIM
} }
@ -1398,17 +1530,21 @@ func inColumnGroupIM(p *parser) bool {
case a.Col: case a.Col:
// Ignore the token. // Ignore the token.
return true return true
case a.Template:
return inHeadIM(p)
} }
case ErrorToken:
return inBodyIM(p)
} }
if p.oe.top().DataAtom != a.Html { if p.oe.top().DataAtom != a.Colgroup {
p.oe.pop() return true
p.im = inTableIM
return false
} }
return true p.oe.pop()
p.im = inTableIM
return false
} }
// Section 12.2.5.4.13. // Section 12.2.6.4.13.
func inTableBodyIM(p *parser) bool { func inTableBodyIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
@ -1460,7 +1596,7 @@ func inTableBodyIM(p *parser) bool {
return inTableIM(p) return inTableIM(p)
} }
// Section 12.2.5.4.14. // Section 12.2.6.4.14.
func inRowIM(p *parser) bool { func inRowIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
@ -1511,7 +1647,7 @@ func inRowIM(p *parser) bool {
return inTableIM(p) return inTableIM(p)
} }
// Section 12.2.5.4.15. // Section 12.2.6.4.15.
func inCellIM(p *parser) bool { func inCellIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
@ -1560,12 +1696,9 @@ func inCellIM(p *parser) bool {
return inBodyIM(p) return inBodyIM(p)
} }
// Section 12.2.5.4.16. // Section 12.2.6.4.16.
func inSelectIM(p *parser) bool { func inSelectIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case ErrorToken:
// Stop parsing.
return true
case TextToken: case TextToken:
p.addText(strings.Replace(p.tok.Data, "\x00", "", -1)) p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
case StartTagToken: case StartTagToken:
@ -1597,7 +1730,7 @@ func inSelectIM(p *parser) bool {
p.tokenizer.NextIsNotRawText() p.tokenizer.NextIsNotRawText()
// Ignore the token. // Ignore the token.
return true return true
case a.Script: case a.Script, a.Template:
return inHeadIM(p) return inHeadIM(p)
} }
case EndTagToken: case EndTagToken:
@ -1618,6 +1751,8 @@ func inSelectIM(p *parser) bool {
if p.popUntil(selectScope, a.Select) { if p.popUntil(selectScope, a.Select) {
p.resetInsertionMode() p.resetInsertionMode()
} }
case a.Template:
return inHeadIM(p)
} }
case CommentToken: case CommentToken:
p.addChild(&Node{ p.addChild(&Node{
@ -1627,12 +1762,14 @@ func inSelectIM(p *parser) bool {
case DoctypeToken: case DoctypeToken:
// Ignore the token. // Ignore the token.
return true return true
case ErrorToken:
return inBodyIM(p)
} }
return true return true
} }
// Section 12.2.5.4.17. // Section 12.2.6.4.17.
func inSelectInTableIM(p *parser) bool { func inSelectInTableIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken, EndTagToken: case StartTagToken, EndTagToken:
@ -1650,7 +1787,73 @@ func inSelectInTableIM(p *parser) bool {
return inSelectIM(p) return inSelectIM(p)
} }
// Section 12.2.5.4.18. // Section 12.2.6.4.18.
func inTemplateIM(p *parser) bool {
switch p.tok.Type {
case TextToken, CommentToken, DoctypeToken:
return inBodyIM(p)
case StartTagToken:
switch p.tok.DataAtom {
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p)
case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableIM)
p.im = inTableIM
return false
case a.Col:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inColumnGroupIM)
p.im = inColumnGroupIM
return false
case a.Tr:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableBodyIM)
p.im = inTableBodyIM
return false
case a.Td, a.Th:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inRowIM)
p.im = inRowIM
return false
default:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inBodyIM)
p.im = inBodyIM
return false
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Template:
return inHeadIM(p)
default:
// Ignore the token.
return true
}
case ErrorToken:
if !p.oe.contains(a.Template) {
// Ignore the token.
return true
}
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.generateImpliedEndTags()
for i := len(p.oe) - 1; i >= 0; i-- {
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
p.oe = p.oe[:i]
break
}
}
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return false
}
return false
}
// Section 12.2.6.4.19.
func afterBodyIM(p *parser) bool { func afterBodyIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case ErrorToken: case ErrorToken:
@ -1688,7 +1891,7 @@ func afterBodyIM(p *parser) bool {
return false return false
} }
// Section 12.2.5.4.19. // Section 12.2.6.4.20.
func inFramesetIM(p *parser) bool { func inFramesetIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case CommentToken: case CommentToken:
@ -1738,7 +1941,7 @@ func inFramesetIM(p *parser) bool {
return true return true
} }
// Section 12.2.5.4.20. // Section 12.2.6.4.21.
func afterFramesetIM(p *parser) bool { func afterFramesetIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case CommentToken: case CommentToken:
@ -1777,7 +1980,7 @@ func afterFramesetIM(p *parser) bool {
return true return true
} }
// Section 12.2.5.4.21. // Section 12.2.6.4.22.
func afterAfterBodyIM(p *parser) bool { func afterAfterBodyIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case ErrorToken: case ErrorToken:
@ -1806,7 +2009,7 @@ func afterAfterBodyIM(p *parser) bool {
return false return false
} }
// Section 12.2.5.4.22. // Section 12.2.6.4.23.
func afterAfterFramesetIM(p *parser) bool { func afterAfterFramesetIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case CommentToken: case CommentToken:
@ -1844,7 +2047,7 @@ func afterAfterFramesetIM(p *parser) bool {
const whitespaceOrNUL = whitespace + "\x00" const whitespaceOrNUL = whitespace + "\x00"
// Section 12.2.5.5. // Section 12.2.6.5
func parseForeignContent(p *parser) bool { func parseForeignContent(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@ -1924,7 +2127,7 @@ func parseForeignContent(p *parser) bool {
return true return true
} }
// Section 12.2.5. // Section 12.2.6.
func (p *parser) inForeignContent() bool { func (p *parser) inForeignContent() bool {
if len(p.oe) == 0 { if len(p.oe) == 0 {
return false return false
@ -2012,6 +2215,15 @@ func (p *parser) parse() error {
} }
// Parse returns the parse tree for the HTML from the given Reader. // Parse returns the parse tree for the HTML from the given Reader.
//
// It implements the HTML5 parsing algorithm
// (https://html.spec.whatwg.org/multipage/syntax.html#tree-construction),
// which is very complicated. The resultant tree can contain implicitly created
// nodes that have no explicit <tag> listed in r's data, and nodes' parents can
// differ from the nesting implied by a naive processing of start and end
// <tag>s. Conversely, explicit <tag>s in r's data can be silently dropped,
// with no corresponding node in the resulting tree.
//
// The input is assumed to be UTF-8 encoded. // The input is assumed to be UTF-8 encoded.
func Parse(r io.Reader) (*Node, error) { func Parse(r io.Reader) (*Node, error) {
p := &parser{ p := &parser{
@ -2033,6 +2245,8 @@ func Parse(r io.Reader) (*Node, error) {
// ParseFragment parses a fragment of HTML and returns the nodes that were // ParseFragment parses a fragment of HTML and returns the nodes that were
// found. If the fragment is the InnerHTML for an existing element, pass that // found. If the fragment is the InnerHTML for an existing element, pass that
// element in context. // element in context.
//
// It has the same intricacies as Parse.
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) { func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
contextTag := "" contextTag := ""
if context != nil { if context != nil {
@ -2064,6 +2278,9 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
} }
p.doc.AppendChild(root) p.doc.AppendChild(root)
p.oe = nodeStack{root} p.oe = nodeStack{root}
if context != nil && context.DataAtom == a.Template {
p.templateStack = append(p.templateStack, inTemplateIM)
}
p.resetInsertionMode() p.resetInsertionMode()
for n := context; n != nil; n = n.Parent { for n := context; n != nil; n = n.Parent {

View File

@ -1161,8 +1161,8 @@ func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
return nil, nil, false return nil, nil, false
} }
// Token returns the next Token. The result's Data and Attr values remain valid // Token returns the current Token. The result's Data and Attr values remain
// after subsequent Next calls. // valid after subsequent Next calls.
func (z *Tokenizer) Token() Token { func (z *Tokenizer) Token() Token {
t := Token{Type: z.tt} t := Token{Type: z.tt}
switch z.tt { switch z.tt {