diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-02-01 19:26:59 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-02-01 19:26:59 +0000 |
commit | 86babf4bfda7c2c2e9be4abc20e4d8073e05e5be (patch) | |
tree | 7e7e6083ebe59999943a211a17f8ef6f07f17c2f /libgo/go/exp | |
parent | df9ff8bf53f716508a120d15cc144e628fd2e9b5 (diff) | |
download | gcc-86babf4bfda7c2c2e9be4abc20e4d8073e05e5be.tar.gz |
libgo: Update to weekly.2012-01-27.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@183810 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/exp')
88 files changed, 23368 insertions, 6535 deletions
diff --git a/libgo/go/exp/ebnflint/ebnflint.go b/libgo/go/exp/ebnflint/ebnflint.go index 6d6f516c905..2cb5aa6ed6c 100644 --- a/libgo/go/exp/ebnflint/ebnflint.go +++ b/libgo/go/exp/ebnflint/ebnflint.go @@ -11,6 +11,7 @@ import ( "fmt" "go/scanner" "go/token" + "io" "io/ioutil" "os" "path/filepath" @@ -76,34 +77,46 @@ func main() { flag.Parse() var ( - filename string - src []byte - err error + name string + r io.Reader ) switch flag.NArg() { case 0: - filename = "<stdin>" - src, err = ioutil.ReadAll(os.Stdin) + name, r = "<stdin>", os.Stdin case 1: - filename = flag.Arg(0) - src, err = ioutil.ReadFile(filename) + name = flag.Arg(0) default: usage() } - if err != nil { + + if err := verify(name, *start, r); err != nil { report(err) } +} - if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 { - src = extractEBNF(src) +func verify(name, start string, r io.Reader) error { + if r == nil { + f, err := os.Open(name) + if err != nil { + return err + } + defer f.Close() + r = f } - grammar, err := ebnf.Parse(filename, bytes.NewBuffer(src)) + src, err := ioutil.ReadAll(r) if err != nil { - report(err) + return err } - if err = ebnf.Verify(grammar, *start); err != nil { - report(err) + if filepath.Ext(name) == ".html" || bytes.Index(src, open) >= 0 { + src = extractEBNF(src) + } + + grammar, err := ebnf.Parse(name, bytes.NewBuffer(src)) + if err != nil { + return err } + + return ebnf.Verify(grammar, start) } diff --git a/libgo/go/exp/ebnflint/ebnflint_test.go b/libgo/go/exp/ebnflint/ebnflint_test.go new file mode 100644 index 00000000000..875dbc19aca --- /dev/null +++ b/libgo/go/exp/ebnflint/ebnflint_test.go @@ -0,0 +1,16 @@ +// Copyright 2012 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 main + +import ( + "runtime" + "testing" +) + +func TestSpec(t *testing.T) { + if err := verify(runtime.GOROOT()+"/doc/go_spec.html", "SourceFile", nil); err != nil { + t.Fatal(err) + } +} diff --git a/libgo/go/exp/html/const.go b/libgo/go/exp/html/const.go new file mode 100644 index 00000000000..d7cc8bb9a99 --- /dev/null +++ b/libgo/go/exp/html/const.go @@ -0,0 +1,100 @@ +// Copyright 2011 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 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 +var isSpecialElementMap = map[string]bool{ + "address": true, + "applet": true, + "area": true, + "article": true, + "aside": true, + "base": true, + "basefont": true, + "bgsound": true, + "blockquote": true, + "body": true, + "br": true, + "button": true, + "caption": true, + "center": true, + "col": true, + "colgroup": true, + "command": true, + "dd": true, + "details": true, + "dir": true, + "div": true, + "dl": true, + "dt": true, + "embed": true, + "fieldset": true, + "figcaption": true, + "figure": true, + "footer": true, + "form": true, + "frame": true, + "frameset": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "header": true, + "hgroup": true, + "hr": true, + "html": true, + "iframe": true, + "img": true, + "input": true, + "isindex": true, + "li": true, + "link": true, + "listing": true, + "marquee": true, + "menu": true, + "meta": true, + "nav": true, + "noembed": true, + "noframes": true, + "noscript": true, + "object": true, + "ol": true, + "p": true, + "param": true, + "plaintext": true, + "pre": true, + "script": true, + "section": true, + "select": true, + "style": true, + "summary": true, + "table": true, + "tbody": true, + "td": true, + "textarea": true, + "tfoot": true, + "th": true, + "thead": true, + "title": true, + "tr": true, + "ul": true, + "wbr": true, + "xmp": true, +} + +func isSpecialElement(element *Node) bool { + switch element.Namespace { + case "", "html": + return isSpecialElementMap[element.Data] + case "svg": + return element.Data == "foreignObject" + } + return false +} diff --git a/libgo/go/exp/html/doc.go b/libgo/go/exp/html/doc.go new file mode 100644 index 00000000000..56b194ffb90 --- /dev/null +++ b/libgo/go/exp/html/doc.go @@ -0,0 +1,107 @@ +// Copyright 2010 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 html implements an HTML5-compliant tokenizer and parser. +INCOMPLETE. + +Tokenization is done by creating a Tokenizer for an io.Reader r. It is the +caller's responsibility to ensure that r provides UTF-8 encoded HTML. + + z := html.NewTokenizer(r) + +Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), +which parses the next token and returns its type, or an error: + + for { + tt := z.Next() + if tt == html.ErrorToken { + // ... + return ... + } + // Process the current token. + } + +There are two APIs for retrieving the current token. The high-level API is to +call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs +allow optionally calling Raw after Next but before Token, Text, TagName, or +TagAttr. In EBNF notation, the valid call sequence per token is: + + Next {Raw} [ Token | Text | TagName {TagAttr} ] + +Token returns an independent data structure that completely describes a token. +Entities (such as "<") are unescaped, tag names and attribute keys are +lower-cased, and attributes are collected into a []Attribute. For example: + + for { + if z.Next() == html.ErrorToken { + // Returning io.EOF indicates success. + return z.Err() + } + emitToken(z.Token()) + } + +The low-level API performs fewer allocations and copies, but the contents of +the []byte values returned by Text, TagName and TagAttr may change on the next +call to Next. For example, to extract an HTML page's anchor text: + + depth := 0 + for { + tt := z.Next() + switch tt { + case ErrorToken: + return z.Err() + case TextToken: + if depth > 0 { + // emitBytes should copy the []byte it receives, + // if it doesn't process it immediately. + emitBytes(z.Text()) + } + case StartTagToken, EndTagToken: + tn, _ := z.TagName() + if len(tn) == 1 && tn[0] == 'a' { + if tt == StartTagToken { + depth++ + } else { + depth-- + } + } + } + } + +Parsing is done by calling Parse with an io.Reader, which returns the root of +the parse tree (the document element) as a *Node. It is the caller's +responsibility to ensure that the Reader provides UTF-8 encoded HTML. For +example, to process each anchor node in depth-first order: + + doc, err := html.Parse(r) + if err != nil { + // ... + } + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "a" { + // Do something with n... + } + for _, c := range n.Child { + f(c) + } + } + 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 +*/ +package html + +// The tokenization algorithm implemented by this package is not a line-by-line +// transliteration of the relatively verbose state-machine in the WHATWG +// specification. A more direct approach is used instead, where the program +// counter implies the state, such as whether it is tokenizing a tag or a text +// node. Specification compliance is verified by checking expected and actual +// outputs over a test suite rather than aiming for algorithmic fidelity. + +// TODO(nigeltao): Does a DOM API belong in this package or a separate one? +// TODO(nigeltao): How does parsing interact with a JavaScript engine? diff --git a/libgo/go/exp/html/doctype.go b/libgo/go/exp/html/doctype.go new file mode 100644 index 00000000000..f692061a551 --- /dev/null +++ b/libgo/go/exp/html/doctype.go @@ -0,0 +1,156 @@ +// Copyright 2011 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 html + +import ( + "strings" +) + +// parseDoctype parses the data from a DoctypeToken into a name, +// public identifier, and system identifier. It returns a Node whose Type +// is DoctypeNode, whose Data is the name, and which has attributes +// named "system" and "public" for the two identifiers if they were present. +// quirks is whether the document should be parsed in "quirks mode". +func parseDoctype(s string) (n *Node, quirks bool) { + n = &Node{Type: DoctypeNode} + + // Find the name. + space := strings.IndexAny(s, whitespace) + if space == -1 { + space = len(s) + } + n.Data = s[:space] + // The comparison to "html" is case-sensitive. + if n.Data != "html" { + quirks = true + } + n.Data = strings.ToLower(n.Data) + s = strings.TrimLeft(s[space:], whitespace) + + if len(s) < 6 { + // It can't start with "PUBLIC" or "SYSTEM". + // Ignore the rest of the string. + return n, quirks || s != "" + } + + key := strings.ToLower(s[:6]) + s = s[6:] + for key == "public" || key == "system" { + s = strings.TrimLeft(s, whitespace) + if s == "" { + break + } + quote := s[0] + if quote != '"' && quote != '\'' { + break + } + s = s[1:] + q := strings.IndexRune(s, rune(quote)) + var id string + if q == -1 { + id = s + s = "" + } else { + id = s[:q] + s = s[q+1:] + } + n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) + if key == "public" { + key = "system" + } else { + key = "" + } + } + + if key != "" || s != "" { + quirks = true + } else if len(n.Attr) > 0 { + if n.Attr[0].Key == "public" { + public := strings.ToLower(n.Attr[0].Val) + switch public { + case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": + quirks = true + default: + for _, q := range quirkyIDs { + if strings.HasPrefix(public, q) { + quirks = true + break + } + } + } + // The following two public IDs only cause quirks mode if there is no system ID. + if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || + strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { + quirks = true + } + } + if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && + strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { + quirks = true + } + } + + return n, quirks +} + +// quirkyIDs is a list of public doctype identifiers that cause a document +// to be interpreted in quirks mode. The identifiers should be in lower case. +var quirkyIDs = []string{ + "+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//", +} diff --git a/libgo/go/exp/html/entity.go b/libgo/go/exp/html/entity.go new file mode 100644 index 00000000000..bd830752359 --- /dev/null +++ b/libgo/go/exp/html/entity.go @@ -0,0 +1,2253 @@ +// Copyright 2010 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 html + +// All entities that do not end with ';' are 6 or fewer bytes long. +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 +// lists both "amp" and "amp;" as two separate entries. +// +// Note that the HTML5 list is larger than the HTML4 list at +// http://www.w3.org/TR/html4/sgml/entities.html +var entity = map[string]rune{ + "AElig;": '\U000000C6', + "AMP;": '\U00000026', + "Aacute;": '\U000000C1', + "Abreve;": '\U00000102', + "Acirc;": '\U000000C2', + "Acy;": '\U00000410', + "Afr;": '\U0001D504', + "Agrave;": '\U000000C0', + "Alpha;": '\U00000391', + "Amacr;": '\U00000100', + "And;": '\U00002A53', + "Aogon;": '\U00000104', + "Aopf;": '\U0001D538', + "ApplyFunction;": '\U00002061', + "Aring;": '\U000000C5', + "Ascr;": '\U0001D49C', + "Assign;": '\U00002254', + "Atilde;": '\U000000C3', + "Auml;": '\U000000C4', + "Backslash;": '\U00002216', + "Barv;": '\U00002AE7', + "Barwed;": '\U00002306', + "Bcy;": '\U00000411', + "Because;": '\U00002235', + "Bernoullis;": '\U0000212C', + "Beta;": '\U00000392', + "Bfr;": '\U0001D505', + "Bopf;": '\U0001D539', + "Breve;": '\U000002D8', + "Bscr;": '\U0000212C', + "Bumpeq;": '\U0000224E', + "CHcy;": '\U00000427', + "COPY;": '\U000000A9', + "Cacute;": '\U00000106', + "Cap;": '\U000022D2', + "CapitalDifferentialD;": '\U00002145', + "Cayleys;": '\U0000212D', + "Ccaron;": '\U0000010C', + "Ccedil;": '\U000000C7', + "Ccirc;": '\U00000108', + "Cconint;": '\U00002230', + "Cdot;": '\U0000010A', + "Cedilla;": '\U000000B8', + "CenterDot;": '\U000000B7', + "Cfr;": '\U0000212D', + "Chi;": '\U000003A7', + "CircleDot;": '\U00002299', + "CircleMinus;": '\U00002296', + "CirclePlus;": '\U00002295', + "CircleTimes;": '\U00002297', + "ClockwiseContourIntegral;": '\U00002232', + "CloseCurlyDoubleQuote;": '\U0000201D', + "CloseCurlyQuote;": '\U00002019', + "Colon;": '\U00002237', + "Colone;": '\U00002A74', + "Congruent;": '\U00002261', + "Conint;": '\U0000222F', + "ContourIntegral;": '\U0000222E', + "Copf;": '\U00002102', + "Coproduct;": '\U00002210', + "CounterClockwiseContourIntegral;": '\U00002233', + "Cross;": '\U00002A2F', + "Cscr;": '\U0001D49E', + "Cup;": '\U000022D3', + "CupCap;": '\U0000224D', + "DD;": '\U00002145', + "DDotrahd;": '\U00002911', + "DJcy;": '\U00000402', + "DScy;": '\U00000405', + "DZcy;": '\U0000040F', + "Dagger;": '\U00002021', + "Darr;": '\U000021A1', + "Dashv;": '\U00002AE4', + "Dcaron;": '\U0000010E', + "Dcy;": '\U00000414', + "Del;": '\U00002207', + "Delta;": '\U00000394', + "Dfr;": '\U0001D507', + "DiacriticalAcute;": '\U000000B4', + "DiacriticalDot;": '\U000002D9', + "DiacriticalDoubleAcute;": '\U000002DD', + "DiacriticalGrave;": '\U00000060', + "DiacriticalTilde;": '\U000002DC', + "Diamond;": '\U000022C4', + "DifferentialD;": '\U00002146', + "Dopf;": '\U0001D53B', + "Dot;": '\U000000A8', + "DotDot;": '\U000020DC', + "DotEqual;": '\U00002250', + "DoubleContourIntegral;": '\U0000222F', + "DoubleDot;": '\U000000A8', + "DoubleDownArrow;": '\U000021D3', + "DoubleLeftArrow;": '\U000021D0', + "DoubleLeftRightArrow;": '\U000021D4', + "DoubleLeftTee;": '\U00002AE4', + "DoubleLongLeftArrow;": '\U000027F8', + "DoubleLongLeftRightArrow;": '\U000027FA', + "DoubleLongRightArrow;": '\U000027F9', + "DoubleRightArrow;": '\U000021D2', + "DoubleRightTee;": '\U000022A8', + "DoubleUpArrow;": '\U000021D1', + "DoubleUpDownArrow;": '\U000021D5', + "DoubleVerticalBar;": '\U00002225', + "DownArrow;": '\U00002193', + "DownArrowBar;": '\U00002913', + "DownArrowUpArrow;": '\U000021F5', + "DownBreve;": '\U00000311', + "DownLeftRightVector;": '\U00002950', + "DownLeftTeeVector;": '\U0000295E', + "DownLeftVector;": '\U000021BD', + "DownLeftVectorBar;": '\U00002956', + "DownRightTeeVector;": '\U0000295F', + "DownRightVector;": '\U000021C1', + "DownRightVectorBar;": '\U00002957', + "DownTee;": '\U000022A4', + "DownTeeArrow;": '\U000021A7', + "Downarrow;": '\U000021D3', + "Dscr;": '\U0001D49F', + "Dstrok;": '\U00000110', + "ENG;": '\U0000014A', + "ETH;": '\U000000D0', + "Eacute;": '\U000000C9', + "Ecaron;": '\U0000011A', + "Ecirc;": '\U000000CA', + "Ecy;": '\U0000042D', + "Edot;": '\U00000116', + "Efr;": '\U0001D508', + "Egrave;": '\U000000C8', + "Element;": '\U00002208', + "Emacr;": '\U00000112', + "EmptySmallSquare;": '\U000025FB', + "EmptyVerySmallSquare;": '\U000025AB', + "Eogon;": '\U00000118', + "Eopf;": '\U0001D53C', + "Epsilon;": '\U00000395', + "Equal;": '\U00002A75', + "EqualTilde;": '\U00002242', + "Equilibrium;": '\U000021CC', + "Escr;": '\U00002130', + "Esim;": '\U00002A73', + "Eta;": '\U00000397', + "Euml;": '\U000000CB', + "Exists;": '\U00002203', + "ExponentialE;": '\U00002147', + "Fcy;": '\U00000424', + "Ffr;": '\U0001D509', + "FilledSmallSquare;": '\U000025FC', + "FilledVerySmallSquare;": '\U000025AA', + "Fopf;": '\U0001D53D', + "ForAll;": '\U00002200', + "Fouriertrf;": '\U00002131', + "Fscr;": '\U00002131', + "GJcy;": '\U00000403', + "GT;": '\U0000003E', + "Gamma;": '\U00000393', + "Gammad;": '\U000003DC', + "Gbreve;": '\U0000011E', + "Gcedil;": '\U00000122', + "Gcirc;": '\U0000011C', + "Gcy;": '\U00000413', + "Gdot;": '\U00000120', + "Gfr;": '\U0001D50A', + "Gg;": '\U000022D9', + "Gopf;": '\U0001D53E', + "GreaterEqual;": '\U00002265', + "GreaterEqualLess;": '\U000022DB', + "GreaterFullEqual;": '\U00002267', + "GreaterGreater;": '\U00002AA2', + "GreaterLess;": '\U00002277', + "GreaterSlantEqual;": '\U00002A7E', + "GreaterTilde;": '\U00002273', + "Gscr;": '\U0001D4A2', + "Gt;": '\U0000226B', + "HARDcy;": '\U0000042A', + "Hacek;": '\U000002C7', + "Hat;": '\U0000005E', + "Hcirc;": '\U00000124', + "Hfr;": '\U0000210C', + "HilbertSpace;": '\U0000210B', + "Hopf;": '\U0000210D', + "HorizontalLine;": '\U00002500', + "Hscr;": '\U0000210B', + "Hstrok;": '\U00000126', + "HumpDownHump;": '\U0000224E', + "HumpEqual;": '\U0000224F', + "IEcy;": '\U00000415', + "IJlig;": '\U00000132', + "IOcy;": '\U00000401', + "Iacute;": '\U000000CD', + "Icirc;": '\U000000CE', + "Icy;": '\U00000418', + "Idot;": '\U00000130', + "Ifr;": '\U00002111', + "Igrave;": '\U000000CC', + "Im;": '\U00002111', + "Imacr;": '\U0000012A', + "ImaginaryI;": '\U00002148', + "Implies;": '\U000021D2', + "Int;": '\U0000222C', + "Integral;": '\U0000222B', + "Intersection;": '\U000022C2', + "InvisibleComma;": '\U00002063', + "InvisibleTimes;": '\U00002062', + "Iogon;": '\U0000012E', + "Iopf;": '\U0001D540', + "Iota;": '\U00000399', + "Iscr;": '\U00002110', + "Itilde;": '\U00000128', + "Iukcy;": '\U00000406', + "Iuml;": '\U000000CF', + "Jcirc;": '\U00000134', + "Jcy;": '\U00000419', + "Jfr;": '\U0001D50D', + "Jopf;": '\U0001D541', + "Jscr;": '\U0001D4A5', + "Jsercy;": '\U00000408', + "Jukcy;": '\U00000404', + "KHcy;": '\U00000425', + "KJcy;": '\U0000040C', + "Kappa;": '\U0000039A', + "Kcedil;": '\U00000136', + "Kcy;": '\U0000041A', + "Kfr;": '\U0001D50E', + "Kopf;": '\U0001D542', + "Kscr;": '\U0001D4A6', + "LJcy;": '\U00000409', + "LT;": '\U0000003C', + "Lacute;": '\U00000139', + "Lambda;": '\U0000039B', + "Lang;": '\U000027EA', + "Laplacetrf;": '\U00002112', + "Larr;": '\U0000219E', + "Lcaron;": '\U0000013D', + "Lcedil;": '\U0000013B', + "Lcy;": '\U0000041B', + "LeftAngleBracket;": '\U000027E8', + "LeftArrow;": '\U00002190', + "LeftArrowBar;": '\U000021E4', + "LeftArrowRightArrow;": '\U000021C6', + "LeftCeiling;": '\U00002308', + "LeftDoubleBracket;": '\U000027E6', + "LeftDownTeeVector;": '\U00002961', + "LeftDownVector;": '\U000021C3', + "LeftDownVectorBar;": '\U00002959', + "LeftFloor;": '\U0000230A', + "LeftRightArrow;": '\U00002194', + "LeftRightVector;": '\U0000294E', + "LeftTee;": '\U000022A3', + "LeftTeeArrow;": '\U000021A4', + "LeftTeeVector;": '\U0000295A', + "LeftTriangle;": '\U000022B2', + "LeftTriangleBar;": '\U000029CF', + "LeftTriangleEqual;": '\U000022B4', + "LeftUpDownVector;": '\U00002951', + "LeftUpTeeVector;": '\U00002960', + "LeftUpVector;": '\U000021BF', + "LeftUpVectorBar;": '\U00002958', + "LeftVector;": '\U000021BC', + "LeftVectorBar;": '\U00002952', + "Leftarrow;": '\U000021D0', + "Leftrightarrow;": '\U000021D4', + "LessEqualGreater;": '\U000022DA', + "LessFullEqual;": '\U00002266', + "LessGreater;": '\U00002276', + "LessLess;": '\U00002AA1', + "LessSlantEqual;": '\U00002A7D', + "LessTilde;": '\U00002272', + "Lfr;": '\U0001D50F', + "Ll;": '\U000022D8', + "Lleftarrow;": '\U000021DA', + "Lmidot;": '\U0000013F', + "LongLeftArrow;": '\U000027F5', + "LongLeftRightArrow;": '\U000027F7', + "LongRightArrow;": '\U000027F6', + "Longleftarrow;": '\U000027F8', + "Longleftrightarrow;": '\U000027FA', + "Longrightarrow;": '\U000027F9', + "Lopf;": '\U0001D543', + "LowerLeftArrow;": '\U00002199', + "LowerRightArrow;": '\U00002198', + "Lscr;": '\U00002112', + "Lsh;": '\U000021B0', + "Lstrok;": '\U00000141', + "Lt;": '\U0000226A', + "Map;": '\U00002905', + "Mcy;": '\U0000041C', + "MediumSpace;": '\U0000205F', + "Mellintrf;": '\U00002133', + "Mfr;": '\U0001D510', + "MinusPlus;": '\U00002213', + "Mopf;": '\U0001D544', + "Mscr;": '\U00002133', + "Mu;": '\U0000039C', + "NJcy;": '\U0000040A', + "Nacute;": '\U00000143', + "Ncaron;": '\U00000147', + "Ncedil;": '\U00000145', + "Ncy;": '\U0000041D', + "NegativeMediumSpace;": '\U0000200B', + "NegativeThickSpace;": '\U0000200B', + "NegativeThinSpace;": '\U0000200B', + "NegativeVeryThinSpace;": '\U0000200B', + "NestedGreaterGreater;": '\U0000226B', + "NestedLessLess;": '\U0000226A', + "NewLine;": '\U0000000A', + "Nfr;": '\U0001D511', + "NoBreak;": '\U00002060', + "NonBreakingSpace;": '\U000000A0', + "Nopf;": '\U00002115', + "Not;": '\U00002AEC', + "NotCongruent;": '\U00002262', + "NotCupCap;": '\U0000226D', + "NotDoubleVerticalBar;": '\U00002226', + "NotElement;": '\U00002209', + "NotEqual;": '\U00002260', + "NotExists;": '\U00002204', + "NotGreater;": '\U0000226F', + "NotGreaterEqual;": '\U00002271', + "NotGreaterLess;": '\U00002279', + "NotGreaterTilde;": '\U00002275', + "NotLeftTriangle;": '\U000022EA', + "NotLeftTriangleEqual;": '\U000022EC', + "NotLess;": '\U0000226E', + "NotLessEqual;": '\U00002270', + "NotLessGreater;": '\U00002278', + "NotLessTilde;": '\U00002274', + "NotPrecedes;": '\U00002280', + "NotPrecedesSlantEqual;": '\U000022E0', + "NotReverseElement;": '\U0000220C', + "NotRightTriangle;": '\U000022EB', + "NotRightTriangleEqual;": '\U000022ED', + "NotSquareSubsetEqual;": '\U000022E2', + "NotSquareSupersetEqual;": '\U000022E3', + "NotSubsetEqual;": '\U00002288', + "NotSucceeds;": '\U00002281', + "NotSucceedsSlantEqual;": '\U000022E1', + "NotSupersetEqual;": '\U00002289', + "NotTilde;": '\U00002241', + "NotTildeEqual;": '\U00002244', + "NotTildeFullEqual;": '\U00002247', + "NotTildeTilde;": '\U00002249', + "NotVerticalBar;": '\U00002224', + "Nscr;": '\U0001D4A9', + "Ntilde;": '\U000000D1', + "Nu;": '\U0000039D', + "OElig;": '\U00000152', + "Oacute;": '\U000000D3', + "Ocirc;": '\U000000D4', + "Ocy;": '\U0000041E', + "Odblac;": '\U00000150', + "Ofr;": '\U0001D512', + "Ograve;": '\U000000D2', + "Omacr;": '\U0000014C', + "Omega;": '\U000003A9', + "Omicron;": '\U0000039F', + "Oopf;": '\U0001D546', + "OpenCurlyDoubleQuote;": '\U0000201C', + "OpenCurlyQuote;": '\U00002018', + "Or;": '\U00002A54', + "Oscr;": '\U0001D4AA', + "Oslash;": '\U000000D8', + "Otilde;": '\U000000D5', + "Otimes;": '\U00002A37', + "Ouml;": '\U000000D6', + "OverBar;": '\U0000203E', + "OverBrace;": '\U000023DE', + "OverBracket;": '\U000023B4', + "OverParenthesis;": '\U000023DC', + "PartialD;": '\U00002202', + "Pcy;": '\U0000041F', + "Pfr;": '\U0001D513', + "Phi;": '\U000003A6', + "Pi;": '\U000003A0', + "PlusMinus;": '\U000000B1', + "Poincareplane;": '\U0000210C', + "Popf;": '\U00002119', + "Pr;": '\U00002ABB', + "Precedes;": '\U0000227A', + "PrecedesEqual;": '\U00002AAF', + "PrecedesSlantEqual;": '\U0000227C', + "PrecedesTilde;": '\U0000227E', + "Prime;": '\U00002033', + "Product;": '\U0000220F', + "Proportion;": '\U00002237', + "Proportional;": '\U0000221D', + "Pscr;": '\U0001D4AB', + "Psi;": '\U000003A8', + "QUOT;": '\U00000022', + "Qfr;": '\U0001D514', + "Qopf;": '\U0000211A', + "Qscr;": '\U0001D4AC', + "RBarr;": '\U00002910', + "REG;": '\U000000AE', + "Racute;": '\U00000154', + "Rang;": '\U000027EB', + "Rarr;": '\U000021A0', + "Rarrtl;": '\U00002916', + "Rcaron;": '\U00000158', + "Rcedil;": '\U00000156', + "Rcy;": '\U00000420', + "Re;": '\U0000211C', + "ReverseElement;": '\U0000220B', + "ReverseEquilibrium;": '\U000021CB', + "ReverseUpEquilibrium;": '\U0000296F', + "Rfr;": '\U0000211C', + "Rho;": '\U000003A1', + "RightAngleBracket;": '\U000027E9', + "RightArrow;": '\U00002192', + "RightArrowBar;": '\U000021E5', + "RightArrowLeftArrow;": '\U000021C4', + "RightCeiling;": '\U00002309', + "RightDoubleBracket;": '\U000027E7', + "RightDownTeeVector;": '\U0000295D', + "RightDownVector;": '\U000021C2', + "RightDownVectorBar;": '\U00002955', + "RightFloor;": '\U0000230B', + "RightTee;": '\U000022A2', + "RightTeeArrow;": '\U000021A6', + "RightTeeVector;": '\U0000295B', + "RightTriangle;": '\U000022B3', + "RightTriangleBar;": '\U000029D0', + "RightTriangleEqual;": '\U000022B5', + "RightUpDownVector;": '\U0000294F', + "RightUpTeeVector;": '\U0000295C', + "RightUpVector;": '\U000021BE', + "RightUpVectorBar;": '\U00002954', + "RightVector;": '\U000021C0', + "RightVectorBar;": '\U00002953', + "Rightarrow;": '\U000021D2', + "Ropf;": '\U0000211D', + "RoundImplies;": '\U00002970', + "Rrightarrow;": '\U000021DB', + "Rscr;": '\U0000211B', + "Rsh;": '\U000021B1', + "RuleDelayed;": '\U000029F4', + "SHCHcy;": '\U00000429', + "SHcy;": '\U00000428', + "SOFTcy;": '\U0000042C', + "Sacute;": '\U0000015A', + "Sc;": '\U00002ABC', + "Scaron;": '\U00000160', + "Scedil;": '\U0000015E', + "Scirc;": '\U0000015C', + "Scy;": '\U00000421', + "Sfr;": '\U0001D516', + "ShortDownArrow;": '\U00002193', + "ShortLeftArrow;": '\U00002190', + "ShortRightArrow;": '\U00002192', + "ShortUpArrow;": '\U00002191', + "Sigma;": '\U000003A3', + "SmallCircle;": '\U00002218', + "Sopf;": '\U0001D54A', + "Sqrt;": '\U0000221A', + "Square;": '\U000025A1', + "SquareIntersection;": '\U00002293', + "SquareSubset;": '\U0000228F', + "SquareSubsetEqual;": '\U00002291', + "SquareSuperset;": '\U00002290', + "SquareSupersetEqual;": '\U00002292', + "SquareUnion;": '\U00002294', + "Sscr;": '\U0001D4AE', + "Star;": '\U000022C6', + "Sub;": '\U000022D0', + "Subset;": '\U000022D0', + "SubsetEqual;": '\U00002286', + "Succeeds;": '\U0000227B', + "SucceedsEqual;": '\U00002AB0', + "SucceedsSlantEqual;": '\U0000227D', + "SucceedsTilde;": '\U0000227F', + "SuchThat;": '\U0000220B', + "Sum;": '\U00002211', + "Sup;": '\U000022D1', + "Superset;": '\U00002283', + "SupersetEqual;": '\U00002287', + "Supset;": '\U000022D1', + "THORN;": '\U000000DE', + "TRADE;": '\U00002122', + "TSHcy;": '\U0000040B', + "TScy;": '\U00000426', + "Tab;": '\U00000009', + "Tau;": '\U000003A4', + "Tcaron;": '\U00000164', + "Tcedil;": '\U00000162', + "Tcy;": '\U00000422', + "Tfr;": '\U0001D517', + "Therefore;": '\U00002234', + "Theta;": '\U00000398', + "ThinSpace;": '\U00002009', + "Tilde;": '\U0000223C', + "TildeEqual;": '\U00002243', + "TildeFullEqual;": '\U00002245', + "TildeTilde;": '\U00002248', + "Topf;": '\U0001D54B', + "TripleDot;": '\U000020DB', + "Tscr;": '\U0001D4AF', + "Tstrok;": '\U00000166', + "Uacute;": '\U000000DA', + "Uarr;": '\U0000219F', + "Uarrocir;": '\U00002949', + "Ubrcy;": '\U0000040E', + "Ubreve;": '\U0000016C', + "Ucirc;": '\U000000DB', + "Ucy;": '\U00000423', + "Udblac;": '\U00000170', + "Ufr;": '\U0001D518', + "Ugrave;": '\U000000D9', + "Umacr;": '\U0000016A', + "UnderBar;": '\U0000005F', + "UnderBrace;": '\U000023DF', + "UnderBracket;": '\U000023B5', + "UnderParenthesis;": '\U000023DD', + "Union;": '\U000022C3', + "UnionPlus;": '\U0000228E', + "Uogon;": '\U00000172', + "Uopf;": '\U0001D54C', + "UpArrow;": '\U00002191', + "UpArrowBar;": '\U00002912', + "UpArrowDownArrow;": '\U000021C5', + "UpDownArrow;": '\U00002195', + "UpEquilibrium;": '\U0000296E', + "UpTee;": '\U000022A5', + "UpTeeArrow;": '\U000021A5', + "Uparrow;": '\U000021D1', + "Updownarrow;": '\U000021D5', + "UpperLeftArrow;": '\U00002196', + "UpperRightArrow;": '\U00002197', + "Upsi;": '\U000003D2', + "Upsilon;": '\U000003A5', + "Uring;": '\U0000016E', + "Uscr;": '\U0001D4B0', + "Utilde;": '\U00000168', + "Uuml;": '\U000000DC', + "VDash;": '\U000022AB', + "Vbar;": '\U00002AEB', + "Vcy;": '\U00000412', + "Vdash;": '\U000022A9', + "Vdashl;": '\U00002AE6', + "Vee;": '\U000022C1', + "Verbar;": '\U00002016', + "Vert;": '\U00002016', + "VerticalBar;": '\U00002223', + "VerticalLine;": '\U0000007C', + "VerticalSeparator;": '\U00002758', + "VerticalTilde;": '\U00002240', + "VeryThinSpace;": '\U0000200A', + "Vfr;": '\U0001D519', + "Vopf;": '\U0001D54D', + "Vscr;": '\U0001D4B1', + "Vvdash;": '\U000022AA', + "Wcirc;": '\U00000174', + "Wedge;": '\U000022C0', + "Wfr;": '\U0001D51A', + "Wopf;": '\U0001D54E', + "Wscr;": '\U0001D4B2', + "Xfr;": '\U0001D51B', + "Xi;": '\U0000039E', + "Xopf;": '\U0001D54F', + "Xscr;": '\U0001D4B3', + "YAcy;": '\U0000042F', + "YIcy;": '\U00000407', + "YUcy;": '\U0000042E', + "Yacute;": '\U000000DD', + "Ycirc;": '\U00000176', + "Ycy;": '\U0000042B', + "Yfr;": '\U0001D51C', + "Yopf;": '\U0001D550', + "Yscr;": '\U0001D4B4', + "Yuml;": '\U00000178', + "ZHcy;": '\U00000416', + "Zacute;": '\U00000179', + "Zcaron;": '\U0000017D', + "Zcy;": '\U00000417', + "Zdot;": '\U0000017B', + "ZeroWidthSpace;": '\U0000200B', + "Zeta;": '\U00000396', + "Zfr;": '\U00002128', + "Zopf;": '\U00002124', + "Zscr;": '\U0001D4B5', + "aacute;": '\U000000E1', + "abreve;": '\U00000103', + "ac;": '\U0000223E', + "acd;": '\U0000223F', + "acirc;": '\U000000E2', + "acute;": '\U000000B4', + "acy;": '\U00000430', + "aelig;": '\U000000E6', + "af;": '\U00002061', + "afr;": '\U0001D51E', + "agrave;": '\U000000E0', + "alefsym;": '\U00002135', + "aleph;": '\U00002135', + "alpha;": '\U000003B1', + "amacr;": '\U00000101', + "amalg;": '\U00002A3F', + "amp;": '\U00000026', + "and;": '\U00002227', + "andand;": '\U00002A55', + "andd;": '\U00002A5C', + "andslope;": '\U00002A58', + "andv;": '\U00002A5A', + "ang;": '\U00002220', + "ange;": '\U000029A4', + "angle;": '\U00002220', + "angmsd;": '\U00002221', + "angmsdaa;": '\U000029A8', + "angmsdab;": '\U000029A9', + "angmsdac;": '\U000029AA', + "angmsdad;": '\U000029AB', + "angmsdae;": '\U000029AC', + "angmsdaf;": '\U000029AD', + "angmsdag;": '\U000029AE', + "angmsdah;": '\U000029AF', + "angrt;": '\U0000221F', + "angrtvb;": '\U000022BE', + "angrtvbd;": '\U0000299D', + "angsph;": '\U00002222', + "angst;": '\U000000C5', + "angzarr;": '\U0000237C', + "aogon;": '\U00000105', + "aopf;": '\U0001D552', + "ap;": '\U00002248', + "apE;": '\U00002A70', + "apacir;": '\U00002A6F', + "ape;": '\U0000224A', + "apid;": '\U0000224B', + "apos;": '\U00000027', + "approx;": '\U00002248', + "approxeq;": '\U0000224A', + "aring;": '\U000000E5', + "ascr;": '\U0001D4B6', + "ast;": '\U0000002A', + "asymp;": '\U00002248', + "asympeq;": '\U0000224D', + "atilde;": '\U000000E3', + "auml;": '\U000000E4', + "awconint;": '\U00002233', + "awint;": '\U00002A11', + "bNot;": '\U00002AED', + "backcong;": '\U0000224C', + "backepsilon;": '\U000003F6', + "backprime;": '\U00002035', + "backsim;": '\U0000223D', + "backsimeq;": '\U000022CD', + "barvee;": '\U000022BD', + "barwed;": '\U00002305', + "barwedge;": '\U00002305', + "bbrk;": '\U000023B5', + "bbrktbrk;": '\U000023B6', + "bcong;": '\U0000224C', + "bcy;": '\U00000431', + "bdquo;": '\U0000201E', + "becaus;": '\U00002235', + "because;": '\U00002235', + "bemptyv;": '\U000029B0', + "bepsi;": '\U000003F6', + "bernou;": '\U0000212C', + "beta;": '\U000003B2', + "beth;": '\U00002136', + "between;": '\U0000226C', + "bfr;": '\U0001D51F', + "bigcap;": '\U000022C2', + "bigcirc;": '\U000025EF', + "bigcup;": '\U000022C3', + "bigodot;": '\U00002A00', + "bigoplus;": '\U00002A01', + "bigotimes;": '\U00002A02', + "bigsqcup;": '\U00002A06', + "bigstar;": '\U00002605', + "bigtriangledown;": '\U000025BD', + "bigtriangleup;": '\U000025B3', + "biguplus;": '\U00002A04', + "bigvee;": '\U000022C1', + "bigwedge;": '\U000022C0', + "bkarow;": '\U0000290D', + "blacklozenge;": '\U000029EB', + "blacksquare;": '\U000025AA', + "blacktriangle;": '\U000025B4', + "blacktriangledown;": '\U000025BE', + "blacktriangleleft;": '\U000025C2', + "blacktriangleright;": '\U000025B8', + "blank;": '\U00002423', + "blk12;": '\U00002592', + "blk14;": '\U00002591', + "blk34;": '\U00002593', + "block;": '\U00002588', + "bnot;": '\U00002310', + "bopf;": '\U0001D553', + "bot;": '\U000022A5', + "bottom;": '\U000022A5', + "bowtie;": '\U000022C8', + "boxDL;": '\U00002557', + "boxDR;": '\U00002554', + "boxDl;": '\U00002556', + "boxDr;": '\U00002553', + "boxH;": '\U00002550', + "boxHD;": '\U00002566', + "boxHU;": '\U00002569', + "boxHd;": '\U00002564', + "boxHu;": '\U00002567', + "boxUL;": '\U0000255D', + "boxUR;": '\U0000255A', + "boxUl;": '\U0000255C', + "boxUr;": '\U00002559', + "boxV;": '\U00002551', + "boxVH;": '\U0000256C', + "boxVL;": '\U00002563', + "boxVR;": '\U00002560', + "boxVh;": '\U0000256B', + "boxVl;": '\U00002562', + "boxVr;": '\U0000255F', + "boxbox;": '\U000029C9', + "boxdL;": '\U00002555', + "boxdR;": '\U00002552', + "boxdl;": '\U00002510', + "boxdr;": '\U0000250C', + "boxh;": '\U00002500', + "boxhD;": '\U00002565', + "boxhU;": '\U00002568', + "boxhd;": '\U0000252C', + "boxhu;": '\U00002534', + "boxminus;": '\U0000229F', + "boxplus;": '\U0000229E', + "boxtimes;": '\U000022A0', + "boxuL;": '\U0000255B', + "boxuR;": '\U00002558', + "boxul;": '\U00002518', + "boxur;": '\U00002514', + "boxv;": '\U00002502', + "boxvH;": '\U0000256A', + "boxvL;": '\U00002561', + "boxvR;": '\U0000255E', + "boxvh;": '\U0000253C', + "boxvl;": '\U00002524', + "boxvr;": '\U0000251C', + "bprime;": '\U00002035', + "breve;": '\U000002D8', + "brvbar;": '\U000000A6', + "bscr;": '\U0001D4B7', + "bsemi;": '\U0000204F', + "bsim;": '\U0000223D', + "bsime;": '\U000022CD', + "bsol;": '\U0000005C', + "bsolb;": '\U000029C5', + "bsolhsub;": '\U000027C8', + "bull;": '\U00002022', + "bullet;": '\U00002022', + "bump;": '\U0000224E', + "bumpE;": '\U00002AAE', + "bumpe;": '\U0000224F', + "bumpeq;": '\U0000224F', + "cacute;": '\U00000107', + "cap;": '\U00002229', + "capand;": '\U00002A44', + "capbrcup;": '\U00002A49', + "capcap;": '\U00002A4B', + "capcup;": '\U00002A47', + "capdot;": '\U00002A40', + "caret;": '\U00002041', + "caron;": '\U000002C7', + "ccaps;": '\U00002A4D', + "ccaron;": '\U0000010D', + "ccedil;": '\U000000E7', + "ccirc;": '\U00000109', + "ccups;": '\U00002A4C', + "ccupssm;": '\U00002A50', + "cdot;": '\U0000010B', + "cedil;": '\U000000B8', + "cemptyv;": '\U000029B2', + "cent;": '\U000000A2', + "centerdot;": '\U000000B7', + "cfr;": '\U0001D520', + "chcy;": '\U00000447', + "check;": '\U00002713', + "checkmark;": '\U00002713', + "chi;": '\U000003C7', + "cir;": '\U000025CB', + "cirE;": '\U000029C3', + "circ;": '\U000002C6', + "circeq;": '\U00002257', + "circlearrowleft;": '\U000021BA', + "circlearrowright;": '\U000021BB', + "circledR;": '\U000000AE', + "circledS;": '\U000024C8', + "circledast;": '\U0000229B', + "circledcirc;": '\U0000229A', + "circleddash;": '\U0000229D', + "cire;": '\U00002257', + "cirfnint;": '\U00002A10', + "cirmid;": '\U00002AEF', + "cirscir;": '\U000029C2', + "clubs;": '\U00002663', + "clubsuit;": '\U00002663', + "colon;": '\U0000003A', + "colone;": '\U00002254', + "coloneq;": '\U00002254', + "comma;": '\U0000002C', + "commat;": '\U00000040', + "comp;": '\U00002201', + "compfn;": '\U00002218', + "complement;": '\U00002201', + "complexes;": '\U00002102', + "cong;": '\U00002245', + "congdot;": '\U00002A6D', + "conint;": '\U0000222E', + "copf;": '\U0001D554', + "coprod;": '\U00002210', + "copy;": '\U000000A9', + "copysr;": '\U00002117', + "crarr;": '\U000021B5', + "cross;": '\U00002717', + "cscr;": '\U0001D4B8', + "csub;": '\U00002ACF', + "csube;": '\U00002AD1', + "csup;": '\U00002AD0', + "csupe;": '\U00002AD2', + "ctdot;": '\U000022EF', + "cudarrl;": '\U00002938', + "cudarrr;": '\U00002935', + "cuepr;": '\U000022DE', + "cuesc;": '\U000022DF', + "cularr;": '\U000021B6', + "cularrp;": '\U0000293D', + "cup;": '\U0000222A', + "cupbrcap;": '\U00002A48', + "cupcap;": '\U00002A46', + "cupcup;": '\U00002A4A', + "cupdot;": '\U0000228D', + "cupor;": '\U00002A45', + "curarr;": '\U000021B7', + "curarrm;": '\U0000293C', + "curlyeqprec;": '\U000022DE', + "curlyeqsucc;": '\U000022DF', + "curlyvee;": '\U000022CE', + "curlywedge;": '\U000022CF', + "curren;": '\U000000A4', + "curvearrowleft;": '\U000021B6', + "curvearrowright;": '\U000021B7', + "cuvee;": '\U000022CE', + "cuwed;": '\U000022CF', + "cwconint;": '\U00002232', + "cwint;": '\U00002231', + "cylcty;": '\U0000232D', + "dArr;": '\U000021D3', + "dHar;": '\U00002965', + "dagger;": '\U00002020', + "daleth;": '\U00002138', + "darr;": '\U00002193', + "dash;": '\U00002010', + "dashv;": '\U000022A3', + "dbkarow;": '\U0000290F', + "dblac;": '\U000002DD', + "dcaron;": '\U0000010F', + "dcy;": '\U00000434', + "dd;": '\U00002146', + "ddagger;": '\U00002021', + "ddarr;": '\U000021CA', + "ddotseq;": '\U00002A77', + "deg;": '\U000000B0', + "delta;": '\U000003B4', + "demptyv;": '\U000029B1', + "dfisht;": '\U0000297F', + "dfr;": '\U0001D521', + "dharl;": '\U000021C3', + "dharr;": '\U000021C2', + "diam;": '\U000022C4', + "diamond;": '\U000022C4', + "diamondsuit;": '\U00002666', + "diams;": '\U00002666', + "die;": '\U000000A8', + "digamma;": '\U000003DD', + "disin;": '\U000022F2', + "div;": '\U000000F7', + "divide;": '\U000000F7', + "divideontimes;": '\U000022C7', + "divonx;": '\U000022C7', + "djcy;": '\U00000452', + "dlcorn;": '\U0000231E', + "dlcrop;": '\U0000230D', + "dollar;": '\U00000024', + "dopf;": '\U0001D555', + "dot;": '\U000002D9', + "doteq;": '\U00002250', + "doteqdot;": '\U00002251', + "dotminus;": '\U00002238', + "dotplus;": '\U00002214', + "dotsquare;": '\U000022A1', + "doublebarwedge;": '\U00002306', + "downarrow;": '\U00002193', + "downdownarrows;": '\U000021CA', + "downharpoonleft;": '\U000021C3', + "downharpoonright;": '\U000021C2', + "drbkarow;": '\U00002910', + "drcorn;": '\U0000231F', + "drcrop;": '\U0000230C', + "dscr;": '\U0001D4B9', + "dscy;": '\U00000455', + "dsol;": '\U000029F6', + "dstrok;": '\U00000111', + "dtdot;": '\U000022F1', + "dtri;": '\U000025BF', + "dtrif;": '\U000025BE', + "duarr;": '\U000021F5', + "duhar;": '\U0000296F', + "dwangle;": '\U000029A6', + "dzcy;": '\U0000045F', + "dzigrarr;": '\U000027FF', + "eDDot;": '\U00002A77', + "eDot;": '\U00002251', + "eacute;": '\U000000E9', + "easter;": '\U00002A6E', + "ecaron;": '\U0000011B', + "ecir;": '\U00002256', + "ecirc;": '\U000000EA', + "ecolon;": '\U00002255', + "ecy;": '\U0000044D', + "edot;": '\U00000117', + "ee;": '\U00002147', + "efDot;": '\U00002252', + "efr;": '\U0001D522', + "eg;": '\U00002A9A', + "egrave;": '\U000000E8', + "egs;": '\U00002A96', + "egsdot;": '\U00002A98', + "el;": '\U00002A99', + "elinters;": '\U000023E7', + "ell;": '\U00002113', + "els;": '\U00002A95', + "elsdot;": '\U00002A97', + "emacr;": '\U00000113', + "empty;": '\U00002205', + "emptyset;": '\U00002205', + "emptyv;": '\U00002205', + "emsp;": '\U00002003', + "emsp13;": '\U00002004', + "emsp14;": '\U00002005', + "eng;": '\U0000014B', + "ensp;": '\U00002002', + "eogon;": '\U00000119', + "eopf;": '\U0001D556', + "epar;": '\U000022D5', + "eparsl;": '\U000029E3', + "eplus;": '\U00002A71', + "epsi;": '\U000003B5', + "epsilon;": '\U000003B5', + "epsiv;": '\U000003F5', + "eqcirc;": '\U00002256', + "eqcolon;": '\U00002255', + "eqsim;": '\U00002242', + "eqslantgtr;": '\U00002A96', + "eqslantless;": '\U00002A95', + "equals;": '\U0000003D', + "equest;": '\U0000225F', + "equiv;": '\U00002261', + "equivDD;": '\U00002A78', + "eqvparsl;": '\U000029E5', + "erDot;": '\U00002253', + "erarr;": '\U00002971', + "escr;": '\U0000212F', + "esdot;": '\U00002250', + "esim;": '\U00002242', + "eta;": '\U000003B7', + "eth;": '\U000000F0', + "euml;": '\U000000EB', + "euro;": '\U000020AC', + "excl;": '\U00000021', + "exist;": '\U00002203', + "expectation;": '\U00002130', + "exponentiale;": '\U00002147', + "fallingdotseq;": '\U00002252', + "fcy;": '\U00000444', + "female;": '\U00002640', + "ffilig;": '\U0000FB03', + "fflig;": '\U0000FB00', + "ffllig;": '\U0000FB04', + "ffr;": '\U0001D523', + "filig;": '\U0000FB01', + "flat;": '\U0000266D', + "fllig;": '\U0000FB02', + "fltns;": '\U000025B1', + "fnof;": '\U00000192', + "fopf;": '\U0001D557', + "forall;": '\U00002200', + "fork;": '\U000022D4', + "forkv;": '\U00002AD9', + "fpartint;": '\U00002A0D', + "frac12;": '\U000000BD', + "frac13;": '\U00002153', + "frac14;": '\U000000BC', + "frac15;": '\U00002155', + "frac16;": '\U00002159', + "frac18;": '\U0000215B', + "frac23;": '\U00002154', + "frac25;": '\U00002156', + "frac34;": '\U000000BE', + "frac35;": '\U00002157', + "frac38;": '\U0000215C', + "frac45;": '\U00002158', + "frac56;": '\U0000215A', + "frac58;": '\U0000215D', + "frac78;": '\U0000215E', + "frasl;": '\U00002044', + "frown;": '\U00002322', + "fscr;": '\U0001D4BB', + "gE;": '\U00002267', + "gEl;": '\U00002A8C', + "gacute;": '\U000001F5', + "gamma;": '\U000003B3', + "gammad;": '\U000003DD', + "gap;": '\U00002A86', + "gbreve;": '\U0000011F', + "gcirc;": '\U0000011D', + "gcy;": '\U00000433', + "gdot;": '\U00000121', + "ge;": '\U00002265', + "gel;": '\U000022DB', + "geq;": '\U00002265', + "geqq;": '\U00002267', + "geqslant;": '\U00002A7E', + "ges;": '\U00002A7E', + "gescc;": '\U00002AA9', + "gesdot;": '\U00002A80', + "gesdoto;": '\U00002A82', + "gesdotol;": '\U00002A84', + "gesles;": '\U00002A94', + "gfr;": '\U0001D524', + "gg;": '\U0000226B', + "ggg;": '\U000022D9', + "gimel;": '\U00002137', + "gjcy;": '\U00000453', + "gl;": '\U00002277', + "glE;": '\U00002A92', + "gla;": '\U00002AA5', + "glj;": '\U00002AA4', + "gnE;": '\U00002269', + "gnap;": '\U00002A8A', + "gnapprox;": '\U00002A8A', + "gne;": '\U00002A88', + "gneq;": '\U00002A88', + "gneqq;": '\U00002269', + "gnsim;": '\U000022E7', + "gopf;": '\U0001D558', + "grave;": '\U00000060', + "gscr;": '\U0000210A', + "gsim;": '\U00002273', + "gsime;": '\U00002A8E', + "gsiml;": '\U00002A90', + "gt;": '\U0000003E', + "gtcc;": '\U00002AA7', + "gtcir;": '\U00002A7A', + "gtdot;": '\U000022D7', + "gtlPar;": '\U00002995', + "gtquest;": '\U00002A7C', + "gtrapprox;": '\U00002A86', + "gtrarr;": '\U00002978', + "gtrdot;": '\U000022D7', + "gtreqless;": '\U000022DB', + "gtreqqless;": '\U00002A8C', + "gtrless;": '\U00002277', + "gtrsim;": '\U00002273', + "hArr;": '\U000021D4', + "hairsp;": '\U0000200A', + "half;": '\U000000BD', + "hamilt;": '\U0000210B', + "hardcy;": '\U0000044A', + "harr;": '\U00002194', + "harrcir;": '\U00002948', + "harrw;": '\U000021AD', + "hbar;": '\U0000210F', + "hcirc;": '\U00000125', + "hearts;": '\U00002665', + "heartsuit;": '\U00002665', + "hellip;": '\U00002026', + "hercon;": '\U000022B9', + "hfr;": '\U0001D525', + "hksearow;": '\U00002925', + "hkswarow;": '\U00002926', + "hoarr;": '\U000021FF', + "homtht;": '\U0000223B', + "hookleftarrow;": '\U000021A9', + "hookrightarrow;": '\U000021AA', + "hopf;": '\U0001D559', + "horbar;": '\U00002015', + "hscr;": '\U0001D4BD', + "hslash;": '\U0000210F', + "hstrok;": '\U00000127', + "hybull;": '\U00002043', + "hyphen;": '\U00002010', + "iacute;": '\U000000ED', + "ic;": '\U00002063', + "icirc;": '\U000000EE', + "icy;": '\U00000438', + "iecy;": '\U00000435', + "iexcl;": '\U000000A1', + "iff;": '\U000021D4', + "ifr;": '\U0001D526', + "igrave;": '\U000000EC', + "ii;": '\U00002148', + "iiiint;": '\U00002A0C', + "iiint;": '\U0000222D', + "iinfin;": '\U000029DC', + "iiota;": '\U00002129', + "ijlig;": '\U00000133', + "imacr;": '\U0000012B', + "image;": '\U00002111', + "imagline;": '\U00002110', + "imagpart;": '\U00002111', + "imath;": '\U00000131', + "imof;": '\U000022B7', + "imped;": '\U000001B5', + "in;": '\U00002208', + "incare;": '\U00002105', + "infin;": '\U0000221E', + "infintie;": '\U000029DD', + "inodot;": '\U00000131', + "int;": '\U0000222B', + "intcal;": '\U000022BA', + "integers;": '\U00002124', + "intercal;": '\U000022BA', + "intlarhk;": '\U00002A17', + "intprod;": '\U00002A3C', + "iocy;": '\U00000451', + "iogon;": '\U0000012F', + "iopf;": '\U0001D55A', + "iota;": '\U000003B9', + "iprod;": '\U00002A3C', + "iquest;": '\U000000BF', + "iscr;": '\U0001D4BE', + "isin;": '\U00002208', + "isinE;": '\U000022F9', + "isindot;": '\U000022F5', + "isins;": '\U000022F4', + "isinsv;": '\U000022F3', + "isinv;": '\U00002208', + "it;": '\U00002062', + "itilde;": '\U00000129', + "iukcy;": '\U00000456', + "iuml;": '\U000000EF', + "jcirc;": '\U00000135', + "jcy;": '\U00000439', + "jfr;": '\U0001D527', + "jmath;": '\U00000237', + "jopf;": '\U0001D55B', + "jscr;": '\U0001D4BF', + "jsercy;": '\U00000458', + "jukcy;": '\U00000454', + "kappa;": '\U000003BA', + "kappav;": '\U000003F0', + "kcedil;": '\U00000137', + "kcy;": '\U0000043A', + "kfr;": '\U0001D528', + "kgreen;": '\U00000138', + "khcy;": '\U00000445', + "kjcy;": '\U0000045C', + "kopf;": '\U0001D55C', + "kscr;": '\U0001D4C0', + "lAarr;": '\U000021DA', + "lArr;": '\U000021D0', + "lAtail;": '\U0000291B', + "lBarr;": '\U0000290E', + "lE;": '\U00002266', + "lEg;": '\U00002A8B', + "lHar;": '\U00002962', + "lacute;": '\U0000013A', + "laemptyv;": '\U000029B4', + "lagran;": '\U00002112', + "lambda;": '\U000003BB', + "lang;": '\U000027E8', + "langd;": '\U00002991', + "langle;": '\U000027E8', + "lap;": '\U00002A85', + "laquo;": '\U000000AB', + "larr;": '\U00002190', + "larrb;": '\U000021E4', + "larrbfs;": '\U0000291F', + "larrfs;": '\U0000291D', + "larrhk;": '\U000021A9', + "larrlp;": '\U000021AB', + "larrpl;": '\U00002939', + "larrsim;": '\U00002973', + "larrtl;": '\U000021A2', + "lat;": '\U00002AAB', + "latail;": '\U00002919', + "late;": '\U00002AAD', + "lbarr;": '\U0000290C', + "lbbrk;": '\U00002772', + "lbrace;": '\U0000007B', + "lbrack;": '\U0000005B', + "lbrke;": '\U0000298B', + "lbrksld;": '\U0000298F', + "lbrkslu;": '\U0000298D', + "lcaron;": '\U0000013E', + "lcedil;": '\U0000013C', + "lceil;": '\U00002308', + "lcub;": '\U0000007B', + "lcy;": '\U0000043B', + "ldca;": '\U00002936', + "ldquo;": '\U0000201C', + "ldquor;": '\U0000201E', + "ldrdhar;": '\U00002967', + "ldrushar;": '\U0000294B', + "ldsh;": '\U000021B2', + "le;": '\U00002264', + "leftarrow;": '\U00002190', + "leftarrowtail;": '\U000021A2', + "leftharpoondown;": '\U000021BD', + "leftharpoonup;": '\U000021BC', + "leftleftarrows;": '\U000021C7', + "leftrightarrow;": '\U00002194', + "leftrightarrows;": '\U000021C6', + "leftrightharpoons;": '\U000021CB', + "leftrightsquigarrow;": '\U000021AD', + "leftthreetimes;": '\U000022CB', + "leg;": '\U000022DA', + "leq;": '\U00002264', + "leqq;": '\U00002266', + "leqslant;": '\U00002A7D', + "les;": '\U00002A7D', + "lescc;": '\U00002AA8', + "lesdot;": '\U00002A7F', + "lesdoto;": '\U00002A81', + "lesdotor;": '\U00002A83', + "lesges;": '\U00002A93', + "lessapprox;": '\U00002A85', + "lessdot;": '\U000022D6', + "lesseqgtr;": '\U000022DA', + "lesseqqgtr;": '\U00002A8B', + "lessgtr;": '\U00002276', + "lesssim;": '\U00002272', + "lfisht;": '\U0000297C', + "lfloor;": '\U0000230A', + "lfr;": '\U0001D529', + "lg;": '\U00002276', + "lgE;": '\U00002A91', + "lhard;": '\U000021BD', + "lharu;": '\U000021BC', + "lharul;": '\U0000296A', + "lhblk;": '\U00002584', + "ljcy;": '\U00000459', + "ll;": '\U0000226A', + "llarr;": '\U000021C7', + "llcorner;": '\U0000231E', + "llhard;": '\U0000296B', + "lltri;": '\U000025FA', + "lmidot;": '\U00000140', + "lmoust;": '\U000023B0', + "lmoustache;": '\U000023B0', + "lnE;": '\U00002268', + "lnap;": '\U00002A89', + "lnapprox;": '\U00002A89', + "lne;": '\U00002A87', + "lneq;": '\U00002A87', + "lneqq;": '\U00002268', + "lnsim;": '\U000022E6', + "loang;": '\U000027EC', + "loarr;": '\U000021FD', + "lobrk;": '\U000027E6', + "longleftarrow;": '\U000027F5', + "longleftrightarrow;": '\U000027F7', + "longmapsto;": '\U000027FC', + "longrightarrow;": '\U000027F6', + "looparrowleft;": '\U000021AB', + "looparrowright;": '\U000021AC', + "lopar;": '\U00002985', + "lopf;": '\U0001D55D', + "loplus;": '\U00002A2D', + "lotimes;": '\U00002A34', + "lowast;": '\U00002217', + "lowbar;": '\U0000005F', + "loz;": '\U000025CA', + "lozenge;": '\U000025CA', + "lozf;": '\U000029EB', + "lpar;": '\U00000028', + "lparlt;": '\U00002993', + "lrarr;": '\U000021C6', + "lrcorner;": '\U0000231F', + "lrhar;": '\U000021CB', + "lrhard;": '\U0000296D', + "lrm;": '\U0000200E', + "lrtri;": '\U000022BF', + "lsaquo;": '\U00002039', + "lscr;": '\U0001D4C1', + "lsh;": '\U000021B0', + "lsim;": '\U00002272', + "lsime;": '\U00002A8D', + "lsimg;": '\U00002A8F', + "lsqb;": '\U0000005B', + "lsquo;": '\U00002018', + "lsquor;": '\U0000201A', + "lstrok;": '\U00000142', + "lt;": '\U0000003C', + "ltcc;": '\U00002AA6', + "ltcir;": '\U00002A79', + "ltdot;": '\U000022D6', + "lthree;": '\U000022CB', + "ltimes;": '\U000022C9', + "ltlarr;": '\U00002976', + "ltquest;": '\U00002A7B', + "ltrPar;": '\U00002996', + "ltri;": '\U000025C3', + "ltrie;": '\U000022B4', + "ltrif;": '\U000025C2', + "lurdshar;": '\U0000294A', + "luruhar;": '\U00002966', + "mDDot;": '\U0000223A', + "macr;": '\U000000AF', + "male;": '\U00002642', + "malt;": '\U00002720', + "maltese;": '\U00002720', + "map;": '\U000021A6', + "mapsto;": '\U000021A6', + "mapstodown;": '\U000021A7', + "mapstoleft;": '\U000021A4', + "mapstoup;": '\U000021A5', + "marker;": '\U000025AE', + "mcomma;": '\U00002A29', + "mcy;": '\U0000043C', + "mdash;": '\U00002014', + "measuredangle;": '\U00002221', + "mfr;": '\U0001D52A', + "mho;": '\U00002127', + "micro;": '\U000000B5', + "mid;": '\U00002223', + "midast;": '\U0000002A', + "midcir;": '\U00002AF0', + "middot;": '\U000000B7', + "minus;": '\U00002212', + "minusb;": '\U0000229F', + "minusd;": '\U00002238', + "minusdu;": '\U00002A2A', + "mlcp;": '\U00002ADB', + "mldr;": '\U00002026', + "mnplus;": '\U00002213', + "models;": '\U000022A7', + "mopf;": '\U0001D55E', + "mp;": '\U00002213', + "mscr;": '\U0001D4C2', + "mstpos;": '\U0000223E', + "mu;": '\U000003BC', + "multimap;": '\U000022B8', + "mumap;": '\U000022B8', + "nLeftarrow;": '\U000021CD', + "nLeftrightarrow;": '\U000021CE', + "nRightarrow;": '\U000021CF', + "nVDash;": '\U000022AF', + "nVdash;": '\U000022AE', + "nabla;": '\U00002207', + "nacute;": '\U00000144', + "nap;": '\U00002249', + "napos;": '\U00000149', + "napprox;": '\U00002249', + "natur;": '\U0000266E', + "natural;": '\U0000266E', + "naturals;": '\U00002115', + "nbsp;": '\U000000A0', + "ncap;": '\U00002A43', + "ncaron;": '\U00000148', + "ncedil;": '\U00000146', + "ncong;": '\U00002247', + "ncup;": '\U00002A42', + "ncy;": '\U0000043D', + "ndash;": '\U00002013', + "ne;": '\U00002260', + "neArr;": '\U000021D7', + "nearhk;": '\U00002924', + "nearr;": '\U00002197', + "nearrow;": '\U00002197', + "nequiv;": '\U00002262', + "nesear;": '\U00002928', + "nexist;": '\U00002204', + "nexists;": '\U00002204', + "nfr;": '\U0001D52B', + "nge;": '\U00002271', + "ngeq;": '\U00002271', + "ngsim;": '\U00002275', + "ngt;": '\U0000226F', + "ngtr;": '\U0000226F', + "nhArr;": '\U000021CE', + "nharr;": '\U000021AE', + "nhpar;": '\U00002AF2', + "ni;": '\U0000220B', + "nis;": '\U000022FC', + "nisd;": '\U000022FA', + "niv;": '\U0000220B', + "njcy;": '\U0000045A', + "nlArr;": '\U000021CD', + "nlarr;": '\U0000219A', + "nldr;": '\U00002025', + "nle;": '\U00002270', + "nleftarrow;": '\U0000219A', + "nleftrightarrow;": '\U000021AE', + "nleq;": '\U00002270', + "nless;": '\U0000226E', + "nlsim;": '\U00002274', + "nlt;": '\U0000226E', + "nltri;": '\U000022EA', + "nltrie;": '\U000022EC', + "nmid;": '\U00002224', + "nopf;": '\U0001D55F', + "not;": '\U000000AC', + "notin;": '\U00002209', + "notinva;": '\U00002209', + "notinvb;": '\U000022F7', + "notinvc;": '\U000022F6', + "notni;": '\U0000220C', + "notniva;": '\U0000220C', + "notnivb;": '\U000022FE', + "notnivc;": '\U000022FD', + "npar;": '\U00002226', + "nparallel;": '\U00002226', + "npolint;": '\U00002A14', + "npr;": '\U00002280', + "nprcue;": '\U000022E0', + "nprec;": '\U00002280', + "nrArr;": '\U000021CF', + "nrarr;": '\U0000219B', + "nrightarrow;": '\U0000219B', + "nrtri;": '\U000022EB', + "nrtrie;": '\U000022ED', + "nsc;": '\U00002281', + "nsccue;": '\U000022E1', + "nscr;": '\U0001D4C3', + "nshortmid;": '\U00002224', + "nshortparallel;": '\U00002226', + "nsim;": '\U00002241', + "nsime;": '\U00002244', + "nsimeq;": '\U00002244', + "nsmid;": '\U00002224', + "nspar;": '\U00002226', + "nsqsube;": '\U000022E2', + "nsqsupe;": '\U000022E3', + "nsub;": '\U00002284', + "nsube;": '\U00002288', + "nsubseteq;": '\U00002288', + "nsucc;": '\U00002281', + "nsup;": '\U00002285', + "nsupe;": '\U00002289', + "nsupseteq;": '\U00002289', + "ntgl;": '\U00002279', + "ntilde;": '\U000000F1', + "ntlg;": '\U00002278', + "ntriangleleft;": '\U000022EA', + "ntrianglelefteq;": '\U000022EC', + "ntriangleright;": '\U000022EB', + "ntrianglerighteq;": '\U000022ED', + "nu;": '\U000003BD', + "num;": '\U00000023', + "numero;": '\U00002116', + "numsp;": '\U00002007', + "nvDash;": '\U000022AD', + "nvHarr;": '\U00002904', + "nvdash;": '\U000022AC', + "nvinfin;": '\U000029DE', + "nvlArr;": '\U00002902', + "nvrArr;": '\U00002903', + "nwArr;": '\U000021D6', + "nwarhk;": '\U00002923', + "nwarr;": '\U00002196', + "nwarrow;": '\U00002196', + "nwnear;": '\U00002927', + "oS;": '\U000024C8', + "oacute;": '\U000000F3', + "oast;": '\U0000229B', + "ocir;": '\U0000229A', + "ocirc;": '\U000000F4', + "ocy;": '\U0000043E', + "odash;": '\U0000229D', + "odblac;": '\U00000151', + "odiv;": '\U00002A38', + "odot;": '\U00002299', + "odsold;": '\U000029BC', + "oelig;": '\U00000153', + "ofcir;": '\U000029BF', + "ofr;": '\U0001D52C', + "ogon;": '\U000002DB', + "ograve;": '\U000000F2', + "ogt;": '\U000029C1', + "ohbar;": '\U000029B5', + "ohm;": '\U000003A9', + "oint;": '\U0000222E', + "olarr;": '\U000021BA', + "olcir;": '\U000029BE', + "olcross;": '\U000029BB', + "oline;": '\U0000203E', + "olt;": '\U000029C0', + "omacr;": '\U0000014D', + "omega;": '\U000003C9', + "omicron;": '\U000003BF', + "omid;": '\U000029B6', + "ominus;": '\U00002296', + "oopf;": '\U0001D560', + "opar;": '\U000029B7', + "operp;": '\U000029B9', + "oplus;": '\U00002295', + "or;": '\U00002228', + "orarr;": '\U000021BB', + "ord;": '\U00002A5D', + "order;": '\U00002134', + "orderof;": '\U00002134', + "ordf;": '\U000000AA', + "ordm;": '\U000000BA', + "origof;": '\U000022B6', + "oror;": '\U00002A56', + "orslope;": '\U00002A57', + "orv;": '\U00002A5B', + "oscr;": '\U00002134', + "oslash;": '\U000000F8', + "osol;": '\U00002298', + "otilde;": '\U000000F5', + "otimes;": '\U00002297', + "otimesas;": '\U00002A36', + "ouml;": '\U000000F6', + "ovbar;": '\U0000233D', + "par;": '\U00002225', + "para;": '\U000000B6', + "parallel;": '\U00002225', + "parsim;": '\U00002AF3', + "parsl;": '\U00002AFD', + "part;": '\U00002202', + "pcy;": '\U0000043F', + "percnt;": '\U00000025', + "period;": '\U0000002E', + "permil;": '\U00002030', + "perp;": '\U000022A5', + "pertenk;": '\U00002031', + "pfr;": '\U0001D52D', + "phi;": '\U000003C6', + "phiv;": '\U000003D5', + "phmmat;": '\U00002133', + "phone;": '\U0000260E', + "pi;": '\U000003C0', + "pitchfork;": '\U000022D4', + "piv;": '\U000003D6', + "planck;": '\U0000210F', + "planckh;": '\U0000210E', + "plankv;": '\U0000210F', + "plus;": '\U0000002B', + "plusacir;": '\U00002A23', + "plusb;": '\U0000229E', + "pluscir;": '\U00002A22', + "plusdo;": '\U00002214', + "plusdu;": '\U00002A25', + "pluse;": '\U00002A72', + "plusmn;": '\U000000B1', + "plussim;": '\U00002A26', + "plustwo;": '\U00002A27', + "pm;": '\U000000B1', + "pointint;": '\U00002A15', + "popf;": '\U0001D561', + "pound;": '\U000000A3', + "pr;": '\U0000227A', + "prE;": '\U00002AB3', + "prap;": '\U00002AB7', + "prcue;": '\U0000227C', + "pre;": '\U00002AAF', + "prec;": '\U0000227A', + "precapprox;": '\U00002AB7', + "preccurlyeq;": '\U0000227C', + "preceq;": '\U00002AAF', + "precnapprox;": '\U00002AB9', + "precneqq;": '\U00002AB5', + "precnsim;": '\U000022E8', + "precsim;": '\U0000227E', + "prime;": '\U00002032', + "primes;": '\U00002119', + "prnE;": '\U00002AB5', + "prnap;": '\U00002AB9', + "prnsim;": '\U000022E8', + "prod;": '\U0000220F', + "profalar;": '\U0000232E', + "profline;": '\U00002312', + "profsurf;": '\U00002313', + "prop;": '\U0000221D', + "propto;": '\U0000221D', + "prsim;": '\U0000227E', + "prurel;": '\U000022B0', + "pscr;": '\U0001D4C5', + "psi;": '\U000003C8', + "puncsp;": '\U00002008', + "qfr;": '\U0001D52E', + "qint;": '\U00002A0C', + "qopf;": '\U0001D562', + "qprime;": '\U00002057', + "qscr;": '\U0001D4C6', + "quaternions;": '\U0000210D', + "quatint;": '\U00002A16', + "quest;": '\U0000003F', + "questeq;": '\U0000225F', + "quot;": '\U00000022', + "rAarr;": '\U000021DB', + "rArr;": '\U000021D2', + "rAtail;": '\U0000291C', + "rBarr;": '\U0000290F', + "rHar;": '\U00002964', + "racute;": '\U00000155', + "radic;": '\U0000221A', + "raemptyv;": '\U000029B3', + "rang;": '\U000027E9', + "rangd;": '\U00002992', + "range;": '\U000029A5', + "rangle;": '\U000027E9', + "raquo;": '\U000000BB', + "rarr;": '\U00002192', + "rarrap;": '\U00002975', + "rarrb;": '\U000021E5', + "rarrbfs;": '\U00002920', + "rarrc;": '\U00002933', + "rarrfs;": '\U0000291E', + "rarrhk;": '\U000021AA', + "rarrlp;": '\U000021AC', + "rarrpl;": '\U00002945', + "rarrsim;": '\U00002974', + "rarrtl;": '\U000021A3', + "rarrw;": '\U0000219D', + "ratail;": '\U0000291A', + "ratio;": '\U00002236', + "rationals;": '\U0000211A', + "rbarr;": '\U0000290D', + "rbbrk;": '\U00002773', + "rbrace;": '\U0000007D', + "rbrack;": '\U0000005D', + "rbrke;": '\U0000298C', + "rbrksld;": '\U0000298E', + "rbrkslu;": '\U00002990', + "rcaron;": '\U00000159', + "rcedil;": '\U00000157', + "rceil;": '\U00002309', + "rcub;": '\U0000007D', + "rcy;": '\U00000440', + "rdca;": '\U00002937', + "rdldhar;": '\U00002969', + "rdquo;": '\U0000201D', + "rdquor;": '\U0000201D', + "rdsh;": '\U000021B3', + "real;": '\U0000211C', + "realine;": '\U0000211B', + "realpart;": '\U0000211C', + "reals;": '\U0000211D', + "rect;": '\U000025AD', + "reg;": '\U000000AE', + "rfisht;": '\U0000297D', + "rfloor;": '\U0000230B', + "rfr;": '\U0001D52F', + "rhard;": '\U000021C1', + "rharu;": '\U000021C0', + "rharul;": '\U0000296C', + "rho;": '\U000003C1', + "rhov;": '\U000003F1', + "rightarrow;": '\U00002192', + "rightarrowtail;": '\U000021A3', + "rightharpoondown;": '\U000021C1', + "rightharpoonup;": '\U000021C0', + "rightleftarrows;": '\U000021C4', + "rightleftharpoons;": '\U000021CC', + "rightrightarrows;": '\U000021C9', + "rightsquigarrow;": '\U0000219D', + "rightthreetimes;": '\U000022CC', + "ring;": '\U000002DA', + "risingdotseq;": '\U00002253', + "rlarr;": '\U000021C4', + "rlhar;": '\U000021CC', + "rlm;": '\U0000200F', + "rmoust;": '\U000023B1', + "rmoustache;": '\U000023B1', + "rnmid;": '\U00002AEE', + "roang;": '\U000027ED', + "roarr;": '\U000021FE', + "robrk;": '\U000027E7', + "ropar;": '\U00002986', + "ropf;": '\U0001D563', + "roplus;": '\U00002A2E', + "rotimes;": '\U00002A35', + "rpar;": '\U00000029', + "rpargt;": '\U00002994', + "rppolint;": '\U00002A12', + "rrarr;": '\U000021C9', + "rsaquo;": '\U0000203A', + "rscr;": '\U0001D4C7', + "rsh;": '\U000021B1', + "rsqb;": '\U0000005D', + "rsquo;": '\U00002019', + "rsquor;": '\U00002019', + "rthree;": '\U000022CC', + "rtimes;": '\U000022CA', + "rtri;": '\U000025B9', + "rtrie;": '\U000022B5', + "rtrif;": '\U000025B8', + "rtriltri;": '\U000029CE', + "ruluhar;": '\U00002968', + "rx;": '\U0000211E', + "sacute;": '\U0000015B', + "sbquo;": '\U0000201A', + "sc;": '\U0000227B', + "scE;": '\U00002AB4', + "scap;": '\U00002AB8', + "scaron;": '\U00000161', + "sccue;": '\U0000227D', + "sce;": '\U00002AB0', + "scedil;": '\U0000015F', + "scirc;": '\U0000015D', + "scnE;": '\U00002AB6', + "scnap;": '\U00002ABA', + "scnsim;": '\U000022E9', + "scpolint;": '\U00002A13', + "scsim;": '\U0000227F', + "scy;": '\U00000441', + "sdot;": '\U000022C5', + "sdotb;": '\U000022A1', + "sdote;": '\U00002A66', + "seArr;": '\U000021D8', + "searhk;": '\U00002925', + "searr;": '\U00002198', + "searrow;": '\U00002198', + "sect;": '\U000000A7', + "semi;": '\U0000003B', + "seswar;": '\U00002929', + "setminus;": '\U00002216', + "setmn;": '\U00002216', + "sext;": '\U00002736', + "sfr;": '\U0001D530', + "sfrown;": '\U00002322', + "sharp;": '\U0000266F', + "shchcy;": '\U00000449', + "shcy;": '\U00000448', + "shortmid;": '\U00002223', + "shortparallel;": '\U00002225', + "shy;": '\U000000AD', + "sigma;": '\U000003C3', + "sigmaf;": '\U000003C2', + "sigmav;": '\U000003C2', + "sim;": '\U0000223C', + "simdot;": '\U00002A6A', + "sime;": '\U00002243', + "simeq;": '\U00002243', + "simg;": '\U00002A9E', + "simgE;": '\U00002AA0', + "siml;": '\U00002A9D', + "simlE;": '\U00002A9F', + "simne;": '\U00002246', + "simplus;": '\U00002A24', + "simrarr;": '\U00002972', + "slarr;": '\U00002190', + "smallsetminus;": '\U00002216', + "smashp;": '\U00002A33', + "smeparsl;": '\U000029E4', + "smid;": '\U00002223', + "smile;": '\U00002323', + "smt;": '\U00002AAA', + "smte;": '\U00002AAC', + "softcy;": '\U0000044C', + "sol;": '\U0000002F', + "solb;": '\U000029C4', + "solbar;": '\U0000233F', + "sopf;": '\U0001D564', + "spades;": '\U00002660', + "spadesuit;": '\U00002660', + "spar;": '\U00002225', + "sqcap;": '\U00002293', + "sqcup;": '\U00002294', + "sqsub;": '\U0000228F', + "sqsube;": '\U00002291', + "sqsubset;": '\U0000228F', + "sqsubseteq;": '\U00002291', + "sqsup;": '\U00002290', + "sqsupe;": '\U00002292', + "sqsupset;": '\U00002290', + "sqsupseteq;": '\U00002292', + "squ;": '\U000025A1', + "square;": '\U000025A1', + "squarf;": '\U000025AA', + "squf;": '\U000025AA', + "srarr;": '\U00002192', + "sscr;": '\U0001D4C8', + "ssetmn;": '\U00002216', + "ssmile;": '\U00002323', + "sstarf;": '\U000022C6', + "star;": '\U00002606', + "starf;": '\U00002605', + "straightepsilon;": '\U000003F5', + "straightphi;": '\U000003D5', + "strns;": '\U000000AF', + "sub;": '\U00002282', + "subE;": '\U00002AC5', + "subdot;": '\U00002ABD', + "sube;": '\U00002286', + "subedot;": '\U00002AC3', + "submult;": '\U00002AC1', + "subnE;": '\U00002ACB', + "subne;": '\U0000228A', + "subplus;": '\U00002ABF', + "subrarr;": '\U00002979', + "subset;": '\U00002282', + "subseteq;": '\U00002286', + "subseteqq;": '\U00002AC5', + "subsetneq;": '\U0000228A', + "subsetneqq;": '\U00002ACB', + "subsim;": '\U00002AC7', + "subsub;": '\U00002AD5', + "subsup;": '\U00002AD3', + "succ;": '\U0000227B', + "succapprox;": '\U00002AB8', + "succcurlyeq;": '\U0000227D', + "succeq;": '\U00002AB0', + "succnapprox;": '\U00002ABA', + "succneqq;": '\U00002AB6', + "succnsim;": '\U000022E9', + "succsim;": '\U0000227F', + "sum;": '\U00002211', + "sung;": '\U0000266A', + "sup;": '\U00002283', + "sup1;": '\U000000B9', + "sup2;": '\U000000B2', + "sup3;": '\U000000B3', + "supE;": '\U00002AC6', + "supdot;": '\U00002ABE', + "supdsub;": '\U00002AD8', + "supe;": '\U00002287', + "supedot;": '\U00002AC4', + "suphsol;": '\U000027C9', + "suphsub;": '\U00002AD7', + "suplarr;": '\U0000297B', + "supmult;": '\U00002AC2', + "supnE;": '\U00002ACC', + "supne;": '\U0000228B', + "supplus;": '\U00002AC0', + "supset;": '\U00002283', + "supseteq;": '\U00002287', + "supseteqq;": '\U00002AC6', + "supsetneq;": '\U0000228B', + "supsetneqq;": '\U00002ACC', + "supsim;": '\U00002AC8', + "supsub;": '\U00002AD4', + "supsup;": '\U00002AD6', + "swArr;": '\U000021D9', + "swarhk;": '\U00002926', + "swarr;": '\U00002199', + "swarrow;": '\U00002199', + "swnwar;": '\U0000292A', + "szlig;": '\U000000DF', + "target;": '\U00002316', + "tau;": '\U000003C4', + "tbrk;": '\U000023B4', + "tcaron;": '\U00000165', + "tcedil;": '\U00000163', + "tcy;": '\U00000442', + "tdot;": '\U000020DB', + "telrec;": '\U00002315', + "tfr;": '\U0001D531', + "there4;": '\U00002234', + "therefore;": '\U00002234', + "theta;": '\U000003B8', + "thetasym;": '\U000003D1', + "thetav;": '\U000003D1', + "thickapprox;": '\U00002248', + "thicksim;": '\U0000223C', + "thinsp;": '\U00002009', + "thkap;": '\U00002248', + "thksim;": '\U0000223C', + "thorn;": '\U000000FE', + "tilde;": '\U000002DC', + "times;": '\U000000D7', + "timesb;": '\U000022A0', + "timesbar;": '\U00002A31', + "timesd;": '\U00002A30', + "tint;": '\U0000222D', + "toea;": '\U00002928', + "top;": '\U000022A4', + "topbot;": '\U00002336', + "topcir;": '\U00002AF1', + "topf;": '\U0001D565', + "topfork;": '\U00002ADA', + "tosa;": '\U00002929', + "tprime;": '\U00002034', + "trade;": '\U00002122', + "triangle;": '\U000025B5', + "triangledown;": '\U000025BF', + "triangleleft;": '\U000025C3', + "trianglelefteq;": '\U000022B4', + "triangleq;": '\U0000225C', + "triangleright;": '\U000025B9', + "trianglerighteq;": '\U000022B5', + "tridot;": '\U000025EC', + "trie;": '\U0000225C', + "triminus;": '\U00002A3A', + "triplus;": '\U00002A39', + "trisb;": '\U000029CD', + "tritime;": '\U00002A3B', + "trpezium;": '\U000023E2', + "tscr;": '\U0001D4C9', + "tscy;": '\U00000446', + "tshcy;": '\U0000045B', + "tstrok;": '\U00000167', + "twixt;": '\U0000226C', + "twoheadleftarrow;": '\U0000219E', + "twoheadrightarrow;": '\U000021A0', + "uArr;": '\U000021D1', + "uHar;": '\U00002963', + "uacute;": '\U000000FA', + "uarr;": '\U00002191', + "ubrcy;": '\U0000045E', + "ubreve;": '\U0000016D', + "ucirc;": '\U000000FB', + "ucy;": '\U00000443', + "udarr;": '\U000021C5', + "udblac;": '\U00000171', + "udhar;": '\U0000296E', + "ufisht;": '\U0000297E', + "ufr;": '\U0001D532', + "ugrave;": '\U000000F9', + "uharl;": '\U000021BF', + "uharr;": '\U000021BE', + "uhblk;": '\U00002580', + "ulcorn;": '\U0000231C', + "ulcorner;": '\U0000231C', + "ulcrop;": '\U0000230F', + "ultri;": '\U000025F8', + "umacr;": '\U0000016B', + "uml;": '\U000000A8', + "uogon;": '\U00000173', + "uopf;": '\U0001D566', + "uparrow;": '\U00002191', + "updownarrow;": '\U00002195', + "upharpoonleft;": '\U000021BF', + "upharpoonright;": '\U000021BE', + "uplus;": '\U0000228E', + "upsi;": '\U000003C5', + "upsih;": '\U000003D2', + "upsilon;": '\U000003C5', + "upuparrows;": '\U000021C8', + "urcorn;": '\U0000231D', + "urcorner;": '\U0000231D', + "urcrop;": '\U0000230E', + "uring;": '\U0000016F', + "urtri;": '\U000025F9', + "uscr;": '\U0001D4CA', + "utdot;": '\U000022F0', + "utilde;": '\U00000169', + "utri;": '\U000025B5', + "utrif;": '\U000025B4', + "uuarr;": '\U000021C8', + "uuml;": '\U000000FC', + "uwangle;": '\U000029A7', + "vArr;": '\U000021D5', + "vBar;": '\U00002AE8', + "vBarv;": '\U00002AE9', + "vDash;": '\U000022A8', + "vangrt;": '\U0000299C', + "varepsilon;": '\U000003F5', + "varkappa;": '\U000003F0', + "varnothing;": '\U00002205', + "varphi;": '\U000003D5', + "varpi;": '\U000003D6', + "varpropto;": '\U0000221D', + "varr;": '\U00002195', + "varrho;": '\U000003F1', + "varsigma;": '\U000003C2', + "vartheta;": '\U000003D1', + "vartriangleleft;": '\U000022B2', + "vartriangleright;": '\U000022B3', + "vcy;": '\U00000432', + "vdash;": '\U000022A2', + "vee;": '\U00002228', + "veebar;": '\U000022BB', + "veeeq;": '\U0000225A', + "vellip;": '\U000022EE', + "verbar;": '\U0000007C', + "vert;": '\U0000007C', + "vfr;": '\U0001D533', + "vltri;": '\U000022B2', + "vopf;": '\U0001D567', + "vprop;": '\U0000221D', + "vrtri;": '\U000022B3', + "vscr;": '\U0001D4CB', + "vzigzag;": '\U0000299A', + "wcirc;": '\U00000175', + "wedbar;": '\U00002A5F', + "wedge;": '\U00002227', + "wedgeq;": '\U00002259', + "weierp;": '\U00002118', + "wfr;": '\U0001D534', + "wopf;": '\U0001D568', + "wp;": '\U00002118', + "wr;": '\U00002240', + "wreath;": '\U00002240', + "wscr;": '\U0001D4CC', + "xcap;": '\U000022C2', + "xcirc;": '\U000025EF', + "xcup;": '\U000022C3', + "xdtri;": '\U000025BD', + "xfr;": '\U0001D535', + "xhArr;": '\U000027FA', + "xharr;": '\U000027F7', + "xi;": '\U000003BE', + "xlArr;": '\U000027F8', + "xlarr;": '\U000027F5', + "xmap;": '\U000027FC', + "xnis;": '\U000022FB', + "xodot;": '\U00002A00', + "xopf;": '\U0001D569', + "xoplus;": '\U00002A01', + "xotime;": '\U00002A02', + "xrArr;": '\U000027F9', + "xrarr;": '\U000027F6', + "xscr;": '\U0001D4CD', + "xsqcup;": '\U00002A06', + "xuplus;": '\U00002A04', + "xutri;": '\U000025B3', + "xvee;": '\U000022C1', + "xwedge;": '\U000022C0', + "yacute;": '\U000000FD', + "yacy;": '\U0000044F', + "ycirc;": '\U00000177', + "ycy;": '\U0000044B', + "yen;": '\U000000A5', + "yfr;": '\U0001D536', + "yicy;": '\U00000457', + "yopf;": '\U0001D56A', + "yscr;": '\U0001D4CE', + "yucy;": '\U0000044E', + "yuml;": '\U000000FF', + "zacute;": '\U0000017A', + "zcaron;": '\U0000017E', + "zcy;": '\U00000437', + "zdot;": '\U0000017C', + "zeetrf;": '\U00002128', + "zeta;": '\U000003B6', + "zfr;": '\U0001D537', + "zhcy;": '\U00000436', + "zigrarr;": '\U000021DD', + "zopf;": '\U0001D56B', + "zscr;": '\U0001D4CF', + "zwj;": '\U0000200D', + "zwnj;": '\U0000200C', + "AElig": '\U000000C6', + "AMP": '\U00000026', + "Aacute": '\U000000C1', + "Acirc": '\U000000C2', + "Agrave": '\U000000C0', + "Aring": '\U000000C5', + "Atilde": '\U000000C3', + "Auml": '\U000000C4', + "COPY": '\U000000A9', + "Ccedil": '\U000000C7', + "ETH": '\U000000D0', + "Eacute": '\U000000C9', + "Ecirc": '\U000000CA', + "Egrave": '\U000000C8', + "Euml": '\U000000CB', + "GT": '\U0000003E', + "Iacute": '\U000000CD', + "Icirc": '\U000000CE', + "Igrave": '\U000000CC', + "Iuml": '\U000000CF', + "LT": '\U0000003C', + "Ntilde": '\U000000D1', + "Oacute": '\U000000D3', + "Ocirc": '\U000000D4', + "Ograve": '\U000000D2', + "Oslash": '\U000000D8', + "Otilde": '\U000000D5', + "Ouml": '\U000000D6', + "QUOT": '\U00000022', + "REG": '\U000000AE', + "THORN": '\U000000DE', + "Uacute": '\U000000DA', + "Ucirc": '\U000000DB', + "Ugrave": '\U000000D9', + "Uuml": '\U000000DC', + "Yacute": '\U000000DD', + "aacute": '\U000000E1', + "acirc": '\U000000E2', + "acute": '\U000000B4', + "aelig": '\U000000E6', + "agrave": '\U000000E0', + "amp": '\U00000026', + "aring": '\U000000E5', + "atilde": '\U000000E3', + "auml": '\U000000E4', + "brvbar": '\U000000A6', + "ccedil": '\U000000E7', + "cedil": '\U000000B8', + "cent": '\U000000A2', + "copy": '\U000000A9', + "curren": '\U000000A4', + "deg": '\U000000B0', + "divide": '\U000000F7', + "eacute": '\U000000E9', + "ecirc": '\U000000EA', + "egrave": '\U000000E8', + "eth": '\U000000F0', + "euml": '\U000000EB', + "frac12": '\U000000BD', + "frac14": '\U000000BC', + "frac34": '\U000000BE', + "gt": '\U0000003E', + "iacute": '\U000000ED', + "icirc": '\U000000EE', + "iexcl": '\U000000A1', + "igrave": '\U000000EC', + "iquest": '\U000000BF', + "iuml": '\U000000EF', + "laquo": '\U000000AB', + "lt": '\U0000003C', + "macr": '\U000000AF', + "micro": '\U000000B5', + "middot": '\U000000B7', + "nbsp": '\U000000A0', + "not": '\U000000AC', + "ntilde": '\U000000F1', + "oacute": '\U000000F3', + "ocirc": '\U000000F4', + "ograve": '\U000000F2', + "ordf": '\U000000AA', + "ordm": '\U000000BA', + "oslash": '\U000000F8', + "otilde": '\U000000F5', + "ouml": '\U000000F6', + "para": '\U000000B6', + "plusmn": '\U000000B1', + "pound": '\U000000A3', + "quot": '\U00000022', + "raquo": '\U000000BB', + "reg": '\U000000AE', + "sect": '\U000000A7', + "shy": '\U000000AD', + "sup1": '\U000000B9', + "sup2": '\U000000B2', + "sup3": '\U000000B3', + "szlig": '\U000000DF', + "thorn": '\U000000FE', + "times": '\U000000D7', + "uacute": '\U000000FA', + "ucirc": '\U000000FB', + "ugrave": '\U000000F9', + "uml": '\U000000A8', + "uuml": '\U000000FC', + "yacute": '\U000000FD', + "yen": '\U000000A5', + "yuml": '\U000000FF', +} + +// HTML entities that are two unicode codepoints. +var entity2 = map[string][2]rune{ + // TODO(nigeltao): Handle replacements that are wider than their names. + // "nLt;": {'\u226A', '\u20D2'}, + // "nGt;": {'\u226B', '\u20D2'}, + "NotEqualTilde;": {'\u2242', '\u0338'}, + "NotGreaterFullEqual;": {'\u2267', '\u0338'}, + "NotGreaterGreater;": {'\u226B', '\u0338'}, + "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, + "NotHumpDownHump;": {'\u224E', '\u0338'}, + "NotHumpEqual;": {'\u224F', '\u0338'}, + "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, + "NotLessLess;": {'\u226A', '\u0338'}, + "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, + "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, + "NotNestedLessLess;": {'\u2AA1', '\u0338'}, + "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, + "NotRightTriangleBar;": {'\u29D0', '\u0338'}, + "NotSquareSubset;": {'\u228F', '\u0338'}, + "NotSquareSuperset;": {'\u2290', '\u0338'}, + "NotSubset;": {'\u2282', '\u20D2'}, + "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, + "NotSucceedsTilde;": {'\u227F', '\u0338'}, + "NotSuperset;": {'\u2283', '\u20D2'}, + "ThickSpace;": {'\u205F', '\u200A'}, + "acE;": {'\u223E', '\u0333'}, + "bne;": {'\u003D', '\u20E5'}, + "bnequiv;": {'\u2261', '\u20E5'}, + "caps;": {'\u2229', '\uFE00'}, + "cups;": {'\u222A', '\uFE00'}, + "fjlig;": {'\u0066', '\u006A'}, + "gesl;": {'\u22DB', '\uFE00'}, + "gvertneqq;": {'\u2269', '\uFE00'}, + "gvnE;": {'\u2269', '\uFE00'}, + "lates;": {'\u2AAD', '\uFE00'}, + "lesg;": {'\u22DA', '\uFE00'}, + "lvertneqq;": {'\u2268', '\uFE00'}, + "lvnE;": {'\u2268', '\uFE00'}, + "nGg;": {'\u22D9', '\u0338'}, + "nGtv;": {'\u226B', '\u0338'}, + "nLl;": {'\u22D8', '\u0338'}, + "nLtv;": {'\u226A', '\u0338'}, + "nang;": {'\u2220', '\u20D2'}, + "napE;": {'\u2A70', '\u0338'}, + "napid;": {'\u224B', '\u0338'}, + "nbump;": {'\u224E', '\u0338'}, + "nbumpe;": {'\u224F', '\u0338'}, + "ncongdot;": {'\u2A6D', '\u0338'}, + "nedot;": {'\u2250', '\u0338'}, + "nesim;": {'\u2242', '\u0338'}, + "ngE;": {'\u2267', '\u0338'}, + "ngeqq;": {'\u2267', '\u0338'}, + "ngeqslant;": {'\u2A7E', '\u0338'}, + "nges;": {'\u2A7E', '\u0338'}, + "nlE;": {'\u2266', '\u0338'}, + "nleqq;": {'\u2266', '\u0338'}, + "nleqslant;": {'\u2A7D', '\u0338'}, + "nles;": {'\u2A7D', '\u0338'}, + "notinE;": {'\u22F9', '\u0338'}, + "notindot;": {'\u22F5', '\u0338'}, + "nparsl;": {'\u2AFD', '\u20E5'}, + "npart;": {'\u2202', '\u0338'}, + "npre;": {'\u2AAF', '\u0338'}, + "npreceq;": {'\u2AAF', '\u0338'}, + "nrarrc;": {'\u2933', '\u0338'}, + "nrarrw;": {'\u219D', '\u0338'}, + "nsce;": {'\u2AB0', '\u0338'}, + "nsubE;": {'\u2AC5', '\u0338'}, + "nsubset;": {'\u2282', '\u20D2'}, + "nsubseteqq;": {'\u2AC5', '\u0338'}, + "nsucceq;": {'\u2AB0', '\u0338'}, + "nsupE;": {'\u2AC6', '\u0338'}, + "nsupset;": {'\u2283', '\u20D2'}, + "nsupseteqq;": {'\u2AC6', '\u0338'}, + "nvap;": {'\u224D', '\u20D2'}, + "nvge;": {'\u2265', '\u20D2'}, + "nvgt;": {'\u003E', '\u20D2'}, + "nvle;": {'\u2264', '\u20D2'}, + "nvlt;": {'\u003C', '\u20D2'}, + "nvltrie;": {'\u22B4', '\u20D2'}, + "nvrtrie;": {'\u22B5', '\u20D2'}, + "nvsim;": {'\u223C', '\u20D2'}, + "race;": {'\u223D', '\u0331'}, + "smtes;": {'\u2AAC', '\uFE00'}, + "sqcaps;": {'\u2293', '\uFE00'}, + "sqcups;": {'\u2294', '\uFE00'}, + "varsubsetneq;": {'\u228A', '\uFE00'}, + "varsubsetneqq;": {'\u2ACB', '\uFE00'}, + "varsupsetneq;": {'\u228B', '\uFE00'}, + "varsupsetneqq;": {'\u2ACC', '\uFE00'}, + "vnsub;": {'\u2282', '\u20D2'}, + "vnsup;": {'\u2283', '\u20D2'}, + "vsubnE;": {'\u2ACB', '\uFE00'}, + "vsubne;": {'\u228A', '\uFE00'}, + "vsupnE;": {'\u2ACC', '\uFE00'}, + "vsupne;": {'\u228B', '\uFE00'}, +} diff --git a/libgo/go/exp/html/entity_test.go b/libgo/go/exp/html/entity_test.go new file mode 100644 index 00000000000..b53f866fa2d --- /dev/null +++ b/libgo/go/exp/html/entity_test.go @@ -0,0 +1,29 @@ +// Copyright 2010 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 html + +import ( + "testing" + "unicode/utf8" +) + +func TestEntityLength(t *testing.T) { + // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). + // The +1 comes from the leading "&". This property implies that the length of + // unescaped text is <= the length of escaped text. + for k, v := range entity { + if 1+len(k) < utf8.RuneLen(v) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) + } + if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { + t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) + } + } + for k, v := range entity2 { + if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) + } + } +} diff --git a/libgo/go/exp/html/escape.go b/libgo/go/exp/html/escape.go new file mode 100644 index 00000000000..42be865ef08 --- /dev/null +++ b/libgo/go/exp/html/escape.go @@ -0,0 +1,253 @@ +// Copyright 2010 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 html + +import ( + "bytes" + "strings" + "unicode/utf8" +) + +// 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 +var replacementTable = [...]rune{ + '\u20AC', // First entry is what 0x80 should be replaced with. + '\u0081', + '\u201A', + '\u0192', + '\u201E', + '\u2026', + '\u2020', + '\u2021', + '\u02C6', + '\u2030', + '\u0160', + '\u2039', + '\u0152', + '\u008D', + '\u017D', + '\u008F', + '\u0090', + '\u2018', + '\u2019', + '\u201C', + '\u201D', + '\u2022', + '\u2013', + '\u2014', + '\u02DC', + '\u2122', + '\u0161', + '\u203A', + '\u0153', + '\u009D', + '\u017E', + '\u0178', // Last entry is 0x9F. + // 0x00->'\uFFFD' is handled programmatically. + // 0x0D->'\u000D' is a no-op. +} + +// unescapeEntity reads an entity like "<" from b[src:] and writes the +// corresponding "<" to b[dst:], returning the incremented dst and src cursors. +// 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 + + // i starts at 1 because we already know that s[0] == '&'. + i, s := 1, b[src:] + + if len(s) <= 1 { + b[dst] = b[src] + return dst + 1, src + 1 + } + + if s[i] == '#' { + if len(s) <= 3 { // We need to have at least "&#.". + b[dst] = b[src] + return dst + 1, src + 1 + } + i++ + c := s[i] + hex := false + if c == 'x' || c == 'X' { + hex = true + i++ + } + + x := '\x00' + for i < len(s) { + c = s[i] + i++ + if hex { + if '0' <= c && c <= '9' { + x = 16*x + rune(c) - '0' + continue + } else if 'a' <= c && c <= 'f' { + x = 16*x + rune(c) - 'a' + 10 + continue + } else if 'A' <= c && c <= 'F' { + x = 16*x + rune(c) - 'A' + 10 + continue + } + } else if '0' <= c && c <= '9' { + x = 10*x + rune(c) - '0' + continue + } + if c != ';' { + i-- + } + break + } + + if i <= 3 { // No characters matched. + b[dst] = b[src] + return dst + 1, src + 1 + } + + if 0x80 <= x && x <= 0x9F { + // Replace characters from Windows-1252 with UTF-8 equivalents. + x = replacementTable[x-0x80] + } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { + // Replace invalid characters with the replacement character. + x = '\uFFFD' + } + + return dst + utf8.EncodeRune(b[dst:], x), src + i + } + + // Consume the maximum number of characters possible, with the + // consumed characters matching one of the named references. + + for i < len(s) { + c := s[i] + i++ + // Lower-cased characters are more common in entities, so we check for them first. + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { + continue + } + if c != ';' { + i-- + } + break + } + + entityName := string(s[1:i]) + if entityName == "" { + // No-op. + } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { + // No-op. + } else if x := entity[entityName]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + i + } else if x := entity2[entityName]; x[0] != 0 { + dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) + return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + } else if !attribute { + maxLen := len(entityName) - 1 + if maxLen > longestEntityWithoutSemicolon { + maxLen = longestEntityWithoutSemicolon + } + for j := maxLen; j > 1; j-- { + if x := entity[entityName[:j]]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + } + } + } + + dst1, src1 = dst+i, src+i + copy(b[dst:dst1], b[src:src1]) + return dst1, src1 +} + +// unescape unescapes b's entities in-place, so that "a<b" becomes "a<b". +func unescape(b []byte) []byte { + for i, c := range b { + if c == '&' { + dst, src := unescapeEntity(b, i, i, false) + for src < len(b) { + c := b[src] + if c == '&' { + dst, src = unescapeEntity(b, dst, src, false) + } else { + b[dst] = c + dst, src = dst+1, src+1 + } + } + return b[0:dst] + } + } + return b +} + +// lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc". +func lower(b []byte) []byte { + for i, c := range b { + if 'A' <= c && c <= 'Z' { + b[i] = c + 'a' - 'A' + } + } + return b +} + +const escapedChars = `&'<>"` + +func escape(w writer, s string) error { + i := strings.IndexAny(s, escapedChars) + for i != -1 { + if _, err := w.WriteString(s[:i]); err != nil { + return err + } + var esc string + switch s[i] { + case '&': + esc = "&" + case '\'': + esc = "'" + case '<': + esc = "<" + case '>': + esc = ">" + case '"': + esc = """ + default: + panic("unrecognized escape character") + } + s = s[i+1:] + if _, err := w.WriteString(esc); err != nil { + return err + } + i = strings.IndexAny(s, escapedChars) + } + _, err := w.WriteString(s) + return err +} + +// EscapeString escapes special characters like "<" to become "<". It +// escapes only five such characters: amp, apos, lt, gt and quot. +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func EscapeString(s string) string { + if strings.IndexAny(s, escapedChars) == -1 { + return s + } + buf := bytes.NewBuffer(nil) + escape(buf, s) + return buf.String() +} + +// UnescapeString unescapes entities like "<" to become "<". It unescapes a +// larger range of entities than EscapeString escapes. For example, "á" +// unescapes to "á", as does "á" and "&xE1;". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func UnescapeString(s string) string { + for _, c := range s { + if c == '&' { + return string(unescape([]byte(s))) + } + } + return s +} diff --git a/libgo/go/exp/html/foreign.go b/libgo/go/exp/html/foreign.go new file mode 100644 index 00000000000..3ba81ce4d6f --- /dev/null +++ b/libgo/go/exp/html/foreign.go @@ -0,0 +1,132 @@ +// Copyright 2011 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 html + +import ( + "strings" +) + +func adjustForeignAttributes(aa []Attribute) { + for i, a := range aa { + if a.Key == "" || a.Key[0] != 'x' { + continue + } + switch a.Key { + case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", + "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": + j := strings.Index(a.Key, ":") + aa[i].Namespace = a.Key[:j] + aa[i].Key = a.Key[j+1:] + } + } +} + +func htmlIntegrationPoint(n *Node) bool { + if n.Type != ElementNode { + return false + } + switch n.Namespace { + case "math": + // TODO: annotation-xml elements whose start tags have "text/html" or + // "application/xhtml+xml" encodings. + case "svg": + switch n.Data { + case "desc", "foreignObject", "title": + return true + } + } + return false +} + +// Section 12.2.5.5. +var breakout = map[string]bool{ + "b": true, + "big": true, + "blockquote": true, + "body": true, + "br": true, + "center": true, + "code": true, + "dd": true, + "div": true, + "dl": true, + "dt": true, + "em": true, + "embed": true, + "font": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "hr": true, + "i": true, + "img": true, + "li": true, + "listing": true, + "menu": true, + "meta": true, + "nobr": true, + "ol": true, + "p": true, + "pre": true, + "ruby": true, + "s": true, + "small": true, + "span": true, + "strong": true, + "strike": true, + "sub": true, + "sup": true, + "table": true, + "tt": true, + "u": true, + "ul": true, + "var": true, +} + +// Section 12.2.5.5. +var svgTagNameAdjustments = map[string]string{ + "altglyph": "altGlyph", + "altglyphdef": "altGlyphDef", + "altglyphitem": "altGlyphItem", + "animatecolor": "animateColor", + "animatemotion": "animateMotion", + "animatetransform": "animateTransform", + "clippath": "clipPath", + "feblend": "feBlend", + "fecolormatrix": "feColorMatrix", + "fecomponenttransfer": "feComponentTransfer", + "fecomposite": "feComposite", + "feconvolvematrix": "feConvolveMatrix", + "fediffuselighting": "feDiffuseLighting", + "fedisplacementmap": "feDisplacementMap", + "fedistantlight": "feDistantLight", + "feflood": "feFlood", + "fefunca": "feFuncA", + "fefuncb": "feFuncB", + "fefuncg": "feFuncG", + "fefuncr": "feFuncR", + "fegaussianblur": "feGaussianBlur", + "feimage": "feImage", + "femerge": "feMerge", + "femergenode": "feMergeNode", + "femorphology": "feMorphology", + "feoffset": "feOffset", + "fepointlight": "fePointLight", + "fespecularlighting": "feSpecularLighting", + "fespotlight": "feSpotLight", + "fetile": "feTile", + "feturbulence": "feTurbulence", + "foreignobject": "foreignObject", + "glyphref": "glyphRef", + "lineargradient": "linearGradient", + "radialgradient": "radialGradient", + "textpath": "textPath", +} + +// TODO: add look-up tables for MathML and SVG attribute adjustments. diff --git a/libgo/go/exp/html/node.go b/libgo/go/exp/html/node.go new file mode 100644 index 00000000000..83f17308b18 --- /dev/null +++ b/libgo/go/exp/html/node.go @@ -0,0 +1,154 @@ +// Copyright 2011 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 html + +// A NodeType is the type of a Node. +type NodeType int + +const ( + ErrorNode NodeType = iota + TextNode + DocumentNode + ElementNode + CommentNode + DoctypeNode + scopeMarkerNode +) + +// Section 12.2.3.3 says "scope markers are inserted when entering applet +// elements, buttons, object elements, marquees, table cells, and table +// captions, and are used to prevent formatting from 'leaking'". +var scopeMarker = Node{Type: scopeMarkerNode} + +// A Node consists of a NodeType and some Data (tag name for element nodes, +// content for text) and are part of a tree of Nodes. Element nodes may also +// have a Namespace and contain a slice of Attributes. Data is unescaped, so +// that it looks like "a<b" rather than "a<b". +// +// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace. +// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and +// "svg" is short for "http://www.w3.org/2000/svg". +type Node struct { + Parent *Node + Child []*Node + Type NodeType + Data string + Namespace string + Attr []Attribute +} + +// Add adds a node as a child of n. +// It will panic if the child's parent is not nil. +func (n *Node) Add(child *Node) { + if child.Parent != nil { + panic("html: Node.Add called for a child Node that already has a parent") + } + child.Parent = n + n.Child = append(n.Child, child) +} + +// Remove removes a node as a child of n. +// It will panic if the child's parent is not n. +func (n *Node) Remove(child *Node) { + if child.Parent == n { + child.Parent = nil + for i, m := range n.Child { + if m == child { + copy(n.Child[i:], n.Child[i+1:]) + j := len(n.Child) - 1 + n.Child[j] = nil + n.Child = n.Child[:j] + return + } + } + } + panic("html: Node.Remove called for a non-child Node") +} + +// reparentChildren reparents all of src's child nodes to dst. +func reparentChildren(dst, src *Node) { + for _, n := range src.Child { + if n.Parent != src { + panic("html: nodes have an inconsistent parent/child relationship") + } + n.Parent = dst + } + dst.Child = append(dst.Child, src.Child...) + src.Child = nil +} + +// clone returns a new node with the same type, data and attributes. +// The clone has no parent and no children. +func (n *Node) clone() *Node { + m := &Node{ + Type: n.Type, + Data: n.Data, + Attr: make([]Attribute, len(n.Attr)), + } + copy(m.Attr, n.Attr) + return m +} + +// nodeStack is a stack of nodes. +type nodeStack []*Node + +// pop pops the stack. It will panic if s is empty. +func (s *nodeStack) pop() *Node { + i := len(*s) + n := (*s)[i-1] + *s = (*s)[:i-1] + return n +} + +// top returns the most recently pushed node, or nil if s is empty. +func (s *nodeStack) top() *Node { + if i := len(*s); i > 0 { + return (*s)[i-1] + } + return nil +} + +// index returns the index of the top-most occurence of n in the stack, or -1 +// if n is not present. +func (s *nodeStack) index(n *Node) int { + for i := len(*s) - 1; i >= 0; i-- { + if (*s)[i] == n { + return i + } + } + return -1 +} + +// insert inserts a node at the given index. +func (s *nodeStack) insert(i int, n *Node) { + (*s) = append(*s, nil) + copy((*s)[i+1:], (*s)[i:]) + (*s)[i] = n +} + +// remove removes a node from the stack. It is a no-op if n is not present. +func (s *nodeStack) remove(n *Node) { + i := s.index(n) + if i == -1 { + return + } + copy((*s)[i:], (*s)[i+1:]) + j := len(*s) - 1 + (*s)[j] = nil + *s = (*s)[:j] +} + +// TODO(nigeltao): forTag no longer used. Should it be deleted? + +// forTag returns the top-most element node with the given tag. +func (s *nodeStack) forTag(tag string) *Node { + for i := len(*s) - 1; i >= 0; i-- { + n := (*s)[i] + if n.Type == ElementNode && n.Data == tag { + return n + } + } + return nil +} diff --git a/libgo/go/exp/html/parse.go b/libgo/go/exp/html/parse.go new file mode 100644 index 00000000000..04f4ae75334 --- /dev/null +++ b/libgo/go/exp/html/parse.go @@ -0,0 +1,1869 @@ +// Copyright 2010 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 html + +import ( + "io" + "strings" +) + +// A parser implements the HTML5 parsing algorithm: +// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction +type parser struct { + // tokenizer provides the tokens for the parser. + tokenizer *Tokenizer + // tok is the most recently read token. + tok Token + // Self-closing tags like <hr/> are re-interpreted as a two-token sequence: + // <hr> followed by </hr>. hasSelfClosingToken is true if we have just read + // the synthetic start tag and the next one due is the matching end tag. + hasSelfClosingToken bool + // doc is the document root element. + doc *Node + // The stack of open elements (section 12.2.3.2) and active formatting + // elements (section 12.2.3.3). + oe, afe nodeStack + // Element pointers (section 12.2.3.4). + head, form *Node + // Other parsing state flags (section 12.2.3.5). + scripting, framesetOK bool + // im is the current insertion mode. + im insertionMode + // originalIM is the insertion mode to go back to after completing a text + // or inTableText insertion mode. + originalIM insertionMode + // fosterParenting is whether new elements should be inserted according to + // the foster parenting rules (section 12.2.5.3). + fosterParenting bool + // quirks is whether the parser is operating in "quirks mode." + quirks bool + // context is the context element when parsing an HTML fragment + // (section 12.4). + context *Node +} + +func (p *parser) top() *Node { + if n := p.oe.top(); n != nil { + return n + } + return p.doc +} + +// Stop tags for use in popUntil. These come from section 12.2.3.2. +var ( + defaultScopeStopTags = map[string][]string{ + "": {"applet", "caption", "html", "table", "td", "th", "marquee", "object"}, + "math": {"annotation-xml", "mi", "mn", "mo", "ms", "mtext"}, + "svg": {"desc", "foreignObject", "title"}, + } +) + +type scope int + +const ( + defaultScope scope = iota + listItemScope + buttonScope + tableScope + tableRowScope +) + +// 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 +// tags (as defined in section 12.2.3.2). It returns whether or not there was +// 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 +// the stack was: +// ["html", "body", "font", "table", "b", "i", "u"] +// then popUntil(tableScope, "font") would return false, but +// popUntil(tableScope, "i") would return true and the stack would become: +// ["html", "body", "font", "table", "b"] +// +// If an element's tag is in both the stop tags and matchTags, then the stack +// will be popped and the function returns true (provided, of course, there was +// no higher element in the stack that was also in the stop tags). For example, +// popUntil(tableScope, "table") returns true and leaves: +// ["html", "body", "font"] +func (p *parser) popUntil(s scope, matchTags ...string) bool { + if i := p.indexOfElementInScope(s, matchTags...); i != -1 { + p.oe = p.oe[:i] + return true + } + return false +} + +// indexOfElementInScope returns the index in p.oe of the highest element whose +// tag is in matchTags that is in scope. If no matching element is in scope, it +// returns -1. +func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int { + for i := len(p.oe) - 1; i >= 0; i-- { + tag := p.oe[i].Data + if p.oe[i].Namespace == "" { + for _, t := range matchTags { + if t == tag { + return i + } + } + switch s { + case defaultScope: + // No-op. + case listItemScope: + if tag == "ol" || tag == "ul" { + return -1 + } + case buttonScope: + if tag == "button" { + return -1 + } + case tableScope: + if tag == "html" || tag == "table" { + return -1 + } + default: + panic("unreachable") + } + } + switch s { + case defaultScope, listItemScope, buttonScope: + for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { + if t == tag { + return -1 + } + } + } + } + return -1 +} + +// elementInScope is like popUntil, except that it doesn't modify the stack of +// open elements. +func (p *parser) elementInScope(s scope, matchTags ...string) bool { + return p.indexOfElementInScope(s, matchTags...) != -1 +} + +// clearStackToContext pops elements off the stack of open elements until a +// scope-defined element is found. +func (p *parser) clearStackToContext(s scope) { + for i := len(p.oe) - 1; i >= 0; i-- { + tag := p.oe[i].Data + switch s { + case tableScope: + if tag == "html" || tag == "table" { + p.oe = p.oe[:i+1] + return + } + case tableRowScope: + if tag == "html" || tag == "tr" { + p.oe = p.oe[:i+1] + return + } + default: + panic("unreachable") + } + } +} + +// addChild adds a child node n to the top element, and pushes n onto the stack +// of open elements if it is an element node. +func (p *parser) addChild(n *Node) { + if p.fosterParenting { + p.fosterParent(n) + } else { + p.top().Add(n) + } + + if n.Type == ElementNode { + p.oe = append(p.oe, n) + } +} + +// fosterParent adds a child node according to the foster parenting rules. +// Section 12.2.5.3, "foster parenting". +func (p *parser) fosterParent(n *Node) { + p.fosterParenting = false + var table, parent *Node + var i int + for i = len(p.oe) - 1; i >= 0; i-- { + if p.oe[i].Data == "table" { + table = p.oe[i] + break + } + } + + if table == nil { + // The foster parent is the html element. + parent = p.oe[0] + } else { + parent = table.Parent + } + if parent == nil { + parent = p.oe[i-1] + } + + var child *Node + for i, child = range parent.Child { + if child == table { + break + } + } + + if i > 0 && parent.Child[i-1].Type == TextNode && n.Type == TextNode { + parent.Child[i-1].Data += n.Data + return + } + + if i == len(parent.Child) { + parent.Add(n) + } else { + // Insert n into parent.Child at index i. + parent.Child = append(parent.Child[:i+1], parent.Child[i:]...) + parent.Child[i] = n + n.Parent = parent + } +} + +// addText adds text to the preceding node if it is a text node, or else it +// calls addChild with a new text node. +func (p *parser) addText(text string) { + // TODO: distinguish whitespace text from others. + t := p.top() + if i := len(t.Child); i > 0 && t.Child[i-1].Type == TextNode { + t.Child[i-1].Data += text + return + } + p.addChild(&Node{ + Type: TextNode, + Data: text, + }) +} + +// addElement calls addChild with an element node. +func (p *parser) addElement(tag string, attr []Attribute) { + p.addChild(&Node{ + Type: ElementNode, + Data: tag, + Attr: attr, + }) +} + +// Section 12.2.3.3. +func (p *parser) addFormattingElement(tag string, attr []Attribute) { + p.addElement(tag, attr) + p.afe = append(p.afe, p.top()) + // TODO. +} + +// Section 12.2.3.3. +func (p *parser) clearActiveFormattingElements() { + for { + n := p.afe.pop() + if len(p.afe) == 0 || n.Type == scopeMarkerNode { + return + } + } +} + +// Section 12.2.3.3. +func (p *parser) reconstructActiveFormattingElements() { + n := p.afe.top() + if n == nil { + return + } + if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { + return + } + i := len(p.afe) - 1 + for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { + if i == 0 { + i = -1 + break + } + i-- + n = p.afe[i] + } + for { + i++ + clone := p.afe[i].clone() + p.addChild(clone) + p.afe[i] = clone + if i == len(p.afe)-1 { + break + } + } +} + +// read reads the next token. This is usually from the tokenizer, but it may +// be the synthesized end tag implied by a self-closing tag. +func (p *parser) read() error { + if p.hasSelfClosingToken { + p.hasSelfClosingToken = false + p.tok.Type = EndTagToken + p.tok.Attr = nil + return nil + } + p.tokenizer.Next() + p.tok = p.tokenizer.Token() + switch p.tok.Type { + case ErrorToken: + return p.tokenizer.Err() + case SelfClosingTagToken: + p.hasSelfClosingToken = true + p.tok.Type = StartTagToken + } + return nil +} + +// Section 12.2.4. +func (p *parser) acknowledgeSelfClosingTag() { + p.hasSelfClosingToken = false +} + +// An insertion mode (section 12.2.3.1) is the state transition function from +// a particular state in the HTML5 parser's state machine. It updates the +// parser's fields depending on parser.tok (where ErrorToken means EOF). +// It returns whether the token was consumed. +type insertionMode func(*parser) bool + +// setOriginalIM sets the insertion mode to return to after completing a text or +// inTableText insertion mode. +// Section 12.2.3.1, "using the rules for". +func (p *parser) setOriginalIM() { + if p.originalIM != nil { + panic("html: bad parser state: originalIM was set twice") + } + p.originalIM = p.im +} + +// Section 12.2.3.1, "reset the insertion mode". +func (p *parser) resetInsertionMode() { + for i := len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if i == 0 && p.context != nil { + n = p.context + } + + switch n.Data { + case "select": + p.im = inSelectIM + case "td", "th": + p.im = inCellIM + case "tr": + p.im = inRowIM + case "tbody", "thead", "tfoot": + p.im = inTableBodyIM + case "caption": + p.im = inCaptionIM + case "colgroup": + p.im = inColumnGroupIM + case "table": + p.im = inTableIM + case "head": + p.im = inBodyIM + case "body": + p.im = inBodyIM + case "frameset": + p.im = inFramesetIM + case "html": + p.im = beforeHeadIM + default: + continue + } + return + } + p.im = inBodyIM +} + +const whitespace = " \t\r\n\f" + +// Section 12.2.5.4.1. +func initialIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case CommentToken: + p.doc.Add(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + n, quirks := parseDoctype(p.tok.Data) + p.doc.Add(n) + p.quirks = quirks + p.im = beforeHTMLIM + return true + } + p.quirks = true + p.im = beforeHTMLIM + return false +} + +// Section 12.2.5.4.2. +func beforeHTMLIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case StartTagToken: + if p.tok.Data == "html" { + p.addElement(p.tok.Data, p.tok.Attr) + p.im = beforeHeadIM + return true + } + case EndTagToken: + switch p.tok.Data { + case "head", "body", "html", "br": + // Drop down to creating an implied <html> tag. + default: + // Ignore the token. + return true + } + case CommentToken: + p.doc.Add(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + // Create an implied <html> tag. + p.addElement("html", nil) + p.im = beforeHeadIM + return false +} + +// Section 12.2.5.4.3. +func beforeHeadIM(p *parser) bool { + var ( + add bool + attr []Attribute + implied bool + ) + switch p.tok.Type { + case ErrorToken: + implied = true + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + implied = true + case StartTagToken: + switch p.tok.Data { + case "head": + add = true + attr = p.tok.Attr + case "html": + return inBodyIM(p) + default: + implied = true + } + case EndTagToken: + switch p.tok.Data { + case "head", "body", "html", "br": + implied = true + default: + // Ignore the token. + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + if add || implied { + p.addElement("head", attr) + p.head = p.top() + } + p.im = inHeadIM + return !implied +} + +// Section 12.2.5.4.4. +func inHeadIM(p *parser) bool { + var ( + pop bool + implied bool + ) + switch p.tok.Type { + case ErrorToken: + implied = true + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + implied = true + case StartTagToken: + switch p.tok.Data { + case "html": + return inBodyIM(p) + case "base", "basefont", "bgsound", "command", "link", "meta": + p.addElement(p.tok.Data, p.tok.Attr) + p.oe.pop() + p.acknowledgeSelfClosingTag() + case "script", "title", "noscript", "noframes", "style": + p.addElement(p.tok.Data, p.tok.Attr) + p.setOriginalIM() + p.im = textIM + return true + case "head": + // Ignore the token. + return true + default: + implied = true + } + case EndTagToken: + switch p.tok.Data { + case "head": + pop = true + case "body", "html", "br": + implied = true + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + if pop || implied { + n := p.oe.pop() + if n.Data != "head" { + panic("html: bad parser state: <head> element not found, in the in-head insertion mode") + } + p.im = afterHeadIM + return !implied + } + return true +} + +// Section 12.2.5.4.6. +func afterHeadIM(p *parser) bool { + var ( + add bool + attr []Attribute + framesetOK bool + implied bool + ) + switch p.tok.Type { + case ErrorToken: + implied = true + framesetOK = true + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + implied = true + framesetOK = true + case StartTagToken: + switch p.tok.Data { + case "html": + // TODO. + case "body": + add = true + attr = p.tok.Attr + framesetOK = false + case "frameset": + p.addElement(p.tok.Data, p.tok.Attr) + p.im = inFramesetIM + return true + case "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title": + p.oe = append(p.oe, p.head) + defer p.oe.pop() + return inHeadIM(p) + case "head": + // Ignore the token. + return true + default: + implied = true + framesetOK = true + } + case EndTagToken: + switch p.tok.Data { + case "body", "html", "br": + implied = true + framesetOK = true + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + if add || implied { + p.addElement("body", attr) + p.framesetOK = framesetOK + } + p.im = inBodyIM + return !implied +} + +// copyAttributes copies attributes of src not found on dst to dst. +func copyAttributes(dst *Node, src Token) { + if len(src.Attr) == 0 { + return + } + attr := map[string]string{} + for _, a := range dst.Attr { + attr[a.Key] = a.Val + } + for _, a := range src.Attr { + if _, ok := attr[a.Key]; !ok { + dst.Attr = append(dst.Attr, a) + attr[a.Key] = a.Val + } + } +} + +// Section 12.2.5.4.7. +func inBodyIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + switch n := p.oe.top(); n.Data { + case "pre", "listing", "textarea": + if len(n.Child) == 0 { + // Ignore a newline at the start of a <pre> block. + d := p.tok.Data + if d != "" && d[0] == '\r' { + d = d[1:] + } + if d != "" && d[0] == '\n' { + d = d[1:] + } + if d == "" { + return true + } + p.tok.Data = d + } + } + p.reconstructActiveFormattingElements() + p.addText(p.tok.Data) + p.framesetOK = false + case StartTagToken: + switch p.tok.Data { + case "html": + copyAttributes(p.oe[0], p.tok) + case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul": + p.popUntil(buttonScope, "p") + p.addElement(p.tok.Data, p.tok.Attr) + case "h1", "h2", "h3", "h4", "h5", "h6": + p.popUntil(buttonScope, "p") + switch n := p.top(); n.Data { + case "h1", "h2", "h3", "h4", "h5", "h6": + p.oe.pop() + } + p.addElement(p.tok.Data, p.tok.Attr) + case "a": + for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- { + if n := p.afe[i]; n.Type == ElementNode && n.Data == "a" { + p.inBodyEndTagFormatting("a") + p.oe.remove(n) + p.afe.remove(n) + break + } + } + p.reconstructActiveFormattingElements() + p.addFormattingElement(p.tok.Data, p.tok.Attr) + case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u": + p.reconstructActiveFormattingElements() + p.addFormattingElement(p.tok.Data, p.tok.Attr) + case "nobr": + p.reconstructActiveFormattingElements() + if p.elementInScope(defaultScope, "nobr") { + p.inBodyEndTagFormatting("nobr") + p.reconstructActiveFormattingElements() + } + p.addFormattingElement(p.tok.Data, p.tok.Attr) + case "applet", "marquee", "object": + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + p.afe = append(p.afe, &scopeMarker) + p.framesetOK = false + case "area", "br", "embed", "img", "input", "keygen", "wbr": + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + p.oe.pop() + p.acknowledgeSelfClosingTag() + p.framesetOK = false + case "table": + if !p.quirks { + p.popUntil(buttonScope, "p") + } + p.addElement(p.tok.Data, p.tok.Attr) + p.framesetOK = false + p.im = inTableIM + return true + case "hr": + p.popUntil(buttonScope, "p") + p.addElement(p.tok.Data, p.tok.Attr) + p.oe.pop() + p.acknowledgeSelfClosingTag() + p.framesetOK = false + case "select": + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + p.framesetOK = false + p.im = inSelectIM + return true + case "form": + if p.form == nil { + p.popUntil(buttonScope, "p") + p.addElement(p.tok.Data, p.tok.Attr) + p.form = p.top() + } + case "li": + p.framesetOK = false + for i := len(p.oe) - 1; i >= 0; i-- { + node := p.oe[i] + switch node.Data { + case "li": + p.popUntil(listItemScope, "li") + case "address", "div", "p": + continue + default: + if !isSpecialElement(node) { + continue + } + } + break + } + p.popUntil(buttonScope, "p") + p.addElement(p.tok.Data, p.tok.Attr) + case "dd", "dt": + p.framesetOK = false + for i := len(p.oe) - 1; i >= 0; i-- { + node := p.oe[i] + switch node.Data { + case "dd", "dt": + p.oe = p.oe[:i] + case "address", "div", "p": + continue + default: + if !isSpecialElement(node) { + continue + } + } + break + } + p.popUntil(buttonScope, "p") + p.addElement(p.tok.Data, p.tok.Attr) + case "plaintext": + p.popUntil(buttonScope, "p") + p.addElement(p.tok.Data, p.tok.Attr) + case "button": + p.popUntil(defaultScope, "button") + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + p.framesetOK = false + case "optgroup", "option": + if p.top().Data == "option" { + p.oe.pop() + } + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + case "body": + if len(p.oe) >= 2 { + body := p.oe[1] + if body.Type == ElementNode && body.Data == "body" { + p.framesetOK = false + copyAttributes(body, p.tok) + } + } + case "frameset": + if !p.framesetOK || len(p.oe) < 2 || p.oe[1].Data != "body" { + // Ignore the token. + return true + } + body := p.oe[1] + if body.Parent != nil { + body.Parent.Remove(body) + } + p.oe = p.oe[:1] + p.addElement(p.tok.Data, p.tok.Attr) + p.im = inFramesetIM + return true + case "base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title": + return inHeadIM(p) + case "image": + p.tok.Data = "img" + return false + case "isindex": + if p.form != nil { + // Ignore the token. + return true + } + action := "" + prompt := "This is a searchable index. Enter search keywords: " + attr := []Attribute{{Key: "name", Val: "isindex"}} + for _, a := range p.tok.Attr { + switch a.Key { + case "action": + action = a.Val + case "name": + // Ignore the attribute. + case "prompt": + prompt = a.Val + default: + attr = append(attr, a) + } + } + p.acknowledgeSelfClosingTag() + p.popUntil(buttonScope, "p") + p.addElement("form", nil) + p.form = p.top() + if action != "" { + p.form.Attr = []Attribute{{Key: "action", Val: action}} + } + p.addElement("hr", nil) + p.oe.pop() + p.addElement("label", nil) + p.addText(prompt) + p.addElement("input", attr) + p.oe.pop() + p.oe.pop() + p.addElement("hr", nil) + p.oe.pop() + p.oe.pop() + p.form = nil + case "xmp": + p.popUntil(buttonScope, "p") + p.reconstructActiveFormattingElements() + p.framesetOK = false + p.addElement(p.tok.Data, p.tok.Attr) + case "math", "svg": + p.reconstructActiveFormattingElements() + if p.tok.Data == "math" { + // TODO: adjust MathML attributes. + } else { + // TODO: adjust SVG attributes. + } + adjustForeignAttributes(p.tok.Attr) + p.addElement(p.tok.Data, p.tok.Attr) + p.top().Namespace = p.tok.Data + return true + case "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr": + // Ignore the token. + default: + // TODO. + p.addElement(p.tok.Data, p.tok.Attr) + } + case EndTagToken: + switch p.tok.Data { + case "body": + // TODO: autoclose the stack of open elements. + p.im = afterBodyIM + return true + case "p": + if !p.elementInScope(buttonScope, "p") { + p.addElement("p", nil) + } + p.popUntil(buttonScope, "p") + case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u": + p.inBodyEndTagFormatting(p.tok.Data) + case "address", "article", "aside", "blockquote", "button", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "listing", "menu", "nav", "ol", "pre", "section", "summary", "ul": + p.popUntil(defaultScope, p.tok.Data) + case "applet", "marquee", "object": + if p.popUntil(defaultScope, p.tok.Data) { + p.clearActiveFormattingElements() + } + case "br": + p.tok.Type = StartTagToken + return false + default: + p.inBodyEndTagOther(p.tok.Data) + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + } + + return true +} + +func (p *parser) inBodyEndTagFormatting(tag string) { + // This is the "adoption agency" algorithm, described at + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.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. + for i := 0; i < 8; i++ { + // Step 4. Find the formatting element. + var formattingElement *Node + for j := len(p.afe) - 1; j >= 0; j-- { + if p.afe[j].Type == scopeMarkerNode { + break + } + if p.afe[j].Data == tag { + formattingElement = p.afe[j] + break + } + } + if formattingElement == nil { + p.inBodyEndTagOther(tag) + return + } + feIndex := p.oe.index(formattingElement) + if feIndex == -1 { + p.afe.remove(formattingElement) + return + } + if !p.elementInScope(defaultScope, tag) { + // Ignore the tag. + return + } + + // Steps 5-6. Find the furthest block. + var furthestBlock *Node + for _, e := range p.oe[feIndex:] { + if isSpecialElement(e) { + furthestBlock = e + break + } + } + if furthestBlock == nil { + e := p.oe.pop() + for e != formattingElement { + e = p.oe.pop() + } + p.afe.remove(e) + return + } + + // Steps 7-8. 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. + lastNode := furthestBlock + node := furthestBlock + x := p.oe.index(node) + // Steps 9.1-9.3. + for j := 0; j < 3; j++ { + // Step 9.4. + x-- + node = p.oe[x] + // Step 9.5. + if p.afe.index(node) == -1 { + p.oe.remove(node) + continue + } + // Step 9.6. + if node == formattingElement { + break + } + // Step 9.7. + clone := node.clone() + p.afe[p.afe.index(node)] = clone + p.oe[p.oe.index(node)] = clone + node = clone + // Step 9.8. + if lastNode == furthestBlock { + bookmark = p.afe.index(node) + 1 + } + // Step 9.9. + if lastNode.Parent != nil { + lastNode.Parent.Remove(lastNode) + } + node.Add(lastNode) + // Step 9.10. + lastNode = node + } + + // Step 10. Reparent lastNode to the common ancestor, + // or for misnested table nodes, to the foster parent. + if lastNode.Parent != nil { + lastNode.Parent.Remove(lastNode) + } + switch commonAncestor.Data { + case "table", "tbody", "tfoot", "thead", "tr": + p.fosterParent(lastNode) + default: + commonAncestor.Add(lastNode) + } + + // Steps 11-13. Reparent nodes from the furthest block's children + // to a clone of the formatting element. + clone := formattingElement.clone() + reparentChildren(clone, furthestBlock) + furthestBlock.Add(clone) + + // Step 14. 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-- + } + p.afe.remove(formattingElement) + p.afe.insert(bookmark, clone) + + // Step 15. 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. +func (p *parser) inBodyEndTagOther(tag string) { + for i := len(p.oe) - 1; i >= 0; i-- { + if p.oe[i].Data == tag { + p.oe = p.oe[:i] + break + } + if isSpecialElement(p.oe[i]) { + break + } + } +} + +// Section 12.2.5.4.8. +func textIM(p *parser) bool { + switch p.tok.Type { + case ErrorToken: + p.oe.pop() + case TextToken: + p.addText(p.tok.Data) + return true + case EndTagToken: + p.oe.pop() + } + p.im = p.originalIM + p.originalIM = nil + return p.tok.Type == EndTagToken +} + +// Section 12.2.5.4.9. +func inTableIM(p *parser) bool { + switch p.tok.Type { + case ErrorToken: + // Stop parsing. + return true + case TextToken: + // TODO. + case StartTagToken: + switch p.tok.Data { + case "caption": + p.clearStackToContext(tableScope) + p.afe = append(p.afe, &scopeMarker) + p.addElement(p.tok.Data, p.tok.Attr) + p.im = inCaptionIM + return true + case "tbody", "tfoot", "thead": + p.clearStackToContext(tableScope) + p.addElement(p.tok.Data, p.tok.Attr) + p.im = inTableBodyIM + return true + case "td", "th", "tr": + p.clearStackToContext(tableScope) + p.addElement("tbody", nil) + p.im = inTableBodyIM + return false + case "table": + if p.popUntil(tableScope, "table") { + p.resetInsertionMode() + return false + } + // Ignore the token. + return true + case "colgroup": + p.clearStackToContext(tableScope) + p.addElement(p.tok.Data, p.tok.Attr) + p.im = inColumnGroupIM + return true + case "col": + p.clearStackToContext(tableScope) + p.addElement("colgroup", p.tok.Attr) + p.im = inColumnGroupIM + return false + case "select": + p.reconstructActiveFormattingElements() + switch p.top().Data { + case "table", "tbody", "tfoot", "thead", "tr": + p.fosterParenting = true + } + p.addElement(p.tok.Data, p.tok.Attr) + p.fosterParenting = false + p.framesetOK = false + p.im = inSelectInTableIM + return true + default: + // TODO. + } + case EndTagToken: + switch p.tok.Data { + case "table": + if p.popUntil(tableScope, "table") { + p.resetInsertionMode() + return true + } + // Ignore the token. + return true + case "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr": + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + + switch p.top().Data { + case "table", "tbody", "tfoot", "thead", "tr": + p.fosterParenting = true + defer func() { p.fosterParenting = false }() + } + + return inBodyIM(p) +} + +// Section 12.2.5.4.11. +func inCaptionIM(p *parser) bool { + switch p.tok.Type { + case StartTagToken: + switch p.tok.Data { + case "caption", "col", "colgroup", "tbody", "td", "tfoot", "thead", "tr": + if p.popUntil(tableScope, "caption") { + p.clearActiveFormattingElements() + p.im = inTableIM + return false + } else { + // Ignore the token. + return true + } + case "select": + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + p.framesetOK = false + p.im = inSelectInTableIM + return true + } + case EndTagToken: + switch p.tok.Data { + case "caption": + if p.popUntil(tableScope, "caption") { + p.clearActiveFormattingElements() + p.im = inTableIM + } + return true + case "table": + if p.popUntil(tableScope, "caption") { + p.clearActiveFormattingElements() + p.im = inTableIM + return false + } else { + // Ignore the token. + return true + } + case "body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr": + // Ignore the token. + return true + } + } + return inBodyIM(p) +} + +// Section 12.2.5.4.12. +func inColumnGroupIM(p *parser) bool { + switch p.tok.Type { + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + case StartTagToken: + switch p.tok.Data { + case "html": + return inBodyIM(p) + case "col": + p.addElement(p.tok.Data, p.tok.Attr) + p.oe.pop() + p.acknowledgeSelfClosingTag() + return true + } + case EndTagToken: + switch p.tok.Data { + case "colgroup": + if p.oe.top().Data != "html" { + p.oe.pop() + p.im = inTableIM + } + return true + case "col": + // Ignore the token. + return true + } + } + if p.oe.top().Data != "html" { + p.oe.pop() + p.im = inTableIM + return false + } + return true +} + +// Section 12.2.5.4.13. +func inTableBodyIM(p *parser) bool { + var ( + add bool + data string + attr []Attribute + consumed bool + ) + switch p.tok.Type { + case ErrorToken: + // TODO. + case TextToken: + // TODO. + case StartTagToken: + switch p.tok.Data { + case "tr": + add = true + data = p.tok.Data + attr = p.tok.Attr + consumed = true + case "td", "th": + add = true + data = "tr" + consumed = false + case "caption", "col", "colgroup", "tbody", "tfoot", "thead": + if !p.popUntil(tableScope, "tbody", "thead", "tfoot") { + // Ignore the token. + return true + } + p.im = inTableIM + return false + default: + // TODO. + } + case EndTagToken: + switch p.tok.Data { + case "table": + if p.popUntil(tableScope, "tbody", "thead", "tfoot") { + p.im = inTableIM + return false + } + // Ignore the token. + return true + case "body", "caption", "col", "colgroup", "html", "td", "th", "tr": + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + if add { + // TODO: clear the stack back to a table body context. + p.addElement(data, attr) + p.im = inRowIM + return consumed + } + return inTableIM(p) +} + +// Section 12.2.5.4.14. +func inRowIM(p *parser) bool { + switch p.tok.Type { + case ErrorToken: + // TODO. + case TextToken: + // TODO. + case StartTagToken: + switch p.tok.Data { + case "td", "th": + p.clearStackToContext(tableRowScope) + p.addElement(p.tok.Data, p.tok.Attr) + p.afe = append(p.afe, &scopeMarker) + p.im = inCellIM + return true + case "caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr": + if p.popUntil(tableScope, "tr") { + p.im = inTableBodyIM + return false + } + // Ignore the token. + return true + default: + // TODO. + } + case EndTagToken: + switch p.tok.Data { + case "tr": + if p.popUntil(tableScope, "tr") { + p.im = inTableBodyIM + return true + } + // Ignore the token. + return true + case "table": + if p.popUntil(tableScope, "tr") { + p.im = inTableBodyIM + return false + } + // Ignore the token. + return true + case "tbody", "tfoot", "thead": + // TODO. + case "body", "caption", "col", "colgroup", "html", "td", "th": + // Ignore the token. + return true + default: + // TODO. + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + return inTableIM(p) +} + +// Section 12.2.5.4.15. +func inCellIM(p *parser) bool { + var ( + closeTheCellAndReprocess bool + ) + switch p.tok.Type { + case StartTagToken: + switch p.tok.Data { + case "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr": + // TODO: check for "td" or "th" in table scope. + closeTheCellAndReprocess = true + case "select": + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + p.framesetOK = false + p.im = inSelectInTableIM + return true + } + case EndTagToken: + switch p.tok.Data { + case "td", "th": + if !p.popUntil(tableScope, p.tok.Data) { + // Ignore the token. + return true + } + p.clearActiveFormattingElements() + p.im = inRowIM + return true + case "body", "caption", "col", "colgroup", "html": + // TODO. + case "table", "tbody", "tfoot", "thead", "tr": + // TODO: check for matching element in table scope. + closeTheCellAndReprocess = true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + if closeTheCellAndReprocess { + if p.popUntil(tableScope, "td") || p.popUntil(tableScope, "th") { + p.clearActiveFormattingElements() + p.im = inRowIM + return false + } + } + return inBodyIM(p) +} + +// Section 12.2.5.4.16. +func inSelectIM(p *parser) bool { + endSelect := false + switch p.tok.Type { + case ErrorToken: + // TODO. + case TextToken: + p.addText(p.tok.Data) + case StartTagToken: + switch p.tok.Data { + case "html": + // TODO. + case "option": + if p.top().Data == "option" { + p.oe.pop() + } + p.addElement(p.tok.Data, p.tok.Attr) + case "optgroup": + if p.top().Data == "option" { + p.oe.pop() + } + if p.top().Data == "optgroup" { + p.oe.pop() + } + p.addElement(p.tok.Data, p.tok.Attr) + case "select": + endSelect = true + case "input", "keygen", "textarea": + // TODO. + case "script": + // TODO. + default: + // Ignore the token. + } + case EndTagToken: + switch p.tok.Data { + case "option": + if p.top().Data == "option" { + p.oe.pop() + } + case "optgroup": + i := len(p.oe) - 1 + if p.oe[i].Data == "option" { + i-- + } + if p.oe[i].Data == "optgroup" { + p.oe = p.oe[:i] + } + case "select": + endSelect = true + default: + // Ignore the token. + } + case CommentToken: + p.doc.Add(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + } + if endSelect { + p.endSelect() + } + return true +} + +// Section 12.2.5.4.17. +func inSelectInTableIM(p *parser) bool { + switch p.tok.Type { + case StartTagToken, EndTagToken: + switch p.tok.Data { + case "caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th": + if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.Data) { + p.endSelect() + return false + } else { + // Ignore the token. + return true + } + } + } + return inSelectIM(p) +} + +func (p *parser) endSelect() { + for i := len(p.oe) - 1; i >= 0; i-- { + switch p.oe[i].Data { + case "option", "optgroup": + continue + case "select": + p.oe = p.oe[:i] + p.resetInsertionMode() + } + return + } +} + +// Section 12.2.5.4.18. +func afterBodyIM(p *parser) bool { + switch p.tok.Type { + case ErrorToken: + // Stop parsing. + return true + case StartTagToken: + if p.tok.Data == "html" { + return inBodyIM(p) + } + case EndTagToken: + if p.tok.Data == "html" { + p.im = afterAfterBodyIM + return true + } + case CommentToken: + // The comment is attached to the <html> element. + if len(p.oe) < 1 || p.oe[0].Data != "html" { + panic("html: bad parser state: <html> element not found, in the after-body insertion mode") + } + p.oe[0].Add(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + p.im = inBodyIM + return false +} + +// Section 12.2.5.4.19. +func inFramesetIM(p *parser) bool { + switch p.tok.Type { + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + case TextToken: + // Ignore all text but whitespace. + s := strings.Map(func(c rune) rune { + switch c { + case ' ', '\t', '\n', '\f', '\r': + return c + } + return -1 + }, p.tok.Data) + if s != "" { + p.addText(s) + } + case StartTagToken: + switch p.tok.Data { + case "html": + return inBodyIM(p) + case "frameset": + p.addElement(p.tok.Data, p.tok.Attr) + case "frame": + p.addElement(p.tok.Data, p.tok.Attr) + p.oe.pop() + p.acknowledgeSelfClosingTag() + case "noframes": + return inHeadIM(p) + } + case EndTagToken: + switch p.tok.Data { + case "frameset": + if p.oe.top().Data != "html" { + p.oe.pop() + if p.oe.top().Data != "frameset" { + p.im = afterFramesetIM + return true + } + } + } + default: + // Ignore the token. + } + return true +} + +// Section 12.2.5.4.20. +func afterFramesetIM(p *parser) bool { + switch p.tok.Type { + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + case TextToken: + // Ignore all text but whitespace. + s := strings.Map(func(c rune) rune { + switch c { + case ' ', '\t', '\n', '\f', '\r': + return c + } + return -1 + }, p.tok.Data) + if s != "" { + p.addText(s) + } + case StartTagToken: + switch p.tok.Data { + case "html": + return inBodyIM(p) + case "noframes": + return inHeadIM(p) + } + case EndTagToken: + switch p.tok.Data { + case "html": + p.im = afterAfterFramesetIM + return true + } + default: + // Ignore the token. + } + return true +} + +// Section 12.2.5.4.21. +func afterAfterBodyIM(p *parser) bool { + switch p.tok.Type { + case ErrorToken: + // Stop parsing. + return true + case TextToken: + // TODO. + case StartTagToken: + if p.tok.Data == "html" { + return inBodyIM(p) + } + case CommentToken: + p.doc.Add(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + p.im = inBodyIM + return false +} + +// Section 12.2.5.4.22. +func afterAfterFramesetIM(p *parser) bool { + switch p.tok.Type { + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + case TextToken: + // Ignore all text but whitespace. + s := strings.Map(func(c rune) rune { + switch c { + case ' ', '\t', '\n', '\f', '\r': + return c + } + return -1 + }, p.tok.Data) + if s != "" { + p.reconstructActiveFormattingElements() + p.addText(s) + } + case StartTagToken: + switch p.tok.Data { + case "html": + return inBodyIM(p) + case "noframes": + return inHeadIM(p) + } + default: + // Ignore the token. + } + return true +} + +// Section 12.2.5.5. +func parseForeignContent(p *parser) bool { + switch p.tok.Type { + case TextToken: + // TODO: HTML integration points. + if p.top().Namespace == "" { + inBodyIM(p) + p.resetInsertionMode() + return true + } + if p.framesetOK { + p.framesetOK = strings.TrimLeft(p.tok.Data, whitespace) == "" + } + p.addText(p.tok.Data) + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + case StartTagToken: + if htmlIntegrationPoint(p.top()) { + inBodyIM(p) + p.resetInsertionMode() + return true + } + if breakout[p.tok.Data] { + for i := len(p.oe) - 1; i >= 0; i-- { + // TODO: MathML integration points. + if p.oe[i].Namespace == "" || htmlIntegrationPoint(p.oe[i]) { + p.oe = p.oe[:i+1] + break + } + } + return false + } + switch p.top().Namespace { + case "math": + // TODO: adjust MathML attributes. + case "svg": + // Adjust SVG tag names. The tokenizer lower-cases tag names, but + // SVG wants e.g. "foreignObject" with a capital second "O". + if x := svgTagNameAdjustments[p.tok.Data]; x != "" { + p.tok.Data = x + } + // TODO: adjust SVG attributes. + default: + panic("html: bad parser state: unexpected namespace") + } + adjustForeignAttributes(p.tok.Attr) + namespace := p.top().Namespace + p.addElement(p.tok.Data, p.tok.Attr) + p.top().Namespace = namespace + case EndTagToken: + for i := len(p.oe) - 1; i >= 0; i-- { + if p.oe[i].Namespace == "" { + return p.im(p) + } + if strings.EqualFold(p.oe[i].Data, p.tok.Data) { + p.oe = p.oe[:i] + break + } + } + return true + default: + // Ignore the token. + } + return true +} + +// Section 12.2.5. +func (p *parser) inForeignContent() bool { + if len(p.oe) == 0 { + return false + } + n := p.oe[len(p.oe)-1] + if n.Namespace == "" { + return false + } + // TODO: MathML, HTML integration points. + // TODO: MathML's annotation-xml combining with SVG's svg. + return true +} + +func (p *parser) parse() error { + // Iterate until EOF. Any other error will cause an early return. + consumed := true + for { + if consumed { + if err := p.read(); err != nil { + if err == io.EOF { + break + } + return err + } + } + if p.inForeignContent() { + consumed = parseForeignContent(p) + } else { + consumed = p.im(p) + } + } + // Loop until the final token (the ErrorToken signifying EOF) is consumed. + for { + if consumed = p.im(p); consumed { + break + } + } + return nil +} + +// Parse returns the parse tree for the HTML from the given Reader. +// The input is assumed to be UTF-8 encoded. +func Parse(r io.Reader) (*Node, error) { + p := &parser{ + tokenizer: NewTokenizer(r), + doc: &Node{ + Type: DocumentNode, + }, + scripting: true, + framesetOK: true, + im: initialIM, + } + err := p.parse() + if err != nil { + return nil, err + } + return p.doc, nil +} + +// 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 +// element in context. +func ParseFragment(r io.Reader, context *Node) ([]*Node, error) { + p := &parser{ + tokenizer: NewTokenizer(r), + doc: &Node{ + Type: DocumentNode, + }, + scripting: true, + context: context, + } + + if context != nil { + switch context.Data { + case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "title", "textarea", "xmp": + p.tokenizer.rawTag = context.Data + } + } + + root := &Node{ + Type: ElementNode, + Data: "html", + } + p.doc.Add(root) + p.oe = nodeStack{root} + p.resetInsertionMode() + + for n := context; n != nil; n = n.Parent { + if n.Type == ElementNode && n.Data == "form" { + p.form = n + break + } + } + + err := p.parse() + if err != nil { + return nil, err + } + + parent := p.doc + if context != nil { + parent = root + } + + result := parent.Child + parent.Child = nil + for _, n := range result { + n.Parent = nil + } + return result, nil +} diff --git a/libgo/go/exp/html/parse_test.go b/libgo/go/exp/html/parse_test.go new file mode 100644 index 00000000000..1528dffaafa --- /dev/null +++ b/libgo/go/exp/html/parse_test.go @@ -0,0 +1,276 @@ +// Copyright 2010 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 html + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "os" + "strings" + "testing" +) + +// readParseTest reads a single test case from r. +func readParseTest(r *bufio.Reader) (text, want, context string, err error) { + line, err := r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + var b []byte + + // Read the HTML. + if string(line) != "#data\n" { + return "", "", "", fmt.Errorf(`got %q want "#data\n"`, line) + } + for { + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + if line[0] == '#' { + break + } + b = append(b, line...) + } + text = strings.TrimRight(string(b), "\n") + b = b[:0] + + // Skip the error list. + if string(line) != "#errors\n" { + return "", "", "", fmt.Errorf(`got %q want "#errors\n"`, line) + } + for { + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + if line[0] == '#' { + break + } + } + + if string(line) == "#document-fragment\n" { + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + context = strings.TrimSpace(string(line)) + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + } + + // Read the dump of what the parse tree should be. + if string(line) != "#document\n" { + return "", "", "", fmt.Errorf(`got %q want "#document\n"`, line) + } + for { + line, err = r.ReadSlice('\n') + if err != nil && err != io.EOF { + return "", "", "", err + } + if len(line) == 0 || len(line) == 1 && line[0] == '\n' { + break + } + b = append(b, line...) + } + return text, string(b), context, nil +} + +func dumpIndent(w io.Writer, level int) { + io.WriteString(w, "| ") + for i := 0; i < level; i++ { + io.WriteString(w, " ") + } +} + +func dumpLevel(w io.Writer, n *Node, level int) error { + dumpIndent(w, level) + switch n.Type { + case ErrorNode: + return errors.New("unexpected ErrorNode") + case DocumentNode: + return errors.New("unexpected DocumentNode") + case ElementNode: + if n.Namespace != "" { + fmt.Fprintf(w, "<%s %s>", n.Namespace, n.Data) + } else { + fmt.Fprintf(w, "<%s>", n.Data) + } + attr := n.Attr + if len(attr) == 2 && attr[0].Namespace == "xml" && attr[1].Namespace == "xlink" { + // Some of the test cases in tests10.dat change the order of adjusted + // foreign attributes, but that behavior is not in the spec, and could + // simply be an implementation detail of html5lib's python map ordering. + attr[0], attr[1] = attr[1], attr[0] + } + for _, a := range attr { + io.WriteString(w, "\n") + dumpIndent(w, level+1) + if a.Namespace != "" { + fmt.Fprintf(w, `%s %s="%s"`, a.Namespace, a.Key, a.Val) + } else { + fmt.Fprintf(w, `%s="%s"`, a.Key, a.Val) + } + } + case TextNode: + fmt.Fprintf(w, `"%s"`, n.Data) + case CommentNode: + fmt.Fprintf(w, "<!-- %s -->", n.Data) + case DoctypeNode: + fmt.Fprintf(w, "<!DOCTYPE %s", n.Data) + if n.Attr != nil { + var p, s string + for _, a := range n.Attr { + switch a.Key { + case "public": + p = a.Val + case "system": + s = a.Val + } + } + if p != "" || s != "" { + fmt.Fprintf(w, ` "%s"`, p) + fmt.Fprintf(w, ` "%s"`, s) + } + } + io.WriteString(w, ">") + case scopeMarkerNode: + return errors.New("unexpected scopeMarkerNode") + default: + return errors.New("unknown node type") + } + io.WriteString(w, "\n") + for _, c := range n.Child { + if err := dumpLevel(w, c, level+1); err != nil { + return err + } + } + return nil +} + +func dump(n *Node) (string, error) { + if n == nil || len(n.Child) == 0 { + return "", nil + } + b := bytes.NewBuffer(nil) + for _, child := range n.Child { + if err := dumpLevel(b, child, 0); err != nil { + return "", err + } + } + return b.String(), nil +} + +func TestParser(t *testing.T) { + testFiles := []struct { + filename string + // n is the number of test cases to run from that file. + // -1 means all test cases. + n int + }{ + // TODO(nigeltao): Process all the test cases from all the .dat files. + {"adoption01.dat", -1}, + {"doctype01.dat", -1}, + {"tests1.dat", -1}, + {"tests2.dat", -1}, + {"tests3.dat", -1}, + {"tests4.dat", -1}, + {"tests5.dat", -1}, + {"tests6.dat", -1}, + {"tests10.dat", 35}, + } + for _, tf := range testFiles { + f, err := os.Open("testdata/webkit/" + tf.filename) + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := bufio.NewReader(f) + for i := 0; i != tf.n; i++ { + text, want, context, err := readParseTest(r) + if err == io.EOF && tf.n == -1 { + break + } + if err != nil { + t.Fatal(err) + } + + var doc *Node + if context == "" { + doc, err = Parse(strings.NewReader(text)) + if err != nil { + t.Fatal(err) + } + } else { + contextNode := &Node{ + Type: ElementNode, + Data: context, + } + nodes, err := ParseFragment(strings.NewReader(text), contextNode) + if err != nil { + t.Fatal(err) + } + doc = &Node{ + Type: DocumentNode, + } + for _, n := range nodes { + doc.Add(n) + } + } + + got, err := dump(doc) + if err != nil { + t.Fatal(err) + } + // Compare the parsed tree to the #document section. + if got != want { + t.Errorf("%s test #%d %q, got vs want:\n----\n%s----\n%s----", tf.filename, i, text, got, want) + continue + } + if renderTestBlacklist[text] || context != "" { + continue + } + // Check that rendering and re-parsing results in an identical tree. + pr, pw := io.Pipe() + go func() { + pw.CloseWithError(Render(pw, doc)) + }() + doc1, err := Parse(pr) + if err != nil { + t.Fatal(err) + } + got1, err := dump(doc1) + if err != nil { + t.Fatal(err) + } + if got != got1 { + t.Errorf("%s test #%d %q, got vs got1:\n----\n%s----\n%s----", tf.filename, i, text, got, got1) + continue + } + } + } +} + +// Some test input result in parse trees are not 'well-formed' despite +// following the HTML5 recovery algorithms. Rendering and re-parsing such a +// tree will not result in an exact clone of that tree. We blacklist such +// inputs from the render test. +var renderTestBlacklist = map[string]bool{ + // The second <a> will be reparented to the first <table>'s parent. This + // results in an <a> whose parent is an <a>, which is not 'well-formed'. + `<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y`: true, + // More cases of <a> being reparented: + `<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe`: true, + `<a><table><a></table><p><a><div><a>`: true, + `<a><table><td><a><table></table><a></tr><a></table><a>`: true, + // A <plaintext> element is reparented, putting it before a table. + // A <plaintext> element can't have anything after it in HTML. + `<table><plaintext><td>`: true, +} diff --git a/libgo/go/exp/html/render.go b/libgo/go/exp/html/render.go new file mode 100644 index 00000000000..07859faa7dd --- /dev/null +++ b/libgo/go/exp/html/render.go @@ -0,0 +1,277 @@ +// Copyright 2011 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 html + +import ( + "bufio" + "errors" + "fmt" + "io" + "strings" +) + +type writer interface { + io.Writer + WriteByte(byte) error + WriteString(string) (int, error) +} + +// Render renders the parse tree n to the given writer. +// +// Rendering is done on a 'best effort' basis: calling Parse on the output of +// Render will always result in something similar to the original tree, but it +// is not necessarily an exact clone unless the original tree was 'well-formed'. +// 'Well-formed' is not easily specified; the HTML5 specification is +// complicated. +// +// Calling Parse on arbitrary input typically results in a 'well-formed' parse +// tree. However, it is possible for Parse to yield a 'badly-formed' parse tree. +// For example, in a 'well-formed' parse tree, no <a> element is a child of +// another <a> element: parsing "<a><a>" results in two sibling elements. +// Similarly, in a 'well-formed' parse tree, no <a> element is a child of a +// <table> element: parsing "<p><table><a>" results in a <p> with two sibling +// children; the <a> is reparented to the <table>'s parent. However, calling +// Parse on "<a><table><a>" does not return an error, but the result has an <a> +// element with an <a> child, and is therefore not 'well-formed'. +// +// Programmatically constructed trees are typically also 'well-formed', but it +// is possible to construct a tree that looks innocuous but, when rendered and +// re-parsed, results in a different tree. A simple example is that a solitary +// text node would become a tree containing <html>, <head> and <body> elements. +// Another example is that the programmatic equivalent of "a<head>b</head>c" +// becomes "<html><head><head/><body>abc</body></html>". +func Render(w io.Writer, n *Node) error { + if x, ok := w.(writer); ok { + return render(x, n) + } + buf := bufio.NewWriter(w) + if err := render(buf, n); err != nil { + return err + } + return buf.Flush() +} + +// plaintextAbort is returned from render1 when a <plaintext> element +// has been rendered. No more end tags should be rendered after that. +var plaintextAbort = errors.New("html: internal error (plaintext abort)") + +func render(w writer, n *Node) error { + err := render1(w, n) + if err == plaintextAbort { + err = nil + } + return err +} + +func render1(w writer, n *Node) error { + // Render non-element nodes; these are the easy cases. + switch n.Type { + case ErrorNode: + return errors.New("html: cannot render an ErrorNode node") + case TextNode: + return escape(w, n.Data) + case DocumentNode: + for _, c := range n.Child { + if err := render1(w, c); err != nil { + return err + } + } + return nil + case ElementNode: + // No-op. + case CommentNode: + if _, err := w.WriteString("<!--"); err != nil { + return err + } + if _, err := w.WriteString(n.Data); err != nil { + return err + } + if _, err := w.WriteString("-->"); err != nil { + return err + } + return nil + case DoctypeNode: + if _, err := w.WriteString("<!DOCTYPE "); err != nil { + return err + } + if _, err := w.WriteString(n.Data); err != nil { + return err + } + if n.Attr != nil { + var p, s string + for _, a := range n.Attr { + switch a.Key { + case "public": + p = a.Val + case "system": + s = a.Val + } + } + if p != "" { + if _, err := w.WriteString(" PUBLIC "); err != nil { + return err + } + if err := writeQuoted(w, p); err != nil { + return err + } + if s != "" { + if err := w.WriteByte(' '); err != nil { + return err + } + if err := writeQuoted(w, s); err != nil { + return err + } + } + } else if s != "" { + if _, err := w.WriteString(" SYSTEM "); err != nil { + return err + } + if err := writeQuoted(w, s); err != nil { + return err + } + } + } + return w.WriteByte('>') + default: + return errors.New("html: unknown node type") + } + + // Render the <xxx> opening tag. + if err := w.WriteByte('<'); err != nil { + return err + } + if _, err := w.WriteString(n.Data); err != nil { + return err + } + for _, a := range n.Attr { + if err := w.WriteByte(' '); err != nil { + return err + } + if a.Namespace != "" { + if _, err := w.WriteString(a.Namespace); err != nil { + return err + } + if err := w.WriteByte(':'); err != nil { + return err + } + } + if _, err := w.WriteString(a.Key); err != nil { + return err + } + if _, err := w.WriteString(`="`); err != nil { + return err + } + if err := escape(w, a.Val); err != nil { + return err + } + if err := w.WriteByte('"'); err != nil { + return err + } + } + if voidElements[n.Data] { + if len(n.Child) != 0 { + return fmt.Errorf("html: void element <%s> has child nodes", n.Data) + } + _, err := w.WriteString("/>") + return err + } + if err := w.WriteByte('>'); err != nil { + return err + } + + // Add initial newline where there is danger of a newline beging ignored. + if len(n.Child) > 0 && n.Child[0].Type == TextNode && strings.HasPrefix(n.Child[0].Data, "\n") { + switch n.Data { + case "pre", "listing", "textarea": + if err := w.WriteByte('\n'); err != nil { + return err + } + } + } + + // Render any child nodes. + switch n.Data { + case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp": + for _, c := range n.Child { + if c.Type != TextNode { + return fmt.Errorf("html: raw text element <%s> has non-text child node", n.Data) + } + if _, err := w.WriteString(c.Data); err != nil { + return err + } + } + if n.Data == "plaintext" { + // Don't render anything else. <plaintext> must be the + // last element in the file, with no closing tag. + return plaintextAbort + } + case "textarea", "title": + for _, c := range n.Child { + if c.Type != TextNode { + return fmt.Errorf("html: RCDATA element <%s> has non-text child node", n.Data) + } + if err := render1(w, c); err != nil { + return err + } + } + default: + for _, c := range n.Child { + if err := render1(w, c); err != nil { + return err + } + } + } + + // Render the </xxx> closing tag. + if _, err := w.WriteString("</"); err != nil { + return err + } + if _, err := w.WriteString(n.Data); err != nil { + return err + } + return w.WriteByte('>') +} + +// writeQuoted writes s to w surrounded by quotes. Normally it will use double +// quotes, but if s contains a double quote, it will use single quotes. +// It is used for writing the identifiers in a doctype declaration. +// In valid HTML, they can't contain both types of quotes. +func writeQuoted(w writer, s string) error { + var q byte = '"' + if strings.Contains(s, `"`) { + q = '\'' + } + if err := w.WriteByte(q); err != nil { + return err + } + if _, err := w.WriteString(s); err != nil { + return err + } + if err := w.WriteByte(q); err != nil { + return err + } + return nil +} + +// Section 12.1.2, "Elements", gives this list of void elements. Void elements +// are those that can't have any contents. +var voidElements = map[string]bool{ + "area": true, + "base": true, + "br": true, + "col": true, + "command": true, + "embed": true, + "hr": true, + "img": true, + "input": true, + "keygen": true, + "link": true, + "meta": true, + "param": true, + "source": true, + "track": true, + "wbr": true, +} diff --git a/libgo/go/exp/html/render_test.go b/libgo/go/exp/html/render_test.go new file mode 100644 index 00000000000..0584f35abdb --- /dev/null +++ b/libgo/go/exp/html/render_test.go @@ -0,0 +1,111 @@ +// Copyright 2010 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 html + +import ( + "bytes" + "testing" +) + +func TestRenderer(t *testing.T) { + n := &Node{ + Type: ElementNode, + Data: "html", + Child: []*Node{ + { + Type: ElementNode, + Data: "head", + }, + { + Type: ElementNode, + Data: "body", + Child: []*Node{ + { + Type: TextNode, + Data: "0<1", + }, + { + Type: ElementNode, + Data: "p", + Attr: []Attribute{ + { + Key: "id", + Val: "A", + }, + { + Key: "foo", + Val: `abc"def`, + }, + }, + Child: []*Node{ + { + Type: TextNode, + Data: "2", + }, + { + Type: ElementNode, + Data: "b", + Attr: []Attribute{ + { + Key: "empty", + Val: "", + }, + }, + Child: []*Node{ + { + Type: TextNode, + Data: "3", + }, + }, + }, + { + Type: ElementNode, + Data: "i", + Attr: []Attribute{ + { + Key: "backslash", + Val: `\`, + }, + }, + Child: []*Node{ + { + Type: TextNode, + Data: "&4", + }, + }, + }, + }, + }, + { + Type: TextNode, + Data: "5", + }, + { + Type: ElementNode, + Data: "blockquote", + }, + { + Type: ElementNode, + Data: "br", + }, + { + Type: TextNode, + Data: "6", + }, + }, + }, + }, + } + want := `<html><head></head><body>0<1<p id="A" foo="abc"def">` + + `2<b empty="">3</b><i backslash="\">&4</i></p>` + + `5<blockquote></blockquote><br/>6</body></html>` + b := new(bytes.Buffer) + if err := Render(b, n); err != nil { + t.Fatal(err) + } + if got := b.String(); got != want { + t.Errorf("got vs want:\n%s\n%s\n", got, want) + } +} diff --git a/libgo/go/exp/html/testdata/webkit/README b/libgo/go/exp/html/testdata/webkit/README new file mode 100644 index 00000000000..9b4c2d8be0a --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/README @@ -0,0 +1,28 @@ +The *.dat files in this directory are copied from The WebKit Open Source +Project, specifically $WEBKITROOT/LayoutTests/html5lib/resources. +WebKit is licensed under a BSD style license. +http://webkit.org/coding/bsd-license.html says: + +Copyright (C) 2009 Apple Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/libgo/go/exp/html/testdata/webkit/adoption01.dat b/libgo/go/exp/html/testdata/webkit/adoption01.dat new file mode 100644 index 00000000000..787e1b01e19 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/adoption01.dat @@ -0,0 +1,194 @@ +#data +<a><p></a></p> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <p> +| <a> + +#data +<a>1<p>2</a>3</p> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| "1" +| <p> +| <a> +| "2" +| "3" + +#data +<a>1<button>2</a>3</button> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| "1" +| <button> +| <a> +| "2" +| "3" + +#data +<a>1<b>2</a>3</b> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| "1" +| <b> +| "2" +| <b> +| "3" + +#data +<a>1<div>2<div>3</a>4</div>5</div> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| "1" +| <div> +| <a> +| "2" +| <div> +| <a> +| "3" +| "4" +| "5" + +#data +<table><a>1<p>2</a>3</p> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| "1" +| <p> +| <a> +| "2" +| "3" +| <table> + +#data +<b><b><a><p></a> +#errors +#document +| <html> +| <head> +| <body> +| <b> +| <b> +| <a> +| <p> +| <a> + +#data +<b><a><b><p></a> +#errors +#document +| <html> +| <head> +| <body> +| <b> +| <a> +| <b> +| <b> +| <p> +| <a> + +#data +<a><b><b><p></a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <b> +| <b> +| <b> +| <b> +| <p> +| <a> + +#data +<p>1<s id="A">2<b id="B">3</p>4</s>5</b> +#errors +#document +| <html> +| <head> +| <body> +| <p> +| "1" +| <s> +| id="A" +| "2" +| <b> +| id="B" +| "3" +| <s> +| id="A" +| <b> +| id="B" +| "4" +| <b> +| id="B" +| "5" + +#data +<table><a>1<td>2</td>3</table> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| "1" +| <a> +| "3" +| <table> +| <tbody> +| <tr> +| <td> +| "2" + +#data +<table>A<td>B</td>C</table> +#errors +#document +| <html> +| <head> +| <body> +| "AC" +| <table> +| <tbody> +| <tr> +| <td> +| "B" + +#data +<a><svg><tr><input></a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <svg svg> +| <svg tr> +| <svg input> diff --git a/libgo/go/exp/html/testdata/webkit/adoption02.dat b/libgo/go/exp/html/testdata/webkit/adoption02.dat new file mode 100644 index 00000000000..d18151b44f0 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/adoption02.dat @@ -0,0 +1,31 @@ +#data +<b>1<i>2<p>3</b>4 +#errors +#document +| <html> +| <head> +| <body> +| <b> +| "1" +| <i> +| "2" +| <i> +| <p> +| <b> +| "3" +| "4" + +#data +<a><div><style></style><address><a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <div> +| <a> +| <style> +| <address> +| <a> +| <a> diff --git a/libgo/go/exp/html/testdata/webkit/comments01.dat b/libgo/go/exp/html/testdata/webkit/comments01.dat new file mode 100644 index 00000000000..44f18768300 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/comments01.dat @@ -0,0 +1,135 @@ +#data +FOO<!-- BAR -->BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- BAR --> +| "BAZ" + +#data +FOO<!-- BAR --!>BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- BAR --> +| "BAZ" + +#data +FOO<!-- BAR -- >BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- BAR -- >BAZ --> + +#data +FOO<!-- BAR -- <QUX> -- MUX -->BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- BAR -- <QUX> -- MUX --> +| "BAZ" + +#data +FOO<!-- BAR -- <QUX> -- MUX --!>BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- BAR -- <QUX> -- MUX --> +| "BAZ" + +#data +FOO<!-- BAR -- <QUX> -- MUX -- >BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- BAR -- <QUX> -- MUX -- >BAZ --> + +#data +FOO<!---->BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- --> +| "BAZ" + +#data +FOO<!--->BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- --> +| "BAZ" + +#data +FOO<!-->BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- --> +| "BAZ" + +#data +<?xml version="1.0">Hi +#errors +#document +| <!-- ?xml version="1.0" --> +| <html> +| <head> +| <body> +| "Hi" + +#data +<?xml version="1.0"> +#errors +#document +| <!-- ?xml version="1.0" --> +| <html> +| <head> +| <body> + +#data +<?xml version +#errors +#document +| <!-- ?xml version --> +| <html> +| <head> +| <body> + +#data +FOO<!----->BAZ +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <!-- - --> +| "BAZ" diff --git a/libgo/go/exp/html/testdata/webkit/doctype01.dat b/libgo/go/exp/html/testdata/webkit/doctype01.dat new file mode 100644 index 00000000000..ae457328a45 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/doctype01.dat @@ -0,0 +1,370 @@ +#data +<!DOCTYPE html>Hello +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!dOctYpE HtMl>Hello +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPEhtml>Hello +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE>Hello +#errors +#document +| <!DOCTYPE > +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE >Hello +#errors +#document +| <!DOCTYPE > +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato >Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato taco>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato taco "ddd>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato sYstEM>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato sYstEM >Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato sYstEM ggg>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato SYSTEM taco >Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato SYSTEM 'taco"'>Hello +#errors +#document +| <!DOCTYPE potato "" "taco""> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato SYSTEM "taco">Hello +#errors +#document +| <!DOCTYPE potato "" "taco"> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato SYSTEM "tai'co">Hello +#errors +#document +| <!DOCTYPE potato "" "tai'co"> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato SYSTEMtaco "ddd">Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato grass SYSTEM taco>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato pUbLIc>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato pUbLIc >Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato pUbLIcgoof>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato PUBLIC goof>Hello +#errors +#document +| <!DOCTYPE potato> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato PUBLIC "go'of">Hello +#errors +#document +| <!DOCTYPE potato "go'of" ""> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato PUBLIC 'go'of'>Hello +#errors +#document +| <!DOCTYPE potato "go" ""> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato PUBLIC 'go:hh of' >Hello +#errors +#document +| <!DOCTYPE potato "go:hh of" ""> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello +#errors +#document +| <!DOCTYPE potato "W3C-//dfdf" ""> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd">Hello +#errors +#document +| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE ...>Hello +#errors +#document +| <!DOCTYPE ...> +| <html> +| <head> +| <body> +| "Hello" + +#data +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +#errors +#document +| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> +#errors +#document +| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [ +<!-- internal declarations --> +]> +#errors +#document +| <!DOCTYPE root-element> +| <html> +| <head> +| <body> +| "]>" + +#data +<!DOCTYPE html PUBLIC + "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" + "http://www.wapforum.org/DTD/xhtml-mobile10.dtd"> +#errors +#document +| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd"> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body> +#errors +#document +| <!DOCTYPE html "" "http://www.w3.org/DTD/HTML4-strict.dtd"> +| <html> +| <head> +| <body> +| <b> +| "Mine!" + +#data +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd"> +#errors +#document +| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'> +#errors +#document +| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'> +#errors +#document +| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'> +#errors +#document +| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +| <html> +| <head> +| <body> diff --git a/libgo/go/exp/html/testdata/webkit/entities01.dat b/libgo/go/exp/html/testdata/webkit/entities01.dat new file mode 100644 index 00000000000..c8073b7810b --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/entities01.dat @@ -0,0 +1,603 @@ +#data +FOO>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO>BAR" + +#data +FOO>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO>BAR" + +#data +FOO> BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO> BAR" + +#data +FOO>;;BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO>;;BAR" + +#data +I'm ¬it; I tell you +#errors +#document +| <html> +| <head> +| <body> +| "I'm ¬it; I tell you" + +#data +I'm ∉ I tell you +#errors +#document +| <html> +| <head> +| <body> +| "I'm ∉ I tell you" + +#data +FOO& BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO& BAR" + +#data +FOO&<BAR> +#errors +#document +| <html> +| <head> +| <body> +| "FOO&" +| <bar> + +#data +FOO&&&>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO&&&>BAR" + +#data +FOO)BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO)BAR" + +#data +FOOABAR +#errors +#document +| <html> +| <head> +| <body> +| "FOOABAR" + +#data +FOOABAR +#errors +#document +| <html> +| <head> +| <body> +| "FOOABAR" + +#data +FOO&#BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO&#BAR" + +#data +FOO&#ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO&#ZOO" + +#data +FOOºR +#errors +#document +| <html> +| <head> +| <body> +| "FOOºR" + +#data +FOO&#xZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO&#xZOO" + +#data +FOO&#XZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO&#XZOO" + +#data +FOO)BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO)BAR" + +#data +FOO䆺R +#errors +#document +| <html> +| <head> +| <body> +| "FOO䆺R" + +#data +FOOAZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOAZOO" + +#data +FOO�ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO�ZOO" + +#data +FOOxZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOxZOO" + +#data +FOOyZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOyZOO" + +#data +FOO€ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO€ZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOO‚ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO‚ZOO" + +#data +FOOƒZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOƒZOO" + +#data +FOO„ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO„ZOO" + +#data +FOO…ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO…ZOO" + +#data +FOO†ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO†ZOO" + +#data +FOO‡ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO‡ZOO" + +#data +FOOˆZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOˆZOO" + +#data +FOO‰ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO‰ZOO" + +#data +FOOŠZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOŠZOO" + +#data +FOO‹ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO‹ZOO" + +#data +FOOŒZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOŒZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOOŽZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOŽZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOO‘ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO‘ZOO" + +#data +FOO’ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO’ZOO" + +#data +FOO“ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO“ZOO" + +#data +FOO”ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO”ZOO" + +#data +FOO•ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO•ZOO" + +#data +FOO–ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO–ZOO" + +#data +FOO—ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO—ZOO" + +#data +FOO˜ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO˜ZOO" + +#data +FOO™ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO™ZOO" + +#data +FOOšZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOšZOO" + +#data +FOO›ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO›ZOO" + +#data +FOOœZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOœZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOOžZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOžZOO" + +#data +FOOŸZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOŸZOO" + +#data +FOO ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO ZOO" + +#data +FOO퟿ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOO�ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO�ZOO" + +#data +FOO�ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO�ZOO" + +#data +FOO�ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO�ZOO" + +#data +FOO�ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO�ZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOO􈟔ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOOZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOOZOO" + +#data +FOO�ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO�ZOO" + +#data +FOO�ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO�ZOO" diff --git a/libgo/go/exp/html/testdata/webkit/entities02.dat b/libgo/go/exp/html/testdata/webkit/entities02.dat new file mode 100644 index 00000000000..e2fb42a078b --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/entities02.dat @@ -0,0 +1,249 @@ +#data +<div bar="ZZ>YY"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>YY" + +#data +<div bar="ZZ&"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ&" + +#data +<div bar='ZZ&'></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ&" + +#data +<div bar=ZZ&></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ&" + +#data +<div bar="ZZ>=YY"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>=YY" + +#data +<div bar="ZZ>0YY"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>0YY" + +#data +<div bar="ZZ>9YY"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>9YY" + +#data +<div bar="ZZ>aYY"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>aYY" + +#data +<div bar="ZZ>ZYY"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>ZYY" + +#data +<div bar="ZZ> YY"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ> YY" + +#data +<div bar="ZZ>"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>" + +#data +<div bar='ZZ>'></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>" + +#data +<div bar=ZZ>></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ>" + +#data +<div bar="ZZ£_id=23"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ£_id=23" + +#data +<div bar="ZZ&prod_id=23"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ&prod_id=23" + +#data +<div bar="ZZ£_id=23"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ£_id=23" + +#data +<div bar="ZZ∏_id=23"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ∏_id=23" + +#data +<div bar="ZZ£=23"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ£=23" + +#data +<div bar="ZZ&prod=23"></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| bar="ZZ&prod=23" + +#data +<div>ZZ£_id=23</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "ZZ£_id=23" + +#data +<div>ZZ&prod_id=23</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "ZZ&prod_id=23" + +#data +<div>ZZ£_id=23</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "ZZ£_id=23" + +#data +<div>ZZ∏_id=23</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "ZZ∏_id=23" + +#data +<div>ZZ£=23</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "ZZ£=23" + +#data +<div>ZZ&prod=23</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "ZZ&prod=23" diff --git a/libgo/go/exp/html/testdata/webkit/html5test-com.dat b/libgo/go/exp/html/testdata/webkit/html5test-com.dat new file mode 100644 index 00000000000..d7cb71db054 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/html5test-com.dat @@ -0,0 +1,246 @@ +#data +<div<div> +#errors +#document +| <html> +| <head> +| <body> +| <div<div> + +#data +<div foo<bar=''> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| foo<bar="" + +#data +<div foo=`bar`> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| foo="`bar`" + +#data +<div \"foo=''> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| \"foo="" + +#data +<a href='\nbar'></a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| href="\nbar" + +#data +<!DOCTYPE html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +⟨⟩ +#errors +#document +| <html> +| <head> +| <body> +| "⟨⟩" + +#data +' +#errors +#document +| <html> +| <head> +| <body> +| "'" + +#data +ⅈ +#errors +#document +| <html> +| <head> +| <body> +| "ⅈ" + +#data +𝕂 +#errors +#document +| <html> +| <head> +| <body> +| "𝕂" + +#data +∉ +#errors +#document +| <html> +| <head> +| <body> +| "∉" + +#data +<?import namespace="foo" implementation="#bar"> +#errors +#document +| <!-- ?import namespace="foo" implementation="#bar" --> +| <html> +| <head> +| <body> + +#data +<!--foo--bar--> +#errors +#document +| <!-- foo--bar --> +| <html> +| <head> +| <body> + +#data +<![CDATA[x]]> +#errors +#document +| <!-- [CDATA[x]] --> +| <html> +| <head> +| <body> + +#data +<textarea><!--</textarea>--></textarea> +#errors +#document +| <html> +| <head> +| <body> +| <textarea> +| "<!--" +| "-->" + +#data +<textarea><!--</textarea>--> +#errors +#document +| <html> +| <head> +| <body> +| <textarea> +| "<!--" +| "-->" + +#data +<style><!--</style>--></style> +#errors +#document +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "-->" + +#data +<style><!--</style>--> +#errors +#document +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "-->" + +#data +<ul><li>A </li> <li>B</li></ul> +#errors +#document +| <html> +| <head> +| <body> +| <ul> +| <li> +| "A " +| " " +| <li> +| "B" + +#data +<table><form><input type=hidden><input></form><div></div></table> +#errors +#document +| <html> +| <head> +| <body> +| <input> +| <div> +| <table> +| <form> +| <input> +| type="hidden" + +#data +<i>A<b>B<p></i>C</b>D +#errors +#document +| <html> +| <head> +| <body> +| <i> +| "A" +| <b> +| "B" +| <b> +| <p> +| <b> +| <i> +| "C" +| "D" + +#data +<div></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> + +#data +<svg></svg> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> + +#data +<math></math> +#errors +#document +| <html> +| <head> +| <body> +| <math math> diff --git a/libgo/go/exp/html/testdata/webkit/inbody01.dat b/libgo/go/exp/html/testdata/webkit/inbody01.dat new file mode 100644 index 00000000000..3f2bd374c03 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/inbody01.dat @@ -0,0 +1,43 @@ +#data +<button>1</foo> +#errors +#document +| <html> +| <head> +| <body> +| <button> +| "1" + +#data +<foo>1<p>2</foo> +#errors +#document +| <html> +| <head> +| <body> +| <foo> +| "1" +| <p> +| "2" + +#data +<dd>1</foo> +#errors +#document +| <html> +| <head> +| <body> +| <dd> +| "1" + +#data +<foo>1<dd>2</foo> +#errors +#document +| <html> +| <head> +| <body> +| <foo> +| "1" +| <dd> +| "2" diff --git a/libgo/go/exp/html/testdata/webkit/isindex.dat b/libgo/go/exp/html/testdata/webkit/isindex.dat new file mode 100644 index 00000000000..88325ffe64c --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/isindex.dat @@ -0,0 +1,40 @@ +#data +<isindex> +#errors +#document +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<isindex name="A" action="B" prompt="C" foo="D"> +#errors +#document +| <html> +| <head> +| <body> +| <form> +| action="B" +| <hr> +| <label> +| "C" +| <input> +| foo="D" +| name="isindex" +| <hr> + +#data +<form><isindex> +#errors +#document +| <html> +| <head> +| <body> +| <form> diff --git a/libgo/go/exp/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat b/libgo/go/exp/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat Binary files differnew file mode 100644 index 00000000000..a5ebb1eb285 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat diff --git a/libgo/go/exp/html/testdata/webkit/pending-spec-changes.dat b/libgo/go/exp/html/testdata/webkit/pending-spec-changes.dat new file mode 100644 index 00000000000..e00ee85d3bf --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/pending-spec-changes.dat @@ -0,0 +1,28 @@ +#data +<input type="hidden"><frameset> +#errors +21: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +31: “frameset” start tag seen. +31: End of file seen and there were open elements. +#document +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><table><caption><svg>foo</table>bar +#errors +47: End tag “table” did not match the name of the current open element (“svg”). +47: “table” closed but “caption” was still open. +47: End tag “table” seen, but there were open elements. +36: Unclosed element “svg”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <svg svg> +| "foo" +| "bar" diff --git a/libgo/go/exp/html/testdata/webkit/plain-text-unsafe.dat b/libgo/go/exp/html/testdata/webkit/plain-text-unsafe.dat new file mode 100644 index 00000000000..2f40e83babc --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/plain-text-unsafe.dat @@ -0,0 +1,8 @@ +#data +FOO
ZOO +#errors +#document +| <html> +| <head> +| <body> +| "FOO
ZOO" diff --git a/libgo/go/exp/html/testdata/webkit/scriptdata01.dat b/libgo/go/exp/html/testdata/webkit/scriptdata01.dat new file mode 100644 index 00000000000..76b67f4ba60 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/scriptdata01.dat @@ -0,0 +1,308 @@ +#data +FOO<script>'Hello'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'Hello'" +| "BAR" + +#data +FOO<script></script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "BAR" + +#data +FOO<script></script >BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "BAR" + +#data +FOO<script></script/>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "BAR" + +#data +FOO<script></script/ >BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "BAR" + +#data +FOO<script type="text/plain"></scriptx>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "</scriptx>BAR" + +#data +FOO<script></script foo=">" dd>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "BAR" + +#data +FOO<script>'<'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<'" +| "BAR" + +#data +FOO<script>'<!'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!'" +| "BAR" + +#data +FOO<script>'<!-'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!-'" +| "BAR" + +#data +FOO<script>'<!--'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!--'" +| "BAR" + +#data +FOO<script>'<!---'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!---'" +| "BAR" + +#data +FOO<script>'<!-->'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!-->'" +| "BAR" + +#data +FOO<script>'<!-->'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!-->'" +| "BAR" + +#data +FOO<script>'<!-- potato'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!-- potato'" +| "BAR" + +#data +FOO<script>'<!-- <sCrIpt'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!-- <sCrIpt'" +| "BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt>'</script>BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt> -'</script>BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt> --'</script>BAR" + +#data +FOO<script>'<!-- <sCrIpt> -->'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| "'<!-- <sCrIpt> -->'" +| "BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt> --!>'</script>BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt> -- >'</script>BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt '</script>BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt/'</script>BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt\'" +| "BAR" + +#data +FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX +#errors +#document +| <html> +| <head> +| <body> +| "FOO" +| <script> +| type="text/plain" +| "'<!-- <sCrIpt/'</script>BAR" +| "QUX" diff --git a/libgo/go/exp/html/testdata/webkit/scripted/adoption01.dat b/libgo/go/exp/html/testdata/webkit/scripted/adoption01.dat new file mode 100644 index 00000000000..4e08d0e84a0 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/scripted/adoption01.dat @@ -0,0 +1,15 @@ +#data +<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b> +#errors +#document +| <html> +| <head> +| <body> +| <p> +| <b> +| id="B" +| <script> +| "document.getElementById("A").id = "B"" +| <b> +| id="A" +| "TEXT" diff --git a/libgo/go/exp/html/testdata/webkit/scripted/webkit01.dat b/libgo/go/exp/html/testdata/webkit/scripted/webkit01.dat new file mode 100644 index 00000000000..ef4a41ca00b --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/scripted/webkit01.dat @@ -0,0 +1,28 @@ +#data +1<script>document.write("2")</script>3 +#errors +#document +| <html> +| <head> +| <body> +| "1" +| <script> +| "document.write("2")" +| "23" + +#data +1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4 +#errors +#document +| <html> +| <head> +| <body> +| "1" +| <script> +| "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")" +| <script> +| "document.write('2')" +| "2" +| <script> +| "document.write('3')" +| "34" diff --git a/libgo/go/exp/html/testdata/webkit/tables01.dat b/libgo/go/exp/html/testdata/webkit/tables01.dat new file mode 100644 index 00000000000..88ef1fe2ee9 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tables01.dat @@ -0,0 +1,197 @@ +#data +<table><th> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <th> + +#data +<table><td> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><col foo='bar'> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <colgroup> +| <col> +| foo="bar" + +#data +<table><colgroup></html>foo +#errors +#document +| <html> +| <head> +| <body> +| "foo" +| <table> +| <colgroup> + +#data +<table></table><p>foo +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <p> +| "foo" + +#data +<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><select><option>3</select></table> +#errors +#document +| <html> +| <head> +| <body> +| <select> +| <option> +| "3" +| <table> + +#data +<table><select><table></table></select></table> +#errors +#document +| <html> +| <head> +| <body> +| <select> +| <table> +| <table> + +#data +<table><select></table> +#errors +#document +| <html> +| <head> +| <body> +| <select> +| <table> + +#data +<table><select><option>A<tr><td>B</td></tr></table> +#errors +#document +| <html> +| <head> +| <body> +| <select> +| <option> +| "A" +| <table> +| <tbody> +| <tr> +| <td> +| "B" + +#data +<table><td></body></caption></col></colgroup></html>foo +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "foo" + +#data +<table><td>A</table>B +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "A" +| "B" + +#data +<table><tr><caption> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <caption> + +#data +<table><tr></body></caption></col></colgroup></html></td></th><td>foo +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "foo" + +#data +<table><td><tr> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <tr> + +#data +<table><td><button><td> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <button> +| <td> diff --git a/libgo/go/exp/html/testdata/webkit/tests1.dat b/libgo/go/exp/html/testdata/webkit/tests1.dat new file mode 100644 index 00000000000..cbf8bdda638 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests1.dat @@ -0,0 +1,1952 @@ +#data +Test +#errors +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "Test" + +#data +<p>One<p>Two +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <p> +| "One" +| <p> +| "Two" + +#data +Line1<br>Line2<br>Line3<br>Line4 +#errors +Line: 1 Col: 5 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "Line1" +| <br> +| "Line2" +| <br> +| "Line3" +| <br> +| "Line4" + +#data +<html> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<head> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<body> +#errors +Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<html><head> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<html><head></head> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<html><head></head><body> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<html><head></head><body></body> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<html><head><body></body></html> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<html><head></body></html> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected end tag (body). +Line: 1 Col: 26 Unexpected end tag (html). +#document +| <html> +| <head> +| <body> + +#data +<html><head><body></html> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<html><body></html> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<body></html> +#errors +Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<head></html> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end tag (html). Ignored. +#document +| <html> +| <head> +| <body> + +#data +</head> +#errors +Line: 1 Col: 7 Unexpected end tag (head). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +</body> +#errors +Line: 1 Col: 7 Unexpected end tag (body). Expected DOCTYPE. +Line: 1 Col: 7 Unexpected end tag (body) after the (implied) root element. +#document +| <html> +| <head> +| <body> + +#data +</html> +#errors +Line: 1 Col: 7 Unexpected end tag (html). Expected DOCTYPE. +Line: 1 Col: 7 Unexpected end tag (html) after the (implied) root element. +#document +| <html> +| <head> +| <body> + +#data +<b><table><td><i></table> +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 25 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| <table> +| <tbody> +| <tr> +| <td> +| <i> + +#data +<b><table><td></b><i></table>X +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 30 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| <table> +| <tbody> +| <tr> +| <td> +| <i> +| "X" + +#data +<h1>Hello<h2>World +#errors +4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +13: Heading cannot be a child of another heading. +18: End of file seen and there were open elements. +#document +| <html> +| <head> +| <body> +| <h1> +| "Hello" +| <h2> +| "World" + +#data +<a><p>X<a>Y</a>Z</p></a> +#errors +Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 10 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +#document +| <html> +| <head> +| <body> +| <a> +| <p> +| <a> +| "X" +| <a> +| "Y" +| "Z" + +#data +<b><button>foo</b>bar +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +#document +| <html> +| <head> +| <body> +| <b> +| <button> +| <b> +| "foo" +| "bar" + +#data +<!DOCTYPE html><span><button>foo</span>bar +#errors +39: End tag “span” seen but there were unclosed elements. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <span> +| <button> +| "foobar" + +#data +<p><b><div><marquee></p></b></div>X +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end tag (p). Ignored. +Line: 1 Col: 24 Unexpected end tag (p). Ignored. +Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 35 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <p> +| <b> +| <div> +| <b> +| <marquee> +| <p> +| "X" + +#data +<script><div></script></div><title><p></title><p><p> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected end tag (div). Ignored. +#document +| <html> +| <head> +| <script> +| "<div>" +| <title> +| "<p>" +| <body> +| <p> +| <p> + +#data +<!--><div>--<!--> +#errors +Line: 1 Col: 5 Incorrect comment. +Line: 1 Col: 10 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 17 Incorrect comment. +Line: 1 Col: 17 Expected closing tag. Unexpected end of file. +#document +| <!-- --> +| <html> +| <head> +| <body> +| <div> +| "--" +| <!-- --> + +#data +<p><hr></p> +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end tag (p). Ignored. +#document +| <html> +| <head> +| <body> +| <p> +| <hr> +| <p> + +#data +<select><b><option><select><option></b></select>X +#errors +Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored. +Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag. +Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 48 Unexpected end tag (select). Ignored. +Line: 1 Col: 49 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <select> +| <option> +| <option> +| "X" + +#data +<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y +#errors +Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase. +Line: 1 Col: 63 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 64 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| <a> +| <table> +| <tbody> +| <tr> +| <td> +| <a> +| <table> +| <a> +| <a> +| <b> +| "X" +| "C" +| <a> +| "Y" + +#data +<a X>0<b>1<a Y>2 +#errors +Line: 1 Col: 5 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 16 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| x="" +| "0" +| <b> +| "1" +| <b> +| <a> +| y="" +| "2" + +#data +<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X--> +#errors +Line: 1 Col: 7 Unexpected '-' after '--' found in comment. +Line: 1 Col: 14 Unexpected start tag (font). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 41 Unexpected start tag (b) in table context caused voodoo mode. +Line: 1 Col: 48 Unexpected implied end tag (b) in the table phase. +Line: 1 Col: 48 Unexpected table cell start tag (th) in the table body phase. +Line: 1 Col: 63 Got table cell end tag (th) while required end tags are missing. +Line: 1 Col: 71 Unexpected end of file. Expected table content. +#document +| <!-- - --> +| <html> +| <head> +| <body> +| <font> +| <div> +| "helloexcite!" +| <b> +| "me!" +| <table> +| <tbody> +| <tr> +| <th> +| <i> +| "please!" +| <!-- X --> + +#data +<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do--> +#errors +Line: 1 Col: 61 Unexpected end tag (li). Missing end tag (body). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <li> +| "hello" +| <li> +| "world" +| <ul> +| "how" +| <li> +| "do" +| "you" +| <!-- do --> + +#data +<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E +#errors +Line: 1 Col: 54 Unexpected end tag (option) in the select phase. Ignored. +Line: 1 Col: 55 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "A" +| <option> +| "B" +| <optgroup> +| "C" +| <select> +| "DE" + +#data +< +#errors +Line: 1 Col: 1 Expected tag name. Got something else instead +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "<" + +#data +<# +#errors +Line: 1 Col: 1 Expected tag name. Got something else instead +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "<#" + +#data +</ +#errors +Line: 1 Col: 2 Expected closing tag. Unexpected end of file. +Line: 1 Col: 2 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "</" + +#data +</# +#errors +Line: 1 Col: 2 Expected closing tag. Unexpected character '#' found. +Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- # --> +| <html> +| <head> +| <body> + +#data +<? +#errors +Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.) +Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- ? --> +| <html> +| <head> +| <body> + +#data +<?# +#errors +Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.) +Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- ?# --> +| <html> +| <head> +| <body> + +#data +<! +#errors +Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found. +Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- --> +| <html> +| <head> +| <body> + +#data +<!# +#errors +Line: 1 Col: 3 Expected '--' or 'DOCTYPE'. Not found. +Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- # --> +| <html> +| <head> +| <body> + +#data +<?COMMENT?> +#errors +Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.) +Line: 1 Col: 11 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- ?COMMENT? --> +| <html> +| <head> +| <body> + +#data +<!COMMENT> +#errors +Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found. +Line: 1 Col: 10 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- COMMENT --> +| <html> +| <head> +| <body> + +#data +</ COMMENT > +#errors +Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found. +Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- COMMENT --> +| <html> +| <head> +| <body> + +#data +<?COM--MENT?> +#errors +Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.) +Line: 1 Col: 13 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- ?COM--MENT? --> +| <html> +| <head> +| <body> + +#data +<!COM--MENT> +#errors +Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found. +Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- COM--MENT --> +| <html> +| <head> +| <body> + +#data +</ COM--MENT > +#errors +Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found. +Line: 1 Col: 14 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- COM--MENT --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><style> EOF +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| " EOF" +| <body> + +#data +<!DOCTYPE html><script> <!-- </script> --> </script> EOF +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| " <!-- " +| " " +| <body> +| "--> EOF" + +#data +<b><p></b>TEST +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 10 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +#document +| <html> +| <head> +| <body> +| <b> +| <p> +| <b> +| "TEST" + +#data +<p id=a><b><p id=b></b>TEST +#errors +Line: 1 Col: 8 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected end tag (p). Ignored. +Line: 1 Col: 23 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm. +#document +| <html> +| <head> +| <body> +| <p> +| id="a" +| <b> +| <p> +| id="b" +| "TEST" + +#data +<b id=a><p><b id=b></p></b>TEST +#errors +Line: 1 Col: 8 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end tag (p). Ignored. +Line: 1 Col: 27 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm. +Line: 1 Col: 31 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| id="a" +| <p> +| <b> +| id="b" +| "TEST" + +#data +<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body> +#errors +Line: 1 Col: 61 Unexpected end tag (p). Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "U-test" +| <body> +| <div> +| <p> +| "Test" +| <u> + +#data +<!DOCTYPE html><font><table></font></table></font> +#errors +Line: 1 Col: 35 Unexpected end tag (font) in table context caused voodoo mode. +Line: 1 Col: 35 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <table> + +#data +<font><p>hello<b>cruel</font>world +#errors +Line: 1 Col: 6 Unexpected start tag (font). Expected DOCTYPE. +Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 34 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <font> +| <p> +| <font> +| "hello" +| <b> +| "cruel" +| <b> +| "world" + +#data +<b>Test</i>Test +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 11 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 15 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| "TestTest" + +#data +<b>A<cite>B<div>C +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 17 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| "A" +| <cite> +| "B" +| <div> +| "C" + +#data +<b>A<cite>B<div>C</cite>D +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 24 Unexpected end tag (cite). Ignored. +Line: 1 Col: 25 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| "A" +| <cite> +| "B" +| <div> +| "CD" + +#data +<b>A<cite>B<div>C</b>D +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 21 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 22 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| "A" +| <cite> +| "B" +| <div> +| <b> +| "C" +| "D" + +#data + +#errors +Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<DIV> +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 5 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> + +#data +<DIV> abc +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 9 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc" + +#data +<DIV> abc <B> +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 13 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> + +#data +<DIV> abc <B> def +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 17 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def" + +#data +<DIV> abc <B> def <I> +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 21 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> + +#data +<DIV> abc <B> def <I> ghi +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 25 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi" + +#data +<DIV> abc <B> def <I> ghi <P> +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 29 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <p> + +#data +<DIV> abc <B> def <I> ghi <P> jkl +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 33 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <p> +| " jkl" + +#data +<DIV> abc <B> def <I> ghi <P> jkl </B> +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 38 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <i> +| <p> +| <b> +| " jkl " + +#data +<DIV> abc <B> def <I> ghi <P> jkl </B> mno +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 42 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <i> +| <p> +| <b> +| " jkl " +| " mno" + +#data +<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 47 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <i> +| <p> +| <i> +| <b> +| " jkl " +| " mno " + +#data +<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 51 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <i> +| <p> +| <i> +| <b> +| " jkl " +| " mno " +| " pqr" + +#data +<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 56 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <i> +| <p> +| <i> +| <b> +| " jkl " +| " mno " +| " pqr " + +#data +<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 60 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " abc " +| <b> +| " def " +| <i> +| " ghi " +| <i> +| <p> +| <i> +| <b> +| " jkl " +| " mno " +| " pqr " +| " stu" + +#data +<test attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------> +#errors +Line: 1 Col: 1040 Unexpected start tag (test). Expected DOCTYPE. +Line: 1 Col: 1040 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <test> +| attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------="" + +#data +<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe +#errors +Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 39 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 39 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 39 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 45 Unexpected implied end tag (a) in the table phase. +Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase. +Line: 1 Col: 71 Expected closing tag. Unexpected end of file. + +#document +| <html> +| <head> +| <body> +| <a> +| href="blah" +| "aba" +| <a> +| href="foo" +| "br" +| <a> +| href="foo" +| "x" +| <table> +| <tbody> +| <tr> +| <td> +| <a> +| href="foo" +| "aoe" + +#data +<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe +#errors +Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 60 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 71 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| href="blah" +| "abax" +| <table> +| <tbody> +| <tr> +| <td> +| <a> +| href="foo" +| "br" +| "aoe" + +#data +<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 29 Unexpected implied end tag (a) in the table phase. +Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase. +Line: 1 Col: 71 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| href="blah" +| "aba" +| <a> +| href="blah" +| "x" +| <table> +| <tbody> +| <tr> +| <td> +| <a> +| href="foo" +| "br" +| <a> +| href="blah" +| "aoe" + +#data +<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa +#errors +Line: 1 Col: 10 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 45 End tag (marquee) seen too early. Expected other end tag. +Line: 1 Col: 47 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| href="a" +| "aa" +| <marquee> +| "aa" +| <a> +| href="b" +| "bb" +| "aa" + +#data +<wbr><strike><code></strike><code><strike></code> +#errors +Line: 1 Col: 5 Unexpected start tag (wbr). Expected DOCTYPE. +Line: 1 Col: 28 End tag (strike) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 49 Unexpected end tag (code). Ignored. +#document +| <html> +| <head> +| <body> +| <wbr> +| <strike> +| <code> +| <code> +| <code> +| <strike> + +#data +<!DOCTYPE html><spacer>foo +#errors +26: End of file seen and there were open elements. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <spacer> +| "foo" + +#data +<title><meta></title><link><title><meta></title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| <html> +| <head> +| <title> +| "<meta>" +| <link> +| <title> +| "<meta>" +| <body> + +#data +<style><!--</style><meta><script>--><link></script> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 51 Unexpected end of file. Expected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--" +| <meta> +| <script> +| "--><link>" +| <body> + +#data +<head><meta></head><link> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 25 Unexpected start tag (link) that can be in head. Moved. +#document +| <html> +| <head> +| <meta> +| <link> +| <body> + +#data +<table><tr><tr><td><td><span><th><span>X</table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 33 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 48 Got table cell end tag (th) while required end tags are missing. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <tr> +| <td> +| <td> +| <span> +| <th> +| <span> +| "X" + +#data +<body><body><base><link><meta><title><p></title><body><p></body> +#errors +Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected start tag (body). +Line: 1 Col: 54 Unexpected start tag (body). +Line: 1 Col: 64 Unexpected end tag (p). Missing end tag (body). +#document +| <html> +| <head> +| <body> +| <base> +| <link> +| <meta> +| <title> +| "<p>" +| <p> + +#data +<textarea><p></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <textarea> +| "<p>" + +#data +<p><image></p> +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected start tag (image). Treated as img. +#document +| <html> +| <head> +| <body> +| <p> +| <img> + +#data +<a><table><a></table><p><a><div><a> +#errors +Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 13 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 13 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 21 Unexpected end tag (table). Expected end tag (a). +Line: 1 Col: 27 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 27 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm. +Line: 1 Col: 32 Unexpected end tag (p). Ignored. +Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 35 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm. +Line: 1 Col: 35 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| <a> +| <table> +| <p> +| <a> +| <div> +| <a> + +#data +<head></p><meta><p> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end tag (p). Ignored. +#document +| <html> +| <head> +| <meta> +| <body> +| <p> + +#data +<head></html><meta><p> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected start tag (meta). +#document +| <html> +| <head> +| <body> +| <meta> +| <p> + +#data +<b><table><td><i></table> +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 25 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| <table> +| <tbody> +| <tr> +| <td> +| <i> + +#data +<b><table><td></b><i></table> +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 29 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| <table> +| <tbody> +| <tr> +| <td> +| <i> + +#data +<h1><h2> +#errors +4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +8: Heading cannot be a child of another heading. +8: End of file seen and there were open elements. +#document +| <html> +| <head> +| <body> +| <h1> +| <h2> + +#data +<a><p><a></a></p></a> +#errors +Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 9 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 21 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +#document +| <html> +| <head> +| <body> +| <a> +| <p> +| <a> +| <a> + +#data +<b><button></b></button></b> +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +#document +| <html> +| <head> +| <body> +| <b> +| <button> +| <b> + +#data +<p><b><div><marquee></p></b></div> +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end tag (p). Ignored. +Line: 1 Col: 24 Unexpected end tag (p). Ignored. +Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 34 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <p> +| <b> +| <div> +| <b> +| <marquee> +| <p> + +#data +<script></script></div><title></title><p><p> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end tag (div). Ignored. +#document +| <html> +| <head> +| <script> +| <title> +| <body> +| <p> +| <p> + +#data +<p><hr></p> +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end tag (p). Ignored. +#document +| <html> +| <head> +| <body> +| <p> +| <hr> +| <p> + +#data +<select><b><option><select><option></b></select> +#errors +Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored. +Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag. +Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 48 Unexpected end tag (select). Ignored. +Line: 1 Col: 48 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <select> +| <option> +| <option> + +#data +<html><head><title></title><body></body></html> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <title> +| <body> + +#data +<a><table><td><a><table></table><a></tr><a></table><a> +#errors +Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing. +Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase. +Line: 1 Col: 54 Unexpected start tag (a) implies end tag (a). +Line: 1 Col: 54 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm. +Line: 1 Col: 54 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| <a> +| <table> +| <tbody> +| <tr> +| <td> +| <a> +| <table> +| <a> +| <a> + +#data +<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul> +#errors +Line: 1 Col: 4 Unexpected start tag (ul). Expected DOCTYPE. +Line: 1 Col: 45 Missing end tag (div, li). +Line: 1 Col: 58 Missing end tag (address, li). +Line: 1 Col: 69 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +#document +| <html> +| <head> +| <body> +| <ul> +| <li> +| <div> +| <li> +| <li> +| <li> +| <div> +| <li> +| <address> +| <li> +| <b> +| <em> +| <li> + +#data +<ul><li><ul></li><li>a</li></ul></li></ul> +#errors +XXX: fix me +#document +| <html> +| <head> +| <body> +| <ul> +| <li> +| <ul> +| <li> +| "a" + +#data +<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +#document +| <html> +| <head> +| <frameset> +| <frame> +| <frameset> +| <frame> +| <noframes> + +#data +<h1><table><td><h3></table><h3></h1> +#errors +4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +15: “td” start tag in table body. +27: Unclosed elements. +31: Heading cannot be a child of another heading. +36: End tag “h1” seen but there were unclosed elements. +#document +| <html> +| <head> +| <body> +| <h1> +| <table> +| <tbody> +| <tr> +| <td> +| <h3> +| <h3> + +#data +<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <table> +| <colgroup> +| <col> +| <colgroup> +| <col> +| <col> +| <col> +| <colgroup> +| <col> +| <col> +| <thead> +| <tr> +| <td> + +#data +<table><col><tbody><col><tr><col><td><col></table><col> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 55 Unexpected start tag col. Ignored. +#document +| <html> +| <head> +| <body> +| <table> +| <colgroup> +| <col> +| <tbody> +| <colgroup> +| <col> +| <tbody> +| <tr> +| <colgroup> +| <col> +| <tbody> +| <tr> +| <td> +| <colgroup> +| <col> + +#data +<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 52 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 80 Unexpected start tag colgroup. Ignored. +#document +| <html> +| <head> +| <body> +| <table> +| <colgroup> +| <tbody> +| <colgroup> +| <tbody> +| <tr> +| <colgroup> +| <tbody> +| <tr> +| <td> +| <colgroup> + +#data +</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea> +#errors +Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element. +Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element. +Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element. +Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element. +Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element. +Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element. +Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element. +Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element. +Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element. +Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element. +Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element. +Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element. +Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element. +Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element. +Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element. +Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element. +Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element. +Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element. +Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element. +Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element. +Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element. +Line: 1 Col: 130 Unexpected end tag (br). Treated as br element. +Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 140 This element (img) has no end tag. +Line: 1 Col: 148 Unexpected end tag (title). Ignored. +Line: 1 Col: 155 Unexpected end tag (span). Ignored. +Line: 1 Col: 163 Unexpected end tag (style). Ignored. +Line: 1 Col: 172 Unexpected end tag (script). Ignored. +Line: 1 Col: 180 Unexpected end tag (table). Ignored. +Line: 1 Col: 185 Unexpected end tag (th). Ignored. +Line: 1 Col: 190 Unexpected end tag (td). Ignored. +Line: 1 Col: 195 Unexpected end tag (tr). Ignored. +Line: 1 Col: 203 This element (frame) has no end tag. +Line: 1 Col: 210 This element (area) has no end tag. +Line: 1 Col: 217 Unexpected end tag (link). Ignored. +Line: 1 Col: 225 This element (param) has no end tag. +Line: 1 Col: 230 This element (hr) has no end tag. +Line: 1 Col: 238 This element (input) has no end tag. +Line: 1 Col: 244 Unexpected end tag (col). Ignored. +Line: 1 Col: 251 Unexpected end tag (base). Ignored. +Line: 1 Col: 258 Unexpected end tag (meta). Ignored. +Line: 1 Col: 269 This element (basefont) has no end tag. +Line: 1 Col: 279 This element (bgsound) has no end tag. +Line: 1 Col: 287 This element (embed) has no end tag. +Line: 1 Col: 296 This element (spacer) has no end tag. +Line: 1 Col: 300 Unexpected end tag (p). Ignored. +Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag. +Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag. +Line: 1 Col: 320 Unexpected end tag (caption). Ignored. +Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 339 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 355 Unexpected end tag (thead). Ignored. +Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag. +Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag. +Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag. +Line: 1 Col: 393 Unexpected end tag (dir). Ignored. +Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag. +Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag. +Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag. +Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag. +Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag. +Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag. +Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag. +Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 460 This element (wbr) has no end tag. +Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag. +Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag. +Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag. +Line: 1 Col: 513 Unexpected end tag (html). Ignored. +Line: 1 Col: 513 Unexpected end tag (frameset). Ignored. +Line: 1 Col: 520 Unexpected end tag (head). Ignored. +Line: 1 Col: 529 Unexpected end tag (iframe). Ignored. +Line: 1 Col: 537 This element (image) has no end tag. +Line: 1 Col: 547 This element (isindex) has no end tag. +Line: 1 Col: 557 Unexpected end tag (noembed). Ignored. +Line: 1 Col: 568 Unexpected end tag (noframes). Ignored. +Line: 1 Col: 579 Unexpected end tag (noscript). Ignored. +Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored. +Line: 1 Col: 599 Unexpected end tag (option). Ignored. +Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored. +Line: 1 Col: 622 Unexpected end tag (textarea). Ignored. +#document +| <html> +| <head> +| <body> +| <br> +| <p> + +#data +<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode. +Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode. +Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode. +Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode. +Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode. +Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode. +Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode. +Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode. +Line: 1 Col: 58 Unexpected end tag (blink). Ignored. +Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode. +Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode. +Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag. +Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode. +Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode. +Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode. +Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode. +Line: 1 Col: 99 Unexpected end tag (select). Ignored. +Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode. +Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag. +Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode. +Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag. +Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode. +Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag. +Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode. +Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag. +Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode. +Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag. +Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode. +Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag. +Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored. +Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode. +Line: 1 Col: 141 Unexpected end tag (br). Treated as br element. +Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode. +Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode. +Line: 1 Col: 151 This element (img) has no end tag. +Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode. +Line: 1 Col: 159 Unexpected end tag (title). Ignored. +Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode. +Line: 1 Col: 166 Unexpected end tag (span). Ignored. +Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode. +Line: 1 Col: 174 Unexpected end tag (style). Ignored. +Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode. +Line: 1 Col: 183 Unexpected end tag (script). Ignored. +Line: 1 Col: 196 Unexpected end tag (th). Ignored. +Line: 1 Col: 201 Unexpected end tag (td). Ignored. +Line: 1 Col: 206 Unexpected end tag (tr). Ignored. +Line: 1 Col: 214 This element (frame) has no end tag. +Line: 1 Col: 221 This element (area) has no end tag. +Line: 1 Col: 228 Unexpected end tag (link). Ignored. +Line: 1 Col: 236 This element (param) has no end tag. +Line: 1 Col: 241 This element (hr) has no end tag. +Line: 1 Col: 249 This element (input) has no end tag. +Line: 1 Col: 255 Unexpected end tag (col). Ignored. +Line: 1 Col: 262 Unexpected end tag (base). Ignored. +Line: 1 Col: 269 Unexpected end tag (meta). Ignored. +Line: 1 Col: 280 This element (basefont) has no end tag. +Line: 1 Col: 290 This element (bgsound) has no end tag. +Line: 1 Col: 298 This element (embed) has no end tag. +Line: 1 Col: 307 This element (spacer) has no end tag. +Line: 1 Col: 311 Unexpected end tag (p). Ignored. +Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag. +Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag. +Line: 1 Col: 331 Unexpected end tag (caption). Ignored. +Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 350 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 366 Unexpected end tag (thead). Ignored. +Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag. +Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag. +Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag. +Line: 1 Col: 404 Unexpected end tag (dir). Ignored. +Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag. +Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag. +Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag. +Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag. +Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag. +Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag. +Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag. +Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm. +Line: 1 Col: 471 This element (wbr) has no end tag. +Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag. +Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag. +Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag. +Line: 1 Col: 524 Unexpected end tag (html). Ignored. +Line: 1 Col: 524 Unexpected end tag (frameset). Ignored. +Line: 1 Col: 531 Unexpected end tag (head). Ignored. +Line: 1 Col: 540 Unexpected end tag (iframe). Ignored. +Line: 1 Col: 548 This element (image) has no end tag. +Line: 1 Col: 558 This element (isindex) has no end tag. +Line: 1 Col: 568 Unexpected end tag (noembed). Ignored. +Line: 1 Col: 579 Unexpected end tag (noframes). Ignored. +Line: 1 Col: 590 Unexpected end tag (noscript). Ignored. +Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored. +Line: 1 Col: 610 Unexpected end tag (option). Ignored. +Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored. +Line: 1 Col: 633 Unexpected end tag (textarea). Ignored. +#document +| <html> +| <head> +| <body> +| <br> +| <table> +| <tbody> +| <tr> +| <p> + +#data +<frameset> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 1 Col: 10 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <frameset> diff --git a/libgo/go/exp/html/testdata/webkit/tests10.dat b/libgo/go/exp/html/testdata/webkit/tests10.dat new file mode 100644 index 00000000000..4f8df86f208 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests10.dat @@ -0,0 +1,799 @@ +#data +<!DOCTYPE html><svg></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> + +#data +<!DOCTYPE html><svg></svg><![CDATA[a]]> +#errors +29: Bogus comment +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <!-- [CDATA[a]] --> + +#data +<!DOCTYPE html><body><svg></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> + +#data +<!DOCTYPE html><body><select><svg></svg></select> +#errors +35: Stray “svg” start tag. +42: Stray end tag “svg” +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!DOCTYPE html><body><select><option><svg></svg></option></select> +#errors +43: Stray “svg” start tag. +50: Stray end tag “svg” +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!DOCTYPE html><body><table><svg></svg></table> +#errors +34: Start tag “svg” seen in “table”. +41: Stray end tag “svg”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <table> + +#data +<!DOCTYPE html><body><table><svg><g>foo</g></svg></table> +#errors +34: Start tag “svg” seen in “table”. +46: Stray end tag “g”. +53: Stray end tag “svg”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg g> +| "foo" +| <table> + +#data +<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table> +#errors +34: Start tag “svg” seen in “table”. +46: Stray end tag “g”. +58: Stray end tag “g”. +65: Stray end tag “svg”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <table> + +#data +<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table> +#errors +41: Start tag “svg” seen in “table”. +53: Stray end tag “g”. +65: Stray end tag “g”. +72: Stray end tag “svg”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <table> +| <tbody> + +#data +<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table> +#errors +45: Start tag “svg” seen in “table”. +57: Stray end tag “g”. +69: Stray end tag “g”. +76: Stray end tag “svg”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <table> +| <tbody> +| <tr> + +#data +<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" + +#data +<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux +#errors +70: HTML start tag “p” in a foreign namespace context. +81: “table” closed but “caption” was still open. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <p> +| "baz" +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux +#errors +78: “table” closed but “caption” was still open. +78: Unclosed elements on stack. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| "baz" +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux +#errors +44: Start tag “svg” seen in “table”. +56: Stray end tag “g”. +68: Stray end tag “g”. +71: HTML start tag “p” in a foreign namespace context. +71: Start tag “p” seen in “table”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <p> +| "baz" +| <table> +| <colgroup> +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux +#errors +50: Stray “svg” start tag. +54: Stray “g” start tag. +62: Stray end tag “g” +66: Stray “g” start tag. +74: Stray end tag “g” +77: Stray “p” start tag. +88: “table” end tag with “select” open. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <select> +| "foobarbaz" +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux +#errors +36: Start tag “select” seen in “table”. +42: Stray “svg” start tag. +46: Stray “g” start tag. +54: Stray end tag “g” +58: Stray “g” start tag. +66: Stray end tag “g” +69: Stray “p” start tag. +80: “table” end tag with “select” open. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| "foobarbaz" +| <table> +| <p> +| "quux" + +#data +<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz +#errors +41: Stray “svg” start tag. +68: HTML start tag “p” in a foreign namespace context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz +#errors +34: Stray “svg” start tag. +61: HTML start tag “p” in a foreign namespace context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg g> +| "foo" +| <svg g> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><frameset><svg><g></g><g></g><p><span> +#errors +31: Stray “svg” start tag. +35: Stray “g” start tag. +40: Stray end tag “g” +44: Stray “g” start tag. +49: Stray end tag “g” +52: Stray “p” start tag. +58: Stray “span” start tag. +58: End of file seen and there were open elements. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span> +#errors +42: Stray “svg” start tag. +46: Stray “g” start tag. +51: Stray end tag “g” +55: Stray “g” start tag. +60: Stray end tag “g” +63: Stray “p” start tag. +69: Stray “span” start tag. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| <svg svg> +| xlink href="foo" + +#data +<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| xml:lang="en" +| <svg svg> +| <svg g> +| xlink href="foo" +| xml lang="en" + +#data +<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| xml:lang="en" +| <svg svg> +| <svg g> +| xlink href="foo" +| xml lang="en" + +#data +<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| xml:lang="en" +| <svg svg> +| <svg g> +| xlink href="foo" +| xml lang="en" +| "bar" + +#data +<svg></path> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> + +#data +<div><svg></div>a +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <svg svg> +| "a" + +#data +<div><svg><path></div>a +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <svg svg> +| <svg path> +| "a" + +#data +<div><svg><path></svg><path> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <svg svg> +| <svg path> +| <path> + +#data +<div><svg><path><foreignObject><math></div>a +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <svg svg> +| <svg path> +| <svg foreignObject> +| <math math> +| "a" + +#data +<div><svg><path><foreignObject><p></div>a +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <svg svg> +| <svg path> +| <svg foreignObject> +| <p> +| "a" + +#data +<!DOCTYPE html><svg><desc><div><svg><ul>a +#errors +40: HTML start tag “ul” in a foreign namespace context. +41: End of file in a foreign namespace context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg desc> +| <div> +| <svg svg> +| <ul> +| "a" + +#data +<!DOCTYPE html><svg><desc><svg><ul>a +#errors +35: HTML start tag “ul” in a foreign namespace context. +36: End of file in a foreign namespace context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg desc> +| <svg svg> +| <ul> +| "a" + +#data +<!DOCTYPE html><p><svg><desc><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <svg svg> +| <svg desc> +| <p> + +#data +<!DOCTYPE html><p><svg><title><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <svg svg> +| <svg title> +| <p> + +#data +<div><svg><path><foreignObject><p></foreignObject><p> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <svg svg> +| <svg path> +| <svg foreignObject> +| <p> +| <p> + +#data +<math><mi><div><object><div><span></span></div></object></div></mi><mi> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| <div> +| <object> +| <div> +| <span> +| <math mi> + +#data +<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| <svg svg> +| <svg foreignObject> +| <div> +| <div> +| <math mi> + +#data +<svg><script></script><path> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <svg script> +| <svg path> + +#data +<table><svg></svg><tr> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <table> +| <tbody> +| <tr> + +#data +<math><mi><mglyph> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| <math mglyph> + +#data +<math><mi><malignmark> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| <math malignmark> + +#data +<math><mo><mglyph> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mo> +| <math mglyph> + +#data +<math><mo><malignmark> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mo> +| <math malignmark> + +#data +<math><mn><mglyph> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mn> +| <math mglyph> + +#data +<math><mn><malignmark> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mn> +| <math malignmark> + +#data +<math><ms><mglyph> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math ms> +| <math mglyph> + +#data +<math><ms><malignmark> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math ms> +| <math malignmark> + +#data +<math><mtext><mglyph> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mtext> +| <math mglyph> + +#data +<math><mtext><malignmark> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mtext> +| <math malignmark> + +#data +<math><annotation-xml><svg></svg></annotation-xml><mi> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| <svg svg> +| <math mi> + +#data +<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| <svg svg> +| <svg foreignObject> +| <div> +| <math math> +| <math mi> +| <span> +| <svg path> +| <math mi> + +#data +<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| <svg svg> +| <svg foreignObject> +| <math math> +| <math mi> +| <svg svg> +| <math mo> +| <span> +| <svg path> +| <math mi> diff --git a/libgo/go/exp/html/testdata/webkit/tests11.dat b/libgo/go/exp/html/testdata/webkit/tests11.dat new file mode 100644 index 00000000000..638cde479f7 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests11.dat @@ -0,0 +1,482 @@ +#data +<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data +<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data +<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' filterunits='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| attributeName="" +| attributeType="" +| baseFrequency="" +| baseProfile="" +| calcMode="" +| clipPathUnits="" +| contentScriptType="" +| contentStyleType="" +| diffuseConstant="" +| edgeMode="" +| externalResourcesRequired="" +| filterRes="" +| filterUnits="" +| glyphRef="" +| gradientTransform="" +| gradientUnits="" +| kernelMatrix="" +| kernelUnitLength="" +| keyPoints="" +| keySplines="" +| keyTimes="" +| lengthAdjust="" +| limitingConeAngle="" +| markerHeight="" +| markerUnits="" +| markerWidth="" +| maskContentUnits="" +| maskUnits="" +| numOctaves="" +| pathLength="" +| patternContentUnits="" +| patternTransform="" +| patternUnits="" +| pointsAtX="" +| pointsAtY="" +| pointsAtZ="" +| preserveAlpha="" +| preserveAspectRatio="" +| primitiveUnits="" +| refX="" +| refY="" +| repeatCount="" +| repeatDur="" +| requiredExtensions="" +| requiredFeatures="" +| specularConstant="" +| specularExponent="" +| spreadMethod="" +| startOffset="" +| stdDeviation="" +| stitchTiles="" +| surfaceScale="" +| systemLanguage="" +| tableValues="" +| targetX="" +| targetY="" +| textLength="" +| viewBox="" +| viewTarget="" +| xChannelSelector="" +| yChannelSelector="" +| zoomAndPan="" + +#data +<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| attributename="" +| attributetype="" +| basefrequency="" +| baseprofile="" +| calcmode="" +| clippathunits="" +| contentscripttype="" +| contentstyletype="" +| diffuseconstant="" +| edgemode="" +| externalresourcesrequired="" +| filterres="" +| filterunits="" +| glyphref="" +| gradienttransform="" +| gradientunits="" +| kernelmatrix="" +| kernelunitlength="" +| keypoints="" +| keysplines="" +| keytimes="" +| lengthadjust="" +| limitingconeangle="" +| markerheight="" +| markerunits="" +| markerwidth="" +| maskcontentunits="" +| maskunits="" +| numoctaves="" +| pathlength="" +| patterncontentunits="" +| patterntransform="" +| patternunits="" +| pointsatx="" +| pointsaty="" +| pointsatz="" +| preservealpha="" +| preserveaspectratio="" +| primitiveunits="" +| refx="" +| refy="" +| repeatcount="" +| repeatdur="" +| requiredextensions="" +| requiredfeatures="" +| specularconstant="" +| specularexponent="" +| spreadmethod="" +| startoffset="" +| stddeviation="" +| stitchtiles="" +| surfacescale="" +| systemlanguage="" +| tablevalues="" +| targetx="" +| targety="" +| textlength="" +| viewbox="" +| viewtarget="" +| xchannelselector="" +| ychannelselector="" +| zoomandpan="" + +#data +<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg altGlyph> +| <svg altGlyphDef> +| <svg altGlyphItem> +| <svg animateColor> +| <svg animateMotion> +| <svg animateTransform> +| <svg clipPath> +| <svg feBlend> +| <svg feColorMatrix> +| <svg feComponentTransfer> +| <svg feComposite> +| <svg feConvolveMatrix> +| <svg feDiffuseLighting> +| <svg feDisplacementMap> +| <svg feDistantLight> +| <svg feFlood> +| <svg feFuncA> +| <svg feFuncB> +| <svg feFuncG> +| <svg feFuncR> +| <svg feGaussianBlur> +| <svg feImage> +| <svg feMerge> +| <svg feMergeNode> +| <svg feMorphology> +| <svg feOffset> +| <svg fePointLight> +| <svg feSpecularLighting> +| <svg feSpotLight> +| <svg feTile> +| <svg feTurbulence> +| <svg foreignObject> +| <svg glyphRef> +| <svg linearGradient> +| <svg radialGradient> +| <svg textPath> + +#data +<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg altGlyph> +| <svg altGlyphDef> +| <svg altGlyphItem> +| <svg animateColor> +| <svg animateMotion> +| <svg animateTransform> +| <svg clipPath> +| <svg feBlend> +| <svg feColorMatrix> +| <svg feComponentTransfer> +| <svg feComposite> +| <svg feConvolveMatrix> +| <svg feDiffuseLighting> +| <svg feDisplacementMap> +| <svg feDistantLight> +| <svg feFlood> +| <svg feFuncA> +| <svg feFuncB> +| <svg feFuncG> +| <svg feFuncR> +| <svg feGaussianBlur> +| <svg feImage> +| <svg feMerge> +| <svg feMergeNode> +| <svg feMorphology> +| <svg feOffset> +| <svg fePointLight> +| <svg feSpecularLighting> +| <svg feSpotLight> +| <svg feTile> +| <svg feTurbulence> +| <svg foreignObject> +| <svg glyphRef> +| <svg linearGradient> +| <svg radialGradient> +| <svg textPath> + +#data +<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg altGlyph> +| <svg altGlyphDef> +| <svg altGlyphItem> +| <svg animateColor> +| <svg animateMotion> +| <svg animateTransform> +| <svg clipPath> +| <svg feBlend> +| <svg feColorMatrix> +| <svg feComponentTransfer> +| <svg feComposite> +| <svg feConvolveMatrix> +| <svg feDiffuseLighting> +| <svg feDisplacementMap> +| <svg feDistantLight> +| <svg feFlood> +| <svg feFuncA> +| <svg feFuncB> +| <svg feFuncG> +| <svg feFuncR> +| <svg feGaussianBlur> +| <svg feImage> +| <svg feMerge> +| <svg feMergeNode> +| <svg feMorphology> +| <svg feOffset> +| <svg fePointLight> +| <svg feSpecularLighting> +| <svg feSpotLight> +| <svg feTile> +| <svg feTurbulence> +| <svg foreignObject> +| <svg glyphRef> +| <svg linearGradient> +| <svg radialGradient> +| <svg textPath> + +#data +<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math altglyph> +| <math altglyphdef> +| <math altglyphitem> +| <math animatecolor> +| <math animatemotion> +| <math animatetransform> +| <math clippath> +| <math feblend> +| <math fecolormatrix> +| <math fecomponenttransfer> +| <math fecomposite> +| <math feconvolvematrix> +| <math fediffuselighting> +| <math fedisplacementmap> +| <math fedistantlight> +| <math feflood> +| <math fefunca> +| <math fefuncb> +| <math fefuncg> +| <math fefuncr> +| <math fegaussianblur> +| <math feimage> +| <math femerge> +| <math femergenode> +| <math femorphology> +| <math feoffset> +| <math fepointlight> +| <math fespecularlighting> +| <math fespotlight> +| <math fetile> +| <math feturbulence> +| <math foreignobject> +| <math glyphref> +| <math lineargradient> +| <math radialgradient> +| <math textpath> + +#data +<!DOCTYPE html><body><svg><solidColor /></svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg solidcolor> diff --git a/libgo/go/exp/html/testdata/webkit/tests12.dat b/libgo/go/exp/html/testdata/webkit/tests12.dat new file mode 100644 index 00000000000..63107d277b6 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests12.dat @@ -0,0 +1,62 @@ +#data +<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "foo" +| <math math> +| <math mtext> +| <i> +| "baz" +| <math annotation-xml> +| <svg svg> +| <svg desc> +| <b> +| "eggs" +| <svg g> +| <svg foreignObject> +| <p> +| "spam" +| <table> +| <tbody> +| <tr> +| <td> +| <img> +| <svg g> +| "quux" +| "bar" + +#data +<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "foo" +| <math math> +| <math mtext> +| <i> +| "baz" +| <math annotation-xml> +| <svg svg> +| <svg desc> +| <b> +| "eggs" +| <svg g> +| <svg foreignObject> +| <p> +| "spam" +| <table> +| <tbody> +| <tr> +| <td> +| <img> +| <svg g> +| "quux" +| "bar" diff --git a/libgo/go/exp/html/testdata/webkit/tests14.dat b/libgo/go/exp/html/testdata/webkit/tests14.dat new file mode 100644 index 00000000000..b8713f88582 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests14.dat @@ -0,0 +1,74 @@ +#data +<!DOCTYPE html><html><body><xyz:abc></xyz:abc> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xyz:abc> + +#data +<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xyz:abc> +| <span> + +#data +<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc> +#errors +15: Unexpected start tag html +#document +| <!DOCTYPE html> +| <html> +| abc:def="gh" +| <head> +| <body> +| <xyz:abc> + +#data +<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo> +#errors +15: Unexpected start tag html +#document +| <!DOCTYPE html> +| <html> +| xml:lang="bar" +| <head> +| <body> + +#data +<!DOCTYPE html><html 123=456> +#errors +#document +| <!DOCTYPE html> +| <html> +| 123="456" +| <head> +| <body> + +#data +<!DOCTYPE html><html 123=456><html 789=012> +#errors +#document +| <!DOCTYPE html> +| <html> +| 123="456" +| 789="012" +| <head> +| <body> + +#data +<!DOCTYPE html><html><body 789=012> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| 789="012" diff --git a/libgo/go/exp/html/testdata/webkit/tests15.dat b/libgo/go/exp/html/testdata/webkit/tests15.dat new file mode 100644 index 00000000000..6ce1c0d1663 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests15.dat @@ -0,0 +1,208 @@ +#data +<!DOCTYPE html><p><b><i><u></p> <p>X +#errors +Line: 1 Col: 31 Unexpected end tag (p). Ignored. +Line: 1 Col: 36 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <b> +| <i> +| <u> +| <b> +| <i> +| <u> +| " " +| <p> +| "X" + +#data +<p><b><i><u></p> +<p>X +#errors +Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end tag (p). Ignored. +Line: 2 Col: 4 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <p> +| <b> +| <i> +| <u> +| <b> +| <i> +| <u> +| " +" +| <p> +| "X" + +#data +<!doctype html></html> <head> +#errors +Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " " + +#data +<!doctype html></body><meta> +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <meta> + +#data +<html></html><!-- foo --> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element. +#document +| <html> +| <head> +| <body> +| <!-- foo --> + +#data +<!doctype html></body><title>X</title> +#errors +Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <title> +| "X" + +#data +<!doctype html><table> X<meta></table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " X" +| <meta> +| <table> + +#data +<!doctype html><table> x</table> +#errors +Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> + +#data +<!doctype html><table> x </table> +#errors +Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x " +| <table> + +#data +<!doctype html><table><tr> x</table> +#errors +Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " x" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table>X<style> <tr>x </style> </table> +#errors +Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <table> +| <style> +| " <tr>x " +| " " + +#data +<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div> +#errors +Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode. +Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <a> +| "foo" +| <table> +| " " +| <tbody> +| <tr> +| <td> +| "bar" +| " " + +#data +<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes> +#errors +6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +13: Stray start tag “frame”. +21: Stray end tag “frame”. +29: Stray end tag “frame”. +39: “frameset” start tag after “body” already open. +105: End of file seen inside an [R]CDATA element. +105: End of file seen and there were open elements. +XXX: These errors are wrong, please fix me! +#document +| <html> +| <head> +| <frameset> +| <frame> +| <frameset> +| <frame> +| <noframes> +| "</frameset><noframes>" + +#data +<!DOCTYPE html><object></html> +#errors +1: Expected closing tag. Unexpected end of file +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> diff --git a/libgo/go/exp/html/testdata/webkit/tests16.dat b/libgo/go/exp/html/testdata/webkit/tests16.dat new file mode 100644 index 00000000000..937dba9f42f --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests16.dat @@ -0,0 +1,2277 @@ +#data +<!doctype html><script> +#errors +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script>a +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<!doctype html><script>< +#errors +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<!doctype html><script></ +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<!doctype html><script></S +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<!doctype html><script></SC +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<!doctype html><script></SCR +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<!doctype html><script></SCRI +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<!doctype html><script></SCRIP +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<!doctype html><script></SCRIPT +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script></s +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<!doctype html><script></sc +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<!doctype html><script></scr +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<!doctype html><script></scri +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<!doctype html><script></scrip +#errors +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<!doctype html><script></script +#errors +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| <body> + +#data +<!doctype html><script><! +#errors +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<!doctype html><script><!a +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<!doctype html><script><!- +#errors +Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<!doctype html><script><!-a +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<!doctype html><script><!-- +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--a +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<!doctype html><script><!--< +#errors +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<!doctype html><script><!--<a +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<!doctype html><script><!--</ +#errors +Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<!doctype html><script><!--</script +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<!doctype html><script><!--<s +#errors +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<!doctype html><script><!--<script +#errors +Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<!doctype html><script><!--<script < +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<!doctype html><script><!--<script <a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<!doctype html><script><!--<script </ +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<!doctype html><script><!--<script </s +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 43 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<!doctype html><script><!--<script </scripta +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<!doctype html><script><!--<script </script +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script> +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<!doctype html><script><!--<script </script/ +#errors +Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<!doctype html><script><!--<script </script < +#errors +Line: 1 Col: 45 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<!doctype html><script><!--<script </script <a +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<!doctype html><script><!--<script </script </ +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<!doctype html><script><!--<script </script </script +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script/ +#errors +Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script </script </script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<!doctype html><script><!--<script - +#errors +Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<!doctype html><script><!--<script -a +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<!doctype html><script><!--<script -< +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -<" +| <body> + +#data +<!doctype html><script><!--<script -- +#errors +Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<!doctype html><script><!--<script --a +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<!doctype html><script><!--<script --< +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --<" +| <body> + +#data +<!doctype html><script><!--<script --> +#errors +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script -->< +#errors +Line: 1 Col: 39 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<!doctype html><script><!--<script --></ +#errors +Line: 1 Col: 40 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<!doctype html><script><!--<script --></script +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script/ +#errors +Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script --></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<!doctype html><script><!--<script><\/script>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<!doctype html><script><!--<script></scr'+'ipt>--></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>--><!--</script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-- ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- -></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>- - ></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<!doctype html><script><!--<script></script><script></script>-></script> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<!doctype html><script><!--<script>--!></script>X +#errors +Line: 1 Col: 49 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<!doctype html><script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 59 Unexpected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<!doctype html><script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 57 Unexpected end of file. Expected end tag (script). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<!doctype html><style><!--<style></style>--></style> +#errors +Line: 1 Col: 52 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<!doctype html><style><!--</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<!doctype html><style><!--...</style>...--></style> +#errors +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<!doctype html><style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 66 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<!doctype html><style><!--...</style><!-- --><style>@import ...</style> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<!doctype html><style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 63 Unexpected end tag (style). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<!doctype html><style>...<!--[if IE]><style>...</style>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<!doctype html><title><!--<title></title>--></title> +#errors +Line: 1 Col: 52 Unexpected end tag (title). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "<!--<title>" +| <body> +| "-->" + +#data +<!doctype html><title></title></title> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "</title>" +| <body> + +#data +<!doctype html><title>foo/title><link></head><body>X +#errors +Line: 1 Col: 52 Unexpected end of file. Expected end tag (title). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<!doctype html><noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 64 Unexpected end tag (noscript). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<!doctype html><noscript><!--</noscript>X<noscript>--></noscript> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<!doctype html><noscript><iframe></noscript>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<!doctype html><noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 64 Unexpected end tag (noframes). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<!doctype html><noframes><body><script><!--...</script></body></noframes></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<!doctype html><textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 64 Unexpected end tag (textarea). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<!doctype html><textarea></textarea></textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<!doctype html><iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 56 Unexpected end tag (iframe). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<!doctype html><iframe>...<!--X->...<!--/X->...</iframe> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<!doctype html><xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 44 Unexpected end tag (xmp). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<!doctype html><noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 60 Unexpected end tag (noembed). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script>a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "a" +| <body> + +#data +<script>< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<" +| <body> + +#data +<script></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</" +| <body> + +#data +<script></S +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</S" +| <body> + +#data +<script></SC +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SC" +| <body> + +#data +<script></SCR +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCR" +| <body> + +#data +<script></SCRI +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRI" +| <body> + +#data +<script></SCRIP +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIP" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</SCRIPT" +| <body> + +#data +<script></SCRIPT +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script></s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</s" +| <body> + +#data +<script></sc +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</sc" +| <body> + +#data +<script></scr +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scr" +| <body> + +#data +<script></scri +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scri" +| <body> + +#data +<script></scrip +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</scrip" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</script" +| <body> + +#data +<script></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| <body> + +#data +<script><! +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!" +| <body> + +#data +<script><!a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!a" +| <body> + +#data +<script><!- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-" +| <body> + +#data +<script><!-a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!-a" +| <body> + +#data +<script><!-- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--a" +| <body> + +#data +<script><!--< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<" +| <body> + +#data +<script><!--<a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<a" +| <body> + +#data +<script><!--</ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--</script" +| <body> + +#data +<script><!--</script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--" +| <body> + +#data +<script><!--<s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<s" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script" +| <body> + +#data +<script><!--<script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script " +| <body> + +#data +<script><!--<script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <" +| <body> + +#data +<script><!--<script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script <a" +| <body> + +#data +<script><!--<script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </" +| <body> + +#data +<script><!--<script </s +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </s" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script" +| <body> + +#data +<script><!--<script </scripta +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </scripta" +| <body> + +#data +<script><!--<script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script>" +| <body> + +#data +<script><!--<script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script/" +| <body> + +#data +<script><!--<script </script < +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <" +| <body> + +#data +<script><!--<script </script <a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script <a" +| <body> + +#data +<script><!--<script </script </ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script </script" +| <body> + +#data +<script><!--<script </script </script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script </script </script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script </script " +| <body> + +#data +<script><!--<script - +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -" +| <body> + +#data +<script><!--<script -a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -a" +| <body> + +#data +<script><!--<script -- +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --" +| <body> + +#data +<script><!--<script --a +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --a" +| <body> + +#data +<script><!--<script --> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script -->< +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --><" +| <body> + +#data +<script><!--<script --></ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script --></script" +| <body> + +#data +<script><!--<script --></script +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script/ +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script --></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script -->" +| <body> + +#data +<script><!--<script><\/script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script><\/script>-->" +| <body> + +#data +<script><!--<script></scr'+'ipt>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt>-->" +| <body> + +#data +<script><!--<script></script><script></script></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>" +| <body> + +#data +<script><!--<script></script><script></script>--><!--</script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>--><!--" +| <body> + +#data +<script><!--<script></script><script></script>-- ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>-- >" +| <body> + +#data +<script><!--<script></script><script></script>- -></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- ->" +| <body> + +#data +<script><!--<script></script><script></script>- - ></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>- - >" +| <body> + +#data +<script><!--<script></script><script></script>-></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| "<!--<script></script><script></script>->" +| <body> + +#data +<script><!--<script>--!></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script>--!></script>X" +| <body> + +#data +<script><!--<scr'+'ipt></script>--></script> +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 44 Unexpected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<scr'+'ipt>" +| <body> +| "-->" + +#data +<script><!--<script></scr'+'ipt></script>X +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 42 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "<!--<script></scr'+'ipt></script>X" +| <body> + +#data +<style><!--<style></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--<style>" +| <body> +| "-->" + +#data +<style><!--</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--" +| <body> +| "X" + +#data +<style><!--...</style>...--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 36 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--..." +| <body> +| "...-->" + +#data +<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" +| <body> +| "X" + +#data +<style><!--...<style><!--...--!></style>--></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 51 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "<!--...<style><!--...--!>" +| <body> +| "-->" + +#data +<style><!--...</style><!-- --><style>@import ...</style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "<!--..." +| <!-- --> +| <style> +| "@import ..." +| <body> + +#data +<style>...<style><!--...</style><!-- --></style> +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 48 Unexpected end tag (style). +#document +| <html> +| <head> +| <style> +| "...<style><!--..." +| <!-- --> +| <body> + +#data +<style>...<!--[if IE]><style>...</style>X +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| "...<!--[if IE]><style>..." +| <body> +| "X" + +#data +<title><!--<title></title>--></title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end tag (title). +#document +| <html> +| <head> +| <title> +| "<!--<title>" +| <body> +| "-->" + +#data +<title></title></title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| <html> +| <head> +| <title> +| "</title>" +| <body> + +#data +<title>foo/title><link></head><body>X +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 37 Unexpected end of file. Expected end tag (title). +#document +| <html> +| <head> +| <title> +| "foo/title><link></head><body>X" +| <body> + +#data +<noscript><!--<noscript></noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noscript). +#document +| <html> +| <head> +| <noscript> +| "<!--<noscript>" +| <body> +| "-->" + +#data +<noscript><!--</noscript>X<noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "X" +| <noscript> +| "-->" + +#data +<noscript><iframe></noscript>X +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<iframe>" +| <body> +| "X" + +#data +<noframes><!--<noframes></noframes>--></noframes> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (noframes). +#document +| <html> +| <head> +| <noframes> +| "<!--<noframes>" +| <body> +| "-->" + +#data +<noframes><body><script><!--...</script></body></noframes></html> +#errors +Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. +#document +| <html> +| <head> +| <noframes> +| "<body><script><!--...</script></body>" +| <body> + +#data +<textarea><!--<textarea></textarea>--></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 49 Unexpected end tag (textarea). +#document +| <html> +| <head> +| <body> +| <textarea> +| "<!--<textarea>" +| "-->" + +#data +<textarea></textarea></textarea> +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <textarea> +| "</textarea>" + +#data +<iframe><!--<iframe></iframe>--></iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +Line: 1 Col: 41 Unexpected end tag (iframe). +#document +| <html> +| <head> +| <body> +| <iframe> +| "<!--<iframe>" +| "-->" + +#data +<iframe>...<!--X->...<!--/X->...</iframe> +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <iframe> +| "...<!--X->...<!--/X->..." + +#data +<xmp><!--<xmp></xmp>--></xmp> +#errors +Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE. +Line: 1 Col: 29 Unexpected end tag (xmp). +#document +| <html> +| <head> +| <body> +| <xmp> +| "<!--<xmp>" +| "-->" + +#data +<noembed><!--<noembed></noembed>--></noembed> +#errors +Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE. +Line: 1 Col: 45 Unexpected end tag (noembed). +#document +| <html> +| <head> +| <body> +| <noembed> +| "<!--<noembed>" +| "-->" + +#data +<!doctype html><table> + +#errors +Line 2 Col 0 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " +" + +#data +<!doctype html><table><td><span><font></span><span> +#errors +Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase. +Line 1 Col 45 Unexpected end tag (span). +Line 1 Col 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <span> +| <font> +| <font> +| <span> + +#data +<!doctype html><form><table></form><form></table></form> +#errors +35: Stray end tag “form”. +41: Start tag “form” seen in “table”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <table> +| <form> diff --git a/libgo/go/exp/html/testdata/webkit/tests17.dat b/libgo/go/exp/html/testdata/webkit/tests17.dat new file mode 100644 index 00000000000..7b555f888de --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests17.dat @@ -0,0 +1,153 @@ +#data +<!doctype html><table><tbody><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tr><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<!doctype html><table><tr><td><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <select> +| <td> + +#data +<!doctype html><table><tr><th><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <th> +| <select> +| <td> + +#data +<!doctype html><table><caption><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <select> +| <tbody> +| <tr> + +#data +<!doctype html><select><tr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><th> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tbody> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><thead> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><select><caption> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><table><tr></table>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| "a" diff --git a/libgo/go/exp/html/testdata/webkit/tests18.dat b/libgo/go/exp/html/testdata/webkit/tests18.dat new file mode 100644 index 00000000000..680e1f068a6 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests18.dat @@ -0,0 +1,269 @@ +#data +<!doctype html><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> + +#data +<!doctype html><table><tbody><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><tbody><tr><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><caption><plaintext></plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <plaintext> +| "</plaintext>" + +#data +<!doctype html><table><tr><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <style> +| "</script>" + +#data +<!doctype html><table><tr><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <tbody> +| <tr> +| <script> +| "</style>" + +#data +<!doctype html><table><caption><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><table><td><style></script></style>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <style> +| "</script>" +| "abc" + +#data +<!doctype html><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" + +#data +<!doctype html><table><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> + +#data +<!doctype html><table><tr><select><script></style></script>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <script> +| "</style>" +| "abc" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><frameset></frameset><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><frameset></frameset></html><noframes>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" + +#data +<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <noframes> +| "abc" +| <!-- abc --> + +#data +<!doctype html><table><tr></tbody><tfoot> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <tfoot> + +#data +<!doctype html><table><td><svg></svg>abc<td> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <svg svg> +| "abc" +| <td> diff --git a/libgo/go/exp/html/testdata/webkit/tests19.dat b/libgo/go/exp/html/testdata/webkit/tests19.dat new file mode 100644 index 00000000000..06222f5b9db --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests19.dat @@ -0,0 +1,1220 @@ +#data +<!doctype html><math><mn DefinitionUrl="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mn> +| definitionURL="foo" + +#data +<!doctype html><html></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <!-- foo --> +| <head> +| <body> + +#data +<!doctype html><head></head></p><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- foo --> +| <body> + +#data +<!doctype html><body><p><pre> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <pre> + +#data +<!doctype html><body><p><listing> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <listing> + +#data +<!doctype html><p><plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <plaintext> + +#data +<!doctype html><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <h1> + +#data +<!doctype html><form><isindex> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> + +#data +<!doctype html><isindex action="POST"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| action="POST" +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex prompt="this is isindex"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "this is isindex" +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><isindex type="hidden"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| type="hidden" +| <hr> + +#data +<!doctype html><isindex name="foo"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| <hr> + +#data +<!doctype html><ruby><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rp> + +#data +<!doctype html><ruby><div><span><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rp> + +#data +<!doctype html><ruby><div><p><rp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rp> + +#data +<!doctype html><ruby><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <p> +| <rt> + +#data +<!doctype html><ruby><div><span><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <span> +| <rt> + +#data +<!doctype html><ruby><div><p><rt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <p> +| <rt> + +#data +<!doctype html><math/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <foo> + +#data +<!doctype html><svg/><foo> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <foo> + +#data +<!doctype html><div></body><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <!-- foo --> + +#data +<!doctype html><h1><div><h3><span></h1>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h1> +| <div> +| <h3> +| <span> +| "foo" + +#data +<!doctype html><p></h3>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "foo" + +#data +<!doctype html><h3><li>abc</h2>foo +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <h3> +| <li> +| "abc" +| "foo" + +#data +<!doctype html><table>abc<!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "abc" +| <table> +| <!-- foo --> + +#data +<!doctype html><table> <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " " +| <!-- foo --> + +#data +<!doctype html><table> b <!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " b " +| <table> +| <!-- foo --> + +#data +<!doctype html><select><option><option> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><select><option></optgroup> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!doctype html><p><math><mi><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mi> +| <p> +| <h1> + +#data +<!doctype html><p><math><mo><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mo> +| <p> +| <h1> + +#data +<!doctype html><p><math><mn><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <p> +| <h1> + +#data +<!doctype html><p><math><ms><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math ms> +| <p> +| <h1> + +#data +<!doctype html><p><math><mtext><p><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mtext> +| <p> +| <h1> + +#data +<!doctype html><frameset></noframes> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html c=d><body></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><html c=d><frameset></frameset></html><html a=b> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><!--foo--> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <!-- foo --> + +#data +<!doctype html><html><frameset></frameset></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| " " + +#data +<!doctype html><html><frameset></frameset></html>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><html><frameset></frameset></html></p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<html><frameset></frameset></html><!doctype html> +#errors +#document +| <html> +| <head> +| <frameset> + +#data +<!doctype html><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!doctype html><p><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><p>a<frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "a" + +#data +<!doctype html><p> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><pre><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> + +#data +<!doctype html><listing><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <listing> + +#data +<!doctype html><li><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <li> + +#data +<!doctype html><dd><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dd> + +#data +<!doctype html><dt><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> + +#data +<!doctype html><button><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <button> + +#data +<!doctype html><applet><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <applet> + +#data +<!doctype html><marquee><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <marquee> + +#data +<!doctype html><object><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <object> + +#data +<!doctype html><table><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> + +#data +<!doctype html><area><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <area> + +#data +<!doctype html><basefont><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <basefont> +| <frameset> + +#data +<!doctype html><bgsound><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <bgsound> +| <frameset> + +#data +<!doctype html><br><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <br> + +#data +<!doctype html><embed><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <embed> + +#data +<!doctype html><img><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html><input><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <input> + +#data +<!doctype html><keygen><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <keygen> + +#data +<!doctype html><wbr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <wbr> + +#data +<!doctype html><hr><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <hr> + +#data +<!doctype html><textarea></textarea><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> + +#data +<!doctype html><xmp></xmp><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <xmp> + +#data +<!doctype html><iframe></iframe><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <iframe> + +#data +<!doctype html><select></select><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!doctype html><svg></svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><math></math><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg><foreignObject><div> <frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<!doctype html><svg>a</svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| "a" + +#data +<!doctype html><svg> </svg><frameset><frame> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> +| <frame> + +#data +<html>aaa<frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "aaa" + +#data +<html> a <frameset></frameset> +#errors +#document +| <html> +| <head> +| <body> +| "a " + +#data +<!doctype html><div><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><div><body><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> + +#data +<!doctype html><p><math></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| "a" + +#data +<!doctype html><p><math><mn><span></p>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <math math> +| <math mn> +| <span> +| <p> +| "a" + +#data +<!doctype html><math></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> + +#data +<!doctype html><meta charset="ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| charset="ascii" +| <body> + +#data +<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| content="text/html;charset=ascii" +| http-equiv="content-type" +| <body> + +#data +<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8"> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --> +| <meta> +| charset="utf8" +| <body> + +#data +<!doctype html><html a=b><head></head><html c=d> +#errors +#document +| <!DOCTYPE html> +| <html> +| a="b" +| c="d" +| <head> +| <body> + +#data +<!doctype html><image/> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> + +#data +<!doctype html>a<i>b<table>c<b>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "a" +| <i> +| "bc" +| <b> +| "de" +| "f" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" + +#data +<!doctype html><table><i>a<b>b<div>c</i> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <i> +| "c" +| <table> + +#data +<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <b> +| "b" +| <b> +| <div> +| <b> +| <i> +| "c" +| <a> +| "d" +| <a> +| "e" +| <a> +| "f" +| <table> + +#data +<!doctype html><table><i>a<div>b<tr>c<b>d</i>e +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <i> +| "a" +| <div> +| "b" +| <i> +| "c" +| <b> +| "d" +| <b> +| "e" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><table><td><table><i>a<div>b<b>c</i>d +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <i> +| "a" +| <div> +| <i> +| "b" +| <b> +| "c" +| <b> +| "d" +| <table> + +#data +<!doctype html><body><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <bgsound> + +#data +<!doctype html><body><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <basefont> + +#data +<!doctype html><a><b></a><basefont> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <basefont> + +#data +<!doctype html><a><b></a><bgsound> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| <b> +| <bgsound> + +#data +<!doctype html><figcaption><article></figcaption>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <figcaption> +| <article> +| "a" + +#data +<!doctype html><summary><article></summary>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <summary> +| <article> +| "a" + +#data +<!doctype html><p><a><plaintext>b +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <a> +| <plaintext> +| <a> +| "b" diff --git a/libgo/go/exp/html/testdata/webkit/tests2.dat b/libgo/go/exp/html/testdata/webkit/tests2.dat new file mode 100644 index 00000000000..60d85922162 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests2.dat @@ -0,0 +1,763 @@ +#data +<!DOCTYPE html>Test +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "Test" + +#data +<textarea>test</div>test +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 24 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <textarea> +| "test</div>test" + +#data +<table><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 11 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><td>test</tbody></table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "test" + +#data +<frame>test +#errors +Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE. +Line: 1 Col: 7 Unexpected start tag frame. Ignored. +#document +| <html> +| <head> +| <body> +| "test" + +#data +<!DOCTYPE html><frameset>test +#errors +Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored. +Line: 1 Col: 29 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><frameset><!DOCTYPE html> +#errors +Line: 1 Col: 40 Unexpected DOCTYPE. Ignored. +Line: 1 Col: 40 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><font><p><b>test</font> +#errors +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <p> +| <font> +| <b> +| "test" + +#data +<!DOCTYPE html><dt><div><dd> +#errors +Line: 1 Col: 28 Missing end tag (div, dt). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <dt> +| <div> +| <dd> + +#data +<script></x +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). +#document +| <html> +| <head> +| <script> +| "</x" +| <body> + +#data +<table><plaintext><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode. +Line: 1 Col: 22 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "<td>" +| <table> + +#data +<plaintext></plaintext> +#errors +Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <plaintext> +| "</plaintext>" + +#data +<!DOCTYPE html><table><tr>TEST +#errors +Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 30 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "TEST" +| <table> +| <tbody> +| <tr> + +#data +<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4> +#errors +Line: 1 Col: 37 Unexpected start tag (body). +Line: 1 Col: 53 Unexpected start tag (body). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| t1="1" +| t2="2" +| t3="3" +| t4="4" + +#data +</b test +#errors +Line: 1 Col: 8 Unexpected end of file in attribute name. +Line: 1 Col: 8 End tag contains unexpected attributes. +Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE. +Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html></b test<b &=&>X +#errors +Line: 1 Col: 32 Named entity didn't end with ';'. +Line: 1 Col: 33 End tag contains unexpected attributes. +Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" + +#data +<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 54 Unexpected end of file in the tag name. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| type="text/x-foobar;baz" +| "X</SCRipt" +| <body> + +#data +& +#errors +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&# +#errors +Line: 1 Col: 1 Numeric entity expected. Got end of file instead. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#" + +#data +&#X +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#X" + +#data +&#x +#errors +Line: 1 Col: 3 Numeric entity expected but none found. +Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&#x" + +#data +- +#errors +Line: 1 Col: 4 Numeric entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "-" + +#data +&x-test +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&x-test" + +#data +<!doctypehtml><p><li> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <li> + +#data +<!doctypehtml><p><dt> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dt> + +#data +<!doctypehtml><p><dd> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <dd> + +#data +<!doctypehtml><p><form> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <form> + +#data +<!DOCTYPE html><p></P>X +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| "X" + +#data +& +#errors +Line: 1 Col: 4 Named entity didn't end with ';'. +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&" + +#data +&AMp; +#errors +Line: 1 Col: 1 Named entity expected. Got none. +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "&AMp;" + +#data +<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY> +#errors +Line: 1 Col: 110 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly> + +#data +<!DOCTYPE html>X</body>X +#errors +Line: 1 Col: 24 Unexpected non-space characters in the after body phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "XX" + +#data +<!DOCTYPE html><!-- X +#errors +Line: 1 Col: 21 Unexpected end of file in comment. +#document +| <!DOCTYPE html> +| <!-- X --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><table><caption>test TEST</caption><td>test +#errors +Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 58 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| "test TEST" +| <tbody> +| <tr> +| <td> +| "test" + +#data +<!DOCTYPE html><select><option><optgroup> +#errors +Line: 1 Col: 41 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option> +#errors +Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag. +Line: 1 Col: 76 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <option> +| <option> + +#data +<!DOCTYPE html><select><optgroup><option><optgroup> +#errors +Line: 1 Col: 51 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> +| <option> +| <optgroup> + +#data +<!DOCTYPE html><datalist><option>foo</datalist>bar +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <datalist> +| <option> +| "foo" +| "bar" + +#data +<!DOCTYPE html><font><input><input></font> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <font> +| <input> +| <input> + +#data +<!DOCTYPE html><!-- XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX +#errors +Line: 1 Col: 29 Unexpected end of file in comment (-) +#document +| <!DOCTYPE html> +| <!-- XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><!-- XXX - XXX - XXX --> +#errors +#document +| <!DOCTYPE html> +| <!-- XXX - XXX - XXX --> +| <html> +| <head> +| <body> + +#data +<isindex test=x name=x> +#errors +Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected start tag isindex. Don't use it! +#document +| <html> +| <head> +| <body> +| <form> +| <hr> +| <label> +| "This is a searchable index. Enter search keywords: " +| <input> +| name="isindex" +| test="x" +| <hr> + +#data +test +test +#errors +Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "test +test" + +#data +<!DOCTYPE html><body><title>test</body></title> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <title> +| "test</body>" + +#data +<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style> +x { content:"</style" } </style> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <title> +| "X" +| <meta> +| name="z" +| <link> +| rel="foo" +| <style> +| " +x { content:"</style" } " + +#data +<!DOCTYPE html><select><optgroup></optgroup></select> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <optgroup> + +#data + + +#errors +Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html> <html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><script> +</script> <title>x</title> </head> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <script> +| " +" +| " " +| <title> +| "x" +| " " +| <body> + +#data +<!DOCTYPE html><html><body><html id=x> +#errors +Line: 1 Col: 38 html needs to be the first start tag. +#document +| <!DOCTYPE html> +| <html> +| id="x" +| <head> +| <body> + +#data +<!DOCTYPE html>X</body><html id="x"> +#errors +Line: 1 Col: 36 Unexpected start tag token (html) in the after body phase. +Line: 1 Col: 36 html needs to be the first start tag. +#document +| <!DOCTYPE html> +| <html> +| id="x" +| <head> +| <body> +| "X" + +#data +<!DOCTYPE html><head><html id=x> +#errors +Line: 1 Col: 32 html needs to be the first start tag. +#document +| <!DOCTYPE html> +| <html> +| id="x" +| <head> +| <body> + +#data +<!DOCTYPE html>X</html>X +#errors +Line: 1 Col: 24 Unexpected non-space characters in the after body phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "XX" + +#data +<!DOCTYPE html>X</html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X " + +#data +<!DOCTYPE html>X</html><p>X +#errors +Line: 1 Col: 26 Unexpected start tag (p). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <p> +| "X" + +#data +<!DOCTYPE html>X<p/x/y/z> +#errors +Line: 1 Col: 19 Expected a > after the /. +Line: 1 Col: 21 Solidus (/) incorrectly placed in tag. +Line: 1 Col: 23 Solidus (/) incorrectly placed in tag. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <p> +| x="" +| y="" +| z="" + +#data +<!DOCTYPE html><!--x-- +#errors +Line: 1 Col: 22 Unexpected end of file in comment (--). +#document +| <!DOCTYPE html> +| <!-- x --> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE html><table><tr><td></p></table> +#errors +Line: 1 Col: 34 Unexpected end tag (p). Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <p> + +#data +<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->--> +#errors +Line: 1 Col: 20 Expected space or '>'. Got '' +Line: 1 Col: 25 Erroneous DOCTYPE. +Line: 1 Col: 35 Unexpected character in comment found. +#document +| <!DOCTYPE <!doctype> +| <html> +| <head> +| <body> +| ">" +| <!-- <!--x --> +| "-->" + +#data +<!doctype html><div><form></form><div></div></div> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <div> +| <form> +| <div> diff --git a/libgo/go/exp/html/testdata/webkit/tests20.dat b/libgo/go/exp/html/testdata/webkit/tests20.dat new file mode 100644 index 00000000000..6bd825608f1 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests20.dat @@ -0,0 +1,455 @@ +#data +<!doctype html><p><button><button> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <button> + +#data +<!doctype html><p><button><address> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <address> + +#data +<!doctype html><p><button><blockquote> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <blockquote> + +#data +<!doctype html><p><button><menu> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <menu> + +#data +<!doctype html><p><button><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <p> + +#data +<!doctype html><p><button><ul> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <ul> + +#data +<!doctype html><p><button><h1> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <h1> + +#data +<!doctype html><p><button><h6> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <h6> + +#data +<!doctype html><p><button><listing> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <listing> + +#data +<!doctype html><p><button><pre> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <pre> + +#data +<!doctype html><p><button><form> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <form> + +#data +<!doctype html><p><button><li> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <li> + +#data +<!doctype html><p><button><dd> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <dd> + +#data +<!doctype html><p><button><dt> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <dt> + +#data +<!doctype html><p><button><plaintext> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <plaintext> + +#data +<!doctype html><p><button><table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <table> + +#data +<!doctype html><p><button><hr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <hr> + +#data +<!doctype html><p><button><xmp> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <xmp> + +#data +<!doctype html><p><button></p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <button> +| <p> + +#data +<!doctype html><address><button></address>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <address> +| <button> +| "a" + +#data +<!doctype html><address><button></address>a +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <address> +| <button> +| "a" + +#data +<p><table></p> +#errors +#document +| <html> +| <head> +| <body> +| <p> +| <p> +| <table> + +#data +<!doctype html><svg> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> + +#data +<!doctype html><p><figcaption> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <figcaption> + +#data +<!doctype html><p><summary> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <summary> + +#data +<!doctype html><form><table><form> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <table> + +#data +<!doctype html><table><form><form> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <form> + +#data +<!doctype html><table><form></table><form> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <form> + +#data +<!doctype html><svg><foreignObject><p> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg foreignObject> +| <p> + +#data +<!doctype html><svg><title>abc +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <svg svg> +| <svg title> +| "abc" + +#data +<option><span><option> +#errors +#document +| <html> +| <head> +| <body> +| <option> +| <span> +| <option> + +#data +<option><option> +#errors +#document +| <html> +| <head> +| <body> +| <option> +| <option> + +#data +<math><annotation-xml><div> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| <div> + +#data +<math><annotation-xml encoding="application/svg+xml"><div> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| encoding="application/svg+xml" +| <div> + +#data +<math><annotation-xml encoding="application/xhtml+xml"><div> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| encoding="application/xhtml+xml" +| <div> + +#data +<math><annotation-xml encoding="aPPlication/xhtmL+xMl"><div> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| encoding="aPPlication/xhtmL+xMl" +| <div> + +#data +<math><annotation-xml encoding="text/html"><div> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| encoding="text/html" +| <div> + +#data +<math><annotation-xml encoding="Text/htmL"><div> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| encoding="Text/htmL" +| <div> + +#data +<math><annotation-xml encoding=" text/html "><div> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| encoding=" text/html " +| <div> diff --git a/libgo/go/exp/html/testdata/webkit/tests21.dat b/libgo/go/exp/html/testdata/webkit/tests21.dat new file mode 100644 index 00000000000..1260ec03e20 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests21.dat @@ -0,0 +1,221 @@ +#data +<svg><![CDATA[foo]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "foo" + +#data +<math><![CDATA[foo]]> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| "foo" + +#data +<div><![CDATA[foo]]> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <!-- [CDATA[foo]] --> + +#data +<svg><![CDATA[foo +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "foo" + +#data +<svg><![CDATA[foo +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "foo" + +#data +<svg><![CDATA[ +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> + +#data +<svg><![CDATA[]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> + +#data +<svg><![CDATA[]] >]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "]] >" + +#data +<svg><![CDATA[]] >]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "]] >" + +#data +<svg><![CDATA[]] +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "]]" + +#data +<svg><![CDATA[] +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "]" + +#data +<svg><![CDATA[]>a +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "]>a" + +#data +<svg><foreignObject><div><![CDATA[foo]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <svg foreignObject> +| <div> +| <!-- [CDATA[foo]] --> + +#data +<svg><![CDATA[<svg>]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "<svg>" + +#data +<svg><![CDATA[</svg>a]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "</svg>a" + +#data +<svg><![CDATA[<svg>a +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "<svg>a" + +#data +<svg><![CDATA[</svg>a +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "</svg>a" + +#data +<svg><![CDATA[<svg>]]><path> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "<svg>" +| <svg path> + +#data +<svg><![CDATA[<svg>]]></path> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "<svg>" + +#data +<svg><![CDATA[<svg>]]><!--path--> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "<svg>" +| <!-- path --> + +#data +<svg><![CDATA[<svg>]]>path +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "<svg>path" + +#data +<svg><![CDATA[<!--svg-->]]> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| "<!--svg-->" diff --git a/libgo/go/exp/html/testdata/webkit/tests22.dat b/libgo/go/exp/html/testdata/webkit/tests22.dat new file mode 100644 index 00000000000..aab27b2e904 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests22.dat @@ -0,0 +1,157 @@ +#data +<a><b><big><em><strong><div>X</a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <b> +| <big> +| <em> +| <strong> +| <big> +| <em> +| <strong> +| <div> +| <a> +| "X" + +#data +<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8>A</a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <b> +| <b> +| <div> +| id="1" +| <a> +| <div> +| id="2" +| <a> +| <div> +| id="3" +| <a> +| <div> +| id="4" +| <a> +| <div> +| id="5" +| <a> +| <div> +| id="6" +| <a> +| <div> +| id="7" +| <a> +| <div> +| id="8" +| <a> +| "A" + +#data +<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9>A</a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <b> +| <b> +| <div> +| id="1" +| <a> +| <div> +| id="2" +| <a> +| <div> +| id="3" +| <a> +| <div> +| id="4" +| <a> +| <div> +| id="5" +| <a> +| <div> +| id="6" +| <a> +| <div> +| id="7" +| <a> +| <div> +| id="8" +| <a> +| <div> +| id="9" +| "A" + +#data +<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9><div id=10>A</a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <b> +| <b> +| <div> +| id="1" +| <a> +| <div> +| id="2" +| <a> +| <div> +| id="3" +| <a> +| <div> +| id="4" +| <a> +| <div> +| id="5" +| <a> +| <div> +| id="6" +| <a> +| <div> +| id="7" +| <a> +| <div> +| id="8" +| <a> +| <div> +| id="9" +| <div> +| id="10" +| "A" + +#data +<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST +#errors +Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE. +Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 50 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <cite> +| <b> +| <cite> +| <i> +| <cite> +| <i> +| <cite> +| <i> +| <i> +| <i> +| <div> +| <b> +| "X" +| "TEST" diff --git a/libgo/go/exp/html/testdata/webkit/tests23.dat b/libgo/go/exp/html/testdata/webkit/tests23.dat new file mode 100644 index 00000000000..34d2a73f1c7 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests23.dat @@ -0,0 +1,155 @@ +#data +<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X +#errors +3: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +116: Unclosed elements. +117: End of file seen and there were open elements. +#document +| <html> +| <head> +| <body> +| <p> +| <font> +| size="4" +| <font> +| color="red" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| color="red" +| <p> +| <font> +| color="red" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| color="red" +| "X" + +#data +<p><font size=4><font size=4><font size=4><font size=4><p>X +#errors +#document +| <html> +| <head> +| <body> +| <p> +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <p> +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| "X" + +#data +<p><font size=4><font size=4><font size=4><font size="5"><font size=4><p>X +#errors +#document +| <html> +| <head> +| <body> +| <p> +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="5" +| <font> +| size="4" +| <p> +| <font> +| size="4" +| <font> +| size="4" +| <font> +| size="5" +| <font> +| size="4" +| "X" + +#data +<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X +#errors +#document +| <html> +| <head> +| <body> +| <p> +| <font> +| id="a" +| size="4" +| <font> +| id="b" +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| <p> +| <font> +| id="a" +| size="4" +| <font> +| id="b" +| size="4" +| <font> +| size="4" +| <font> +| size="4" +| "X" + +#data +<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y +#errors +#document +| <html> +| <head> +| <body> +| <p> +| <b> +| id="a" +| <b> +| id="a" +| <b> +| id="a" +| <b> +| <object> +| <b> +| id="a" +| <b> +| id="a" +| "X" +| <p> +| <b> +| id="a" +| <b> +| id="a" +| <b> +| id="a" +| <b> +| "Y" diff --git a/libgo/go/exp/html/testdata/webkit/tests24.dat b/libgo/go/exp/html/testdata/webkit/tests24.dat new file mode 100644 index 00000000000..f6dc7eb48a5 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests24.dat @@ -0,0 +1,79 @@ +#data +<!DOCTYPE html>≂̸ +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "≂̸" + +#data +<!DOCTYPE html>≂̸A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "≂̸A" + +#data +<!DOCTYPE html>   +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " " + +#data +<!DOCTYPE html>  A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| " A" + +#data +<!DOCTYPE html>⊂⃒ +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "⊂⃒" + +#data +<!DOCTYPE html>⊂⃒A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "⊂⃒A" + +#data +<!DOCTYPE html>𝔾 +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "𝔾" + +#data +<!DOCTYPE html>𝔾A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "𝔾A" diff --git a/libgo/go/exp/html/testdata/webkit/tests25.dat b/libgo/go/exp/html/testdata/webkit/tests25.dat new file mode 100644 index 00000000000..00de7295b71 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests25.dat @@ -0,0 +1,219 @@ +#data +<!DOCTYPE html><body><foo>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <foo> +| "A" + +#data +<!DOCTYPE html><body><area>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <area> +| "A" + +#data +<!DOCTYPE html><body><base>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <base> +| "A" + +#data +<!DOCTYPE html><body><basefont>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <basefont> +| "A" + +#data +<!DOCTYPE html><body><bgsound>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <bgsound> +| "A" + +#data +<!DOCTYPE html><body><br>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <br> +| "A" + +#data +<!DOCTYPE html><body><col>A +#errors +26: Stray start tag “col”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "A" + +#data +<!DOCTYPE html><body><command>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <command> +| "A" + +#data +<!DOCTYPE html><body><embed>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <embed> +| "A" + +#data +<!DOCTYPE html><body><frame>A +#errors +26: Stray start tag “frame”. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "A" + +#data +<!DOCTYPE html><body><hr>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <hr> +| "A" + +#data +<!DOCTYPE html><body><img>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <img> +| "A" + +#data +<!DOCTYPE html><body><input>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <input> +| "A" + +#data +<!DOCTYPE html><body><keygen>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <keygen> +| "A" + +#data +<!DOCTYPE html><body><link>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <link> +| "A" + +#data +<!DOCTYPE html><body><meta>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <meta> +| "A" + +#data +<!DOCTYPE html><body><param>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <param> +| "A" + +#data +<!DOCTYPE html><body><source>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <source> +| "A" + +#data +<!DOCTYPE html><body><track>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <track> +| "A" + +#data +<!DOCTYPE html><body><wbr>A +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <wbr> +| "A" diff --git a/libgo/go/exp/html/testdata/webkit/tests26.dat b/libgo/go/exp/html/testdata/webkit/tests26.dat new file mode 100644 index 00000000000..da128e7794b --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests26.dat @@ -0,0 +1,195 @@ +#data +<!DOCTYPE html><body><a href='#1'><nobr>1<nobr></a><br><a href='#2'><nobr>2<nobr></a><br><a href='#3'><nobr>3<nobr></a> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <a> +| href="#1" +| <nobr> +| "1" +| <nobr> +| <nobr> +| <br> +| <a> +| href="#2" +| <a> +| href="#2" +| <nobr> +| "2" +| <nobr> +| <nobr> +| <br> +| <a> +| href="#3" +| <a> +| href="#3" +| <nobr> +| "3" +| <nobr> + +#data +<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3 +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| <nobr> +| "1" +| <nobr> +| <nobr> +| <i> +| <i> +| <nobr> +| "2" +| <nobr> +| <nobr> +| "3" + +#data +<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3 +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| <nobr> +| "1" +| <nobr> +| <i> +| <i> +| <nobr> +| "2" +| <nobr> +| <nobr> +| "3" +| <table> + +#data +<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3 +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| <nobr> +| "1" +| <table> +| <tbody> +| <tr> +| <td> +| <nobr> +| <i> +| <i> +| <nobr> +| "2" +| <nobr> +| <nobr> +| "3" + +#data +<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3 +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| <nobr> +| "1" +| <div> +| <b> +| <nobr> +| <nobr> +| <nobr> +| <i> +| <i> +| <nobr> +| "2" +| <nobr> +| <nobr> +| "3" + +#data +<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3 +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| <nobr> +| "1" +| <nobr> +| <div> +| <nobr> +| <i> +| <i> +| <nobr> +| "2" +| <nobr> +| <nobr> +| "3" + +#data +<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| <nobr> +| "1" +| <nobr> +| <ins> +| <nobr> +| <i> +| <i> +| <nobr> + +#data +<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2 +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| <nobr> +| "1" +| <ins> +| <nobr> +| <nobr> +| <i> +| "2" + +#data +<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <b> +| "1" +| <nobr> +| <nobr> +| <i> +| <i> +| <nobr> +| "2" diff --git a/libgo/go/exp/html/testdata/webkit/tests3.dat b/libgo/go/exp/html/testdata/webkit/tests3.dat new file mode 100644 index 00000000000..38dc501be35 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests3.dat @@ -0,0 +1,305 @@ +#data +<head></head><style></style> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected start tag (style) that can be in head. Moved. +#document +| <html> +| <head> +| <style> +| <body> + +#data +<head></head><script></script> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved. +#document +| <html> +| <head> +| <script> +| <body> + +#data +<head></head><!-- --><style></style><!-- --><script></script> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved. +#document +| <html> +| <head> +| <style> +| <script> +| <!-- --> +| <!-- --> +| <body> + +#data +<head></head><!-- -->x<style></style><!-- --><script></script> +#errors +Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. +#document +| <html> +| <head> +| <!-- --> +| <body> +| "x" +| <style> +| <!-- --> +| <script> + +#data +<!DOCTYPE html><html><head></head><body><pre> +</pre></body></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> + +#data +<!DOCTYPE html><html><head></head><body><pre> +foo</pre></body></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> +| "foo" + +#data +<!DOCTYPE html><html><head></head><body><pre> + +foo</pre></body></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> +| " +foo" + +#data +<!DOCTYPE html><html><head></head><body><pre> +foo +</pre></body></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> +| "foo +" + +#data +<!DOCTYPE html><html><head></head><body><pre>x</pre><span> +</span></body></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> +| "x" +| <span> +| " +" + +#data +<!DOCTYPE html><html><head></head><body><pre>x +y</pre></body></html> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> +| "x +y" + +#data +<!DOCTYPE html><html><head></head><body><pre>x<div> +y</pre></body></html> +#errors +Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> +| "x" +| <div> +| " +y" + +#data +<!DOCTYPE html><pre>

A</pre> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <pre> +| " +A" + +#data +<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML> +#errors +Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <meta> +| <body> + +#data +<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML> +#errors +Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<textarea>foo<span>bar</span><i>baz +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +Line: 1 Col: 35 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <textarea> +| "foo<span>bar</span><i>baz" + +#data +<title>foo<span>bar</em><i>baz +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 30 Unexpected end of file. Expected end tag (title). +#document +| <html> +| <head> +| <title> +| "foo<span>bar</em><i>baz" +| <body> + +#data +<!DOCTYPE html><textarea> +</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> + +#data +<!DOCTYPE html><textarea> +foo</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| "foo" + +#data +<!DOCTYPE html><textarea> + +foo</textarea> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <textarea> +| " +foo" + +#data +<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html> +#errors +Line: 1 Col: 60 Missing end tag (div, li). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <ul> +| <li> +| <div> +| <p> +| <li> + +#data +<!doctype html><nobr><nobr><nobr> +#errors +Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr). +Line: 1 Col: 33 Unexpected start tag (nobr) implies end tag (nobr). +Line: 1 Col: 33 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <nobr> +| <nobr> +| <nobr> + +#data +<!doctype html><nobr><nobr></nobr><nobr> +#errors +Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr). +Line: 1 Col: 40 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <nobr> +| <nobr> +| <nobr> + +#data +<!doctype html><html><body><p><table></table></body></html> +#errors +Not known +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <table> + +#data +<p><table></table> +#errors +Not known +#document +| <html> +| <head> +| <body> +| <p> +| <table> diff --git a/libgo/go/exp/html/testdata/webkit/tests4.dat b/libgo/go/exp/html/testdata/webkit/tests4.dat new file mode 100644 index 00000000000..3c506326d1f --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests4.dat @@ -0,0 +1,59 @@ +#data +direct div content +#errors +#document-fragment +div +#document +| "direct div content" + +#data +direct textarea content +#errors +#document-fragment +textarea +#document +| "direct textarea content" + +#data +textarea content with <em>pseudo</em> <foo>markup +#errors +#document-fragment +textarea +#document +| "textarea content with <em>pseudo</em> <foo>markup" + +#data +this is CDATA inside a <style> element +#errors +#document-fragment +style +#document +| "this is CDATA inside a <style> element" + +#data +</plaintext> +#errors +#document-fragment +plaintext +#document +| "</plaintext>" + +#data +setting html's innerHTML +#errors +Line: 1 Col: 24 Unexpected EOF in inner html mode. +#document-fragment +html +#document +| <head> +| <body> +| "setting html's innerHTML" + +#data +<title>setting head's innerHTML</title> +#errors +#document-fragment +head +#document +| <title> +| "setting head's innerHTML" diff --git a/libgo/go/exp/html/testdata/webkit/tests5.dat b/libgo/go/exp/html/testdata/webkit/tests5.dat new file mode 100644 index 00000000000..d7b5128a44d --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests5.dat @@ -0,0 +1,191 @@ +#data +<style> <!-- </style>x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end of file. Expected end tag (style). +#document +| <html> +| <head> +| <style> +| " <!-- " +| <body> +| "x" + +#data +<style> <!-- </style> --> </style>x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| " <!-- " +| " " +| <body> +| "--> x" + +#data +<style> <!--> </style>x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| " <!--> " +| <body> +| "x" + +#data +<style> <!---> </style>x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| " <!---> " +| <body> +| "x" + +#data +<iframe> <!---> </iframe>x +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <iframe> +| " <!---> " +| "x" + +#data +<iframe> <!--- </iframe>->x</iframe> --> </iframe>x +#errors +Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <iframe> +| " <!--- " +| "->x --> x" + +#data +<script> <!-- </script> --> </script>x +#errors +Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. +#document +| <html> +| <head> +| <script> +| " <!-- " +| " " +| <body> +| "--> x" + +#data +<title> <!-- </title> --> </title>x +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| <html> +| <head> +| <title> +| " <!-- " +| " " +| <body> +| "--> x" + +#data +<textarea> <!--- </textarea>->x</textarea> --> </textarea>x +#errors +Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <textarea> +| " <!--- " +| "->x --> x" + +#data +<style> <!</-- </style>x +#errors +Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. +#document +| <html> +| <head> +| <style> +| " <!</-- " +| <body> +| "x" + +#data +<p><xmp></xmp> +#errors +XXX: Unknown +#document +| <html> +| <head> +| <body> +| <p> +| <xmp> + +#data +<xmp> <!-- > --> </xmp> +#errors +Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <xmp> +| " <!-- > --> " + +#data +<title>&</title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| <html> +| <head> +| <title> +| "&" +| <body> + +#data +<title><!--&--></title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +#document +| <html> +| <head> +| <title> +| "<!--&-->" +| <body> + +#data +<title><!--</title> +#errors +Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. +Line: 1 Col: 19 Unexpected end of file. Expected end tag (title). +#document +| <html> +| <head> +| <title> +| "<!--" +| <body> + +#data +<noscript><!--</noscript>--></noscript> +#errors +Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. +#document +| <html> +| <head> +| <noscript> +| "<!--" +| <body> +| "-->" diff --git a/libgo/go/exp/html/testdata/webkit/tests6.dat b/libgo/go/exp/html/testdata/webkit/tests6.dat new file mode 100644 index 00000000000..f28ece4fb00 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests6.dat @@ -0,0 +1,663 @@ +#data +<!doctype html></head> <head> +#errors +Line: 1 Col: 29 Unexpected start tag head. Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| " " +| <body> + +#data +<!doctype html><form><div></form><div> +#errors +33: End tag "form" seen but there were unclosed elements. +38: End of file seen and there were open elements. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <form> +| <div> +| <div> + +#data +<!doctype html><title>&</title> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "&" +| <body> + +#data +<!doctype html><title><!--&--></title> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "<!--&-->" +| <body> + +#data +<!doctype> +#errors +Line: 1 Col: 9 No space after literal string 'DOCTYPE'. +Line: 1 Col: 10 Unexpected > character. Expected DOCTYPE name. +Line: 1 Col: 10 Erroneous DOCTYPE. +#document +| <!DOCTYPE > +| <html> +| <head> +| <body> + +#data +<!---x +#errors +Line: 1 Col: 6 Unexpected end of file in comment. +Line: 1 Col: 6 Unexpected End of file. Expected DOCTYPE. +#document +| <!-- -x --> +| <html> +| <head> +| <body> + +#data +<body> +<div> +#errors +Line: 1 Col: 6 Unexpected start tag (body). +Line: 2 Col: 5 Expected closing tag. Unexpected end of file. +#document-fragment +div +#document +| " +" +| <div> + +#data +<frameset></frameset> +foo +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 2 Col: 3 Unexpected non-space characters in the after frameset phase. Ignored. +#document +| <html> +| <head> +| <frameset> +| " +" + +#data +<frameset></frameset> +<noframes> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 2 Col: 10 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <frameset> +| " +" +| <noframes> + +#data +<frameset></frameset> +<div> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 2 Col: 5 Unexpected start tag (div) in the after frameset phase. Ignored. +#document +| <html> +| <head> +| <frameset> +| " +" + +#data +<frameset></frameset> +</html> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +#document +| <html> +| <head> +| <frameset> +| " +" + +#data +<frameset></frameset> +</div> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 2 Col: 6 Unexpected end tag (div) in the after frameset phase. Ignored. +#document +| <html> +| <head> +| <frameset> +| " +" + +#data +<form><form> +#errors +Line: 1 Col: 6 Unexpected start tag (form). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected start tag (form). +Line: 1 Col: 12 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <form> + +#data +<button><button> +#errors +Line: 1 Col: 8 Unexpected start tag (button). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected start tag (button) implies end tag (button). +Line: 1 Col: 16 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <button> +| <button> + +#data +<table><tr><td></th> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end tag (th). Ignored. +Line: 1 Col: 20 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><caption><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end tag (td). Ignored. +Line: 1 Col: 20 Unexpected table cell start tag (td) in the table body phase. +Line: 1 Col: 20 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <caption> +| <tbody> +| <tr> +| <td> + +#data +<table><caption><div> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 21 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <caption> +| <div> + +#data +</caption><div> +#errors +Line: 1 Col: 10 Unexpected end tag (caption). Ignored. +Line: 1 Col: 15 Expected closing tag. Unexpected end of file. +#document-fragment +caption +#document +| <div> + +#data +<table><caption><div></caption> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 31 Unexpected end tag (caption). Missing end tag (div). +Line: 1 Col: 31 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <table> +| <caption> +| <div> + +#data +<table><caption></table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 24 Unexpected end table tag in caption. Generates implied end caption. +#document +| <html> +| <head> +| <body> +| <table> +| <caption> + +#data +</table><div> +#errors +Line: 1 Col: 8 Unexpected end table tag in caption. Generates implied end caption. +Line: 1 Col: 8 Unexpected end tag (caption). Ignored. +Line: 1 Col: 13 Expected closing tag. Unexpected end of file. +#document-fragment +caption +#document +| <div> + +#data +<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 23 Unexpected end tag (body). Ignored. +Line: 1 Col: 29 Unexpected end tag (col). Ignored. +Line: 1 Col: 40 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 47 Unexpected end tag (html). Ignored. +Line: 1 Col: 55 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 60 Unexpected end tag (td). Ignored. +Line: 1 Col: 68 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 73 Unexpected end tag (th). Ignored. +Line: 1 Col: 81 Unexpected end tag (thead). Ignored. +Line: 1 Col: 86 Unexpected end tag (tr). Ignored. +Line: 1 Col: 86 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <caption> + +#data +<table><caption><div></div> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 27 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <caption> +| <div> + +#data +<table><tr><td></body></caption></col></colgroup></html> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end tag (body). Ignored. +Line: 1 Col: 32 Unexpected end tag (caption). Ignored. +Line: 1 Col: 38 Unexpected end tag (col). Ignored. +Line: 1 Col: 49 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 56 Unexpected end tag (html). Ignored. +Line: 1 Col: 56 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> + +#data +</table></tbody></tfoot></thead></tr><div> +#errors +Line: 1 Col: 8 Unexpected end tag (table). Ignored. +Line: 1 Col: 16 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 24 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 32 Unexpected end tag (thead). Ignored. +Line: 1 Col: 37 Unexpected end tag (tr). Ignored. +Line: 1 Col: 42 Expected closing tag. Unexpected end of file. +#document-fragment +td +#document +| <div> + +#data +<table><colgroup>foo +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 20 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| "foo" +| <table> +| <colgroup> + +#data +foo<col> +#errors +Line: 1 Col: 3 Unexpected end tag (colgroup). Ignored. +#document-fragment +colgroup +#document +| <col> + +#data +<table><colgroup></col> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 23 This element (col) has no end tag. +Line: 1 Col: 23 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <table> +| <colgroup> + +#data +<frameset><div> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 1 Col: 15 Unexpected start tag token (div) in the frameset phase. Ignored. +Line: 1 Col: 15 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <frameset> + +#data +</frameset><frame> +#errors +Line: 1 Col: 11 Unexpected end tag token (frameset) in the frameset phase (innerHTML). +#document-fragment +frameset +#document +| <frame> + +#data +<frameset></div> +#errors +Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected end tag token (div) in the frameset phase. Ignored. +Line: 1 Col: 16 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <frameset> + +#data +</body><div> +#errors +Line: 1 Col: 7 Unexpected end tag (body). Ignored. +Line: 1 Col: 12 Expected closing tag. Unexpected end of file. +#document-fragment +body +#document +| <div> + +#data +<table><tr><div> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode. +Line: 1 Col: 16 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <div> +| <table> +| <tbody> +| <tr> + +#data +</tr><td> +#errors +Line: 1 Col: 5 Unexpected end tag (tr). Ignored. +#document-fragment +tr +#document +| <td> + +#data +</tbody></tfoot></thead><td> +#errors +Line: 1 Col: 8 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 16 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 24 Unexpected end tag (thead). Ignored. +#document-fragment +tr +#document +| <td> + +#data +<table><tr><div><td> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode. +Line: 1 Col: 20 Unexpected implied end tag (div) in the table row phase. +Line: 1 Col: 20 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| <table> +| <tbody> +| <tr> +| <td> + +#data +<caption><col><colgroup><tbody><tfoot><thead><tr> +#errors +Line: 1 Col: 9 Unexpected start tag (caption). +Line: 1 Col: 14 Unexpected start tag (col). +Line: 1 Col: 24 Unexpected start tag (colgroup). +Line: 1 Col: 31 Unexpected start tag (tbody). +Line: 1 Col: 38 Unexpected start tag (tfoot). +Line: 1 Col: 45 Unexpected start tag (thead). +Line: 1 Col: 49 Unexpected end of file. Expected table content. +#document-fragment +tbody +#document +| <tr> + +#data +<table><tbody></thead> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 22 Unexpected end tag (thead) in the table body phase. Ignored. +Line: 1 Col: 22 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> + +#data +</table><tr> +#errors +Line: 1 Col: 8 Unexpected end tag (table). Ignored. +Line: 1 Col: 12 Unexpected end of file. Expected table content. +#document-fragment +tbody +#document +| <tr> + +#data +<table><tbody></body></caption></col></colgroup></html></td></th></tr> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 21 Unexpected end tag (body) in the table body phase. Ignored. +Line: 1 Col: 31 Unexpected end tag (caption) in the table body phase. Ignored. +Line: 1 Col: 37 Unexpected end tag (col) in the table body phase. Ignored. +Line: 1 Col: 48 Unexpected end tag (colgroup) in the table body phase. Ignored. +Line: 1 Col: 55 Unexpected end tag (html) in the table body phase. Ignored. +Line: 1 Col: 60 Unexpected end tag (td) in the table body phase. Ignored. +Line: 1 Col: 65 Unexpected end tag (th) in the table body phase. Ignored. +Line: 1 Col: 70 Unexpected end tag (tr) in the table body phase. Ignored. +Line: 1 Col: 70 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> + +#data +<table><tbody></div> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 20 Unexpected end tag (div) in table context caused voodoo mode. +Line: 1 Col: 20 End tag (div) seen too early. Expected other end tag. +Line: 1 Col: 20 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> + +#data +<table><table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected start tag (table) implies end tag (table). +Line: 1 Col: 14 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <table> +| <table> + +#data +<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 14 Unexpected end tag (body). Ignored. +Line: 1 Col: 24 Unexpected end tag (caption). Ignored. +Line: 1 Col: 30 Unexpected end tag (col). Ignored. +Line: 1 Col: 41 Unexpected end tag (colgroup). Ignored. +Line: 1 Col: 48 Unexpected end tag (html). Ignored. +Line: 1 Col: 56 Unexpected end tag (tbody). Ignored. +Line: 1 Col: 61 Unexpected end tag (td). Ignored. +Line: 1 Col: 69 Unexpected end tag (tfoot). Ignored. +Line: 1 Col: 74 Unexpected end tag (th). Ignored. +Line: 1 Col: 82 Unexpected end tag (thead). Ignored. +Line: 1 Col: 87 Unexpected end tag (tr). Ignored. +Line: 1 Col: 87 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <table> + +#data +</table><tr> +#errors +Line: 1 Col: 8 Unexpected end tag (table). Ignored. +Line: 1 Col: 12 Unexpected end of file. Expected table content. +#document-fragment +table +#document +| <tbody> +| <tr> + +#data +<body></body></html> +#errors +Line: 1 Col: 20 Unexpected html end tag in inner html mode. +Line: 1 Col: 20 Unexpected EOF in inner html mode. +#document-fragment +html +#document +| <head> +| <body> + +#data +<html><frameset></frameset></html> +#errors +Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. +#document +| <html> +| <head> +| <frameset> +| " " + +#data +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html> +#errors +Line: 1 Col: 50 Erroneous DOCTYPE. +Line: 1 Col: 63 Unexpected end tag (html) after the (implied) root element. +#document +| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" ""> +| <html> +| <head> +| <body> + +#data +<param><frameset></frameset> +#errors +Line: 1 Col: 7 Unexpected start tag (param). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected start tag (frameset). +#document +| <html> +| <head> +| <frameset> + +#data +<source><frameset></frameset> +#errors +Line: 1 Col: 7 Unexpected start tag (source). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected start tag (frameset). +#document +| <html> +| <head> +| <frameset> + +#data +<track><frameset></frameset> +#errors +Line: 1 Col: 7 Unexpected start tag (track). Expected DOCTYPE. +Line: 1 Col: 17 Unexpected start tag (frameset). +#document +| <html> +| <head> +| <frameset> + +#data +</html><frameset></frameset> +#errors +7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +17: Stray “frameset” start tag. +17: “frameset” start tag seen. +#document +| <html> +| <head> +| <frameset> + +#data +</body><frameset></frameset> +#errors +7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”. +17: Stray “frameset” start tag. +17: “frameset” start tag seen. +#document +| <html> +| <head> +| <frameset> diff --git a/libgo/go/exp/html/testdata/webkit/tests7.dat b/libgo/go/exp/html/testdata/webkit/tests7.dat new file mode 100644 index 00000000000..f5193c660bc --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests7.dat @@ -0,0 +1,390 @@ +#data +<!doctype html><body><title>X</title> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <title> +| "X" + +#data +<!doctype html><table><title>X</title></table> +#errors +Line: 1 Col: 29 Unexpected start tag (title) in table context caused voodoo mode. +Line: 1 Col: 38 Unexpected end tag (title) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <title> +| "X" +| <table> + +#data +<!doctype html><head></head><title>X</title> +#errors +Line: 1 Col: 35 Unexpected start tag (title) that can be in head. Moved. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "X" +| <body> + +#data +<!doctype html></head><title>X</title> +#errors +Line: 1 Col: 29 Unexpected start tag (title) that can be in head. Moved. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <title> +| "X" +| <body> + +#data +<!doctype html><table><meta></table> +#errors +Line: 1 Col: 28 Unexpected start tag (meta) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <meta> +| <table> + +#data +<!doctype html><table>X<tr><td><table> <meta></table></table> +#errors +Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 45 Unexpected start tag (meta) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <table> +| <tbody> +| <tr> +| <td> +| <meta> +| <table> +| " " + +#data +<!doctype html><html> <head> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!doctype html> <head> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!doctype html><table><style> <tr>x </style> </table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <style> +| " <tr>x " +| " " + +#data +<!doctype html><table><TBODY><script> <tr>x </script> </table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <script> +| " <tr>x " +| " " + +#data +<!doctype html><p><applet><p>X</p></applet> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <p> +| <applet> +| <p> +| "X" + +#data +<!doctype html><listing> +X</listing> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <listing> +| "X" + +#data +<!doctype html><select><input>X +#errors +Line: 1 Col: 30 Unexpected input start tag in the select phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <input> +| "X" + +#data +<!doctype html><select><select>X +#errors +Line: 1 Col: 31 Unexpected select start tag in the select phase treated as select end tag. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| "X" + +#data +<!doctype html><table><input type=hidDEN></table> +#errors +Line: 1 Col: 41 Unexpected input with type hidden in table context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <input> +| type="hidDEN" + +#data +<!doctype html><table>X<input type=hidDEN></table> +#errors +Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| "X" +| <table> +| <input> +| type="hidDEN" + +#data +<!doctype html><table> <input type=hidDEN></table> +#errors +Line: 1 Col: 43 Unexpected input with type hidden in table context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " " +| <input> +| type="hidDEN" + +#data +<!doctype html><table> <input type='hidDEN'></table> +#errors +Line: 1 Col: 45 Unexpected input with type hidden in table context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| " " +| <input> +| type="hidDEN" + +#data +<!doctype html><table><input type=" hidden"><input type=hidDEN></table> +#errors +Line: 1 Col: 44 Unexpected start tag (input) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <input> +| type=" hidden" +| <table> +| <input> +| type="hidDEN" + +#data +<!doctype html><table><select>X<tr> +#errors +Line: 1 Col: 30 Unexpected start tag (select) in table context caused voodoo mode. +Line: 1 Col: 35 Unexpected table element start tag (trs) in the select in table phase. +Line: 1 Col: 35 Unexpected end of file. Expected table content. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| "X" +| <table> +| <tbody> +| <tr> + +#data +<!doctype html><select>X</select> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| "X" + +#data +<!DOCTYPE hTmL><html></html> +#errors +Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<!DOCTYPE HTML><html></html> +#errors +Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> + +#data +<body>X</body></body> +#errors +Line: 1 Col: 21 Unexpected end tag token (body) in the after body phase. +Line: 1 Col: 21 Unexpected EOF in inner html mode. +#document-fragment +html +#document +| <head> +| <body> +| "X" + +#data +<div><p>a</x> b +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 13 Unexpected end tag (x). Ignored. +Line: 1 Col: 15 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| <p> +| "a b" + +#data +<table><tr><td><code></code> </table> +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <code> +| " " + +#data +<table><b><tr><td>aaa</td></tr>bbb</table>ccc +#errors +XXX: Fix me +#document +| <html> +| <head> +| <body> +| <b> +| <b> +| "bbb" +| <table> +| <tbody> +| <tr> +| <td> +| "aaa" +| <b> +| "ccc" + +#data +A<table><tr> B</tr> B</table> +#errors +XXX: Fix me +#document +| <html> +| <head> +| <body> +| "A B B" +| <table> +| <tbody> +| <tr> + +#data +A<table><tr> B</tr> </em>C</table> +#errors +XXX: Fix me +#document +| <html> +| <head> +| <body> +| "A BC" +| <table> +| <tbody> +| <tr> +| " " + +#data +<select><keygen> +#errors +Not known +#document +| <html> +| <head> +| <body> +| <select> +| <keygen> diff --git a/libgo/go/exp/html/testdata/webkit/tests8.dat b/libgo/go/exp/html/testdata/webkit/tests8.dat new file mode 100644 index 00000000000..90e6c919e84 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests8.dat @@ -0,0 +1,148 @@ +#data +<div> +<div></div> +</span>x +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 3 Col: 7 Unexpected end tag (span). Ignored. +Line: 3 Col: 8 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| " +" +| <div> +| " +x" + +#data +<div>x<div></div> +</span>x +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 2 Col: 7 Unexpected end tag (span). Ignored. +Line: 2 Col: 8 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| "x" +| <div> +| " +x" + +#data +<div>x<div></div>x</span>x +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 25 Unexpected end tag (span). Ignored. +Line: 1 Col: 26 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| "x" +| <div> +| "xx" + +#data +<div>x<div></div>y</span>z +#errors +Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE. +Line: 1 Col: 25 Unexpected end tag (span). Ignored. +Line: 1 Col: 26 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <div> +| "x" +| <div> +| "yz" + +#data +<table><div>x<div></div>x</span>x +#errors +Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. +Line: 1 Col: 12 Unexpected start tag (div) in table context caused voodoo mode. +Line: 1 Col: 18 Unexpected start tag (div) in table context caused voodoo mode. +Line: 1 Col: 24 Unexpected end tag (div) in table context caused voodoo mode. +Line: 1 Col: 32 Unexpected end tag (span) in table context caused voodoo mode. +Line: 1 Col: 32 Unexpected end tag (span). Ignored. +Line: 1 Col: 33 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| <div> +| "x" +| <div> +| "xx" +| <table> + +#data +x<table>x +#errors +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +Line: 1 Col: 9 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 9 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| "xx" +| <table> + +#data +x<table><table>x +#errors +Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. +Line: 1 Col: 15 Unexpected start tag (table) implies end tag (table). +Line: 1 Col: 16 Unexpected non-space characters in table context caused voodoo mode. +Line: 1 Col: 16 Unexpected end of file. Expected table content. +#document +| <html> +| <head> +| <body> +| "x" +| <table> +| "x" +| <table> + +#data +<b>a<div></div><div></b>y +#errors +Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE. +Line: 1 Col: 24 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 25 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <b> +| "a" +| <div> +| <div> +| <b> +| "y" + +#data +<a><div><p></a> +#errors +Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE. +Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm. +Line: 1 Col: 15 Expected closing tag. Unexpected end of file. +#document +| <html> +| <head> +| <body> +| <a> +| <div> +| <a> +| <p> +| <a> diff --git a/libgo/go/exp/html/testdata/webkit/tests9.dat b/libgo/go/exp/html/testdata/webkit/tests9.dat new file mode 100644 index 00000000000..554e27aecf6 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests9.dat @@ -0,0 +1,457 @@ +#data +<!DOCTYPE html><math></math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> + +#data +<!DOCTYPE html><body><math></math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> + +#data +<!DOCTYPE html><math><mi> +#errors +25: End of file in a foreign namespace context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> + +#data +<!DOCTYPE html><math><annotation-xml><svg><u> +#errors +45: HTML start tag “u” in a foreign namespace context. +45: End of file seen and there were open elements. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math annotation-xml> +| <svg svg> +| <u> + +#data +<!DOCTYPE html><body><select><math></math></select> +#errors +Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored. +Line: 1 Col: 42 Unexpected end tag (math) in the select phase. Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> + +#data +<!DOCTYPE html><body><select><option><math></math></option></select> +#errors +Line: 1 Col: 43 Unexpected start tag token (math) in the select phase. Ignored. +Line: 1 Col: 50 Unexpected end tag (math) in the select phase. Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| <option> + +#data +<!DOCTYPE html><body><table><math></math></table> +#errors +Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode. +Line: 1 Col: 41 Unexpected end tag (math) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <table> + +#data +<!DOCTYPE html><body><table><math><mi>foo</mi></math></table> +#errors +Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode. +Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 53 Unexpected end tag (math) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| "foo" +| <table> + +#data +<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table> +#errors +Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode. +Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 58 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 65 Unexpected end tag (math) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <table> + +#data +<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table> +#errors +Line: 1 Col: 41 Unexpected start tag (math) in table context caused voodoo mode. +Line: 1 Col: 53 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 65 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 72 Unexpected end tag (math) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <table> +| <tbody> + +#data +<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table> +#errors +Line: 1 Col: 45 Unexpected start tag (math) in table context caused voodoo mode. +Line: 1 Col: 57 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 69 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 76 Unexpected end tag (math) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <table> +| <tbody> +| <tr> + +#data +<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" + +#data +<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux +#errors +Line: 1 Col: 70 HTML start tag "p" in a foreign namespace context. +Line: 1 Col: 81 Unexpected end table tag in caption. Generates implied end caption. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <p> +| "baz" +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux +#errors +Line: 1 Col: 78 Unexpected end table tag in caption. Generates implied end caption. +Line: 1 Col: 78 Unexpected end tag (caption). Missing end tag (math). +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <caption> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| "baz" +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux +#errors +Line: 1 Col: 44 Unexpected start tag (math) in table context caused voodoo mode. +Line: 1 Col: 56 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 68 Unexpected end tag (mi) in table context caused voodoo mode. +Line: 1 Col: 71 HTML start tag "p" in a foreign namespace context. +Line: 1 Col: 71 Unexpected start tag (p) in table context caused voodoo mode. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <p> +| "baz" +| <table> +| <colgroup> +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux +#errors +Line: 1 Col: 50 Unexpected start tag token (math) in the select phase. Ignored. +Line: 1 Col: 54 Unexpected start tag token (mi) in the select phase. Ignored. +Line: 1 Col: 62 Unexpected end tag (mi) in the select phase. Ignored. +Line: 1 Col: 66 Unexpected start tag token (mi) in the select phase. Ignored. +Line: 1 Col: 74 Unexpected end tag (mi) in the select phase. Ignored. +Line: 1 Col: 77 Unexpected start tag token (p) in the select phase. Ignored. +Line: 1 Col: 88 Unexpected table element end tag (tables) in the select in table phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <select> +| "foobarbaz" +| <p> +| "quux" + +#data +<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux +#errors +Line: 1 Col: 36 Unexpected start tag (select) in table context caused voodoo mode. +Line: 1 Col: 42 Unexpected start tag token (math) in the select phase. Ignored. +Line: 1 Col: 46 Unexpected start tag token (mi) in the select phase. Ignored. +Line: 1 Col: 54 Unexpected end tag (mi) in the select phase. Ignored. +Line: 1 Col: 58 Unexpected start tag token (mi) in the select phase. Ignored. +Line: 1 Col: 66 Unexpected end tag (mi) in the select phase. Ignored. +Line: 1 Col: 69 Unexpected start tag token (p) in the select phase. Ignored. +Line: 1 Col: 80 Unexpected table element end tag (tables) in the select in table phase. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <select> +| "foobarbaz" +| <table> +| <p> +| "quux" + +#data +<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz +#errors +Line: 1 Col: 41 Unexpected start tag (math). +Line: 1 Col: 68 HTML start tag "p" in a foreign namespace context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz +#errors +Line: 1 Col: 34 Unexpected start tag token (math) in the after body phase. +Line: 1 Col: 61 HTML start tag "p" in a foreign namespace context. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <math math> +| <math mi> +| "foo" +| <math mi> +| "bar" +| <p> +| "baz" + +#data +<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span> +#errors +Line: 1 Col: 31 Unexpected start tag token (math) in the frameset phase. Ignored. +Line: 1 Col: 35 Unexpected start tag token (mi) in the frameset phase. Ignored. +Line: 1 Col: 40 Unexpected end tag token (mi) in the frameset phase. Ignored. +Line: 1 Col: 44 Unexpected start tag token (mi) in the frameset phase. Ignored. +Line: 1 Col: 49 Unexpected end tag token (mi) in the frameset phase. Ignored. +Line: 1 Col: 52 Unexpected start tag token (p) in the frameset phase. Ignored. +Line: 1 Col: 58 Unexpected start tag token (span) in the frameset phase. Ignored. +Line: 1 Col: 58 Expected closing tag. Unexpected end of file. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span> +#errors +Line: 1 Col: 42 Unexpected start tag (math) in the after frameset phase. Ignored. +Line: 1 Col: 46 Unexpected start tag (mi) in the after frameset phase. Ignored. +Line: 1 Col: 51 Unexpected end tag (mi) in the after frameset phase. Ignored. +Line: 1 Col: 55 Unexpected start tag (mi) in the after frameset phase. Ignored. +Line: 1 Col: 60 Unexpected end tag (mi) in the after frameset phase. Ignored. +Line: 1 Col: 63 Unexpected start tag (p) in the after frameset phase. Ignored. +Line: 1 Col: 69 Unexpected start tag (span) in the after frameset phase. Ignored. +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| <math math> +| xlink href="foo" + +#data +<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| xml:lang="en" +| <math math> +| <math mi> +| xlink href="foo" +| xml lang="en" + +#data +<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| xml:lang="en" +| <math math> +| <math mi> +| xlink href="foo" +| xml lang="en" + +#data +<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| xlink:href="foo" +| xml:lang="en" +| <math math> +| <math mi> +| xlink href="foo" +| xml lang="en" +| "bar" diff --git a/libgo/go/exp/html/testdata/webkit/tests_innerHTML_1.dat b/libgo/go/exp/html/testdata/webkit/tests_innerHTML_1.dat new file mode 100644 index 00000000000..052fac7d554 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tests_innerHTML_1.dat @@ -0,0 +1,733 @@ +#data +<body><span> +#errors +#document-fragment +body +#document +| <span> + +#data +<span><body> +#errors +#document-fragment +body +#document +| <span> + +#data +<span><body> +#errors +#document-fragment +div +#document +| <span> + +#data +<body><span> +#errors +#document-fragment +html +#document +| <head> +| <body> +| <span> + +#data +<frameset><span> +#errors +#document-fragment +body +#document +| <span> + +#data +<span><frameset> +#errors +#document-fragment +body +#document +| <span> + +#data +<span><frameset> +#errors +#document-fragment +div +#document +| <span> + +#data +<frameset><span> +#errors +#document-fragment +html +#document +| <head> +| <frameset> + +#data +<table><tr> +#errors +#document-fragment +table +#document +| <tbody> +| <tr> + +#data +</table><tr> +#errors +#document-fragment +table +#document +| <tbody> +| <tr> + +#data +<a> +#errors +#document-fragment +table +#document +| <a> + +#data +<a> +#errors +#document-fragment +table +#document +| <a> + +#data +<a><caption>a +#errors +#document-fragment +table +#document +| <a> +| <caption> +| "a" + +#data +<a><colgroup><col> +#errors +#document-fragment +table +#document +| <a> +| <colgroup> +| <col> + +#data +<a><tbody><tr> +#errors +#document-fragment +table +#document +| <a> +| <tbody> +| <tr> + +#data +<a><tfoot><tr> +#errors +#document-fragment +table +#document +| <a> +| <tfoot> +| <tr> + +#data +<a><thead><tr> +#errors +#document-fragment +table +#document +| <a> +| <thead> +| <tr> + +#data +<a><tr> +#errors +#document-fragment +table +#document +| <a> +| <tbody> +| <tr> + +#data +<a><th> +#errors +#document-fragment +table +#document +| <a> +| <tbody> +| <tr> +| <th> + +#data +<a><td> +#errors +#document-fragment +table +#document +| <a> +| <tbody> +| <tr> +| <td> + +#data +<table></table><tbody> +#errors +#document-fragment +caption +#document +| <table> + +#data +</table><span> +#errors +#document-fragment +caption +#document +| <span> + +#data +<span></table> +#errors +#document-fragment +caption +#document +| <span> + +#data +</caption><span> +#errors +#document-fragment +caption +#document +| <span> + +#data +<span></caption><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><caption><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><col><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><colgroup><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><html><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><tbody><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><td><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><tfoot><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><thead><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><th><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span><tr><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +<span></table><span> +#errors +#document-fragment +caption +#document +| <span> +| <span> + +#data +</colgroup><col> +#errors +#document-fragment +colgroup +#document +| <col> + +#data +<a><col> +#errors +#document-fragment +colgroup +#document +| <col> + +#data +<caption><a> +#errors +#document-fragment +tbody +#document +| <a> + +#data +<col><a> +#errors +#document-fragment +tbody +#document +| <a> + +#data +<colgroup><a> +#errors +#document-fragment +tbody +#document +| <a> + +#data +<tbody><a> +#errors +#document-fragment +tbody +#document +| <a> + +#data +<tfoot><a> +#errors +#document-fragment +tbody +#document +| <a> + +#data +<thead><a> +#errors +#document-fragment +tbody +#document +| <a> + +#data +</table><a> +#errors +#document-fragment +tbody +#document +| <a> + +#data +<a><tr> +#errors +#document-fragment +tbody +#document +| <a> +| <tr> + +#data +<a><td> +#errors +#document-fragment +tbody +#document +| <a> +| <tr> +| <td> + +#data +<a><td> +#errors +#document-fragment +tbody +#document +| <a> +| <tr> +| <td> + +#data +<a><td> +#errors +#document-fragment +tbody +#document +| <a> +| <tr> +| <td> + +#data +<td><table><tbody><a><tr> +#errors +#document-fragment +tbody +#document +| <tr> +| <td> +| <a> +| <table> +| <tbody> +| <tr> + +#data +</tr><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<td><table><a><tr></tr><tr> +#errors +#document-fragment +tr +#document +| <td> +| <a> +| <table> +| <tbody> +| <tr> +| <tr> + +#data +<caption><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<col><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<colgroup><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<tbody><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<tfoot><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<thead><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<tr><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +</table><td> +#errors +#document-fragment +tr +#document +| <td> + +#data +<td><table></table><td> +#errors +#document-fragment +tr +#document +| <td> +| <table> +| <td> + +#data +<td><table></table><td> +#errors +#document-fragment +tr +#document +| <td> +| <table> +| <td> + +#data +<caption><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<col><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<colgroup><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<tbody><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<tfoot><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<th><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<thead><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<tr><a> +#errors +#document-fragment +td +#document +| <a> + +#data +</table><a> +#errors +#document-fragment +td +#document +| <a> + +#data +</tbody><a> +#errors +#document-fragment +td +#document +| <a> + +#data +</td><a> +#errors +#document-fragment +td +#document +| <a> + +#data +</tfoot><a> +#errors +#document-fragment +td +#document +| <a> + +#data +</thead><a> +#errors +#document-fragment +td +#document +| <a> + +#data +</th><a> +#errors +#document-fragment +td +#document +| <a> + +#data +</tr><a> +#errors +#document-fragment +td +#document +| <a> + +#data +<table><td><td> +#errors +#document-fragment +td +#document +| <table> +| <tbody> +| <tr> +| <td> +| <td> + +#data +</select><option> +#errors +#document-fragment +select +#document +| <option> + +#data +<input><option> +#errors +#document-fragment +select +#document +| <option> + +#data +<keygen><option> +#errors +#document-fragment +select +#document +| <option> + +#data +<textarea><option> +#errors +#document-fragment +select +#document +| <option> + +#data +</html><!--abc--> +#errors +#document-fragment +html +#document +| <head> +| <body> +| <!-- abc --> + +#data +</frameset><frame> +#errors +#document-fragment +frameset +#document +| <frame> diff --git a/libgo/go/exp/html/testdata/webkit/tricky01.dat b/libgo/go/exp/html/testdata/webkit/tricky01.dat new file mode 100644 index 00000000000..08419924486 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/tricky01.dat @@ -0,0 +1,261 @@ +#data +<b><p>Bold </b> Not bold</p> +Also not bold. +#errors +#document +| <html> +| <head> +| <body> +| <b> +| <p> +| <b> +| "Bold " +| " Not bold" +| " +Also not bold." + +#data +<html> +<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain +<p>I should not be red. <font color=red>Red. <i>Italic and red.</p> +<p>Italic and red. </i> Red.</font> I should not be red.</p> +<b>Bold <i>Bold and italic</b> Only Italic </i> Plain +#errors +#document +| <html> +| <head> +| <body> +| <font> +| color="red" +| <i> +| "Italic and Red" +| <i> +| <p> +| <font> +| color="red" +| "Italic and Red " +| " Just italic." +| " Italic only." +| " Plain +" +| <p> +| "I should not be red. " +| <font> +| color="red" +| "Red. " +| <i> +| "Italic and red." +| <font> +| color="red" +| <i> +| " +" +| <p> +| <font> +| color="red" +| <i> +| "Italic and red. " +| " Red." +| " I should not be red." +| " +" +| <b> +| "Bold " +| <i> +| "Bold and italic" +| <i> +| " Only Italic " +| " Plain" + +#data +<html><body> +<p><font size="7">First paragraph.</p> +<p>Second paragraph.</p></font> +<b><p><i>Bold and Italic</b> Italic</p> +#errors +#document +| <html> +| <head> +| <body> +| " +" +| <p> +| <font> +| size="7" +| "First paragraph." +| <font> +| size="7" +| " +" +| <p> +| "Second paragraph." +| " +" +| <b> +| <p> +| <b> +| <i> +| "Bold and Italic" +| <i> +| " Italic" + +#data +<html> +<dl> +<dt><b>Boo +<dd>Goo? +</dl> +</html> +#errors +#document +| <html> +| <head> +| <body> +| <dl> +| " +" +| <dt> +| <b> +| "Boo +" +| <dd> +| <b> +| "Goo? +" +| <b> +| " +" + +#data +<html><body> +<label><a><div>Hello<div>World</div></a></label> +</body></html> +#errors +#document +| <html> +| <head> +| <body> +| " +" +| <label> +| <a> +| <div> +| <a> +| "Hello" +| <div> +| "World" +| " +" + +#data +<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table> +#errors +#document +| <html> +| <head> +| <body> +| <center> +| " " +| <font> +| "a" +| <font> +| <img> +| " " +| <table> +| " " +| <tbody> +| <tr> +| <td> +| " " +| " " +| " " + +#data +<table><tr><p><a><p>You should see this text. +#errors +#document +| <html> +| <head> +| <body> +| <p> +| <a> +| <p> +| <a> +| "You should see this text." +| <table> +| <tbody> +| <tr> + +#data +<TABLE> +<TR> +<CENTER><CENTER><TD></TD></TR><TR> +<FONT> +<TABLE><tr></tr></TABLE> +</P> +<a></font><font></a> +This page contains an insanely badly-nested tag sequence. +#errors +#document +| <html> +| <head> +| <body> +| <center> +| <center> +| <font> +| " +" +| <table> +| " +" +| <tbody> +| <tr> +| " +" +| <td> +| <tr> +| " +" +| <table> +| <tbody> +| <tr> +| <font> +| " +" +| <p> +| " +" +| <a> +| <a> +| <font> +| <font> +| " +This page contains an insanely badly-nested tag sequence." + +#data +<html> +<body> +<b><nobr><div>This text is in a div inside a nobr</nobr>More text that should not be in the nobr, i.e., the +nobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre> +</body> +</html> +#errors +#document +| <html> +| <head> +| <body> +| " +" +| <b> +| <nobr> +| <div> +| <b> +| <nobr> +| "This text is in a div inside a nobr" +| "More text that should not be in the nobr, i.e., the +nobr should have closed the div inside it implicitly. " +| <pre> +| "A pre tag outside everything else." +| " + +" diff --git a/libgo/go/exp/html/testdata/webkit/webkit01.dat b/libgo/go/exp/html/testdata/webkit/webkit01.dat new file mode 100644 index 00000000000..4101b216e18 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/webkit01.dat @@ -0,0 +1,609 @@ +#data +Test +#errors +Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. +#document +| <html> +| <head> +| <body> +| "Test" + +#data +<div></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> + +#data +<div>Test</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "Test" + +#data +<di +#errors +#document +| <html> +| <head> +| <body> + +#data +<div>Hello</div> +<script> +console.log("PASS"); +</script> +<div>Bye</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "Hello" +| " +" +| <script> +| " +console.log("PASS"); +" +| " +" +| <div> +| "Bye" + +#data +<div foo="bar">Hello</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| foo="bar" +| "Hello" + +#data +<div>Hello</div> +<script> +console.log("FOO<span>BAR</span>BAZ"); +</script> +<div>Bye</div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| "Hello" +| " +" +| <script> +| " +console.log("FOO<span>BAR</span>BAZ"); +" +| " +" +| <div> +| "Bye" + +#data +<foo bar="baz"></foo><potato quack="duck"></potato> +#errors +#document +| <html> +| <head> +| <body> +| <foo> +| bar="baz" +| <potato> +| quack="duck" + +#data +<foo bar="baz"><potato quack="duck"></potato></foo> +#errors +#document +| <html> +| <head> +| <body> +| <foo> +| bar="baz" +| <potato> +| quack="duck" + +#data +<foo></foo bar="baz"><potato></potato quack="duck"> +#errors +#document +| <html> +| <head> +| <body> +| <foo> +| <potato> + +#data +</ tttt> +#errors +#document +| <!-- tttt --> +| <html> +| <head> +| <body> + +#data +<div FOO ><img><img></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| foo="" +| <img> +| <img> + +#data +<p>Test</p<p>Test2</p> +#errors +#document +| <html> +| <head> +| <body> +| <p> +| "TestTest2" + +#data +<rdar://problem/6869687> +#errors +#document +| <html> +| <head> +| <body> +| <rdar:> +| 6869687="" +| problem="" + +#data +<A>test< /A> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| "test< /A>" + +#data +< +#errors +#document +| <html> +| <head> +| <body> +| "<" + +#data +<body foo='bar'><body foo='baz' yo='mama'> +#errors +#document +| <html> +| <head> +| <body> +| foo="bar" +| yo="mama" + +#data +<body></br foo="bar"></body> +#errors +#document +| <html> +| <head> +| <body> +| <br> + +#data +<bdy><br foo="bar"></body> +#errors +#document +| <html> +| <head> +| <body> +| <bdy> +| <br> +| foo="bar" + +#data +<body></body></br foo="bar"> +#errors +#document +| <html> +| <head> +| <body> +| <br> + +#data +<bdy></body><br foo="bar"> +#errors +#document +| <html> +| <head> +| <body> +| <bdy> +| <br> +| foo="bar" + +#data +<html><body></body></html><!-- Hi there --> +#errors +#document +| <html> +| <head> +| <body> +| <!-- Hi there --> + +#data +<html><body></body></html>x<!-- Hi there --> +#errors +#document +| <html> +| <head> +| <body> +| "x" +| <!-- Hi there --> + +#data +<html><body></body></html>x<!-- Hi there --></html><!-- Again --> +#errors +#document +| <html> +| <head> +| <body> +| "x" +| <!-- Hi there --> +| <!-- Again --> + +#data +<html><body></body></html>x<!-- Hi there --></body></html><!-- Again --> +#errors +#document +| <html> +| <head> +| <body> +| "x" +| <!-- Hi there --> +| <!-- Again --> + +#data +<html><body><ruby><div><rp>xx</rp></div></ruby></body></html> +#errors +#document +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <rp> +| "xx" + +#data +<html><body><ruby><div><rt>xx</rt></div></ruby></body></html> +#errors +#document +| <html> +| <head> +| <body> +| <ruby> +| <div> +| <rt> +| "xx" + +#data +<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6--> +#errors +#document +| <html> +| <head> +| <frameset> +| <!-- 1 --> +| <noframes> +| "A" +| <!-- 2 --> +| <!-- 3 --> +| <noframes> +| "B" +| <!-- 4 --> +| <noframes> +| "C" +| <!-- 5 --> +| <!-- 6 --> + +#data +<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select> +#errors +#document +| <html> +| <head> +| <body> +| <select> +| <option> +| "A" +| <option> +| "B" +| <select> +| <option> +| "C" +| <option> +| "D" +| <select> +| <option> +| "E" +| <option> +| "F" +| <select> +| <option> +| "G" + +#data +<dd><dd><dt><dt><dd><li><li> +#errors +#document +| <html> +| <head> +| <body> +| <dd> +| <dd> +| <dt> +| <dt> +| <dd> +| <li> +| <li> + +#data +<div><b></div><div><nobr>a<nobr> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <b> +| <div> +| <b> +| <nobr> +| "a" +| <nobr> + +#data +<head></head> +<body></body> +#errors +#document +| <html> +| <head> +| " +" +| <body> + +#data +<head></head> <style></style>ddd +#errors +#document +| <html> +| <head> +| <style> +| " " +| <body> +| "ddd" + +#data +<kbd><table></kbd><col><select><tr> +#errors +#document +| <html> +| <head> +| <body> +| <kbd> +| <select> +| <table> +| <colgroup> +| <col> +| <tbody> +| <tr> + +#data +<kbd><table></kbd><col><select><tr></table><div> +#errors +#document +| <html> +| <head> +| <body> +| <kbd> +| <select> +| <table> +| <colgroup> +| <col> +| <tbody> +| <tr> +| <div> + +#data +<a><li><style></style><title></title></a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <li> +| <a> +| <style> +| <title> + +#data +<font></p><p><meta><title></title></font> +#errors +#document +| <html> +| <head> +| <body> +| <font> +| <p> +| <p> +| <font> +| <meta> +| <title> + +#data +<a><center><title></title><a> +#errors +#document +| <html> +| <head> +| <body> +| <a> +| <center> +| <a> +| <title> +| <a> + +#data +<svg><title><div> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <svg title> +| <div> + +#data +<svg><title><rect><div> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <svg title> +| <rect> +| <div> + +#data +<svg><title><svg><div> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <svg title> +| <svg svg> +| <div> + +#data +<img <="" FAIL> +#errors +#document +| <html> +| <head> +| <body> +| <img> +| <="" +| fail="" + +#data +<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul> +#errors +#document +| <html> +| <head> +| <body> +| <ul> +| <li> +| <div> +| id="foo" +| "A" +| <li> +| "B" +| <div> +| "C" + +#data +<svg><em><desc></em> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <em> +| <desc> + +#data +<table><tr><td><svg><desc><td></desc><circle> +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| <svg svg> +| <svg desc> +| <svg circle> + +#data +<svg><tfoot></mi><td> +#errors +#document +| <html> +| <head> +| <body> +| <svg svg> +| <svg tfoot> +| <svg td> + +#data +<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math> +#errors +#document +| <html> +| <head> +| <body> +| <math math> +| <math mrow> +| <math mrow> +| <math mn> +| "1" +| <math mi> +| "a" + +#data +<!doctype html><input type="hidden"><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <frameset> + +#data +<!doctype html><input type="button"><frameset> +#errors +#document +| <!DOCTYPE html> +| <html> +| <head> +| <body> +| <input> +| type="button" diff --git a/libgo/go/exp/html/testdata/webkit/webkit02.dat b/libgo/go/exp/html/testdata/webkit/webkit02.dat new file mode 100644 index 00000000000..2218f4298c5 --- /dev/null +++ b/libgo/go/exp/html/testdata/webkit/webkit02.dat @@ -0,0 +1,104 @@ +#data +<foo bar=qux/> +#errors +#document +| <html> +| <head> +| <body> +| <foo> +| bar="qux/" + +#data +<p id="status"><noscript><strong>A</strong></noscript><span>B</span></p> +#errors +#document +| <html> +| <head> +| <body> +| <p> +| id="status" +| <noscript> +| "<strong>A</strong>" +| <span> +| "B" + +#data +<div><sarcasm><div></div></sarcasm></div> +#errors +#document +| <html> +| <head> +| <body> +| <div> +| <sarcasm> +| <div> + +#data +<html><body><img src="" border="0" alt="><div>A</div></body></html> +#errors +#document +| <html> +| <head> +| <body> + +#data +<table><td></tbody>A +#errors +#document +| <html> +| <head> +| <body> +| "A" +| <table> +| <tbody> +| <tr> +| <td> + +#data +<table><td></thead>A +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "A" + +#data +<table><td></tfoot>A +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <tbody> +| <tr> +| <td> +| "A" + +#data +<table><thead><td></tbody>A +#errors +#document +| <html> +| <head> +| <body> +| <table> +| <thead> +| <tr> +| <td> +| "A" + +#data +<legend>test</legend> +#errors +#document +| <html> +| <head> +| <body> +| <legend> +| "test" diff --git a/libgo/go/exp/html/token.go b/libgo/go/exp/html/token.go new file mode 100644 index 00000000000..5a385a1b5c5 --- /dev/null +++ b/libgo/go/exp/html/token.go @@ -0,0 +1,780 @@ +// Copyright 2010 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 html + +import ( + "bytes" + "io" + "strconv" + "strings" +) + +// A TokenType is the type of a Token. +type TokenType int + +const ( + // ErrorToken means that an error occurred during tokenization. + ErrorToken TokenType = iota + // TextToken means a text node. + TextToken + // A StartTagToken looks like <a>. + StartTagToken + // An EndTagToken looks like </a>. + EndTagToken + // A SelfClosingTagToken tag looks like <br/>. + SelfClosingTagToken + // A CommentToken looks like <!--x-->. + CommentToken + // A DoctypeToken looks like <!DOCTYPE x> + DoctypeToken +) + +// String returns a string representation of the TokenType. +func (t TokenType) String() string { + switch t { + case ErrorToken: + return "Error" + case TextToken: + return "Text" + case StartTagToken: + return "StartTag" + case EndTagToken: + return "EndTag" + case SelfClosingTagToken: + return "SelfClosingTag" + case CommentToken: + return "Comment" + case DoctypeToken: + return "Doctype" + } + return "Invalid(" + strconv.Itoa(int(t)) + ")" +} + +// An Attribute is an attribute namespace-key-value triple. Namespace is +// non-empty for foreign attributes like xlink, Key is alphabetic (and hence +// does not contain escapable characters like '&', '<' or '>'), and Val is +// unescaped (it looks like "a<b" rather than "a<b"). +// +// Namespace is only used by the parser, not the tokenizer. +type Attribute struct { + Namespace, Key, Val string +} + +// A Token consists of a TokenType and some Data (tag name for start and end +// tags, content for text, comments and doctypes). A tag Token may also contain +// a slice of Attributes. Data is unescaped for all Tokens (it looks like "a<b" +// rather than "a<b"). +type Token struct { + Type TokenType + Data string + Attr []Attribute +} + +// tagString returns a string representation of a tag Token's Data and Attr. +func (t Token) tagString() string { + if len(t.Attr) == 0 { + return t.Data + } + buf := bytes.NewBuffer(nil) + buf.WriteString(t.Data) + for _, a := range t.Attr { + buf.WriteByte(' ') + buf.WriteString(a.Key) + buf.WriteString(`="`) + escape(buf, a.Val) + buf.WriteByte('"') + } + return buf.String() +} + +// String returns a string representation of the Token. +func (t Token) String() string { + switch t.Type { + case ErrorToken: + return "" + case TextToken: + return EscapeString(t.Data) + case StartTagToken: + return "<" + t.tagString() + ">" + case EndTagToken: + return "</" + t.tagString() + ">" + case SelfClosingTagToken: + return "<" + t.tagString() + "/>" + case CommentToken: + return "<!--" + t.Data + "-->" + case DoctypeToken: + return "<!DOCTYPE " + t.Data + ">" + } + return "Invalid(" + strconv.Itoa(int(t.Type)) + ")" +} + +// span is a range of bytes in a Tokenizer's buffer. The start is inclusive, +// the end is exclusive. +type span struct { + start, end int +} + +// A Tokenizer returns a stream of HTML Tokens. +type Tokenizer struct { + // r is the source of the HTML text. + r io.Reader + // tt is the TokenType of the current token. + tt TokenType + // err is the first error encountered during tokenization. It is possible + // for tt != Error && err != nil to hold: this means that Next returned a + // valid token but the subsequent Next call will return an error token. + // For example, if the HTML text input was just "plain", then the first + // Next call would set z.err to io.EOF but return a TextToken, and all + // subsequent Next calls would return an ErrorToken. + // err is never reset. Once it becomes non-nil, it stays non-nil. + err error + // buf[raw.start:raw.end] holds the raw bytes of the current token. + // buf[raw.end:] is buffered input that will yield future tokens. + raw span + buf []byte + // buf[data.start:data.end] holds the raw bytes of the current token's data: + // a text token's text, a tag token's tag name, etc. + data span + // pendingAttr is the attribute key and value currently being tokenized. + // When complete, pendingAttr is pushed onto attr. nAttrReturned is + // incremented on each call to TagAttr. + pendingAttr [2]span + attr [][2]span + nAttrReturned int + // rawTag is the "script" in "</script>" that closes the next token. If + // non-empty, the subsequent call to Next will return a raw or RCDATA text + // token: one that treats "<p>" as text instead of an element. + // rawTag's contents are lower-cased. + rawTag string + // textIsRaw is whether the current text token's data is not escaped. + textIsRaw bool +} + +// Err returns the error associated with the most recent ErrorToken token. +// This is typically io.EOF, meaning the end of tokenization. +func (z *Tokenizer) Err() error { + if z.tt != ErrorToken { + return nil + } + return z.err +} + +// readByte returns the next byte from the input stream, doing a buffered read +// from z.r into z.buf if necessary. z.buf[z.raw.start:z.raw.end] remains a contiguous byte +// slice that holds all the bytes read so far for the current token. +// It sets z.err if the underlying reader returns an error. +// Pre-condition: z.err == nil. +func (z *Tokenizer) readByte() byte { + if z.raw.end >= len(z.buf) { + // Our buffer is exhausted and we have to read from z.r. + // We copy z.buf[z.raw.start:z.raw.end] to the beginning of z.buf. If the length + // z.raw.end - z.raw.start is more than half the capacity of z.buf, then we + // allocate a new buffer before the copy. + c := cap(z.buf) + d := z.raw.end - z.raw.start + var buf1 []byte + if 2*d > c { + buf1 = make([]byte, d, 2*c) + } else { + buf1 = z.buf[:d] + } + copy(buf1, z.buf[z.raw.start:z.raw.end]) + if x := z.raw.start; x != 0 { + // Adjust the data/attr spans to refer to the same contents after the copy. + z.data.start -= x + z.data.end -= x + z.pendingAttr[0].start -= x + z.pendingAttr[0].end -= x + z.pendingAttr[1].start -= x + z.pendingAttr[1].end -= x + for i := range z.attr { + z.attr[i][0].start -= x + z.attr[i][0].end -= x + z.attr[i][1].start -= x + z.attr[i][1].end -= x + } + } + z.raw.start, z.raw.end, z.buf = 0, d, buf1[:d] + // Now that we have copied the live bytes to the start of the buffer, + // we read from z.r into the remainder. + n, err := z.r.Read(buf1[d:cap(buf1)]) + if err != nil { + z.err = err + return 0 + } + z.buf = buf1[:d+n] + } + x := z.buf[z.raw.end] + z.raw.end++ + return x +} + +// skipWhiteSpace skips past any white space. +func (z *Tokenizer) skipWhiteSpace() { + if z.err != nil { + return + } + for { + c := z.readByte() + if z.err != nil { + return + } + switch c { + case ' ', '\n', '\r', '\t', '\f': + // No-op. + default: + z.raw.end-- + return + } + } +} + +// readRawOrRCDATA reads until the next "</foo>", where "foo" is z.rawTag and +// is typically something like "script" or "textarea". +func (z *Tokenizer) readRawOrRCDATA() { +loop: + for { + c := z.readByte() + if z.err != nil { + break loop + } + if c != '<' { + continue loop + } + c = z.readByte() + if z.err != nil { + break loop + } + if c != '/' { + continue loop + } + for i := 0; i < len(z.rawTag); i++ { + c = z.readByte() + if z.err != nil { + break loop + } + if c != z.rawTag[i] && c != z.rawTag[i]-('a'-'A') { + continue loop + } + } + c = z.readByte() + if z.err != nil { + break loop + } + switch c { + case ' ', '\n', '\r', '\t', '\f', '/', '>': + // The 3 is 2 for the leading "</" plus 1 for the trailing character c. + z.raw.end -= 3 + len(z.rawTag) + break loop + case '<': + // Step back one, to catch "</foo</foo>". + z.raw.end-- + } + } + z.data.end = z.raw.end + // A textarea's or title's RCDATA can contain escaped entities. + z.textIsRaw = z.rawTag != "textarea" && z.rawTag != "title" + z.rawTag = "" +} + +// readComment reads the next comment token starting with "<!--". The opening +// "<!--" has already been consumed. +func (z *Tokenizer) readComment() { + z.data.start = z.raw.end + defer func() { + if z.data.end < z.data.start { + // It's a comment with no data, like <!-->. + z.data.end = z.data.start + } + }() + for dashCount := 2; ; { + c := z.readByte() + if z.err != nil { + // Ignore up to two dashes at EOF. + if dashCount > 2 { + dashCount = 2 + } + z.data.end = z.raw.end - dashCount + return + } + switch c { + case '-': + dashCount++ + continue + case '>': + if dashCount >= 2 { + z.data.end = z.raw.end - len("-->") + return + } + case '!': + if dashCount >= 2 { + c = z.readByte() + if z.err != nil { + z.data.end = z.raw.end + return + } + if c == '>' { + z.data.end = z.raw.end - len("--!>") + return + } + } + } + dashCount = 0 + } +} + +// readUntilCloseAngle reads until the next ">". +func (z *Tokenizer) readUntilCloseAngle() { + z.data.start = z.raw.end + for { + c := z.readByte() + if z.err != nil { + z.data.end = z.raw.end + return + } + if c == '>' { + z.data.end = z.raw.end - len(">") + return + } + } +} + +// readMarkupDeclaration reads the next token starting with "<!". It might be +// a "<!--comment-->", a "<!DOCTYPE foo>", or "<!a bogus comment". The opening +// "<!" has already been consumed. +func (z *Tokenizer) readMarkupDeclaration() TokenType { + z.data.start = z.raw.end + var c [2]byte + for i := 0; i < 2; i++ { + c[i] = z.readByte() + if z.err != nil { + z.data.end = z.raw.end + return CommentToken + } + } + if c[0] == '-' && c[1] == '-' { + z.readComment() + return CommentToken + } + z.raw.end -= 2 + const s = "DOCTYPE" + for i := 0; i < len(s); i++ { + c := z.readByte() + if z.err != nil { + z.data.end = z.raw.end + return CommentToken + } + if c != s[i] && c != s[i]+('a'-'A') { + // Back up to read the fragment of "DOCTYPE" again. + z.raw.end = z.data.start + z.readUntilCloseAngle() + return CommentToken + } + } + if z.skipWhiteSpace(); z.err != nil { + z.data.start = z.raw.end + z.data.end = z.raw.end + return DoctypeToken + } + z.readUntilCloseAngle() + return DoctypeToken +} + +// startTagIn returns whether the start tag in z.buf[z.data.start:z.data.end] +// case-insensitively matches any element of ss. +func (z *Tokenizer) startTagIn(ss ...string) bool { +loop: + for _, s := range ss { + if z.data.end-z.data.start != len(s) { + continue loop + } + for i := 0; i < len(s); i++ { + c := z.buf[z.data.start+i] + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + if c != s[i] { + continue loop + } + } + return true + } + return false +} + +// readStartTag reads the next start tag token. The opening "<a" has already +// been consumed, where 'a' means anything in [A-Za-z]. +func (z *Tokenizer) readStartTag() TokenType { + z.attr = z.attr[:0] + z.nAttrReturned = 0 + // Read the tag name and attribute key/value pairs. + z.readTagName() + if z.skipWhiteSpace(); z.err != nil { + return ErrorToken + } + for { + c := z.readByte() + if z.err != nil || c == '>' { + break + } + z.raw.end-- + z.readTagAttrKey() + z.readTagAttrVal() + // Save pendingAttr if it has a non-empty key. + if z.pendingAttr[0].start != z.pendingAttr[0].end { + z.attr = append(z.attr, z.pendingAttr) + } + if z.skipWhiteSpace(); z.err != nil { + break + } + } + // Several tags flag the tokenizer's next token as raw. + c, raw := z.buf[z.data.start], false + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + switch c { + case 'i': + raw = z.startTagIn("iframe") + case 'n': + raw = z.startTagIn("noembed", "noframes", "noscript") + case 'p': + raw = z.startTagIn("plaintext") + case 's': + raw = z.startTagIn("script", "style") + case 't': + raw = z.startTagIn("textarea", "title") + case 'x': + raw = z.startTagIn("xmp") + } + if raw { + z.rawTag = strings.ToLower(string(z.buf[z.data.start:z.data.end])) + } + // Look for a self-closing token like "<br/>". + if z.err == nil && z.buf[z.raw.end-2] == '/' { + return SelfClosingTagToken + } + return StartTagToken +} + +// readEndTag reads the next end tag token. The opening "</a" has already +// been consumed, where 'a' means anything in [A-Za-z]. +func (z *Tokenizer) readEndTag() { + z.attr = z.attr[:0] + z.nAttrReturned = 0 + z.readTagName() + for { + c := z.readByte() + if z.err != nil || c == '>' { + return + } + } +} + +// readTagName sets z.data to the "div" in "<div k=v>". The reader (z.raw.end) +// is positioned such that the first byte of the tag name (the "d" in "<div") +// has already been consumed. +func (z *Tokenizer) readTagName() { + z.data.start = z.raw.end - 1 + for { + c := z.readByte() + if z.err != nil { + z.data.end = z.raw.end + return + } + switch c { + case ' ', '\n', '\r', '\t', '\f': + z.data.end = z.raw.end - 1 + return + case '/', '>': + z.raw.end-- + z.data.end = z.raw.end + return + } + } +} + +// readTagAttrKey sets z.pendingAttr[0] to the "k" in "<div k=v>". +// Precondition: z.err == nil. +func (z *Tokenizer) readTagAttrKey() { + z.pendingAttr[0].start = z.raw.end + for { + c := z.readByte() + if z.err != nil { + z.pendingAttr[0].end = z.raw.end + return + } + switch c { + case ' ', '\n', '\r', '\t', '\f', '/': + z.pendingAttr[0].end = z.raw.end - 1 + return + case '=', '>': + z.raw.end-- + z.pendingAttr[0].end = z.raw.end + return + } + } +} + +// readTagAttrVal sets z.pendingAttr[1] to the "v" in "<div k=v>". +func (z *Tokenizer) readTagAttrVal() { + z.pendingAttr[1].start = z.raw.end + z.pendingAttr[1].end = z.raw.end + if z.skipWhiteSpace(); z.err != nil { + return + } + c := z.readByte() + if z.err != nil { + return + } + if c != '=' { + z.raw.end-- + return + } + if z.skipWhiteSpace(); z.err != nil { + return + } + quote := z.readByte() + if z.err != nil { + return + } + switch quote { + case '>': + z.raw.end-- + return + + case '\'', '"': + z.pendingAttr[1].start = z.raw.end + for { + c := z.readByte() + if z.err != nil { + z.pendingAttr[1].end = z.raw.end + return + } + if c == quote { + z.pendingAttr[1].end = z.raw.end - 1 + return + } + } + + default: + z.pendingAttr[1].start = z.raw.end - 1 + for { + c := z.readByte() + if z.err != nil { + z.pendingAttr[1].end = z.raw.end + return + } + switch c { + case ' ', '\n', '\r', '\t', '\f': + z.pendingAttr[1].end = z.raw.end - 1 + return + case '>': + z.raw.end-- + z.pendingAttr[1].end = z.raw.end + return + } + } + } +} + +// Next scans the next token and returns its type. +func (z *Tokenizer) Next() TokenType { + if z.err != nil { + z.tt = ErrorToken + return z.tt + } + z.raw.start = z.raw.end + z.data.start = z.raw.end + z.data.end = z.raw.end + if z.rawTag != "" { + if z.rawTag == "plaintext" { + // Read everything up to EOF. + for z.err == nil { + z.readByte() + } + z.textIsRaw = true + } else { + z.readRawOrRCDATA() + } + if z.data.end > z.data.start { + z.tt = TextToken + return z.tt + } + } + z.textIsRaw = false + +loop: + for { + c := z.readByte() + if z.err != nil { + break loop + } + if c != '<' { + continue loop + } + + // Check if the '<' we have just read is part of a tag, comment + // or doctype. If not, it's part of the accumulated text token. + c = z.readByte() + if z.err != nil { + break loop + } + var tokenType TokenType + switch { + case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': + tokenType = StartTagToken + case c == '/': + tokenType = EndTagToken + case c == '!' || c == '?': + // We use CommentToken to mean any of "<!--actual comments-->", + // "<!DOCTYPE declarations>" and "<?xml processing instructions?>". + tokenType = CommentToken + default: + continue + } + + // We have a non-text token, but we might have accumulated some text + // before that. If so, we return the text first, and return the non- + // text token on the subsequent call to Next. + if x := z.raw.end - len("<a"); z.raw.start < x { + z.raw.end = x + z.data.end = x + z.tt = TextToken + return z.tt + } + switch tokenType { + case StartTagToken: + z.tt = z.readStartTag() + return z.tt + case EndTagToken: + c = z.readByte() + if z.err != nil { + break loop + } + if c == '>' { + // "</>" does not generate a token at all. + // Reset the tokenizer state and start again. + z.raw.start = z.raw.end + z.data.start = z.raw.end + z.data.end = z.raw.end + continue loop + } + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' { + z.readEndTag() + z.tt = EndTagToken + return z.tt + } + z.raw.end-- + z.readUntilCloseAngle() + z.tt = CommentToken + return z.tt + case CommentToken: + if c == '!' { + z.tt = z.readMarkupDeclaration() + return z.tt + } + z.raw.end-- + z.readUntilCloseAngle() + z.tt = CommentToken + return z.tt + } + } + if z.raw.start < z.raw.end { + z.data.end = z.raw.end + z.tt = TextToken + return z.tt + } + z.tt = ErrorToken + return z.tt +} + +// Raw returns the unmodified text of the current token. Calling Next, Token, +// Text, TagName or TagAttr may change the contents of the returned slice. +func (z *Tokenizer) Raw() []byte { + return z.buf[z.raw.start:z.raw.end] +} + +// Text returns the unescaped text of a text, comment or doctype token. The +// contents of the returned slice may change on the next call to Next. +func (z *Tokenizer) Text() []byte { + switch z.tt { + case TextToken, CommentToken, DoctypeToken: + s := z.buf[z.data.start:z.data.end] + z.data.start = z.raw.end + z.data.end = z.raw.end + if !z.textIsRaw { + s = unescape(s) + } + return s + } + return nil +} + +// TagName returns the lower-cased name of a tag token (the `img` out of +// `<IMG SRC="foo">`) and whether the tag has attributes. +// The contents of the returned slice may change on the next call to Next. +func (z *Tokenizer) TagName() (name []byte, hasAttr bool) { + if z.data.start < z.data.end { + switch z.tt { + case StartTagToken, EndTagToken, SelfClosingTagToken: + s := z.buf[z.data.start:z.data.end] + z.data.start = z.raw.end + z.data.end = z.raw.end + return lower(s), z.nAttrReturned < len(z.attr) + } + } + return nil, false +} + +// TagAttr returns the lower-cased key and unescaped value of the next unparsed +// attribute for the current tag token and whether there are more attributes. +// The contents of the returned slices may change on the next call to Next. +func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) { + if z.nAttrReturned < len(z.attr) { + switch z.tt { + case StartTagToken, SelfClosingTagToken: + x := z.attr[z.nAttrReturned] + z.nAttrReturned++ + key = z.buf[x[0].start:x[0].end] + val = z.buf[x[1].start:x[1].end] + return lower(key), unescape(val), z.nAttrReturned < len(z.attr) + } + } + return nil, nil, false +} + +// Token returns the next Token. The result's Data and Attr values remain valid +// after subsequent Next calls. +func (z *Tokenizer) Token() Token { + t := Token{Type: z.tt} + switch z.tt { + case TextToken, CommentToken, DoctypeToken: + t.Data = string(z.Text()) + case StartTagToken, SelfClosingTagToken: + var attr []Attribute + name, moreAttr := z.TagName() + for moreAttr { + var key, val []byte + key, val, moreAttr = z.TagAttr() + attr = append(attr, Attribute{"", string(key), string(val)}) + } + t.Data = string(name) + t.Attr = attr + case EndTagToken: + name, _ := z.TagName() + t.Data = string(name) + } + return t +} + +// NewTokenizer returns a new HTML Tokenizer for the given Reader. +// The input is assumed to be UTF-8 encoded. +func NewTokenizer(r io.Reader) *Tokenizer { + return &Tokenizer{ + r: r, + buf: make([]byte, 0, 4096), + } +} diff --git a/libgo/go/exp/html/token_test.go b/libgo/go/exp/html/token_test.go new file mode 100644 index 00000000000..672d60c4209 --- /dev/null +++ b/libgo/go/exp/html/token_test.go @@ -0,0 +1,590 @@ +// Copyright 2010 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 html + +import ( + "bytes" + "io" + "strings" + "testing" +) + +type tokenTest struct { + // A short description of the test case. + desc string + // The HTML to parse. + html string + // The string representations of the expected tokens, joined by '$'. + golden string +} + +var tokenTests = []tokenTest{ + { + "empty", + "", + "", + }, + // A single text node. The tokenizer should not break text nodes on whitespace, + // nor should it normalize whitespace within a text node. + { + "text", + "foo bar", + "foo bar", + }, + // An entity. + { + "entity", + "one < two", + "one < two", + }, + // A start, self-closing and end tag. The tokenizer does not care if the start + // and end tokens don't match; that is the job of the parser. + { + "tags", + "<a>b<c/>d</e>", + "<a>$b$<c/>$d$</e>", + }, + // Angle brackets that aren't a tag. + { + "not a tag #0", + "<", + "<", + }, + { + "not a tag #1", + "</", + "</", + }, + { + "not a tag #2", + "</>", + "", + }, + { + "not a tag #3", + "a</>b", + "a$b", + }, + { + "not a tag #4", + "</ >", + "<!-- -->", + }, + { + "not a tag #5", + "</.", + "<!--.-->", + }, + { + "not a tag #6", + "</.>", + "<!--.-->", + }, + { + "not a tag #7", + "a < b", + "a < b", + }, + { + "not a tag #8", + "<.>", + "<.>", + }, + { + "not a tag #9", + "a<<<b>>>c", + "a<<$<b>$>>c", + }, + { + "not a tag #10", + "if x<0 and y < 0 then x*y>0", + "if x<0 and y < 0 then x*y>0", + }, + // EOF in a tag name. + { + "tag name eof #0", + "<a", + "", + }, + { + "tag name eof #1", + "<a ", + "", + }, + { + "tag name eof #2", + "a<b", + "a", + }, + { + "tag name eof #3", + "<a><b", + "<a>", + }, + { + "tag name eof #4", + `<a x`, + `<a x="">`, + }, + // Some malformed tags that are missing a '>'. + { + "malformed tag #0", + `<p</p>`, + `<p< p="">`, + }, + { + "malformed tag #1", + `<p </p>`, + `<p <="" p="">`, + }, + { + "malformed tag #2", + `<p id`, + `<p id="">`, + }, + { + "malformed tag #3", + `<p id=`, + `<p id="">`, + }, + { + "malformed tag #4", + `<p id=>`, + `<p id="">`, + }, + { + "malformed tag #5", + `<p id=0`, + `<p id="0">`, + }, + { + "malformed tag #6", + `<p id=0</p>`, + `<p id="0</p">`, + }, + { + "malformed tag #7", + `<p id="0</p>`, + `<p id="0</p>">`, + }, + { + "malformed tag #8", + `<p id="0"</p>`, + `<p id="0" <="" p="">`, + }, + // Raw text and RCDATA. + { + "basic raw text", + "<script><a></b></script>", + "<script>$<a></b>$</script>", + }, + { + "unfinished script end tag", + "<SCRIPT>a</SCR", + "<script>$a</SCR", + }, + { + "broken script end tag", + "<SCRIPT>a</SCR ipt>", + "<script>$a</SCR ipt>", + }, + { + "EOF in script end tag", + "<SCRIPT>a</SCRipt", + "<script>$a</SCRipt", + }, + { + "scriptx end tag", + "<SCRIPT>a</SCRiptx", + "<script>$a</SCRiptx", + }, + { + "' ' completes script end tag", + "<SCRIPT>a</SCRipt ", + "<script>$a$</script>", + }, + { + "'>' completes script end tag", + "<SCRIPT>a</SCRipt>", + "<script>$a$</script>", + }, + { + "self-closing script end tag", + "<SCRIPT>a</SCRipt/>", + "<script>$a$</script>", + }, + { + "nested script tag", + "<SCRIPT>a</SCRipt<script>", + "<script>$a</SCRipt<script>", + }, + { + "script end tag after unfinished", + "<SCRIPT>a</SCRipt</script>", + "<script>$a</SCRipt$</script>", + }, + { + "script/style mismatched tags", + "<script>a</style>", + "<script>$a</style>", + }, + { + "style element with entity", + "<style>'", + "<style>$&apos;", + }, + { + "textarea with tag", + "<textarea><div></textarea>", + "<textarea>$<div>$</textarea>", + }, + { + "title with tag and entity", + "<title><b>K&R C</b></title>", + "<title>$<b>K&R C</b>$</title>", + }, + // DOCTYPE tests. + { + "Proper DOCTYPE", + "<!DOCTYPE html>", + "<!DOCTYPE html>", + }, + { + "DOCTYPE with no space", + "<!doctypehtml>", + "<!DOCTYPE html>", + }, + { + "DOCTYPE with two spaces", + "<!doctype html>", + "<!DOCTYPE html>", + }, + { + "looks like DOCTYPE but isn't", + "<!DOCUMENT html>", + "<!--DOCUMENT html-->", + }, + { + "DOCTYPE at EOF", + "<!DOCtype", + "<!DOCTYPE >", + }, + // XML processing instructions. + { + "XML processing instruction", + "<?xml?>", + "<!--?xml?-->", + }, + // Comments. + { + "comment0", + "abc<b><!-- skipme --></b>def", + "abc$<b>$<!-- skipme -->$</b>$def", + }, + { + "comment1", + "a<!-->z", + "a$<!---->$z", + }, + { + "comment2", + "a<!--->z", + "a$<!---->$z", + }, + { + "comment3", + "a<!--x>-->z", + "a$<!--x>-->$z", + }, + { + "comment4", + "a<!--x->-->z", + "a$<!--x->-->$z", + }, + { + "comment5", + "a<!>z", + "a$<!---->$z", + }, + { + "comment6", + "a<!->z", + "a$<!----->$z", + }, + { + "comment7", + "a<!---<>z", + "a$<!---<>z-->", + }, + { + "comment8", + "a<!--z", + "a$<!--z-->", + }, + { + "comment9", + "a<!--z-", + "a$<!--z-->", + }, + { + "comment10", + "a<!--z--", + "a$<!--z-->", + }, + { + "comment11", + "a<!--z---", + "a$<!--z--->", + }, + { + "comment12", + "a<!--z----", + "a$<!--z---->", + }, + { + "comment13", + "a<!--x--!>z", + "a$<!--x-->$z", + }, + // An attribute with a backslash. + { + "backslash", + `<p id="a\"b">`, + `<p id="a\" b"="">`, + }, + // Entities, tag name and attribute key lower-casing, and whitespace + // normalization within a tag. + { + "tricky", + "<p \t\n iD=\"a"B\" foo=\"bar\"><EM>te<&;xt</em></p>", + `<p id="a"B" foo="bar">$<em>$te<&;xt$</em>$</p>`, + }, + // A nonexistent entity. Tokenizing and converting back to a string should + // escape the "&" to become "&". + { + "noSuchEntity", + `<a b="c&noSuchEntity;d"><&alsoDoesntExist;&`, + `<a b="c&noSuchEntity;d">$<&alsoDoesntExist;&`, + }, + /* + // TODO: re-enable this test when it works. This input/output matches html5lib's behavior. + { + "entity without semicolon", + `¬it;∉<a b="q=z&=5¬ice=hello¬=world">`, + `¬it;∉$<a b="q=z&amp=5&notice=hello¬=world">`, + }, + */ + { + "entity with digits", + "½", + "½", + }, + // Attribute tests: + // http://dev.w3.org/html5/spec/Overview.html#attributes-0 + { + "Empty attribute", + `<input disabled FOO>`, + `<input disabled="" foo="">`, + }, + { + "Empty attribute, whitespace", + `<input disabled FOO >`, + `<input disabled="" foo="">`, + }, + { + "Unquoted attribute value", + `<input value=yes FOO=BAR>`, + `<input value="yes" foo="BAR">`, + }, + { + "Unquoted attribute value, spaces", + `<input value = yes FOO = BAR>`, + `<input value="yes" foo="BAR">`, + }, + { + "Unquoted attribute value, trailing space", + `<input value=yes FOO=BAR >`, + `<input value="yes" foo="BAR">`, + }, + { + "Single-quoted attribute value", + `<input value='yes' FOO='BAR'>`, + `<input value="yes" foo="BAR">`, + }, + { + "Single-quoted attribute value, trailing space", + `<input value='yes' FOO='BAR' >`, + `<input value="yes" foo="BAR">`, + }, + { + "Double-quoted attribute value", + `<input value="I'm an attribute" FOO="BAR">`, + `<input value="I'm an attribute" foo="BAR">`, + }, + { + "Attribute name characters", + `<meta http-equiv="content-type">`, + `<meta http-equiv="content-type">`, + }, + { + "Mixed attributes", + `a<P V="0 1" w='2' X=3 y>z`, + `a$<p v="0 1" w="2" x="3" y="">$z`, + }, + { + "Attributes with a solitary single quote", + `<p id=can't><p id=won't>`, + `<p id="can't">$<p id="won't">`, + }, +} + +func TestTokenizer(t *testing.T) { +loop: + for _, tt := range tokenTests { + z := NewTokenizer(strings.NewReader(tt.html)) + if tt.golden != "" { + for i, s := range strings.Split(tt.golden, "$") { + if z.Next() == ErrorToken { + t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Err()) + continue loop + } + actual := z.Token().String() + if s != actual { + t.Errorf("%s token %d: want %q got %q", tt.desc, i, s, actual) + continue loop + } + } + } + z.Next() + if z.Err() != io.EOF { + t.Errorf("%s: want EOF got %q", tt.desc, z.Err()) + } + } +} + +type unescapeTest struct { + // A short description of the test case. + desc string + // The HTML text. + html string + // The unescaped text. + unescaped string +} + +var unescapeTests = []unescapeTest{ + // Handle no entities. + { + "copy", + "A\ttext\nstring", + "A\ttext\nstring", + }, + // Handle simple named entities. + { + "simple", + "& > <", + "& > <", + }, + // Handle hitting the end of the string. + { + "stringEnd", + "& &", + "& &", + }, + // Handle entities with two codepoints. + { + "multiCodepoint", + "text ⋛︀ blah", + "text \u22db\ufe00 blah", + }, + // Handle decimal numeric entities. + { + "decimalEntity", + "Delta = Δ ", + "Delta = Δ ", + }, + // Handle hexadecimal numeric entities. + { + "hexadecimalEntity", + "Lambda = λ = λ ", + "Lambda = λ = λ ", + }, + // Handle numeric early termination. + { + "numericEnds", + "&# &#x €43 © = ©f = ©", + "&# &#x €43 © = ©f = ©", + }, + // Handle numeric ISO-8859-1 entity replacements. + { + "numericReplacements", + "Footnote‡", + "Footnote‡", + }, +} + +func TestUnescape(t *testing.T) { + for _, tt := range unescapeTests { + unescaped := UnescapeString(tt.html) + if unescaped != tt.unescaped { + t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped) + } + } +} + +func TestUnescapeEscape(t *testing.T) { + ss := []string{ + ``, + `abc def`, + `a & b`, + `a&b`, + `a & b`, + `"`, + `"`, + `"<&>"`, + `"<&>"`, + `3&5==1 && 0<1, "0<1", a+acute=á`, + } + for _, s := range ss { + if s != UnescapeString(EscapeString(s)) { + t.Errorf("s != UnescapeString(EscapeString(s)), s=%q", s) + } + } +} + +func TestBufAPI(t *testing.T) { + s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9" + z := NewTokenizer(bytes.NewBuffer([]byte(s))) + result := bytes.NewBuffer(nil) + depth := 0 +loop: + for { + tt := z.Next() + switch tt { + case ErrorToken: + if z.Err() != io.EOF { + t.Error(z.Err()) + } + break loop + case TextToken: + if depth > 0 { + result.Write(z.Text()) + } + case StartTagToken, EndTagToken: + tn, _ := z.TagName() + if len(tn) == 1 && tn[0] == 'a' { + if tt == StartTagToken { + depth++ + } else { + depth-- + } + } + } + } + u := "14567" + v := string(result.Bytes()) + if u != v { + t.Errorf("TestBufAPI: want %q got %q", u, v) + } +} diff --git a/libgo/go/exp/norm/tables.go b/libgo/go/exp/norm/tables.go index 55ff052dcbc..9044a72fd47 100644 --- a/libgo/go/exp/norm/tables.go +++ b/libgo/go/exp/norm/tables.go @@ -2804,12 +2804,12 @@ var nfcDecompSparseValues = [341]valueRange{ {value: 0x0005, lo: 0x01}, {value: 0x068d, lo: 0xa2, hi: 0xa6}, // Block 0xc, offset 0xd - {value: 0x0005, lo: 0x03}, + {value: 0x0000, lo: 0x03}, {value: 0x06ba, lo: 0x80, hi: 0x80}, {value: 0x06bf, lo: 0x82, hi: 0x82}, {value: 0x06c4, lo: 0x93, hi: 0x93}, // Block 0xd, offset 0xe - {value: 0x0007, lo: 0x03}, + {value: 0x0000, lo: 0x03}, {value: 0x06c9, lo: 0xa9, hi: 0xa9}, {value: 0x06d0, lo: 0xb1, hi: 0xb1}, {value: 0x06d7, lo: 0xb4, hi: 0xb4}, @@ -2822,7 +2822,7 @@ var nfcDecompSparseValues = [341]valueRange{ {value: 0x0724, lo: 0x9c, hi: 0x9d}, {value: 0x0732, lo: 0x9f, hi: 0x9f}, // Block 0x10, offset 0x11 - {value: 0x0007, lo: 0x02}, + {value: 0x0000, lo: 0x02}, {value: 0x0739, lo: 0xb3, hi: 0xb3}, {value: 0x0740, lo: 0xb6, hi: 0xb6}, // Block 0x11, offset 0x12 @@ -2868,7 +2868,7 @@ var nfcDecompSparseValues = [341]valueRange{ {value: 0x0854, lo: 0xb5, hi: 0xb6}, {value: 0x086c, lo: 0xb8, hi: 0xb8}, // Block 0x1a, offset 0x1b - {value: 0x0007, lo: 0x07}, + {value: 0x0000, lo: 0x07}, {value: 0x087d, lo: 0x81, hi: 0x81}, {value: 0x0884, lo: 0x93, hi: 0x93}, {value: 0x088b, lo: 0x9d, hi: 0x9d}, @@ -2880,7 +2880,7 @@ var nfcDecompSparseValues = [341]valueRange{ {value: 0x0000, lo: 0x01}, {value: 0x08ae, lo: 0xa6, hi: 0xa6}, // Block 0x1c, offset 0x1d - {value: 0x0007, lo: 0x08}, + {value: 0x0000, lo: 0x08}, {value: 0x08b9, lo: 0x86, hi: 0x86}, {value: 0x08c0, lo: 0x88, hi: 0x88}, {value: 0x08c7, lo: 0x8a, hi: 0x8a}, @@ -2924,7 +2924,7 @@ var nfcDecompSparseValues = [341]valueRange{ {value: 0x0006, lo: 0x01}, {value: 0x15b1, lo: 0x8d, hi: 0x8f}, // Block 0x23, offset 0x24 - {value: 0x0006, lo: 0x05}, + {value: 0x0000, lo: 0x05}, {value: 0x15c3, lo: 0x84, hi: 0x84}, {value: 0x15c9, lo: 0x89, hi: 0x89}, {value: 0x15cf, lo: 0x8c, hi: 0x8c}, @@ -2960,7 +2960,7 @@ var nfcDecompSparseValues = [341]valueRange{ {value: 0x0000, lo: 0x01}, {value: 0x1814, lo: 0x9c, hi: 0x9c}, // Block 0x29, offset 0x2a - {value: 0x0007, lo: 0x0c}, + {value: 0x0000, lo: 0x0c}, {value: 0x1c39, lo: 0x94, hi: 0x94}, {value: 0x1c4a, lo: 0x9e, hi: 0x9e}, {value: 0x1c58, lo: 0xac, hi: 0xac}, @@ -3084,7 +3084,7 @@ var nfcDecompSparseValues = [341]valueRange{ {value: 0x3191, lo: 0x83, hi: 0x84}, {value: 0x319b, lo: 0x86, hi: 0x8e}, // Block 0x33, offset 0x34 - {value: 0x0009, lo: 0x03}, + {value: 0x0000, lo: 0x03}, {value: 0x3a73, lo: 0x9a, hi: 0x9a}, {value: 0x3a7c, lo: 0x9c, hi: 0x9c}, {value: 0x3a85, lo: 0xab, hi: 0xab}, @@ -3897,10 +3897,10 @@ var nfkcDecompValues = [4224]uint16{ } // nfkcDecompSparseOffset: 93 entries, 186 bytes -var nfkcDecompSparseOffset = []uint16{0x0, 0xc, 0x16, 0x1e, 0x24, 0x27, 0x31, 0x37, 0x3e, 0x44, 0x4c, 0x59, 0x60, 0x66, 0x6e, 0x70, 0x72, 0x74, 0x78, 0x7c, 0x7e, 0x82, 0x85, 0x88, 0x8c, 0x8e, 0x90, 0x92, 0x96, 0x98, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xae, 0xb6, 0xb8, 0xba, 0xc3, 0xc6, 0xcd, 0xd8, 0xe6, 0xf4, 0xfe, 0x102, 0x104, 0x10e, 0x11a, 0x11f, 0x122, 0x124, 0x126, 0x129, 0x12b, 0x12d, 0x12f, 0x131, 0x133, 0x135, 0x137, 0x139, 0x13b, 0x140, 0x14f, 0x15d, 0x15f, 0x161, 0x169, 0x179, 0x17b, 0x186, 0x18d, 0x198, 0x1a4, 0x1b5, 0x1c6, 0x1cd, 0x1de, 0x1ec, 0x1fa, 0x209, 0x21a, 0x21f, 0x22c, 0x230, 0x234, 0x238, 0x23a, 0x249, 0x24b, 0x24f} +var nfkcDecompSparseOffset = []uint16{0x0, 0xc, 0x16, 0x1e, 0x24, 0x27, 0x31, 0x37, 0x3e, 0x44, 0x4c, 0x59, 0x60, 0x66, 0x6e, 0x70, 0x72, 0x74, 0x78, 0x7c, 0x7e, 0x82, 0x85, 0x88, 0x8c, 0x8e, 0x90, 0x92, 0x96, 0x98, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xae, 0xb6, 0xb8, 0xba, 0xc3, 0xc6, 0xcd, 0xd8, 0xe6, 0xf4, 0xfe, 0x102, 0x104, 0x10c, 0x118, 0x11d, 0x120, 0x122, 0x124, 0x127, 0x129, 0x12b, 0x12d, 0x12f, 0x131, 0x133, 0x135, 0x137, 0x139, 0x13e, 0x14d, 0x15b, 0x15d, 0x15f, 0x167, 0x177, 0x179, 0x184, 0x18b, 0x196, 0x1a2, 0x1b3, 0x1c4, 0x1cb, 0x1dc, 0x1ea, 0x1f8, 0x207, 0x218, 0x21d, 0x22a, 0x22e, 0x232, 0x236, 0x238, 0x247, 0x249, 0x24d} -// nfkcDecompSparseValues: 605 entries, 2420 bytes -var nfkcDecompSparseValues = [605]valueRange{ +// nfkcDecompSparseValues: 603 entries, 2412 bytes +var nfkcDecompSparseValues = [603]valueRange{ // Block 0x0, offset 0x1 {value: 0x0002, lo: 0x0b}, {value: 0x0001, lo: 0xa0, hi: 0xa0}, @@ -4035,12 +4035,12 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x0005, lo: 0x01}, {value: 0x06a6, lo: 0xb5, hi: 0xb8}, // Block 0x11, offset 0x12 - {value: 0x0005, lo: 0x03}, + {value: 0x0000, lo: 0x03}, {value: 0x06ba, lo: 0x80, hi: 0x80}, {value: 0x06bf, lo: 0x82, hi: 0x82}, {value: 0x06c4, lo: 0x93, hi: 0x93}, // Block 0x12, offset 0x13 - {value: 0x0007, lo: 0x03}, + {value: 0x0000, lo: 0x03}, {value: 0x06c9, lo: 0xa9, hi: 0xa9}, {value: 0x06d0, lo: 0xb1, hi: 0xb1}, {value: 0x06d7, lo: 0xb4, hi: 0xb4}, @@ -4053,7 +4053,7 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x0724, lo: 0x9c, hi: 0x9d}, {value: 0x0732, lo: 0x9f, hi: 0x9f}, // Block 0x15, offset 0x16 - {value: 0x0007, lo: 0x02}, + {value: 0x0000, lo: 0x02}, {value: 0x0739, lo: 0xb3, hi: 0xb3}, {value: 0x0740, lo: 0xb6, hi: 0xb6}, // Block 0x16, offset 0x17 @@ -4111,7 +4111,7 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x0854, lo: 0xb5, hi: 0xb7}, {value: 0x086c, lo: 0xb8, hi: 0xb9}, // Block 0x23, offset 0x24 - {value: 0x0007, lo: 0x07}, + {value: 0x0000, lo: 0x07}, {value: 0x087d, lo: 0x81, hi: 0x81}, {value: 0x0884, lo: 0x93, hi: 0x93}, {value: 0x088b, lo: 0x9d, hi: 0x9d}, @@ -4126,7 +4126,7 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x0000, lo: 0x01}, {value: 0x08b5, lo: 0xbc, hi: 0xbc}, // Block 0x26, offset 0x27 - {value: 0x0007, lo: 0x08}, + {value: 0x0000, lo: 0x08}, {value: 0x08b9, lo: 0x86, hi: 0x86}, {value: 0x08c0, lo: 0x88, hi: 0x88}, {value: 0x08c7, lo: 0x8a, hi: 0x8a}, @@ -4209,16 +4209,14 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x0006, lo: 0x01}, {value: 0x15b1, lo: 0x8d, hi: 0x8f}, // Block 0x2f, offset 0x30 - {value: 0x0006, lo: 0x09}, + {value: 0x0007, lo: 0x07}, {value: 0x15c3, lo: 0x84, hi: 0x84}, {value: 0x15c9, lo: 0x89, hi: 0x89}, {value: 0x15cf, lo: 0x8c, hi: 0x8c}, {value: 0x15d5, lo: 0xa4, hi: 0xa4}, {value: 0x15db, lo: 0xa6, hi: 0xa6}, - {value: 0x15e1, lo: 0xac, hi: 0xac}, - {value: 0x15e8, lo: 0xad, hi: 0xad}, - {value: 0x15f2, lo: 0xaf, hi: 0xaf}, - {value: 0x15f9, lo: 0xb0, hi: 0xb0}, + {value: 0x15e1, lo: 0xac, hi: 0xad}, + {value: 0x15f2, lo: 0xaf, hi: 0xb0}, // Block 0x30, offset 0x31 {value: 0x0006, lo: 0x0b}, {value: 0x1603, lo: 0x81, hi: 0x81}, @@ -4249,9 +4247,9 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x0000, lo: 0x01}, {value: 0x17fc, lo: 0x8c, hi: 0x8c}, // Block 0x35, offset 0x36 - {value: 0x0004, lo: 0x02}, - {value: 0x1809, lo: 0xb4, hi: 0xb5}, - {value: 0x1810, lo: 0xb6, hi: 0xb6}, + {value: 0x0003, lo: 0x02}, + {value: 0x1809, lo: 0xb4, hi: 0xb4}, + {value: 0x180d, lo: 0xb5, hi: 0xb6}, // Block 0x36, offset 0x37 {value: 0x0000, lo: 0x01}, {value: 0x1814, lo: 0x9c, hi: 0x9c}, @@ -4280,17 +4278,17 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x0004, lo: 0x01}, {value: 0x1b26, lo: 0x80, hi: 0x95}, // Block 0x3f, offset 0x40 - {value: 0x0300, lo: 0x04}, + {value: 0x0004, lo: 0x04}, {value: 0x0001, lo: 0x80, hi: 0x80}, {value: 0x1b7e, lo: 0xb6, hi: 0xb6}, - {value: 0x1882, lo: 0xb8, hi: 0xb9}, - {value: 0x1b86, lo: 0xba, hi: 0xba}, + {value: 0x1882, lo: 0xb8, hi: 0xb8}, + {value: 0x1b82, lo: 0xb9, hi: 0xba}, // Block 0x40, offset 0x41 - {value: 0x0007, lo: 0x0e}, + {value: 0x0005, lo: 0x0e}, {value: 0x1c39, lo: 0x94, hi: 0x94}, - {value: 0x1c40, lo: 0x9b, hi: 0x9b}, - {value: 0x1c45, lo: 0x9c, hi: 0x9c}, - {value: 0x1c4a, lo: 0x9e, hi: 0x9f}, + {value: 0x1c40, lo: 0x9b, hi: 0x9c}, + {value: 0x1c4a, lo: 0x9e, hi: 0x9e}, + {value: 0x1c51, lo: 0x9f, hi: 0x9f}, {value: 0x1c58, lo: 0xac, hi: 0xac}, {value: 0x1c5f, lo: 0xae, hi: 0xae}, {value: 0x1c66, lo: 0xb0, hi: 0xb0}, @@ -4543,7 +4541,7 @@ var nfkcDecompSparseValues = [605]valueRange{ {value: 0x3a53, lo: 0xa6, hi: 0xa6}, {value: 0x3a57, lo: 0xa8, hi: 0xae}, // Block 0x55, offset 0x56 - {value: 0x0009, lo: 0x03}, + {value: 0x0000, lo: 0x03}, {value: 0x3a73, lo: 0x9a, hi: 0x9a}, {value: 0x3a7c, lo: 0x9c, hi: 0x9c}, {value: 0x3a85, lo: 0xab, hi: 0xab}, @@ -5760,10 +5758,10 @@ var charInfoValues = [1024]uint16{ } // charInfoSparseOffset: 156 entries, 312 bytes -var charInfoSparseOffset = []uint16{0x0, 0x8, 0x13, 0x21, 0x25, 0x2f, 0x36, 0x39, 0x3c, 0x4a, 0x56, 0x58, 0x62, 0x67, 0x6e, 0x7d, 0x8a, 0x92, 0x96, 0x9b, 0x9d, 0xa5, 0xab, 0xae, 0xb5, 0xb9, 0xbd, 0xbf, 0xc1, 0xc8, 0xcc, 0xd1, 0xd7, 0xda, 0xe3, 0xe5, 0xed, 0xf1, 0xf3, 0xf6, 0xf9, 0xff, 0x10f, 0x11b, 0x11d, 0x123, 0x125, 0x127, 0x129, 0x12b, 0x12d, 0x12f, 0x131, 0x134, 0x137, 0x139, 0x13c, 0x13f, 0x143, 0x152, 0x15a, 0x15c, 0x15f, 0x161, 0x16a, 0x16e, 0x172, 0x174, 0x183, 0x187, 0x18d, 0x195, 0x199, 0x1a2, 0x1ab, 0x1b6, 0x1bc, 0x1c0, 0x1ce, 0x1dd, 0x1e1, 0x1e8, 0x1ed, 0x1fc, 0x208, 0x20b, 0x20d, 0x20f, 0x211, 0x213, 0x215, 0x217, 0x219, 0x21b, 0x21d, 0x220, 0x222, 0x224, 0x226, 0x228, 0x231, 0x233, 0x236, 0x239, 0x23c, 0x23e, 0x241, 0x243, 0x245, 0x247, 0x24a, 0x24c, 0x24e, 0x250, 0x252, 0x258, 0x25a, 0x25c, 0x25e, 0x260, 0x262, 0x26c, 0x26f, 0x271, 0x27b, 0x280, 0x282, 0x284, 0x286, 0x288, 0x28b, 0x28e, 0x292, 0x29a, 0x29c, 0x29e, 0x2a5, 0x2a7, 0x2ae, 0x2b6, 0x2bd, 0x2c3, 0x2c5, 0x2c7, 0x2ca, 0x2d3, 0x2d6, 0x2dd, 0x2e2, 0x2e5, 0x2e8, 0x2ec, 0x2ee, 0x2f0, 0x2f3, 0x2f6} +var charInfoSparseOffset = []uint16{0x0, 0x8, 0x13, 0x21, 0x25, 0x2f, 0x36, 0x39, 0x3c, 0x4a, 0x56, 0x58, 0x62, 0x67, 0x6e, 0x7d, 0x8a, 0x92, 0x96, 0x9b, 0x9d, 0xa5, 0xab, 0xae, 0xb5, 0xb9, 0xbd, 0xbf, 0xc1, 0xc8, 0xcc, 0xd1, 0xd6, 0xd9, 0xe2, 0xe4, 0xec, 0xf0, 0xf2, 0xf5, 0xf8, 0xfe, 0x10e, 0x11a, 0x11c, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12c, 0x12e, 0x130, 0x133, 0x136, 0x138, 0x13b, 0x13e, 0x142, 0x151, 0x159, 0x15b, 0x15e, 0x160, 0x169, 0x16d, 0x171, 0x173, 0x182, 0x186, 0x18c, 0x194, 0x198, 0x1a1, 0x1aa, 0x1b5, 0x1bb, 0x1bf, 0x1cd, 0x1dc, 0x1e0, 0x1e7, 0x1ec, 0x1fa, 0x206, 0x209, 0x20b, 0x20d, 0x20f, 0x211, 0x213, 0x215, 0x217, 0x219, 0x21b, 0x21e, 0x220, 0x222, 0x224, 0x226, 0x22f, 0x231, 0x234, 0x237, 0x23a, 0x23c, 0x23f, 0x241, 0x243, 0x245, 0x248, 0x24a, 0x24c, 0x24e, 0x250, 0x256, 0x258, 0x25a, 0x25c, 0x25e, 0x260, 0x26a, 0x26d, 0x26f, 0x279, 0x27e, 0x280, 0x282, 0x284, 0x286, 0x289, 0x28c, 0x290, 0x298, 0x29a, 0x29c, 0x2a3, 0x2a5, 0x2ab, 0x2b3, 0x2ba, 0x2c0, 0x2c2, 0x2c4, 0x2c7, 0x2d0, 0x2d3, 0x2da, 0x2df, 0x2e2, 0x2e5, 0x2e9, 0x2eb, 0x2ed, 0x2f0, 0x2f3} -// charInfoSparseValues: 760 entries, 3040 bytes -var charInfoSparseValues = [760]valueRange{ +// charInfoSparseValues: 757 entries, 3028 bytes +var charInfoSparseValues = [757]valueRange{ // Block 0x0, offset 0x1 {value: 0x0000, lo: 0x07}, {value: 0x3000, lo: 0xa0, hi: 0xa0}, @@ -5942,7 +5940,7 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x0000, lo: 0x01}, {value: 0x00dc, lo: 0x99, hi: 0x9b}, // Block 0x14, offset 0x15 - {value: 0x7700, lo: 0x07}, + {value: 0x0000, lo: 0x07}, {value: 0x8800, lo: 0xa8, hi: 0xa8}, {value: 0x1100, lo: 0xa9, hi: 0xa9}, {value: 0x8800, lo: 0xb0, hi: 0xb0}, @@ -5958,7 +5956,7 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x00e6, lo: 0x93, hi: 0x94}, {value: 0x3300, lo: 0x98, hi: 0x9f}, // Block 0x16, offset 0x17 - {value: 0x65f9, lo: 0x02}, + {value: 0x0000, lo: 0x02}, {value: 0x0007, lo: 0xbc, hi: 0xbc}, {value: 0x6600, lo: 0xbe, hi: 0xbe}, // Block 0x17, offset 0x18 @@ -5994,7 +5992,7 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x6600, lo: 0x96, hi: 0x97}, {value: 0x3300, lo: 0x9c, hi: 0x9d}, // Block 0x1d, offset 0x1e - {value: 0x5500, lo: 0x03}, + {value: 0x0000, lo: 0x03}, {value: 0x8800, lo: 0x92, hi: 0x92}, {value: 0x1100, lo: 0x94, hi: 0x94}, {value: 0x6600, lo: 0xbe, hi: 0xbe}, @@ -6005,14 +6003,13 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x0009, lo: 0x8d, hi: 0x8d}, {value: 0x6600, lo: 0x97, hi: 0x97}, // Block 0x1f, offset 0x20 - {value: 0x004b, lo: 0x05}, + {value: 0x6607, lo: 0x04}, {value: 0x8800, lo: 0x86, hi: 0x86}, {value: 0x1100, lo: 0x88, hi: 0x88}, {value: 0x0009, lo: 0x8d, hi: 0x8d}, - {value: 0x0054, lo: 0x95, hi: 0x95}, - {value: 0x665b, lo: 0x96, hi: 0x96}, + {value: 0x0054, lo: 0x95, hi: 0x96}, // Block 0x20, offset 0x21 - {value: 0x87f9, lo: 0x02}, + {value: 0x0000, lo: 0x02}, {value: 0x0007, lo: 0xbc, hi: 0xbc}, {value: 0x8800, lo: 0xbf, hi: 0xbf}, // Block 0x21, offset 0x22 @@ -6126,7 +6123,7 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x0009, lo: 0x94, hi: 0x94}, {value: 0x0009, lo: 0xb4, hi: 0xb4}, // Block 0x35, offset 0x36 - {value: 0x00dd, lo: 0x02}, + {value: 0x0000, lo: 0x02}, {value: 0x0009, lo: 0x92, hi: 0x92}, {value: 0x00e6, lo: 0x9d, hi: 0x9d}, // Block 0x36, offset 0x37 @@ -6340,7 +6337,7 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x8800, lo: 0x92, hi: 0x92}, {value: 0x8800, lo: 0x94, hi: 0x94}, // Block 0x52, offset 0x53 - {value: 0x7700, lo: 0x0e}, + {value: 0x0000, lo: 0x0d}, {value: 0x8800, lo: 0x83, hi: 0x83}, {value: 0x1100, lo: 0x84, hi: 0x84}, {value: 0x8800, lo: 0x88, hi: 0x88}, @@ -6348,12 +6345,11 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x8800, lo: 0x8b, hi: 0x8b}, {value: 0x1100, lo: 0x8c, hi: 0x8c}, {value: 0x8800, lo: 0xa3, hi: 0xa3}, - {value: 0x1100, lo: 0xa4, hi: 0xa5}, + {value: 0x1100, lo: 0xa4, hi: 0xa4}, + {value: 0x8800, lo: 0xa5, hi: 0xa5}, {value: 0x1100, lo: 0xa6, hi: 0xa6}, - {value: 0x3000, lo: 0xac, hi: 0xac}, - {value: 0x3000, lo: 0xad, hi: 0xad}, - {value: 0x3000, lo: 0xaf, hi: 0xaf}, - {value: 0x3000, lo: 0xb0, hi: 0xb0}, + {value: 0x3000, lo: 0xac, hi: 0xad}, + {value: 0x3000, lo: 0xaf, hi: 0xb0}, {value: 0x8800, lo: 0xbc, hi: 0xbc}, // Block 0x53, offset 0x54 {value: 0x0000, lo: 0x0b}, @@ -6581,22 +6577,21 @@ var charInfoSparseValues = [760]valueRange{ {value: 0x0000, lo: 0x01}, {value: 0x00dc, lo: 0xbd, hi: 0xbd}, // Block 0x89, offset 0x8a - {value: 0x0000, lo: 0x06}, + {value: 0x00db, lo: 0x05}, {value: 0x00dc, lo: 0x8d, hi: 0x8d}, {value: 0x00e6, lo: 0x8f, hi: 0x8f}, {value: 0x00e6, lo: 0xb8, hi: 0xb8}, - {value: 0x0001, lo: 0xb9, hi: 0xb9}, - {value: 0x00dc, lo: 0xba, hi: 0xba}, + {value: 0x0001, lo: 0xb9, hi: 0xba}, {value: 0x0009, lo: 0xbf, hi: 0xbf}, // Block 0x8a, offset 0x8b - {value: 0x7700, lo: 0x07}, + {value: 0x65fe, lo: 0x07}, {value: 0x8800, lo: 0x99, hi: 0x99}, - {value: 0x1100, lo: 0x9a, hi: 0x9b}, + {value: 0x1100, lo: 0x9a, hi: 0x9a}, + {value: 0x8800, lo: 0x9b, hi: 0x9b}, {value: 0x1100, lo: 0x9c, hi: 0x9c}, {value: 0x8800, lo: 0xa5, hi: 0xa5}, {value: 0x1100, lo: 0xab, hi: 0xab}, - {value: 0x0009, lo: 0xb9, hi: 0xb9}, - {value: 0x6607, lo: 0xba, hi: 0xba}, + {value: 0x0009, lo: 0xb9, hi: 0xba}, // Block 0x8b, offset 0x8c {value: 0x0000, lo: 0x06}, {value: 0x3300, lo: 0x9e, hi: 0xa4}, @@ -6768,4 +6763,4 @@ var charInfoLookup = [1152]uint8{ var charInfoTrie = trie{charInfoLookup[:], charInfoValues[:], charInfoSparseValues[:], charInfoSparseOffset[:], 16} -// Total size of tables: 48KB (48756 bytes) +// Total size of tables: 48KB (48736 bytes) diff --git a/libgo/go/exp/norm/triegen.go b/libgo/go/exp/norm/triegen.go index 5edadac0a41..4ad9e0e057c 100644 --- a/libgo/go/exp/norm/triegen.go +++ b/libgo/go/exp/norm/triegen.go @@ -65,11 +65,13 @@ func (n trieNode) mostFrequentStride() int { counts[stride]++ } v = t.value + } else { + v = 0 } } var maxs, maxc int for stride, cnt := range counts { - if cnt > maxc { + if cnt > maxc || (cnt == maxc && stride < maxs) { maxs, maxc = stride, cnt } } diff --git a/libgo/go/exp/spdy/read.go b/libgo/go/exp/spdy/read.go deleted file mode 100644 index 4830a1d6bfd..00000000000 --- a/libgo/go/exp/spdy/read.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2011 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 spdy - -import ( - "compress/zlib" - "encoding/binary" - "io" - "net/http" - "strings" -) - -func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error { - return f.readSynStreamFrame(h, frame) -} - -func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error { - return f.readSynReplyFrame(h, frame) -} - -func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error { - frame.CFHeader = h - if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { - return err - } - if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil { - return err - } - return nil -} - -func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error { - frame.CFHeader = h - var numSettings uint32 - if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil { - return err - } - frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings) - for i := uint32(0); i < numSettings; i++ { - if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil { - return err - } - frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24) - frame.FlagIdValues[i].Id &= 0xffffff - if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil { - return err - } - } - return nil -} - -func (frame *NoopFrame) read(h ControlFrameHeader, f *Framer) error { - frame.CFHeader = h - return nil -} - -func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error { - frame.CFHeader = h - if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil { - return err - } - return nil -} - -func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error { - frame.CFHeader = h - if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil { - return err - } - return nil -} - -func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error { - return f.readHeadersFrame(h, frame) -} - -func newControlFrame(frameType ControlFrameType) (controlFrame, error) { - ctor, ok := cframeCtor[frameType] - if !ok { - return nil, &Error{Err: InvalidControlFrame} - } - return ctor(), nil -} - -var cframeCtor = map[ControlFrameType]func() controlFrame{ - TypeSynStream: func() controlFrame { return new(SynStreamFrame) }, - TypeSynReply: func() controlFrame { return new(SynReplyFrame) }, - TypeRstStream: func() controlFrame { return new(RstStreamFrame) }, - TypeSettings: func() controlFrame { return new(SettingsFrame) }, - TypeNoop: func() controlFrame { return new(NoopFrame) }, - TypePing: func() controlFrame { return new(PingFrame) }, - TypeGoAway: func() controlFrame { return new(GoAwayFrame) }, - TypeHeaders: func() controlFrame { return new(HeadersFrame) }, - // TODO(willchan): Add TypeWindowUpdate -} - -func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error { - if f.headerDecompressor != nil { - f.headerReader.N = payloadSize - return nil - } - f.headerReader = io.LimitedReader{R: f.r, N: payloadSize} - decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(HeaderDictionary)) - if err != nil { - return err - } - f.headerDecompressor = decompressor - return nil -} - -// ReadFrame reads SPDY encoded data and returns a decompressed Frame. -func (f *Framer) ReadFrame() (Frame, error) { - var firstWord uint32 - if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil { - return nil, err - } - if (firstWord & 0x80000000) != 0 { - frameType := ControlFrameType(firstWord & 0xffff) - version := uint16(0x7fff & (firstWord >> 16)) - return f.parseControlFrame(version, frameType) - } - return f.parseDataFrame(firstWord & 0x7fffffff) -} - -func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) { - var length uint32 - if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { - return nil, err - } - flags := ControlFlags((length & 0xff000000) >> 24) - length &= 0xffffff - header := ControlFrameHeader{version, frameType, flags, length} - cframe, err := newControlFrame(frameType) - if err != nil { - return nil, err - } - if err = cframe.read(header, f); err != nil { - return nil, err - } - return cframe, nil -} - -func parseHeaderValueBlock(r io.Reader, streamId uint32) (http.Header, error) { - var numHeaders uint16 - if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil { - return nil, err - } - var e error - h := make(http.Header, int(numHeaders)) - for i := 0; i < int(numHeaders); i++ { - var length uint16 - if err := binary.Read(r, binary.BigEndian, &length); err != nil { - return nil, err - } - nameBytes := make([]byte, length) - if _, err := io.ReadFull(r, nameBytes); err != nil { - return nil, err - } - name := string(nameBytes) - if name != strings.ToLower(name) { - e = &Error{UnlowercasedHeaderName, streamId} - name = strings.ToLower(name) - } - if h[name] != nil { - e = &Error{DuplicateHeaders, streamId} - } - if err := binary.Read(r, binary.BigEndian, &length); err != nil { - return nil, err - } - value := make([]byte, length) - if _, err := io.ReadFull(r, value); err != nil { - return nil, err - } - valueList := strings.Split(string(value), "\x00") - for _, v := range valueList { - h.Add(name, v) - } - } - if e != nil { - return h, e - } - return h, nil -} - -func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error { - frame.CFHeader = h - var err error - if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { - return err - } - if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil { - return err - } - if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil { - return err - } - frame.Priority >>= 14 - - reader := f.r - if !f.headerCompressionDisabled { - f.uncorkHeaderDecompressor(int64(h.length - 10)) - reader = f.headerDecompressor - } - - frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) - if !f.headerCompressionDisabled && ((err == io.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) { - err = &Error{WrongCompressedPayloadSize, 0} - } - if err != nil { - return err - } - // Remove this condition when we bump Version to 3. - if Version >= 3 { - for h := range frame.Headers { - if invalidReqHeaders[h] { - return &Error{InvalidHeaderPresent, frame.StreamId} - } - } - } - return nil -} - -func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error { - frame.CFHeader = h - var err error - if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { - return err - } - var unused uint16 - if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil { - return err - } - reader := f.r - if !f.headerCompressionDisabled { - f.uncorkHeaderDecompressor(int64(h.length - 6)) - reader = f.headerDecompressor - } - frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) - if !f.headerCompressionDisabled && ((err == io.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) { - err = &Error{WrongCompressedPayloadSize, 0} - } - if err != nil { - return err - } - // Remove this condition when we bump Version to 3. - if Version >= 3 { - for h := range frame.Headers { - if invalidRespHeaders[h] { - return &Error{InvalidHeaderPresent, frame.StreamId} - } - } - } - return nil -} - -func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error { - frame.CFHeader = h - var err error - if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { - return err - } - var unused uint16 - if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil { - return err - } - reader := f.r - if !f.headerCompressionDisabled { - f.uncorkHeaderDecompressor(int64(h.length - 6)) - reader = f.headerDecompressor - } - frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) - if !f.headerCompressionDisabled && ((err == io.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) { - err = &Error{WrongCompressedPayloadSize, 0} - } - if err != nil { - return err - } - - // Remove this condition when we bump Version to 3. - if Version >= 3 { - var invalidHeaders map[string]bool - if frame.StreamId%2 == 0 { - invalidHeaders = invalidReqHeaders - } else { - invalidHeaders = invalidRespHeaders - } - for h := range frame.Headers { - if invalidHeaders[h] { - return &Error{InvalidHeaderPresent, frame.StreamId} - } - } - } - return nil -} - -func (f *Framer) parseDataFrame(streamId uint32) (*DataFrame, error) { - var length uint32 - if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { - return nil, err - } - var frame DataFrame - frame.StreamId = streamId - frame.Flags = DataFlags(length >> 24) - length &= 0xffffff - frame.Data = make([]byte, length) - if _, err := io.ReadFull(f.r, frame.Data); err != nil { - return nil, err - } - return &frame, nil -} diff --git a/libgo/go/exp/spdy/spdy_test.go b/libgo/go/exp/spdy/spdy_test.go deleted file mode 100644 index c1cad4b37c6..00000000000 --- a/libgo/go/exp/spdy/spdy_test.go +++ /dev/null @@ -1,497 +0,0 @@ -// Copyright 2011 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 spdy - -import ( - "bytes" - "io" - "net/http" - "reflect" - "testing" -) - -func TestHeaderParsing(t *testing.T) { - headers := http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - } - var headerValueBlockBuf bytes.Buffer - writeHeaderValueBlock(&headerValueBlockBuf, headers) - - const bogusStreamId = 1 - newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf, bogusStreamId) - if err != nil { - t.Fatal("parseHeaderValueBlock:", err) - } - - if !reflect.DeepEqual(headers, newHeaders) { - t.Fatal("got: ", newHeaders, "\nwant: ", headers) - } -} - -func TestCreateParseSynStreamFrame(t *testing.T) { - buffer := new(bytes.Buffer) - framer := &Framer{ - headerCompressionDisabled: true, - w: buffer, - headerBuf: new(bytes.Buffer), - r: buffer, - } - synStreamFrame := SynStreamFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeSynStream, - }, - Headers: http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - }, - } - if err := framer.WriteFrame(&synStreamFrame); err != nil { - t.Fatal("WriteFrame without compression:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame without compression:", err) - } - parsedSynStreamFrame, ok := frame.(*SynStreamFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { - t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) - } - - // Test again with compression - buffer.Reset() - framer, err = NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - if err := framer.WriteFrame(&synStreamFrame); err != nil { - t.Fatal("WriteFrame with compression:", err) - } - frame, err = framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame with compression:", err) - } - parsedSynStreamFrame, ok = frame.(*SynStreamFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { - t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) - } -} - -func TestCreateParseSynReplyFrame(t *testing.T) { - buffer := new(bytes.Buffer) - framer := &Framer{ - headerCompressionDisabled: true, - w: buffer, - headerBuf: new(bytes.Buffer), - r: buffer, - } - synReplyFrame := SynReplyFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeSynReply, - }, - Headers: http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - }, - } - if err := framer.WriteFrame(&synReplyFrame); err != nil { - t.Fatal("WriteFrame without compression:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame without compression:", err) - } - parsedSynReplyFrame, ok := frame.(*SynReplyFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) { - t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame) - } - - // Test again with compression - buffer.Reset() - framer, err = NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - if err := framer.WriteFrame(&synReplyFrame); err != nil { - t.Fatal("WriteFrame with compression:", err) - } - frame, err = framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame with compression:", err) - } - parsedSynReplyFrame, ok = frame.(*SynReplyFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) { - t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame) - } -} - -func TestCreateParseRstStream(t *testing.T) { - buffer := new(bytes.Buffer) - framer, err := NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - rstStreamFrame := RstStreamFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeRstStream, - }, - StreamId: 1, - Status: InvalidStream, - } - if err := framer.WriteFrame(&rstStreamFrame); err != nil { - t.Fatal("WriteFrame:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame:", err) - } - parsedRstStreamFrame, ok := frame.(*RstStreamFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(rstStreamFrame, *parsedRstStreamFrame) { - t.Fatal("got: ", *parsedRstStreamFrame, "\nwant: ", rstStreamFrame) - } -} - -func TestCreateParseSettings(t *testing.T) { - buffer := new(bytes.Buffer) - framer, err := NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - settingsFrame := SettingsFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeSettings, - }, - FlagIdValues: []SettingsFlagIdValue{ - {FlagSettingsPersistValue, SettingsCurrentCwnd, 10}, - {FlagSettingsPersisted, SettingsUploadBandwidth, 1}, - }, - } - if err := framer.WriteFrame(&settingsFrame); err != nil { - t.Fatal("WriteFrame:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame:", err) - } - parsedSettingsFrame, ok := frame.(*SettingsFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(settingsFrame, *parsedSettingsFrame) { - t.Fatal("got: ", *parsedSettingsFrame, "\nwant: ", settingsFrame) - } -} - -func TestCreateParseNoop(t *testing.T) { - buffer := new(bytes.Buffer) - framer, err := NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - noopFrame := NoopFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeNoop, - }, - } - if err := framer.WriteFrame(&noopFrame); err != nil { - t.Fatal("WriteFrame:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame:", err) - } - parsedNoopFrame, ok := frame.(*NoopFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(noopFrame, *parsedNoopFrame) { - t.Fatal("got: ", *parsedNoopFrame, "\nwant: ", noopFrame) - } -} - -func TestCreateParsePing(t *testing.T) { - buffer := new(bytes.Buffer) - framer, err := NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - pingFrame := PingFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypePing, - }, - Id: 31337, - } - if err := framer.WriteFrame(&pingFrame); err != nil { - t.Fatal("WriteFrame:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame:", err) - } - parsedPingFrame, ok := frame.(*PingFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(pingFrame, *parsedPingFrame) { - t.Fatal("got: ", *parsedPingFrame, "\nwant: ", pingFrame) - } -} - -func TestCreateParseGoAway(t *testing.T) { - buffer := new(bytes.Buffer) - framer, err := NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - goAwayFrame := GoAwayFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeGoAway, - }, - LastGoodStreamId: 31337, - } - if err := framer.WriteFrame(&goAwayFrame); err != nil { - t.Fatal("WriteFrame:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame:", err) - } - parsedGoAwayFrame, ok := frame.(*GoAwayFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(goAwayFrame, *parsedGoAwayFrame) { - t.Fatal("got: ", *parsedGoAwayFrame, "\nwant: ", goAwayFrame) - } -} - -func TestCreateParseHeadersFrame(t *testing.T) { - buffer := new(bytes.Buffer) - framer := &Framer{ - headerCompressionDisabled: true, - w: buffer, - headerBuf: new(bytes.Buffer), - r: buffer, - } - headersFrame := HeadersFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeHeaders, - }, - } - headersFrame.Headers = http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - } - if err := framer.WriteFrame(&headersFrame); err != nil { - t.Fatal("WriteFrame without compression:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame without compression:", err) - } - parsedHeadersFrame, ok := frame.(*HeadersFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { - t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) - } - - // Test again with compression - buffer.Reset() - framer, err = NewFramer(buffer, buffer) - if err := framer.WriteFrame(&headersFrame); err != nil { - t.Fatal("WriteFrame with compression:", err) - } - frame, err = framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame with compression:", err) - } - parsedHeadersFrame, ok = frame.(*HeadersFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { - t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) - } -} - -func TestCreateParseDataFrame(t *testing.T) { - buffer := new(bytes.Buffer) - framer, err := NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - dataFrame := DataFrame{ - StreamId: 1, - Data: []byte{'h', 'e', 'l', 'l', 'o'}, - } - if err := framer.WriteFrame(&dataFrame); err != nil { - t.Fatal("WriteFrame:", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame:", err) - } - parsedDataFrame, ok := frame.(*DataFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(dataFrame, *parsedDataFrame) { - t.Fatal("got: ", *parsedDataFrame, "\nwant: ", dataFrame) - } -} - -func TestCompressionContextAcrossFrames(t *testing.T) { - buffer := new(bytes.Buffer) - framer, err := NewFramer(buffer, buffer) - if err != nil { - t.Fatal("Failed to create new framer:", err) - } - headersFrame := HeadersFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeHeaders, - }, - Headers: http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - }, - } - if err := framer.WriteFrame(&headersFrame); err != nil { - t.Fatal("WriteFrame (HEADERS):", err) - } - synStreamFrame := SynStreamFrame{ControlFrameHeader{Version, TypeSynStream, 0, 0}, 0, 0, 0, nil} - synStreamFrame.Headers = http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - } - if err := framer.WriteFrame(&synStreamFrame); err != nil { - t.Fatal("WriteFrame (SYN_STREAM):", err) - } - frame, err := framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame (HEADERS):", err, buffer.Bytes()) - } - parsedHeadersFrame, ok := frame.(*HeadersFrame) - if !ok { - t.Fatalf("expected HeadersFrame; got %T %v", frame, frame) - } - if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { - t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) - } - frame, err = framer.ReadFrame() - if err != nil { - t.Fatal("ReadFrame (SYN_STREAM):", err, buffer.Bytes()) - } - parsedSynStreamFrame, ok := frame.(*SynStreamFrame) - if !ok { - t.Fatalf("expected SynStreamFrame; got %T %v", frame, frame) - } - if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { - t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) - } -} - -func TestMultipleSPDYFrames(t *testing.T) { - // Initialize the framers. - pr1, pw1 := io.Pipe() - pr2, pw2 := io.Pipe() - writer, err := NewFramer(pw1, pr2) - if err != nil { - t.Fatal("Failed to create writer:", err) - } - reader, err := NewFramer(pw2, pr1) - if err != nil { - t.Fatal("Failed to create reader:", err) - } - - // Set up the frames we're actually transferring. - headersFrame := HeadersFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeHeaders, - }, - Headers: http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - }, - } - synStreamFrame := SynStreamFrame{ - CFHeader: ControlFrameHeader{ - version: Version, - frameType: TypeSynStream, - }, - Headers: http.Header{ - "Url": []string{"http://www.google.com/"}, - "Method": []string{"get"}, - "Version": []string{"http/1.1"}, - }, - } - - // Start the goroutines to write the frames. - go func() { - if err := writer.WriteFrame(&headersFrame); err != nil { - t.Fatal("WriteFrame (HEADERS): ", err) - } - if err := writer.WriteFrame(&synStreamFrame); err != nil { - t.Fatal("WriteFrame (SYN_STREAM): ", err) - } - }() - - // Read the frames and verify they look as expected. - frame, err := reader.ReadFrame() - if err != nil { - t.Fatal("ReadFrame (HEADERS): ", err) - } - parsedHeadersFrame, ok := frame.(*HeadersFrame) - if !ok { - t.Fatal("Parsed incorrect frame type:", frame) - } - if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { - t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) - } - frame, err = reader.ReadFrame() - if err != nil { - t.Fatal("ReadFrame (SYN_STREAM):", err) - } - parsedSynStreamFrame, ok := frame.(*SynStreamFrame) - if !ok { - t.Fatal("Parsed incorrect frame type.") - } - if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { - t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) - } -} diff --git a/libgo/go/exp/spdy/types.go b/libgo/go/exp/spdy/types.go deleted file mode 100644 index 2648c4f75f9..00000000000 --- a/libgo/go/exp/spdy/types.go +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2011 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 spdy - -import ( - "bytes" - "compress/zlib" - "io" - "net/http" -) - -// Data Frame Format -// +----------------------------------+ -// |0| Stream-ID (31bits) | -// +----------------------------------+ -// | flags (8) | Length (24 bits) | -// +----------------------------------+ -// | Data | -// +----------------------------------+ -// -// Control Frame Format -// +----------------------------------+ -// |1| Version(15bits) | Type(16bits) | -// +----------------------------------+ -// | flags (8) | Length (24 bits) | -// +----------------------------------+ -// | Data | -// +----------------------------------+ -// -// Control Frame: SYN_STREAM -// +----------------------------------+ -// |1|000000000000001|0000000000000001| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | >= 12 -// +----------------------------------+ -// |X| Stream-ID(31bits) | -// +----------------------------------+ -// |X|Associated-To-Stream-ID (31bits)| -// +----------------------------------+ -// |Pri| unused | Length (16bits)| -// +----------------------------------+ -// -// Control Frame: SYN_REPLY -// +----------------------------------+ -// |1|000000000000001|0000000000000010| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | >= 8 -// +----------------------------------+ -// |X| Stream-ID(31bits) | -// +----------------------------------+ -// | unused (16 bits)| Length (16bits)| -// +----------------------------------+ -// -// Control Frame: RST_STREAM -// +----------------------------------+ -// |1|000000000000001|0000000000000011| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | >= 4 -// +----------------------------------+ -// |X| Stream-ID(31bits) | -// +----------------------------------+ -// | Status code (32 bits) | -// +----------------------------------+ -// -// Control Frame: SETTINGS -// +----------------------------------+ -// |1|000000000000001|0000000000000100| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | -// +----------------------------------+ -// | # of entries (32) | -// +----------------------------------+ -// -// Control Frame: NOOP -// +----------------------------------+ -// |1|000000000000001|0000000000000101| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | = 0 -// +----------------------------------+ -// -// Control Frame: PING -// +----------------------------------+ -// |1|000000000000001|0000000000000110| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | = 4 -// +----------------------------------+ -// | Unique id (32 bits) | -// +----------------------------------+ -// -// Control Frame: GOAWAY -// +----------------------------------+ -// |1|000000000000001|0000000000000111| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | = 4 -// +----------------------------------+ -// |X| Last-accepted-stream-id | -// +----------------------------------+ -// -// Control Frame: HEADERS -// +----------------------------------+ -// |1|000000000000001|0000000000001000| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | >= 8 -// +----------------------------------+ -// |X| Stream-ID (31 bits) | -// +----------------------------------+ -// | unused (16 bits)| Length (16bits)| -// +----------------------------------+ -// -// Control Frame: WINDOW_UPDATE -// +----------------------------------+ -// |1|000000000000001|0000000000001001| -// +----------------------------------+ -// | flags (8) | Length (24 bits) | = 8 -// +----------------------------------+ -// |X| Stream-ID (31 bits) | -// +----------------------------------+ -// | Delta-Window-Size (32 bits) | -// +----------------------------------+ - -// Version is the protocol version number that this package implements. -const Version = 2 - -// ControlFrameType stores the type field in a control frame header. -type ControlFrameType uint16 - -// Control frame type constants -const ( - TypeSynStream ControlFrameType = 0x0001 - TypeSynReply = 0x0002 - TypeRstStream = 0x0003 - TypeSettings = 0x0004 - TypeNoop = 0x0005 - TypePing = 0x0006 - TypeGoAway = 0x0007 - TypeHeaders = 0x0008 - TypeWindowUpdate = 0x0009 -) - -// ControlFlags are the flags that can be set on a control frame. -type ControlFlags uint8 - -const ( - ControlFlagFin ControlFlags = 0x01 -) - -// DataFlags are the flags that can be set on a data frame. -type DataFlags uint8 - -const ( - DataFlagFin DataFlags = 0x01 - DataFlagCompressed = 0x02 -) - -// MaxDataLength is the maximum number of bytes that can be stored in one frame. -const MaxDataLength = 1<<24 - 1 - -// Frame is a single SPDY frame in its unpacked in-memory representation. Use -// Framer to read and write it. -type Frame interface { - write(f *Framer) error -} - -// ControlFrameHeader contains all the fields in a control frame header, -// in its unpacked in-memory representation. -type ControlFrameHeader struct { - // Note, high bit is the "Control" bit. - version uint16 - frameType ControlFrameType - Flags ControlFlags - length uint32 -} - -type controlFrame interface { - Frame - read(h ControlFrameHeader, f *Framer) error -} - -// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM -// frame. -type SynStreamFrame struct { - CFHeader ControlFrameHeader - StreamId uint32 - AssociatedToStreamId uint32 - // Note, only 2 highest bits currently used - // Rest of Priority is unused. - Priority uint16 - Headers http.Header -} - -// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame. -type SynReplyFrame struct { - CFHeader ControlFrameHeader - StreamId uint32 - Headers http.Header -} - -// StatusCode represents the status that led to a RST_STREAM -type StatusCode uint32 - -const ( - ProtocolError StatusCode = 1 - InvalidStream = 2 - RefusedStream = 3 - UnsupportedVersion = 4 - Cancel = 5 - InternalError = 6 - FlowControlError = 7 -) - -// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM -// frame. -type RstStreamFrame struct { - CFHeader ControlFrameHeader - StreamId uint32 - Status StatusCode -} - -// SettingsFlag represents a flag in a SETTINGS frame. -type SettingsFlag uint8 - -const ( - FlagSettingsPersistValue SettingsFlag = 0x1 - FlagSettingsPersisted = 0x2 -) - -// SettingsFlag represents the id of an id/value pair in a SETTINGS frame. -type SettingsId uint32 - -const ( - SettingsUploadBandwidth SettingsId = 1 - SettingsDownloadBandwidth = 2 - SettingsRoundTripTime = 3 - SettingsMaxConcurrentStreams = 4 - SettingsCurrentCwnd = 5 -) - -// SettingsFlagIdValue is the unpacked, in-memory representation of the -// combined flag/id/value for a setting in a SETTINGS frame. -type SettingsFlagIdValue struct { - Flag SettingsFlag - Id SettingsId - Value uint32 -} - -// SettingsFrame is the unpacked, in-memory representation of a SPDY -// SETTINGS frame. -type SettingsFrame struct { - CFHeader ControlFrameHeader - FlagIdValues []SettingsFlagIdValue -} - -// NoopFrame is the unpacked, in-memory representation of a NOOP frame. -type NoopFrame struct { - CFHeader ControlFrameHeader -} - -// PingFrame is the unpacked, in-memory representation of a PING frame. -type PingFrame struct { - CFHeader ControlFrameHeader - Id uint32 -} - -// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame. -type GoAwayFrame struct { - CFHeader ControlFrameHeader - LastGoodStreamId uint32 -} - -// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame. -type HeadersFrame struct { - CFHeader ControlFrameHeader - StreamId uint32 - Headers http.Header -} - -// DataFrame is the unpacked, in-memory representation of a DATA frame. -type DataFrame struct { - // Note, high bit is the "Control" bit. Should be 0 for data frames. - StreamId uint32 - Flags DataFlags - Data []byte -} - -// HeaderDictionary is the dictionary sent to the zlib compressor/decompressor. -// Even though the specification states there is no null byte at the end, Chrome sends it. -const HeaderDictionary = "optionsgetheadpostputdeletetrace" + - "acceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhost" + - "if-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsince" + - "max-forwardsproxy-authorizationrangerefererteuser-agent" + - "100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505" + - "accept-rangesageetaglocationproxy-authenticatepublicretry-after" + - "servervarywarningwww-authenticateallowcontent-basecontent-encodingcache-control" + - "connectiondatetrailertransfer-encodingupgradeviawarning" + - "content-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookie" + - "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" + - "JanFebMarAprMayJunJulAugSepOctNovDec" + - "chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" + - "charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00" - -// A SPDY specific error. -type ErrorCode string - -const ( - UnlowercasedHeaderName ErrorCode = "header was not lowercased" - DuplicateHeaders ErrorCode = "multiple headers with same name" - WrongCompressedPayloadSize ErrorCode = "compressed payload size was incorrect" - UnknownFrameType ErrorCode = "unknown frame type" - InvalidControlFrame ErrorCode = "invalid control frame" - InvalidDataFrame ErrorCode = "invalid data frame" - InvalidHeaderPresent ErrorCode = "frame contained invalid header" -) - -// Error contains both the type of error and additional values. StreamId is 0 -// if Error is not associated with a stream. -type Error struct { - Err ErrorCode - StreamId uint32 -} - -func (e *Error) Error() string { - return string(e.Err) -} - -var invalidReqHeaders = map[string]bool{ - "Connection": true, - "Keep-Alive": true, - "Proxy-Connection": true, - "Transfer-Encoding": true, -} - -var invalidRespHeaders = map[string]bool{ - "Connection": true, - "Keep-Alive": true, - "Transfer-Encoding": true, -} - -// Framer handles serializing/deserializing SPDY frames, including compressing/ -// decompressing payloads. -type Framer struct { - headerCompressionDisabled bool - w io.Writer - headerBuf *bytes.Buffer - headerCompressor *zlib.Writer - r io.Reader - headerReader io.LimitedReader - headerDecompressor io.ReadCloser -} - -// NewFramer allocates a new Framer for a given SPDY connection, repesented by -// a io.Writer and io.Reader. Note that Framer will read and write individual fields -// from/to the Reader and Writer, so the caller should pass in an appropriately -// buffered implementation to optimize performance. -func NewFramer(w io.Writer, r io.Reader) (*Framer, error) { - compressBuf := new(bytes.Buffer) - compressor, err := zlib.NewWriterDict(compressBuf, zlib.BestCompression, []byte(HeaderDictionary)) - if err != nil { - return nil, err - } - framer := &Framer{ - w: w, - headerBuf: compressBuf, - headerCompressor: compressor, - r: r, - } - return framer, nil -} diff --git a/libgo/go/exp/spdy/write.go b/libgo/go/exp/spdy/write.go deleted file mode 100644 index 3dd2ca1d5d8..00000000000 --- a/libgo/go/exp/spdy/write.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2011 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 spdy - -import ( - "encoding/binary" - "io" - "net/http" - "strings" -) - -func (frame *SynStreamFrame) write(f *Framer) error { - return f.writeSynStreamFrame(frame) -} - -func (frame *SynReplyFrame) write(f *Framer) error { - return f.writeSynReplyFrame(frame) -} - -func (frame *RstStreamFrame) write(f *Framer) (err error) { - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypeRstStream - frame.CFHeader.length = 8 - - // Serialize frame to Writer - if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil { - return - } - return -} - -func (frame *SettingsFrame) write(f *Framer) (err error) { - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypeSettings - frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4) - - // Serialize frame to Writer - if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil { - return - } - for _, flagIdValue := range frame.FlagIdValues { - flagId := (uint32(flagIdValue.Flag) << 24) | uint32(flagIdValue.Id) - if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil { - return - } - } - return -} - -func (frame *NoopFrame) write(f *Framer) error { - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypeNoop - - // Serialize frame to Writer - return writeControlFrameHeader(f.w, frame.CFHeader) -} - -func (frame *PingFrame) write(f *Framer) (err error) { - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypePing - frame.CFHeader.length = 4 - - // Serialize frame to Writer - if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil { - return - } - return -} - -func (frame *GoAwayFrame) write(f *Framer) (err error) { - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypeGoAway - frame.CFHeader.length = 4 - - // Serialize frame to Writer - if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil { - return - } - return nil -} - -func (frame *HeadersFrame) write(f *Framer) error { - return f.writeHeadersFrame(frame) -} - -func (frame *DataFrame) write(f *Framer) error { - return f.writeDataFrame(frame) -} - -// WriteFrame writes a frame. -func (f *Framer) WriteFrame(frame Frame) error { - return frame.write(f) -} - -func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error { - if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil { - return err - } - if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil { - return err - } - flagsAndLength := (uint32(h.Flags) << 24) | h.length - if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil { - return err - } - return nil -} - -func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) { - n = 0 - if err = binary.Write(w, binary.BigEndian, uint16(len(h))); err != nil { - return - } - n += 2 - for name, values := range h { - if err = binary.Write(w, binary.BigEndian, uint16(len(name))); err != nil { - return - } - n += 2 - name = strings.ToLower(name) - if _, err = io.WriteString(w, name); err != nil { - return - } - n += len(name) - v := strings.Join(values, "\x00") - if err = binary.Write(w, binary.BigEndian, uint16(len(v))); err != nil { - return - } - n += 2 - if _, err = io.WriteString(w, v); err != nil { - return - } - n += len(v) - } - return -} - -func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) { - // Marshal the headers. - var writer io.Writer = f.headerBuf - if !f.headerCompressionDisabled { - writer = f.headerCompressor - } - if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil { - return - } - if !f.headerCompressionDisabled { - f.headerCompressor.Flush() - } - - // Set ControlFrameHeader - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypeSynStream - frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10) - - // Serialize frame to Writer - if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { - return err - } - if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { - return err - } - if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil { - return err - } - if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<14); err != nil { - return err - } - if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil { - return err - } - f.headerBuf.Reset() - return nil -} - -func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) { - // Marshal the headers. - var writer io.Writer = f.headerBuf - if !f.headerCompressionDisabled { - writer = f.headerCompressor - } - if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil { - return - } - if !f.headerCompressionDisabled { - f.headerCompressor.Flush() - } - - // Set ControlFrameHeader - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypeSynReply - frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6) - - // Serialize frame to Writer - if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil { - return - } - if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil { - return - } - f.headerBuf.Reset() - return -} - -func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) { - // Marshal the headers. - var writer io.Writer = f.headerBuf - if !f.headerCompressionDisabled { - writer = f.headerCompressor - } - if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil { - return - } - if !f.headerCompressionDisabled { - f.headerCompressor.Flush() - } - - // Set ControlFrameHeader - frame.CFHeader.version = Version - frame.CFHeader.frameType = TypeHeaders - frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6) - - // Serialize frame to Writer - if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { - return - } - if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil { - return - } - if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil { - return - } - f.headerBuf.Reset() - return -} - -func (f *Framer) writeDataFrame(frame *DataFrame) (err error) { - // Validate DataFrame - if frame.StreamId&0x80000000 != 0 || len(frame.Data) >= 0x0f000000 { - return &Error{InvalidDataFrame, frame.StreamId} - } - - // Serialize frame to Writer - if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil { - return - } - flagsAndLength := (uint32(frame.Flags) << 24) | uint32(len(frame.Data)) - if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil { - return - } - if _, err = f.w.Write(frame.Data); err != nil { - return - } - - return nil -} diff --git a/libgo/go/exp/ssh/channel.go b/libgo/go/exp/ssh/channel.go deleted file mode 100644 index 9d75f37de74..00000000000 --- a/libgo/go/exp/ssh/channel.go +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "errors" - "io" - "sync" -) - -// A Channel is an ordered, reliable, duplex stream that is multiplexed over an -// SSH connection. -type Channel interface { - // Accept accepts the channel creation request. - Accept() error - // Reject rejects the channel creation request. After calling this, no - // other methods on the Channel may be called. If they are then the - // peer is likely to signal a protocol error and drop the connection. - Reject(reason RejectionReason, message string) error - - // Read may return a ChannelRequest as an error. - Read(data []byte) (int, error) - Write(data []byte) (int, error) - Close() error - - // AckRequest either sends an ack or nack to the channel request. - AckRequest(ok bool) error - - // ChannelType returns the type of the channel, as supplied by the - // client. - ChannelType() string - // ExtraData returns the arbitary payload for this channel, as supplied - // by the client. This data is specific to the channel type. - ExtraData() []byte -} - -// ChannelRequest represents a request sent on a channel, outside of the normal -// stream of bytes. It may result from calling Read on a Channel. -type ChannelRequest struct { - Request string - WantReply bool - Payload []byte -} - -func (c ChannelRequest) Error() string { - return "channel request received" -} - -// RejectionReason is an enumeration used when rejecting channel creation -// requests. See RFC 4254, section 5.1. -type RejectionReason int - -const ( - Prohibited RejectionReason = iota + 1 - ConnectionFailed - UnknownChannelType - ResourceShortage -) - -type channel struct { - // immutable once created - chanType string - extraData []byte - - theyClosed bool - theySentEOF bool - weClosed bool - dead bool - - serverConn *ServerConn - myId, theirId uint32 - myWindow, theirWindow uint32 - maxPacketSize uint32 - err error - - pendingRequests []ChannelRequest - pendingData []byte - head, length int - - // This lock is inferior to serverConn.lock - lock sync.Mutex - cond *sync.Cond -} - -func (c *channel) Accept() error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - confirm := channelOpenConfirmMsg{ - PeersId: c.theirId, - MyId: c.myId, - MyWindow: c.myWindow, - MaxPacketSize: c.maxPacketSize, - } - return c.serverConn.writePacket(marshal(msgChannelOpenConfirm, confirm)) -} - -func (c *channel) Reject(reason RejectionReason, message string) error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - reject := channelOpenFailureMsg{ - PeersId: c.theirId, - Reason: uint32(reason), - Message: message, - Language: "en", - } - return c.serverConn.writePacket(marshal(msgChannelOpenFailure, reject)) -} - -func (c *channel) handlePacket(packet interface{}) { - c.lock.Lock() - defer c.lock.Unlock() - - switch packet := packet.(type) { - case *channelRequestMsg: - req := ChannelRequest{ - Request: packet.Request, - WantReply: packet.WantReply, - Payload: packet.RequestSpecificData, - } - - c.pendingRequests = append(c.pendingRequests, req) - c.cond.Signal() - case *channelCloseMsg: - c.theyClosed = true - c.cond.Signal() - case *channelEOFMsg: - c.theySentEOF = true - c.cond.Signal() - default: - panic("unknown packet type") - } -} - -func (c *channel) handleData(data []byte) { - c.lock.Lock() - defer c.lock.Unlock() - - // The other side should never send us more than our window. - if len(data)+c.length > len(c.pendingData) { - // TODO(agl): we should tear down the channel with a protocol - // error. - return - } - - c.myWindow -= uint32(len(data)) - for i := 0; i < 2; i++ { - tail := c.head + c.length - if tail > len(c.pendingData) { - tail -= len(c.pendingData) - } - n := copy(c.pendingData[tail:], data) - data = data[n:] - c.length += n - } - - c.cond.Signal() -} - -func (c *channel) Read(data []byte) (n int, err error) { - c.lock.Lock() - defer c.lock.Unlock() - - if c.err != nil { - return 0, c.err - } - - if c.myWindow <= uint32(len(c.pendingData))/2 { - packet := marshal(msgChannelWindowAdjust, windowAdjustMsg{ - PeersId: c.theirId, - AdditionalBytes: uint32(len(c.pendingData)) - c.myWindow, - }) - if err := c.serverConn.writePacket(packet); err != nil { - return 0, err - } - } - - for { - if c.theySentEOF || c.theyClosed || c.dead { - return 0, io.EOF - } - - if len(c.pendingRequests) > 0 { - req := c.pendingRequests[0] - if len(c.pendingRequests) == 1 { - c.pendingRequests = nil - } else { - oldPendingRequests := c.pendingRequests - c.pendingRequests = make([]ChannelRequest, len(oldPendingRequests)-1) - copy(c.pendingRequests, oldPendingRequests[1:]) - } - - return 0, req - } - - if c.length > 0 { - tail := c.head + c.length - if tail > len(c.pendingData) { - tail -= len(c.pendingData) - } - n = copy(data, c.pendingData[c.head:tail]) - c.head += n - c.length -= n - if c.head == len(c.pendingData) { - c.head = 0 - } - return - } - - c.cond.Wait() - } - - panic("unreachable") -} - -func (c *channel) Write(data []byte) (n int, err error) { - for len(data) > 0 { - c.lock.Lock() - if c.dead || c.weClosed { - return 0, io.EOF - } - - if c.theirWindow == 0 { - c.cond.Wait() - continue - } - c.lock.Unlock() - - todo := data - if uint32(len(todo)) > c.theirWindow { - todo = todo[:c.theirWindow] - } - - packet := make([]byte, 1+4+4+len(todo)) - packet[0] = msgChannelData - packet[1] = byte(c.theirId >> 24) - packet[2] = byte(c.theirId >> 16) - packet[3] = byte(c.theirId >> 8) - packet[4] = byte(c.theirId) - packet[5] = byte(len(todo) >> 24) - packet[6] = byte(len(todo) >> 16) - packet[7] = byte(len(todo) >> 8) - packet[8] = byte(len(todo)) - copy(packet[9:], todo) - - c.serverConn.lock.Lock() - if err = c.serverConn.writePacket(packet); err != nil { - c.serverConn.lock.Unlock() - return - } - c.serverConn.lock.Unlock() - - n += len(todo) - data = data[len(todo):] - } - - return -} - -func (c *channel) Close() error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - if c.weClosed { - return errors.New("ssh: channel already closed") - } - c.weClosed = true - - closeMsg := channelCloseMsg{ - PeersId: c.theirId, - } - return c.serverConn.writePacket(marshal(msgChannelClose, closeMsg)) -} - -func (c *channel) AckRequest(ok bool) error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - if ok { - ack := channelRequestSuccessMsg{ - PeersId: c.theirId, - } - return c.serverConn.writePacket(marshal(msgChannelSuccess, ack)) - } else { - ack := channelRequestFailureMsg{ - PeersId: c.theirId, - } - return c.serverConn.writePacket(marshal(msgChannelFailure, ack)) - } - panic("unreachable") -} - -func (c *channel) ChannelType() string { - return c.chanType -} - -func (c *channel) ExtraData() []byte { - return c.extraData -} diff --git a/libgo/go/exp/ssh/cipher.go b/libgo/go/exp/ssh/cipher.go deleted file mode 100644 index d91929aa99a..00000000000 --- a/libgo/go/exp/ssh/cipher.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rc4" -) - -// streamDump is used to dump the initial keystream for stream ciphers. It is a -// a write-only buffer, and not intended for reading so do not require a mutex. -var streamDump [512]byte - -// noneCipher implements cipher.Stream and provides no encryption. It is used -// by the transport before the first key-exchange. -type noneCipher struct{} - -func (c noneCipher) XORKeyStream(dst, src []byte) { - copy(dst, src) -} - -func newAESCTR(key, iv []byte) (cipher.Stream, error) { - c, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - return cipher.NewCTR(c, iv), nil -} - -func newRC4(key, iv []byte) (cipher.Stream, error) { - return rc4.NewCipher(key) -} - -type cipherMode struct { - keySize int - ivSize int - skip int - createFn func(key, iv []byte) (cipher.Stream, error) -} - -func (c *cipherMode) createCipher(key, iv []byte) (cipher.Stream, error) { - if len(key) < c.keySize { - panic("ssh: key length too small for cipher") - } - if len(iv) < c.ivSize { - panic("ssh: iv too small for cipher") - } - - stream, err := c.createFn(key[:c.keySize], iv[:c.ivSize]) - if err != nil { - return nil, err - } - - for remainingToDump := c.skip; remainingToDump > 0; { - dumpThisTime := remainingToDump - if dumpThisTime > len(streamDump) { - dumpThisTime = len(streamDump) - } - stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) - remainingToDump -= dumpThisTime - } - - return stream, nil -} - -// Specifies a default set of ciphers and a preference order. This is based on -// OpenSSH's default client preference order, minus algorithms that are not -// implemented. -var DefaultCipherOrder = []string{ - "aes128-ctr", "aes192-ctr", "aes256-ctr", - "arcfour256", "arcfour128", -} - -var cipherModes = map[string]*cipherMode{ - // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms - // are defined in the order specified in the RFC. - "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, - "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, - "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, - - // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. - // They are defined in the order specified in the RFC. - "arcfour128": {16, 0, 1536, newRC4}, - "arcfour256": {32, 0, 1536, newRC4}, -} diff --git a/libgo/go/exp/ssh/cipher_test.go b/libgo/go/exp/ssh/cipher_test.go deleted file mode 100644 index ea27bd8a803..00000000000 --- a/libgo/go/exp/ssh/cipher_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "bytes" - "testing" -) - -// TestCipherReversal tests that each cipher factory produces ciphers that can -// encrypt and decrypt some data successfully. -func TestCipherReversal(t *testing.T) { - testData := []byte("abcdefghijklmnopqrstuvwxyz012345") - testKey := []byte("AbCdEfGhIjKlMnOpQrStUvWxYz012345") - testIv := []byte("sdflkjhsadflkjhasdflkjhsadfklhsa") - - cryptBuffer := make([]byte, 32) - - for name, cipherMode := range cipherModes { - encrypter, err := cipherMode.createCipher(testKey, testIv) - if err != nil { - t.Errorf("failed to create encrypter for %q: %s", name, err) - continue - } - decrypter, err := cipherMode.createCipher(testKey, testIv) - if err != nil { - t.Errorf("failed to create decrypter for %q: %s", name, err) - continue - } - - copy(cryptBuffer, testData) - - encrypter.XORKeyStream(cryptBuffer, cryptBuffer) - if name == "none" { - if !bytes.Equal(cryptBuffer, testData) { - t.Errorf("encryption made change with 'none' cipher") - continue - } - } else { - if bytes.Equal(cryptBuffer, testData) { - t.Errorf("encryption made no change with %q", name) - continue - } - } - - decrypter.XORKeyStream(cryptBuffer, cryptBuffer) - if !bytes.Equal(cryptBuffer, testData) { - t.Errorf("decrypted bytes not equal to input with %q", name) - continue - } - } -} - -func TestDefaultCiphersExist(t *testing.T) { - for _, cipherAlgo := range DefaultCipherOrder { - if _, ok := cipherModes[cipherAlgo]; !ok { - t.Errorf("default cipher %q is unknown", cipherAlgo) - } - } -} diff --git a/libgo/go/exp/ssh/client.go b/libgo/go/exp/ssh/client.go deleted file mode 100644 index eb6c0352210..00000000000 --- a/libgo/go/exp/ssh/client.go +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "crypto" - "crypto/rand" - "errors" - "fmt" - "io" - "math/big" - "net" - "sync" -) - -// clientVersion is the fixed identification string that the client will use. -var clientVersion = []byte("SSH-2.0-Go\r\n") - -// ClientConn represents the client side of an SSH connection. -type ClientConn struct { - *transport - config *ClientConfig - chanlist -} - -// Client returns a new SSH client connection using c as the underlying transport. -func Client(c net.Conn, config *ClientConfig) (*ClientConn, error) { - conn := &ClientConn{ - transport: newTransport(c, config.rand()), - config: config, - } - if err := conn.handshake(); err != nil { - conn.Close() - return nil, err - } - go conn.mainLoop() - return conn, nil -} - -// handshake performs the client side key exchange. See RFC 4253 Section 7. -func (c *ClientConn) handshake() error { - var magics handshakeMagics - - if _, err := c.Write(clientVersion); err != nil { - return err - } - if err := c.Flush(); err != nil { - return err - } - magics.clientVersion = clientVersion[:len(clientVersion)-2] - - // read remote server version - version, err := readVersion(c) - if err != nil { - return err - } - magics.serverVersion = version - clientKexInit := kexInitMsg{ - KexAlgos: supportedKexAlgos, - ServerHostKeyAlgos: supportedHostKeyAlgos, - CiphersClientServer: c.config.Crypto.ciphers(), - CiphersServerClient: c.config.Crypto.ciphers(), - MACsClientServer: supportedMACs, - MACsServerClient: supportedMACs, - CompressionClientServer: supportedCompressions, - CompressionServerClient: supportedCompressions, - } - kexInitPacket := marshal(msgKexInit, clientKexInit) - magics.clientKexInit = kexInitPacket - - if err := c.writePacket(kexInitPacket); err != nil { - return err - } - packet, err := c.readPacket() - if err != nil { - return err - } - - magics.serverKexInit = packet - - var serverKexInit kexInitMsg - if err = unmarshal(&serverKexInit, packet, msgKexInit); err != nil { - return err - } - - kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(c.transport, &clientKexInit, &serverKexInit) - if !ok { - return errors.New("ssh: no common algorithms") - } - - if serverKexInit.FirstKexFollows && kexAlgo != serverKexInit.KexAlgos[0] { - // The server sent a Kex message for the wrong algorithm, - // which we have to ignore. - if _, err := c.readPacket(); err != nil { - return err - } - } - - var H, K []byte - var hashFunc crypto.Hash - switch kexAlgo { - case kexAlgoDH14SHA1: - hashFunc = crypto.SHA1 - dhGroup14Once.Do(initDHGroup14) - H, K, err = c.kexDH(dhGroup14, hashFunc, &magics, hostKeyAlgo) - default: - err = fmt.Errorf("ssh: unexpected key exchange algorithm %v", kexAlgo) - } - if err != nil { - return err - } - - if err = c.writePacket([]byte{msgNewKeys}); err != nil { - return err - } - if err = c.transport.writer.setupKeys(clientKeys, K, H, H, hashFunc); err != nil { - return err - } - if packet, err = c.readPacket(); err != nil { - return err - } - if packet[0] != msgNewKeys { - return UnexpectedMessageError{msgNewKeys, packet[0]} - } - if err := c.transport.reader.setupKeys(serverKeys, K, H, H, hashFunc); err != nil { - return err - } - return c.authenticate(H) -} - -// kexDH performs Diffie-Hellman key agreement on a ClientConn. The -// returned values are given the same names as in RFC 4253, section 8. -func (c *ClientConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) ([]byte, []byte, error) { - x, err := rand.Int(c.config.rand(), group.p) - if err != nil { - return nil, nil, err - } - X := new(big.Int).Exp(group.g, x, group.p) - kexDHInit := kexDHInitMsg{ - X: X, - } - if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil { - return nil, nil, err - } - - packet, err := c.readPacket() - if err != nil { - return nil, nil, err - } - - var kexDHReply = new(kexDHReplyMsg) - if err = unmarshal(kexDHReply, packet, msgKexDHReply); err != nil { - return nil, nil, err - } - - if kexDHReply.Y.Sign() == 0 || kexDHReply.Y.Cmp(group.p) >= 0 { - return nil, nil, errors.New("server DH parameter out of bounds") - } - - kInt := new(big.Int).Exp(kexDHReply.Y, x, group.p) - h := hashFunc.New() - writeString(h, magics.clientVersion) - writeString(h, magics.serverVersion) - writeString(h, magics.clientKexInit) - writeString(h, magics.serverKexInit) - writeString(h, kexDHReply.HostKey) - writeInt(h, X) - writeInt(h, kexDHReply.Y) - K := make([]byte, intLength(kInt)) - marshalInt(K, kInt) - h.Write(K) - - H := h.Sum(nil) - - return H, K, nil -} - -// mainLoop reads incoming messages and routes channel messages -// to their respective ClientChans. -func (c *ClientConn) mainLoop() { - // TODO(dfc) signal the underlying close to all channels - defer c.Close() - for { - packet, err := c.readPacket() - if err != nil { - break - } - // TODO(dfc) A note on blocking channel use. - // The msg, win, data and dataExt channels of a clientChan can - // cause this loop to block indefinately if the consumer does - // not service them. - switch packet[0] { - case msgChannelData: - if len(packet) < 9 { - // malformed data packet - break - } - peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4]) - if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 { - packet = packet[9:] - c.getChan(peersId).stdout.handleData(packet[:length]) - } - case msgChannelExtendedData: - if len(packet) < 13 { - // malformed data packet - break - } - peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4]) - datatype := uint32(packet[5])<<24 | uint32(packet[6])<<16 | uint32(packet[7])<<8 | uint32(packet[8]) - if length := int(packet[9])<<24 | int(packet[10])<<16 | int(packet[11])<<8 | int(packet[12]); length > 0 { - packet = packet[13:] - // RFC 4254 5.2 defines data_type_code 1 to be data destined - // for stderr on interactive sessions. Other data types are - // silently discarded. - if datatype == 1 { - c.getChan(peersId).stderr.handleData(packet[:length]) - } - } - default: - switch msg := decode(packet).(type) { - case *channelOpenMsg: - c.getChan(msg.PeersId).msg <- msg - case *channelOpenConfirmMsg: - c.getChan(msg.PeersId).msg <- msg - case *channelOpenFailureMsg: - c.getChan(msg.PeersId).msg <- msg - case *channelCloseMsg: - ch := c.getChan(msg.PeersId) - ch.theyClosed = true - close(ch.stdin.win) - ch.stdout.eof() - ch.stderr.eof() - close(ch.msg) - if !ch.weClosed { - ch.weClosed = true - ch.sendClose() - } - c.chanlist.remove(msg.PeersId) - case *channelEOFMsg: - ch := c.getChan(msg.PeersId) - ch.stdout.eof() - // RFC 4254 is mute on how EOF affects dataExt messages but - // it is logical to signal EOF at the same time. - ch.stderr.eof() - case *channelRequestSuccessMsg: - c.getChan(msg.PeersId).msg <- msg - case *channelRequestFailureMsg: - c.getChan(msg.PeersId).msg <- msg - case *channelRequestMsg: - c.getChan(msg.PeersId).msg <- msg - case *windowAdjustMsg: - c.getChan(msg.PeersId).stdin.win <- int(msg.AdditionalBytes) - case *disconnectMsg: - break - default: - fmt.Printf("mainLoop: unhandled message %T: %v\n", msg, msg) - } - } - } -} - -// Dial connects to the given network address using net.Dial and -// then initiates a SSH handshake, returning the resulting client connection. -func Dial(network, addr string, config *ClientConfig) (*ClientConn, error) { - conn, err := net.Dial(network, addr) - if err != nil { - return nil, err - } - return Client(conn, config) -} - -// A ClientConfig structure is used to configure a ClientConn. After one has -// been passed to an SSH function it must not be modified. -type ClientConfig struct { - // Rand provides the source of entropy for key exchange. If Rand is - // nil, the cryptographic random reader in package crypto/rand will - // be used. - Rand io.Reader - - // The username to authenticate. - User string - - // A slice of ClientAuth methods. Only the first instance - // of a particular RFC 4252 method will be used during authentication. - Auth []ClientAuth - - // Cryptographic-related configuration. - Crypto CryptoConfig -} - -func (c *ClientConfig) rand() io.Reader { - if c.Rand == nil { - return rand.Reader - } - return c.Rand -} - -// A clientChan represents a single RFC 4254 channel that is multiplexed -// over a single SSH connection. -type clientChan struct { - packetWriter - id, peersId uint32 - stdin *chanWriter // receives window adjustments - stdout *chanReader // receives the payload of channelData messages - stderr *chanReader // receives the payload of channelExtendedData messages - msg chan interface{} // incoming messages - theyClosed bool // indicates the close msg has been received from the remote side - weClosed bool // incidates the close msg has been sent from our side -} - -// newClientChan returns a partially constructed *clientChan -// using the local id provided. To be usable clientChan.peersId -// needs to be assigned once known. -func newClientChan(t *transport, id uint32) *clientChan { - c := &clientChan{ - packetWriter: t, - id: id, - msg: make(chan interface{}, 16), - } - c.stdin = &chanWriter{ - win: make(chan int, 16), - clientChan: c, - } - c.stdout = &chanReader{ - data: make(chan []byte, 16), - clientChan: c, - } - c.stderr = &chanReader{ - data: make(chan []byte, 16), - clientChan: c, - } - return c -} - -// waitForChannelOpenResponse, if successful, fills out -// the peerId and records any initial window advertisement. -func (c *clientChan) waitForChannelOpenResponse() error { - switch msg := (<-c.msg).(type) { - case *channelOpenConfirmMsg: - // fixup peersId field - c.peersId = msg.MyId - c.stdin.win <- int(msg.MyWindow) - return nil - case *channelOpenFailureMsg: - return errors.New(safeString(msg.Message)) - } - return errors.New("unexpected packet") -} - -// sendEOF sends EOF to the server. RFC 4254 Section 5.3 -func (c *clientChan) sendEOF() error { - return c.writePacket(marshal(msgChannelEOF, channelEOFMsg{ - PeersId: c.peersId, - })) -} - -// sendClose signals the intent to close the channel. -func (c *clientChan) sendClose() error { - return c.writePacket(marshal(msgChannelClose, channelCloseMsg{ - PeersId: c.peersId, - })) -} - -// Close closes the channel. This does not close the underlying connection. -func (c *clientChan) Close() error { - if !c.weClosed { - c.weClosed = true - return c.sendClose() - } - return nil -} - -// Thread safe channel list. -type chanlist struct { - // protects concurrent access to chans - sync.Mutex - // chans are indexed by the local id of the channel, clientChan.id. - // The PeersId value of messages received by ClientConn.mainLoop is - // used to locate the right local clientChan in this slice. - chans []*clientChan -} - -// Allocate a new ClientChan with the next avail local id. -func (c *chanlist) newChan(t *transport) *clientChan { - c.Lock() - defer c.Unlock() - for i := range c.chans { - if c.chans[i] == nil { - ch := newClientChan(t, uint32(i)) - c.chans[i] = ch - return ch - } - } - i := len(c.chans) - ch := newClientChan(t, uint32(i)) - c.chans = append(c.chans, ch) - return ch -} - -func (c *chanlist) getChan(id uint32) *clientChan { - c.Lock() - defer c.Unlock() - return c.chans[int(id)] -} - -func (c *chanlist) remove(id uint32) { - c.Lock() - defer c.Unlock() - c.chans[int(id)] = nil -} - -// A chanWriter represents the stdin of a remote process. -type chanWriter struct { - win chan int // receives window adjustments - rwin int // current rwin size - clientChan *clientChan // the channel backing this writer -} - -// Write writes data to the remote process's standard input. -func (w *chanWriter) Write(data []byte) (written int, err error) { - for len(data) > 0 { - for w.rwin < 1 { - win, ok := <-w.win - if !ok { - return 0, io.EOF - } - w.rwin += win - } - n := min(len(data), w.rwin) - peersId := w.clientChan.peersId - packet := []byte{ - msgChannelData, - byte(peersId >> 24), byte(peersId >> 16), byte(peersId >> 8), byte(peersId), - byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n), - } - if err = w.clientChan.writePacket(append(packet, data[:n]...)); err != nil { - break - } - data = data[n:] - w.rwin -= n - written += n - } - return -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -func (w *chanWriter) Close() error { - return w.clientChan.sendEOF() -} - -// A chanReader represents stdout or stderr of a remote process. -type chanReader struct { - // TODO(dfc) a fixed size channel may not be the right data structure. - // If writes to this channel block, they will block mainLoop, making - // it unable to receive new messages from the remote side. - data chan []byte // receives data from remote - dataClosed bool // protects data from being closed twice - clientChan *clientChan // the channel backing this reader - buf []byte -} - -// eof signals to the consumer that there is no more data to be received. -func (r *chanReader) eof() { - if !r.dataClosed { - r.dataClosed = true - close(r.data) - } -} - -// handleData sends buf to the reader's consumer. If r.data is closed -// the data will be silently discarded -func (r *chanReader) handleData(buf []byte) { - if !r.dataClosed { - r.data <- buf - } -} - -// Read reads data from the remote process's stdout or stderr. -func (r *chanReader) Read(data []byte) (int, error) { - var ok bool - for { - if len(r.buf) > 0 { - n := copy(data, r.buf) - r.buf = r.buf[n:] - msg := windowAdjustMsg{ - PeersId: r.clientChan.peersId, - AdditionalBytes: uint32(n), - } - return n, r.clientChan.writePacket(marshal(msgChannelWindowAdjust, msg)) - } - r.buf, ok = <-r.data - if !ok { - return 0, io.EOF - } - } - panic("unreachable") -} diff --git a/libgo/go/exp/ssh/client_auth.go b/libgo/go/exp/ssh/client_auth.go deleted file mode 100644 index 3a7e9fb9801..00000000000 --- a/libgo/go/exp/ssh/client_auth.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "errors" - "io" -) - -// authenticate authenticates with the remote server. See RFC 4252. -func (c *ClientConn) authenticate(session []byte) error { - // initiate user auth session - if err := c.writePacket(marshal(msgServiceRequest, serviceRequestMsg{serviceUserAuth})); err != nil { - return err - } - packet, err := c.readPacket() - if err != nil { - return err - } - var serviceAccept serviceAcceptMsg - if err := unmarshal(&serviceAccept, packet, msgServiceAccept); err != nil { - return err - } - // during the authentication phase the client first attempts the "none" method - // then any untried methods suggested by the server. - tried, remain := make(map[string]bool), make(map[string]bool) - for auth := ClientAuth(new(noneAuth)); auth != nil; { - ok, methods, err := auth.auth(session, c.config.User, c.transport, c.config.rand()) - if err != nil { - return err - } - if ok { - // success - return nil - } - tried[auth.method()] = true - delete(remain, auth.method()) - for _, meth := range methods { - if tried[meth] { - // if we've tried meth already, skip it. - continue - } - remain[meth] = true - } - auth = nil - for _, a := range c.config.Auth { - if remain[a.method()] { - auth = a - break - } - } - } - return errors.New("ssh: unable to authenticate, no supported methods remain") -} - -// A ClientAuth represents an instance of an RFC 4252 authentication method. -type ClientAuth interface { - // auth authenticates user over transport t. - // Returns true if authentication is successful. - // If authentication is not successful, a []string of alternative - // method names is returned. - auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) - - // method returns the RFC 4252 method name. - method() string -} - -// "none" authentication, RFC 4252 section 5.2. -type noneAuth int - -func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { - if err := t.writePacket(marshal(msgUserAuthRequest, userAuthRequestMsg{ - User: user, - Service: serviceSSH, - Method: "none", - })); err != nil { - return false, nil, err - } - - return handleAuthResponse(t) -} - -func (n *noneAuth) method() string { - return "none" -} - -// "password" authentication, RFC 4252 Section 8. -type passwordAuth struct { - ClientPassword -} - -func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { - type passwordAuthMsg struct { - User string - Service string - Method string - Reply bool - Password string - } - - pw, err := p.Password(user) - if err != nil { - return false, nil, err - } - - if err := t.writePacket(marshal(msgUserAuthRequest, passwordAuthMsg{ - User: user, - Service: serviceSSH, - Method: "password", - Reply: false, - Password: pw, - })); err != nil { - return false, nil, err - } - - return handleAuthResponse(t) -} - -func (p *passwordAuth) method() string { - return "password" -} - -// A ClientPassword implements access to a client's passwords. -type ClientPassword interface { - // Password returns the password to use for user. - Password(user string) (password string, err error) -} - -// ClientAuthPassword returns a ClientAuth using password authentication. -func ClientAuthPassword(impl ClientPassword) ClientAuth { - return &passwordAuth{impl} -} - -// ClientKeyring implements access to a client key ring. -type ClientKeyring interface { - // Key returns the i'th rsa.Publickey or dsa.Publickey, or nil if - // no key exists at i. - Key(i int) (key interface{}, err error) - - // Sign returns a signature of the given data using the i'th key - // and the supplied random source. - Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) -} - -// "publickey" authentication, RFC 4252 Section 7. -type publickeyAuth struct { - ClientKeyring -} - -type publickeyAuthMsg struct { - User string - Service string - Method string - // HasSig indicates to the reciver packet that the auth request is signed and - // should be used for authentication of the request. - HasSig bool - Algoname string - Pubkey string - // Sig is defined as []byte so marshal will exclude it during validateKey - Sig []byte `ssh:"rest"` -} - -func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { - - // Authentication is performed in two stages. The first stage sends an - // enquiry to test if each key is acceptable to the remote. The second - // stage attempts to authenticate with the valid keys obtained in the - // first stage. - - var index int - // a map of public keys to their index in the keyring - validKeys := make(map[int]interface{}) - for { - key, err := p.Key(index) - if err != nil { - return false, nil, err - } - if key == nil { - // no more keys in the keyring - break - } - - if ok, err := p.validateKey(key, user, t); ok { - validKeys[index] = key - } else { - if err != nil { - return false, nil, err - } - } - index++ - } - - // methods that may continue if this auth is not successful. - var methods []string - for i, key := range validKeys { - pubkey := serializePublickey(key) - algoname := algoName(key) - sign, err := p.Sign(i, rand, buildDataSignedForAuth(session, userAuthRequestMsg{ - User: user, - Service: serviceSSH, - Method: p.method(), - }, []byte(algoname), pubkey)) - if err != nil { - return false, nil, err - } - // manually wrap the serialized signature in a string - s := serializeSignature(algoname, sign) - sig := make([]byte, stringLength(s)) - marshalString(sig, s) - msg := publickeyAuthMsg{ - User: user, - Service: serviceSSH, - Method: p.method(), - HasSig: true, - Algoname: algoname, - Pubkey: string(pubkey), - Sig: sig, - } - p := marshal(msgUserAuthRequest, msg) - if err := t.writePacket(p); err != nil { - return false, nil, err - } - success, methods, err := handleAuthResponse(t) - if err != nil { - return false, nil, err - } - if success { - return success, methods, err - } - } - return false, methods, nil -} - -// validateKey validates the key provided it is acceptable to the server. -func (p *publickeyAuth) validateKey(key interface{}, user string, t *transport) (bool, error) { - pubkey := serializePublickey(key) - algoname := algoName(key) - msg := publickeyAuthMsg{ - User: user, - Service: serviceSSH, - Method: p.method(), - HasSig: false, - Algoname: algoname, - Pubkey: string(pubkey), - } - if err := t.writePacket(marshal(msgUserAuthRequest, msg)); err != nil { - return false, err - } - - return p.confirmKeyAck(key, t) -} - -func (p *publickeyAuth) confirmKeyAck(key interface{}, t *transport) (bool, error) { - pubkey := serializePublickey(key) - algoname := algoName(key) - - for { - packet, err := t.readPacket() - if err != nil { - return false, err - } - switch packet[0] { - case msgUserAuthBanner: - // TODO(gpaul): add callback to present the banner to the user - case msgUserAuthPubKeyOk: - msg := decode(packet).(*userAuthPubKeyOkMsg) - if msg.Algo != algoname || msg.PubKey != string(pubkey) { - return false, nil - } - return true, nil - case msgUserAuthFailure: - return false, nil - default: - return false, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} - } - } - panic("unreachable") -} - -func (p *publickeyAuth) method() string { - return "publickey" -} - -// ClientAuthKeyring returns a ClientAuth using public key authentication. -func ClientAuthKeyring(impl ClientKeyring) ClientAuth { - return &publickeyAuth{impl} -} - -// handleAuthResponse returns whether the preceding authentication request succeeded -// along with a list of remaining authentication methods to try next and -// an error if an unexpected response was received. -func handleAuthResponse(t *transport) (bool, []string, error) { - for { - packet, err := t.readPacket() - if err != nil { - return false, nil, err - } - - switch packet[0] { - case msgUserAuthBanner: - // TODO: add callback to present the banner to the user - case msgUserAuthFailure: - msg := decode(packet).(*userAuthFailureMsg) - return false, msg.Methods, nil - case msgUserAuthSuccess: - return true, nil, nil - case msgDisconnect: - return false, nil, io.EOF - default: - return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} - } - } - panic("unreachable") -} diff --git a/libgo/go/exp/ssh/client_auth_test.go b/libgo/go/exp/ssh/client_auth_test.go deleted file mode 100644 index c41a93b5c7d..00000000000 --- a/libgo/go/exp/ssh/client_auth_test.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "bytes" - "crypto" - "crypto/dsa" - "crypto/rsa" - _ "crypto/sha1" - "crypto/x509" - "encoding/pem" - "errors" - "io" - "io/ioutil" - "math/big" - "testing" -) - -// private key for mock server -const testServerPrivateKey = `-----BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU -70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx -9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF -tupdMODN064vd3gyMKTwrlQ8tZM6aYuyOPsutLlUY7M5x5FwMDYvnPDSeyT/Iw0z -s3B+NCyqeeMd2T7YzQFnRATj0M7rM5LoSs7DVqVriOEABssFyLj31PboaoLhOKgc -qoM9khkNzr7FHVvi+DhYM2jD0DwvqZLN6NmnLwIDAQABAoIBAQCGVj+kuSFOV1lT -+IclQYA6bM6uY5mroqcSBNegVxCNhWU03BxlW//BE9tA/+kq53vWylMeN9mpGZea -riEMIh25KFGWXqXlOOioH8bkMsqA8S7sBmc7jljyv+0toQ9vCCtJ+sueNPhxQQxH -D2YvUjfzBQ04I9+wn30BByDJ1QA/FoPsunxIOUCcRBE/7jxuLYcpR+JvEF68yYIh -atXRld4W4in7T65YDR8jK1Uj9XAcNeDYNpT/M6oFLx1aPIlkG86aCWRO19S1jLPT -b1ZAKHHxPMCVkSYW0RqvIgLXQOR62D0Zne6/2wtzJkk5UCjkSQ2z7ZzJpMkWgDgN -ifCULFPBAoGBAPoMZ5q1w+zB+knXUD33n1J+niN6TZHJulpf2w5zsW+m2K6Zn62M -MXndXlVAHtk6p02q9kxHdgov34Uo8VpuNjbS1+abGFTI8NZgFo+bsDxJdItemwC4 -KJ7L1iz39hRN/ZylMRLz5uTYRGddCkeIHhiG2h7zohH/MaYzUacXEEy3AoGBANz8 -e/msleB+iXC0cXKwds26N4hyMdAFE5qAqJXvV3S2W8JZnmU+sS7vPAWMYPlERPk1 -D8Q2eXqdPIkAWBhrx4RxD7rNc5qFNcQWEhCIxC9fccluH1y5g2M+4jpMX2CT8Uv+ -3z+NoJ5uDTXZTnLCfoZzgZ4nCZVZ+6iU5U1+YXFJAoGBANLPpIV920n/nJmmquMj -orI1R/QXR9Cy56cMC65agezlGOfTYxk5Cfl5Ve+/2IJCfgzwJyjWUsFx7RviEeGw -64o7JoUom1HX+5xxdHPsyZ96OoTJ5RqtKKoApnhRMamau0fWydH1yeOEJd+TRHhc -XStGfhz8QNa1dVFvENczja1vAoGABGWhsd4VPVpHMc7lUvrf4kgKQtTC2PjA4xoc -QJ96hf/642sVE76jl+N6tkGMzGjnVm4P2j+bOy1VvwQavKGoXqJBRd5Apppv727g -/SM7hBXKFc/zH80xKBBgP/i1DR7kdjakCoeu4ngeGywvu2jTS6mQsqzkK+yWbUxJ -I7mYBsECgYB/KNXlTEpXtz/kwWCHFSYA8U74l7zZbVD8ul0e56JDK+lLcJ0tJffk -gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl -NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw== ------END RSA PRIVATE KEY-----` - -const testClientPrivateKey = `-----BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBALdGZxkXDAjsYk10ihwU6Id2KeILz1TAJuoq4tOgDWxEEGeTrcld -r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ -tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC -nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW -2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB -y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr -rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg== ------END RSA PRIVATE KEY-----` - -// keychain implements the ClientPublickey interface -type keychain struct { - keys []interface{} -} - -func (k *keychain) Key(i int) (interface{}, error) { - if i < 0 || i >= len(k.keys) { - return nil, nil - } - switch key := k.keys[i].(type) { - case *rsa.PrivateKey: - return key.PublicKey, nil - case *dsa.PrivateKey: - return key.PublicKey, nil - } - panic("unknown key type") -} - -func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) { - hashFunc := crypto.SHA1 - h := hashFunc.New() - h.Write(data) - digest := h.Sum(nil) - switch key := k.keys[i].(type) { - case *rsa.PrivateKey: - return rsa.SignPKCS1v15(rand, key, hashFunc, digest) - } - return nil, errors.New("unknown key type") -} - -func (k *keychain) loadPEM(file string) error { - buf, err := ioutil.ReadFile(file) - if err != nil { - return err - } - block, _ := pem.Decode(buf) - if block == nil { - return errors.New("ssh: no key found") - } - r, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return err - } - k.keys = append(k.keys, r) - return nil -} - -// password implements the ClientPassword interface -type password string - -func (p password) Password(user string) (string, error) { - return string(p), nil -} - -// reused internally by tests -var ( - rsakey *rsa.PrivateKey - dsakey *dsa.PrivateKey - clientKeychain = new(keychain) - clientPassword = password("tiger") - serverConfig = &ServerConfig{ - PasswordCallback: func(user, pass string) bool { - return user == "testuser" && pass == string(clientPassword) - }, - PublicKeyCallback: func(user, algo string, pubkey []byte) bool { - key := clientKeychain.keys[0].(*rsa.PrivateKey).PublicKey - expected := []byte(serializePublickey(key)) - algoname := algoName(key) - return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected) - }, - } -) - -func init() { - if err := serverConfig.SetRSAPrivateKey([]byte(testServerPrivateKey)); err != nil { - panic("unable to set private key: " + err.Error()) - } - - block, _ := pem.Decode([]byte(testClientPrivateKey)) - rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes) - - clientKeychain.keys = append(clientKeychain.keys, rsakey) - dsakey = new(dsa.PrivateKey) - // taken from crypto/dsa/dsa_test.go - dsakey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16) - dsakey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16) - dsakey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16) - dsakey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16) - dsakey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16) -} - -// newMockAuthServer creates a new Server bound to -// the loopback interface. The server exits after -// processing one handshake. -func newMockAuthServer(t *testing.T) string { - l, err := Listen("tcp", "127.0.0.1:0", serverConfig) - if err != nil { - t.Fatalf("unable to newMockAuthServer: %s", err) - } - go func() { - defer l.Close() - c, err := l.Accept() - defer c.Close() - if err != nil { - t.Errorf("Unable to accept incoming connection: %v", err) - return - } - if err := c.Handshake(); err != nil { - // not Errorf because this is expected to - // fail for some tests. - t.Logf("Handshaking error: %v", err) - return - } - }() - return l.Addr().String() -} - -func TestClientAuthPublickey(t *testing.T) { - config := &ClientConfig{ - User: "testuser", - Auth: []ClientAuth{ - ClientAuthKeyring(clientKeychain), - }, - } - c, err := Dial("tcp", newMockAuthServer(t), config) - if err != nil { - t.Fatalf("unable to dial remote side: %s", err) - } - c.Close() -} - -func TestClientAuthPassword(t *testing.T) { - config := &ClientConfig{ - User: "testuser", - Auth: []ClientAuth{ - ClientAuthPassword(clientPassword), - }, - } - - c, err := Dial("tcp", newMockAuthServer(t), config) - if err != nil { - t.Fatalf("unable to dial remote side: %s", err) - } - c.Close() -} - -func TestClientAuthWrongPassword(t *testing.T) { - wrongPw := password("wrong") - config := &ClientConfig{ - User: "testuser", - Auth: []ClientAuth{ - ClientAuthPassword(wrongPw), - ClientAuthKeyring(clientKeychain), - }, - } - - c, err := Dial("tcp", newMockAuthServer(t), config) - if err != nil { - t.Fatalf("unable to dial remote side: %s", err) - } - c.Close() -} - -// the mock server will only authenticate ssh-rsa keys -func TestClientAuthInvalidPublickey(t *testing.T) { - kc := new(keychain) - kc.keys = append(kc.keys, dsakey) - config := &ClientConfig{ - User: "testuser", - Auth: []ClientAuth{ - ClientAuthKeyring(kc), - }, - } - - c, err := Dial("tcp", newMockAuthServer(t), config) - if err == nil { - c.Close() - t.Fatalf("dsa private key should not have authenticated with rsa public key") - } -} - -// the client should authenticate with the second key -func TestClientAuthRSAandDSA(t *testing.T) { - kc := new(keychain) - kc.keys = append(kc.keys, dsakey, rsakey) - config := &ClientConfig{ - User: "testuser", - Auth: []ClientAuth{ - ClientAuthKeyring(kc), - }, - } - c, err := Dial("tcp", newMockAuthServer(t), config) - if err != nil { - t.Fatalf("client could not authenticate with rsa key: %v", err) - } - c.Close() -} diff --git a/libgo/go/exp/ssh/client_func_test.go b/libgo/go/exp/ssh/client_func_test.go deleted file mode 100644 index b4bdba95396..00000000000 --- a/libgo/go/exp/ssh/client_func_test.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2011 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 ssh - -// ClientConn functional tests. -// These tests require a running ssh server listening on port 22 -// on the local host. Functional tests will be skipped unless -// -ssh.user and -ssh.pass must be passed to gotest. - -import ( - "flag" - "testing" -) - -var ( - sshuser = flag.String("ssh.user", "", "ssh username") - sshpass = flag.String("ssh.pass", "", "ssh password") - sshprivkey = flag.String("ssh.privkey", "", "ssh privkey file") -) - -func TestFuncPasswordAuth(t *testing.T) { - if *sshuser == "" { - t.Log("ssh.user not defined, skipping test") - return - } - config := &ClientConfig{ - User: *sshuser, - Auth: []ClientAuth{ - ClientAuthPassword(password(*sshpass)), - }, - } - conn, err := Dial("tcp", "localhost:22", config) - if err != nil { - t.Fatalf("Unable to connect: %s", err) - } - defer conn.Close() -} - -func TestFuncPublickeyAuth(t *testing.T) { - if *sshuser == "" { - t.Log("ssh.user not defined, skipping test") - return - } - kc := new(keychain) - if err := kc.loadPEM(*sshprivkey); err != nil { - t.Fatalf("unable to load private key: %s", err) - } - config := &ClientConfig{ - User: *sshuser, - Auth: []ClientAuth{ - ClientAuthKeyring(kc), - }, - } - conn, err := Dial("tcp", "localhost:22", config) - if err != nil { - t.Fatalf("unable to connect: %s", err) - } - defer conn.Close() -} diff --git a/libgo/go/exp/ssh/common.go b/libgo/go/exp/ssh/common.go deleted file mode 100644 index 6844fb89b79..00000000000 --- a/libgo/go/exp/ssh/common.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "crypto/dsa" - "crypto/rsa" - "math/big" - "strconv" - "sync" -) - -// These are string constants in the SSH protocol. -const ( - kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" - hostAlgoRSA = "ssh-rsa" - macSHA196 = "hmac-sha1-96" - compressionNone = "none" - serviceUserAuth = "ssh-userauth" - serviceSSH = "ssh-connection" -) - -var supportedKexAlgos = []string{kexAlgoDH14SHA1} -var supportedHostKeyAlgos = []string{hostAlgoRSA} -var supportedMACs = []string{macSHA196} -var supportedCompressions = []string{compressionNone} - -// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. -type dhGroup struct { - g, p *big.Int -} - -// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and -// Oakley Group 14 in RFC 3526. -var dhGroup14 *dhGroup - -var dhGroup14Once sync.Once - -func initDHGroup14() { - p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) - - dhGroup14 = &dhGroup{ - g: new(big.Int).SetInt64(2), - p: p, - } -} - -// UnexpectedMessageError results when the SSH message that we received didn't -// match what we wanted. -type UnexpectedMessageError struct { - expected, got uint8 -} - -func (u UnexpectedMessageError) Error() string { - return "ssh: unexpected message type " + strconv.Itoa(int(u.got)) + " (expected " + strconv.Itoa(int(u.expected)) + ")" -} - -// ParseError results from a malformed SSH message. -type ParseError struct { - msgType uint8 -} - -func (p ParseError) Error() string { - return "ssh: parse error in message type " + strconv.Itoa(int(p.msgType)) -} - -type handshakeMagics struct { - clientVersion, serverVersion []byte - clientKexInit, serverKexInit []byte -} - -func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) { - for _, clientAlgo := range clientAlgos { - for _, serverAlgo := range serverAlgos { - if clientAlgo == serverAlgo { - return clientAlgo, true - } - } - } - - return -} - -func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) { - kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos) - if !ok { - return - } - - hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) - if !ok { - return - } - - transport.writer.cipherAlgo, ok = findCommonAlgorithm(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) - if !ok { - return - } - - transport.reader.cipherAlgo, ok = findCommonAlgorithm(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) - if !ok { - return - } - - transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) - if !ok { - return - } - - transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) - if !ok { - return - } - - transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) - if !ok { - return - } - - transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) - if !ok { - return - } - - ok = true - return -} - -// Cryptographic configuration common to both ServerConfig and ClientConfig. -type CryptoConfig struct { - // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is - // used. - Ciphers []string -} - -func (c *CryptoConfig) ciphers() []string { - if c.Ciphers == nil { - return DefaultCipherOrder - } - return c.Ciphers -} - -// serialize a signed slice according to RFC 4254 6.6. -func serializeSignature(algoname string, sig []byte) []byte { - length := stringLength([]byte(algoname)) - length += stringLength(sig) - - ret := make([]byte, length) - r := marshalString(ret, []byte(algoname)) - r = marshalString(r, sig) - - return ret -} - -// serialize an rsa.PublicKey or dsa.PublicKey according to RFC 4253 6.6. -func serializePublickey(key interface{}) []byte { - algoname := algoName(key) - switch key := key.(type) { - case rsa.PublicKey: - e := new(big.Int).SetInt64(int64(key.E)) - length := stringLength([]byte(algoname)) - length += intLength(e) - length += intLength(key.N) - ret := make([]byte, length) - r := marshalString(ret, []byte(algoname)) - r = marshalInt(r, e) - marshalInt(r, key.N) - return ret - case dsa.PublicKey: - length := stringLength([]byte(algoname)) - length += intLength(key.P) - length += intLength(key.Q) - length += intLength(key.G) - length += intLength(key.Y) - ret := make([]byte, length) - r := marshalString(ret, []byte(algoname)) - r = marshalInt(r, key.P) - r = marshalInt(r, key.Q) - r = marshalInt(r, key.G) - marshalInt(r, key.Y) - return ret - } - panic("unexpected key type") -} - -func algoName(key interface{}) string { - switch key.(type) { - case rsa.PublicKey: - return "ssh-rsa" - case dsa.PublicKey: - return "ssh-dss" - } - panic("unexpected key type") -} - -// buildDataSignedForAuth returns the data that is signed in order to prove -// posession of a private key. See RFC 4252, section 7. -func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { - user := []byte(req.User) - service := []byte(req.Service) - method := []byte(req.Method) - - length := stringLength(sessionId) - length += 1 - length += stringLength(user) - length += stringLength(service) - length += stringLength(method) - length += 1 - length += stringLength(algo) - length += stringLength(pubKey) - - ret := make([]byte, length) - r := marshalString(ret, sessionId) - r[0] = msgUserAuthRequest - r = r[1:] - r = marshalString(r, user) - r = marshalString(r, service) - r = marshalString(r, method) - r[0] = 1 - r = r[1:] - r = marshalString(r, algo) - r = marshalString(r, pubKey) - return ret -} - -// safeString sanitises s according to RFC 4251, section 9.2. -// All control characters except tab, carriage return and newline are -// replaced by 0x20. -func safeString(s string) string { - out := []byte(s) - for i, c := range out { - if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 { - out[i] = 0x20 - } - } - return string(out) -} diff --git a/libgo/go/exp/ssh/common_test.go b/libgo/go/exp/ssh/common_test.go deleted file mode 100644 index 058fb04fe1b..00000000000 --- a/libgo/go/exp/ssh/common_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "testing" -) - -func TestSafeString(t *testing.T) { - strings := map[string]string{ - "\x20\x0d\x0a": "\x20\x0d\x0a", - "flibble": "flibble", - "new\x20line": "new\x20line", - "123456\x07789": "123456 789", - "\t\t\x10\r\n": "\t\t \r\n", - } - - for s, expected := range strings { - actual := safeString(s) - if expected != actual { - t.Errorf("expected: %v, actual: %v", []byte(expected), []byte(actual)) - } - } -} diff --git a/libgo/go/exp/ssh/doc.go b/libgo/go/exp/ssh/doc.go deleted file mode 100644 index e7deb5ec168..00000000000 --- a/libgo/go/exp/ssh/doc.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2011 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 ssh implements an SSH client and server. - -SSH is a transport security protocol, an authentication protocol and a -family of application protocols. The most typical application level -protocol is a remote shell and this is specifically implemented. However, -the multiplexed nature of SSH is exposed to users that wish to support -others. - -An SSH server is represented by a ServerConfig, which holds certificate -details and handles authentication of ServerConns. - - config := new(ssh.ServerConfig) - config.PubKeyCallback = pubKeyAuth - config.PasswordCallback = passwordAuth - - pemBytes, err := ioutil.ReadFile("id_rsa") - if err != nil { - panic("Failed to load private key") - } - err = config.SetRSAPrivateKey(pemBytes) - if err != nil { - panic("Failed to parse private key") - } - -Once a ServerConfig has been configured, connections can be accepted. - - listener := Listen("tcp", "0.0.0.0:2022", config) - sConn, err := listener.Accept() - if err != nil { - panic("failed to accept incoming connection") - } - if err := sConn.Handshake(conn); err != nil { - panic("failed to handshake") - } - -An SSH connection multiplexes several channels, which must be accepted themselves: - - for { - channel, err := sConn.Accept() - if err != nil { - panic("error from Accept") - } - - ... - } - -Accept reads from the connection, demultiplexes packets to their corresponding -channels and returns when a new channel request is seen. Some goroutine must -always be calling Accept; otherwise no messages will be forwarded to the -channels. - -Channels have a type, depending on the application level protocol intended. In -the case of a shell, the type is "session" and ServerShell may be used to -present a simple terminal interface. - - if channel.ChannelType() != "session" { - channel.Reject(UnknownChannelType, "unknown channel type") - return - } - channel.Accept() - - term := terminal.NewTerminal(channel, "> ") - serverTerm := &ssh.ServerTerminal{ - Term: term, - Channel: channel, - } - go func() { - defer channel.Close() - for { - line, err := serverTerm.ReadLine() - if err != nil { - break - } - println(line) - } - return - }() - -To authenticate with the remote server you must pass at least one implementation of -ClientAuth via the Auth field in ClientConfig. - - // password implements the ClientPassword interface - type password string - - func (p password) Password(user string) (string, error) { - return string(p), nil - } - - config := &ssh.ClientConfig { - User: "username", - Auth: []ClientAuth { - // ClientAuthPassword wraps a ClientPassword implementation - // in a type that implements ClientAuth. - ClientAuthPassword(password("yourpassword")), - } - } - -An SSH client is represented with a ClientConn. Currently only the "password" -authentication method is supported. - - config := &ClientConfig{ - User: "username", - Auth: []ClientAuth{ ... }, - } - client, err := Dial("yourserver.com:22", config) - -Each ClientConn can support multiple interactive sessions, represented by a Session. - - session, err := client.NewSession() - -Once a Session is created, you can execute a single command on the remote side -using the Exec method. - - b := bytes.NewBuffer() - session.Stdin = b - if err := session.Run("/usr/bin/whoami"); err != nil { - panic("Failed to exec: " + err.String()) - } - fmt.Println(bytes.String()) - session.Close() -*/ -package ssh diff --git a/libgo/go/exp/ssh/messages.go b/libgo/go/exp/ssh/messages.go deleted file mode 100644 index 34ad131ff64..00000000000 --- a/libgo/go/exp/ssh/messages.go +++ /dev/null @@ -1,640 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "bytes" - "io" - "math/big" - "reflect" -) - -// These are SSH message type numbers. They are scattered around several -// documents but many were taken from -// http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 -const ( - msgDisconnect = 1 - msgIgnore = 2 - msgUnimplemented = 3 - msgDebug = 4 - msgServiceRequest = 5 - msgServiceAccept = 6 - - msgKexInit = 20 - msgNewKeys = 21 - - msgKexDHInit = 30 - msgKexDHReply = 31 - - msgUserAuthRequest = 50 - msgUserAuthFailure = 51 - msgUserAuthSuccess = 52 - msgUserAuthBanner = 53 - msgUserAuthPubKeyOk = 60 - - msgGlobalRequest = 80 - msgRequestSuccess = 81 - msgRequestFailure = 82 - - msgChannelOpen = 90 - msgChannelOpenConfirm = 91 - msgChannelOpenFailure = 92 - msgChannelWindowAdjust = 93 - msgChannelData = 94 - msgChannelExtendedData = 95 - msgChannelEOF = 96 - msgChannelClose = 97 - msgChannelRequest = 98 - msgChannelSuccess = 99 - msgChannelFailure = 100 -) - -// SSH messages: -// -// These structures mirror the wire format of the corresponding SSH messages. -// They are marshaled using reflection with the marshal and unmarshal functions -// in this file. The only wrinkle is that a final member of type []byte with a -// ssh tag of "rest" receives the remainder of a packet when unmarshaling. - -// See RFC 4253, section 11.1. -type disconnectMsg struct { - Reason uint32 - Message string - Language string -} - -// See RFC 4253, section 7.1. -type kexInitMsg struct { - Cookie [16]byte - KexAlgos []string - ServerHostKeyAlgos []string - CiphersClientServer []string - CiphersServerClient []string - MACsClientServer []string - MACsServerClient []string - CompressionClientServer []string - CompressionServerClient []string - LanguagesClientServer []string - LanguagesServerClient []string - FirstKexFollows bool - Reserved uint32 -} - -// See RFC 4253, section 8. -type kexDHInitMsg struct { - X *big.Int -} - -type kexDHReplyMsg struct { - HostKey []byte - Y *big.Int - Signature []byte -} - -// See RFC 4253, section 10. -type serviceRequestMsg struct { - Service string -} - -// See RFC 4253, section 10. -type serviceAcceptMsg struct { - Service string -} - -// See RFC 4252, section 5. -type userAuthRequestMsg struct { - User string - Service string - Method string - Payload []byte `ssh:"rest"` -} - -// See RFC 4252, section 5.1 -type userAuthFailureMsg struct { - Methods []string - PartialSuccess bool -} - -// See RFC 4254, section 5.1. -type channelOpenMsg struct { - ChanType string - PeersId uint32 - PeersWindow uint32 - MaxPacketSize uint32 - TypeSpecificData []byte `ssh:"rest"` -} - -// See RFC 4254, section 5.1. -type channelOpenConfirmMsg struct { - PeersId uint32 - MyId uint32 - MyWindow uint32 - MaxPacketSize uint32 - TypeSpecificData []byte `ssh:"rest"` -} - -// See RFC 4254, section 5.1. -type channelOpenFailureMsg struct { - PeersId uint32 - Reason uint32 - Message string - Language string -} - -type channelRequestMsg struct { - PeersId uint32 - Request string - WantReply bool - RequestSpecificData []byte `ssh:"rest"` -} - -// See RFC 4254, section 5.4. -type channelRequestSuccessMsg struct { - PeersId uint32 -} - -// See RFC 4254, section 5.4. -type channelRequestFailureMsg struct { - PeersId uint32 -} - -// See RFC 4254, section 5.3 -type channelCloseMsg struct { - PeersId uint32 -} - -// See RFC 4254, section 5.3 -type channelEOFMsg struct { - PeersId uint32 -} - -// See RFC 4254, section 4 -type globalRequestMsg struct { - Type string - WantReply bool -} - -// See RFC 4254, section 5.2 -type windowAdjustMsg struct { - PeersId uint32 - AdditionalBytes uint32 -} - -// See RFC 4252, section 7 -type userAuthPubKeyOkMsg struct { - Algo string - PubKey string -} - -// unmarshal parses the SSH wire data in packet into out using reflection. -// expectedType is the expected SSH message type. It either returns nil on -// success, or a ParseError or UnexpectedMessageError on error. -func unmarshal(out interface{}, packet []byte, expectedType uint8) error { - if len(packet) == 0 { - return ParseError{expectedType} - } - if packet[0] != expectedType { - return UnexpectedMessageError{expectedType, packet[0]} - } - packet = packet[1:] - - v := reflect.ValueOf(out).Elem() - structType := v.Type() - var ok bool - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - t := field.Type() - switch t.Kind() { - case reflect.Bool: - if len(packet) < 1 { - return ParseError{expectedType} - } - field.SetBool(packet[0] != 0) - packet = packet[1:] - case reflect.Array: - if t.Elem().Kind() != reflect.Uint8 { - panic("array of non-uint8") - } - if len(packet) < t.Len() { - return ParseError{expectedType} - } - for j := 0; j < t.Len(); j++ { - field.Index(j).Set(reflect.ValueOf(packet[j])) - } - packet = packet[t.Len():] - case reflect.Uint32: - var u32 uint32 - if u32, packet, ok = parseUint32(packet); !ok { - return ParseError{expectedType} - } - field.SetUint(uint64(u32)) - case reflect.String: - var s []byte - if s, packet, ok = parseString(packet); !ok { - return ParseError{expectedType} - } - field.SetString(string(s)) - case reflect.Slice: - switch t.Elem().Kind() { - case reflect.Uint8: - if structType.Field(i).Tag.Get("ssh") == "rest" { - field.Set(reflect.ValueOf(packet)) - packet = nil - } else { - var s []byte - if s, packet, ok = parseString(packet); !ok { - return ParseError{expectedType} - } - field.Set(reflect.ValueOf(s)) - } - case reflect.String: - var nl []string - if nl, packet, ok = parseNameList(packet); !ok { - return ParseError{expectedType} - } - field.Set(reflect.ValueOf(nl)) - default: - panic("slice of unknown type") - } - case reflect.Ptr: - if t == bigIntType { - var n *big.Int - if n, packet, ok = parseInt(packet); !ok { - return ParseError{expectedType} - } - field.Set(reflect.ValueOf(n)) - } else { - panic("pointer to unknown type") - } - default: - panic("unknown type") - } - } - - if len(packet) != 0 { - return ParseError{expectedType} - } - - return nil -} - -// marshal serializes the message in msg, using the given message type. -func marshal(msgType uint8, msg interface{}) []byte { - var out []byte - out = append(out, msgType) - - v := reflect.ValueOf(msg) - structType := v.Type() - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - t := field.Type() - switch t.Kind() { - case reflect.Bool: - var v uint8 - if field.Bool() { - v = 1 - } - out = append(out, v) - case reflect.Array: - if t.Elem().Kind() != reflect.Uint8 { - panic("array of non-uint8") - } - for j := 0; j < t.Len(); j++ { - out = append(out, byte(field.Index(j).Uint())) - } - case reflect.Uint32: - u32 := uint32(field.Uint()) - out = append(out, byte(u32>>24)) - out = append(out, byte(u32>>16)) - out = append(out, byte(u32>>8)) - out = append(out, byte(u32)) - case reflect.String: - s := field.String() - out = append(out, byte(len(s)>>24)) - out = append(out, byte(len(s)>>16)) - out = append(out, byte(len(s)>>8)) - out = append(out, byte(len(s))) - out = append(out, s...) - case reflect.Slice: - switch t.Elem().Kind() { - case reflect.Uint8: - length := field.Len() - if structType.Field(i).Tag.Get("ssh") != "rest" { - out = append(out, byte(length>>24)) - out = append(out, byte(length>>16)) - out = append(out, byte(length>>8)) - out = append(out, byte(length)) - } - for j := 0; j < length; j++ { - out = append(out, byte(field.Index(j).Uint())) - } - case reflect.String: - var length int - for j := 0; j < field.Len(); j++ { - if j != 0 { - length++ /* comma */ - } - length += len(field.Index(j).String()) - } - - out = append(out, byte(length>>24)) - out = append(out, byte(length>>16)) - out = append(out, byte(length>>8)) - out = append(out, byte(length)) - for j := 0; j < field.Len(); j++ { - if j != 0 { - out = append(out, ',') - } - out = append(out, field.Index(j).String()...) - } - default: - panic("slice of unknown type") - } - case reflect.Ptr: - if t == bigIntType { - var n *big.Int - nValue := reflect.ValueOf(&n) - nValue.Elem().Set(field) - needed := intLength(n) - oldLength := len(out) - - if cap(out)-len(out) < needed { - newOut := make([]byte, len(out), 2*(len(out)+needed)) - copy(newOut, out) - out = newOut - } - out = out[:oldLength+needed] - marshalInt(out[oldLength:], n) - } else { - panic("pointer to unknown type") - } - } - } - - return out -} - -var bigOne = big.NewInt(1) - -func parseString(in []byte) (out, rest []byte, ok bool) { - if len(in) < 4 { - return - } - length := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3]) - if uint32(len(in)) < 4+length { - return - } - out = in[4 : 4+length] - rest = in[4+length:] - ok = true - return -} - -var ( - comma = []byte{','} - emptyNameList = []string{} -) - -func parseNameList(in []byte) (out []string, rest []byte, ok bool) { - contents, rest, ok := parseString(in) - if !ok { - return - } - if len(contents) == 0 { - out = emptyNameList - return - } - parts := bytes.Split(contents, comma) - out = make([]string, len(parts)) - for i, part := range parts { - out[i] = string(part) - } - return -} - -func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) { - contents, rest, ok := parseString(in) - if !ok { - return - } - out = new(big.Int) - - if len(contents) > 0 && contents[0]&0x80 == 0x80 { - // This is a negative number - notBytes := make([]byte, len(contents)) - for i := range notBytes { - notBytes[i] = ^contents[i] - } - out.SetBytes(notBytes) - out.Add(out, bigOne) - out.Neg(out) - } else { - // Positive number - out.SetBytes(contents) - } - ok = true - return -} - -func parseUint32(in []byte) (out uint32, rest []byte, ok bool) { - if len(in) < 4 { - return - } - out = uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3]) - rest = in[4:] - ok = true - return -} - -func nameListLength(namelist []string) int { - length := 4 /* uint32 length prefix */ - for i, name := range namelist { - if i != 0 { - length++ /* comma */ - } - length += len(name) - } - return length -} - -func intLength(n *big.Int) int { - length := 4 /* length bytes */ - if n.Sign() < 0 { - nMinus1 := new(big.Int).Neg(n) - nMinus1.Sub(nMinus1, bigOne) - bitLen := nMinus1.BitLen() - if bitLen%8 == 0 { - // The number will need 0xff padding - length++ - } - length += (bitLen + 7) / 8 - } else if n.Sign() == 0 { - // A zero is the zero length string - } else { - bitLen := n.BitLen() - if bitLen%8 == 0 { - // The number will need 0x00 padding - length++ - } - length += (bitLen + 7) / 8 - } - - return length -} - -func marshalUint32(to []byte, n uint32) []byte { - to[0] = byte(n >> 24) - to[1] = byte(n >> 16) - to[2] = byte(n >> 8) - to[3] = byte(n) - return to[4:] -} - -func marshalUint64(to []byte, n uint64) []byte { - to[0] = byte(n >> 56) - to[1] = byte(n >> 48) - to[2] = byte(n >> 40) - to[3] = byte(n >> 32) - to[4] = byte(n >> 24) - to[5] = byte(n >> 16) - to[6] = byte(n >> 8) - to[7] = byte(n) - return to[8:] -} - -func marshalInt(to []byte, n *big.Int) []byte { - lengthBytes := to - to = to[4:] - length := 0 - - if n.Sign() < 0 { - // A negative number has to be converted to two's-complement - // form. So we'll subtract 1 and invert. If the - // most-significant-bit isn't set then we'll need to pad the - // beginning with 0xff in order to keep the number negative. - nMinus1 := new(big.Int).Neg(n) - nMinus1.Sub(nMinus1, bigOne) - bytes := nMinus1.Bytes() - for i := range bytes { - bytes[i] ^= 0xff - } - if len(bytes) == 0 || bytes[0]&0x80 == 0 { - to[0] = 0xff - to = to[1:] - length++ - } - nBytes := copy(to, bytes) - to = to[nBytes:] - length += nBytes - } else if n.Sign() == 0 { - // A zero is the zero length string - } else { - bytes := n.Bytes() - if len(bytes) > 0 && bytes[0]&0x80 != 0 { - // We'll have to pad this with a 0x00 in order to - // stop it looking like a negative number. - to[0] = 0 - to = to[1:] - length++ - } - nBytes := copy(to, bytes) - to = to[nBytes:] - length += nBytes - } - - lengthBytes[0] = byte(length >> 24) - lengthBytes[1] = byte(length >> 16) - lengthBytes[2] = byte(length >> 8) - lengthBytes[3] = byte(length) - return to -} - -func writeInt(w io.Writer, n *big.Int) { - length := intLength(n) - buf := make([]byte, length) - marshalInt(buf, n) - w.Write(buf) -} - -func writeString(w io.Writer, s []byte) { - var lengthBytes [4]byte - lengthBytes[0] = byte(len(s) >> 24) - lengthBytes[1] = byte(len(s) >> 16) - lengthBytes[2] = byte(len(s) >> 8) - lengthBytes[3] = byte(len(s)) - w.Write(lengthBytes[:]) - w.Write(s) -} - -func stringLength(s []byte) int { - return 4 + len(s) -} - -func marshalString(to []byte, s []byte) []byte { - to[0] = byte(len(s) >> 24) - to[1] = byte(len(s) >> 16) - to[2] = byte(len(s) >> 8) - to[3] = byte(len(s)) - to = to[4:] - copy(to, s) - return to[len(s):] -} - -var bigIntType = reflect.TypeOf((*big.Int)(nil)) - -// Decode a packet into it's corresponding message. -func decode(packet []byte) interface{} { - var msg interface{} - switch packet[0] { - case msgDisconnect: - msg = new(disconnectMsg) - case msgServiceRequest: - msg = new(serviceRequestMsg) - case msgServiceAccept: - msg = new(serviceAcceptMsg) - case msgKexInit: - msg = new(kexInitMsg) - case msgKexDHInit: - msg = new(kexDHInitMsg) - case msgKexDHReply: - msg = new(kexDHReplyMsg) - case msgUserAuthRequest: - msg = new(userAuthRequestMsg) - case msgUserAuthFailure: - msg = new(userAuthFailureMsg) - case msgUserAuthPubKeyOk: - msg = new(userAuthPubKeyOkMsg) - case msgGlobalRequest: - msg = new(globalRequestMsg) - case msgRequestSuccess: - msg = new(channelRequestSuccessMsg) - case msgRequestFailure: - msg = new(channelRequestFailureMsg) - case msgChannelOpen: - msg = new(channelOpenMsg) - case msgChannelOpenConfirm: - msg = new(channelOpenConfirmMsg) - case msgChannelOpenFailure: - msg = new(channelOpenFailureMsg) - case msgChannelWindowAdjust: - msg = new(windowAdjustMsg) - case msgChannelEOF: - msg = new(channelEOFMsg) - case msgChannelClose: - msg = new(channelCloseMsg) - case msgChannelRequest: - msg = new(channelRequestMsg) - case msgChannelSuccess: - msg = new(channelRequestSuccessMsg) - case msgChannelFailure: - msg = new(channelRequestFailureMsg) - default: - return UnexpectedMessageError{0, packet[0]} - } - if err := unmarshal(msg, packet, packet[0]); err != nil { - return err - } - return msg -} diff --git a/libgo/go/exp/ssh/messages_test.go b/libgo/go/exp/ssh/messages_test.go deleted file mode 100644 index fe4c397dc3a..00000000000 --- a/libgo/go/exp/ssh/messages_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "math/big" - "math/rand" - "reflect" - "testing" - "testing/quick" -) - -var intLengthTests = []struct { - val, length int -}{ - {0, 4 + 0}, - {1, 4 + 1}, - {127, 4 + 1}, - {128, 4 + 2}, - {-1, 4 + 1}, -} - -func TestIntLength(t *testing.T) { - for _, test := range intLengthTests { - v := new(big.Int).SetInt64(int64(test.val)) - length := intLength(v) - if length != test.length { - t.Errorf("For %d, got length %d but expected %d", test.val, length, test.length) - } - } -} - -var messageTypes = []interface{}{ - &kexInitMsg{}, - &kexDHInitMsg{}, - &serviceRequestMsg{}, - &serviceAcceptMsg{}, - &userAuthRequestMsg{}, - &channelOpenMsg{}, - &channelOpenConfirmMsg{}, - &channelRequestMsg{}, - &channelRequestSuccessMsg{}, -} - -func TestMarshalUnmarshal(t *testing.T) { - rand := rand.New(rand.NewSource(0)) - for i, iface := range messageTypes { - ty := reflect.ValueOf(iface).Type() - - n := 100 - if testing.Short() { - n = 5 - } - for j := 0; j < n; j++ { - v, ok := quick.Value(ty, rand) - if !ok { - t.Errorf("#%d: failed to create value", i) - break - } - - m1 := v.Elem().Interface() - m2 := iface - - marshaled := marshal(msgIgnore, m1) - if err := unmarshal(m2, marshaled, msgIgnore); err != nil { - t.Errorf("#%d failed to unmarshal %#v: %s", i, m1, err) - break - } - - if !reflect.DeepEqual(v.Interface(), m2) { - t.Errorf("#%d\ngot: %#v\nwant:%#v\n%x", i, m2, m1, marshaled) - break - } - } - } -} - -func randomBytes(out []byte, rand *rand.Rand) { - for i := 0; i < len(out); i++ { - out[i] = byte(rand.Int31()) - } -} - -func randomNameList(rand *rand.Rand) []string { - ret := make([]string, rand.Int31()&15) - for i := range ret { - s := make([]byte, 1+(rand.Int31()&15)) - for j := range s { - s[j] = 'a' + uint8(rand.Int31()&15) - } - ret[i] = string(s) - } - return ret -} - -func randomInt(rand *rand.Rand) *big.Int { - return new(big.Int).SetInt64(int64(int32(rand.Uint32()))) -} - -func (*kexInitMsg) Generate(rand *rand.Rand, size int) reflect.Value { - ki := &kexInitMsg{} - randomBytes(ki.Cookie[:], rand) - ki.KexAlgos = randomNameList(rand) - ki.ServerHostKeyAlgos = randomNameList(rand) - ki.CiphersClientServer = randomNameList(rand) - ki.CiphersServerClient = randomNameList(rand) - ki.MACsClientServer = randomNameList(rand) - ki.MACsServerClient = randomNameList(rand) - ki.CompressionClientServer = randomNameList(rand) - ki.CompressionServerClient = randomNameList(rand) - ki.LanguagesClientServer = randomNameList(rand) - ki.LanguagesServerClient = randomNameList(rand) - if rand.Int31()&1 == 1 { - ki.FirstKexFollows = true - } - return reflect.ValueOf(ki) -} - -func (*kexDHInitMsg) Generate(rand *rand.Rand, size int) reflect.Value { - dhi := &kexDHInitMsg{} - dhi.X = randomInt(rand) - return reflect.ValueOf(dhi) -} diff --git a/libgo/go/exp/ssh/server.go b/libgo/go/exp/ssh/server.go deleted file mode 100644 index 31011c66176..00000000000 --- a/libgo/go/exp/ssh/server.go +++ /dev/null @@ -1,676 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "bytes" - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "errors" - "io" - "math/big" - "net" - "sync" -) - -type ServerConfig struct { - rsa *rsa.PrivateKey - rsaSerialized []byte - - // Rand provides the source of entropy for key exchange. If Rand is - // nil, the cryptographic random reader in package crypto/rand will - // be used. - Rand io.Reader - - // NoClientAuth is true if clients are allowed to connect without - // authenticating. - NoClientAuth bool - - // PasswordCallback, if non-nil, is called when a user attempts to - // authenticate using a password. It may be called concurrently from - // several goroutines. - PasswordCallback func(user, password string) bool - - // PublicKeyCallback, if non-nil, is called when a client attempts public - // key authentication. It must return true iff the given public key is - // valid for the given user. - PublicKeyCallback func(user, algo string, pubkey []byte) bool - - // Cryptographic-related configuration. - Crypto CryptoConfig -} - -func (c *ServerConfig) rand() io.Reader { - if c.Rand == nil { - return rand.Reader - } - return c.Rand -} - -// SetRSAPrivateKey sets the private key for a Server. A Server must have a -// private key configured in order to accept connections. The private key must -// be in the form of a PEM encoded, PKCS#1, RSA private key. The file "id_rsa" -// typically contains such a key. -func (s *ServerConfig) SetRSAPrivateKey(pemBytes []byte) error { - block, _ := pem.Decode(pemBytes) - if block == nil { - return errors.New("ssh: no key found") - } - var err error - s.rsa, err = x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return err - } - - s.rsaSerialized = marshalRSA(s.rsa) - return nil -} - -// marshalRSA serializes an RSA private key according to RFC 4256, section 6.6. -func marshalRSA(priv *rsa.PrivateKey) []byte { - e := new(big.Int).SetInt64(int64(priv.E)) - length := stringLength([]byte(hostAlgoRSA)) - length += intLength(e) - length += intLength(priv.N) - - ret := make([]byte, length) - r := marshalString(ret, []byte(hostAlgoRSA)) - r = marshalInt(r, e) - r = marshalInt(r, priv.N) - - return ret -} - -// parseRSA parses an RSA key according to RFC 4256, section 6.6. -func parseRSA(in []byte) (pubKey *rsa.PublicKey, ok bool) { - algo, in, ok := parseString(in) - if !ok || string(algo) != hostAlgoRSA { - return nil, false - } - bigE, in, ok := parseInt(in) - if !ok || bigE.BitLen() > 24 { - return nil, false - } - e := bigE.Int64() - if e < 3 || e&1 == 0 { - return nil, false - } - N, in, ok := parseInt(in) - if !ok || len(in) > 0 { - return nil, false - } - return &rsa.PublicKey{ - N: N, - E: int(e), - }, true -} - -func parseRSASig(in []byte) (sig []byte, ok bool) { - algo, in, ok := parseString(in) - if !ok || string(algo) != hostAlgoRSA { - return nil, false - } - sig, in, ok = parseString(in) - if len(in) > 0 { - ok = false - } - return -} - -// cachedPubKey contains the results of querying whether a public key is -// acceptable for a user. The cache only applies to a single ServerConn. -type cachedPubKey struct { - user, algo string - pubKey []byte - result bool -} - -const maxCachedPubKeys = 16 - -// A ServerConn represents an incomming connection. -type ServerConn struct { - *transport - config *ServerConfig - - channels map[uint32]*channel - nextChanId uint32 - - // lock protects err and also allows Channels to serialise their writes - // to out. - lock sync.RWMutex - err error - - // cachedPubKeys contains the cache results of tests for public keys. - // Since SSH clients will query whether a public key is acceptable - // before attempting to authenticate with it, we end up with duplicate - // queries for public key validity. - cachedPubKeys []cachedPubKey -} - -// Server returns a new SSH server connection -// using c as the underlying transport. -func Server(c net.Conn, config *ServerConfig) *ServerConn { - conn := &ServerConn{ - transport: newTransport(c, config.rand()), - channels: make(map[uint32]*channel), - config: config, - } - return conn -} - -// kexDH performs Diffie-Hellman key agreement on a ServerConnection. The -// returned values are given the same names as in RFC 4253, section 8. -func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) (H, K []byte, err error) { - packet, err := s.readPacket() - if err != nil { - return - } - var kexDHInit kexDHInitMsg - if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil { - return - } - - if kexDHInit.X.Sign() == 0 || kexDHInit.X.Cmp(group.p) >= 0 { - return nil, nil, errors.New("client DH parameter out of bounds") - } - - y, err := rand.Int(s.config.rand(), group.p) - if err != nil { - return - } - - Y := new(big.Int).Exp(group.g, y, group.p) - kInt := new(big.Int).Exp(kexDHInit.X, y, group.p) - - var serializedHostKey []byte - switch hostKeyAlgo { - case hostAlgoRSA: - serializedHostKey = s.config.rsaSerialized - default: - return nil, nil, errors.New("internal error") - } - - h := hashFunc.New() - writeString(h, magics.clientVersion) - writeString(h, magics.serverVersion) - writeString(h, magics.clientKexInit) - writeString(h, magics.serverKexInit) - writeString(h, serializedHostKey) - writeInt(h, kexDHInit.X) - writeInt(h, Y) - K = make([]byte, intLength(kInt)) - marshalInt(K, kInt) - h.Write(K) - - H = h.Sum(nil) - - h.Reset() - h.Write(H) - hh := h.Sum(nil) - - var sig []byte - switch hostKeyAlgo { - case hostAlgoRSA: - sig, err = rsa.SignPKCS1v15(s.config.rand(), s.config.rsa, hashFunc, hh) - if err != nil { - return - } - default: - return nil, nil, errors.New("internal error") - } - - serializedSig := serializeSignature(hostAlgoRSA, sig) - - kexDHReply := kexDHReplyMsg{ - HostKey: serializedHostKey, - Y: Y, - Signature: serializedSig, - } - packet = marshal(msgKexDHReply, kexDHReply) - - err = s.writePacket(packet) - return -} - -// serverVersion is the fixed identification string that Server will use. -var serverVersion = []byte("SSH-2.0-Go\r\n") - -// Handshake performs an SSH transport and client authentication on the given ServerConn. -func (s *ServerConn) Handshake() error { - var magics handshakeMagics - if _, err := s.Write(serverVersion); err != nil { - return err - } - if err := s.Flush(); err != nil { - return err - } - magics.serverVersion = serverVersion[:len(serverVersion)-2] - - version, err := readVersion(s) - if err != nil { - return err - } - magics.clientVersion = version - - serverKexInit := kexInitMsg{ - KexAlgos: supportedKexAlgos, - ServerHostKeyAlgos: supportedHostKeyAlgos, - CiphersClientServer: s.config.Crypto.ciphers(), - CiphersServerClient: s.config.Crypto.ciphers(), - MACsClientServer: supportedMACs, - MACsServerClient: supportedMACs, - CompressionClientServer: supportedCompressions, - CompressionServerClient: supportedCompressions, - } - kexInitPacket := marshal(msgKexInit, serverKexInit) - magics.serverKexInit = kexInitPacket - - if err := s.writePacket(kexInitPacket); err != nil { - return err - } - - packet, err := s.readPacket() - if err != nil { - return err - } - - magics.clientKexInit = packet - - var clientKexInit kexInitMsg - if err = unmarshal(&clientKexInit, packet, msgKexInit); err != nil { - return err - } - - kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(s.transport, &clientKexInit, &serverKexInit) - if !ok { - return errors.New("ssh: no common algorithms") - } - - if clientKexInit.FirstKexFollows && kexAlgo != clientKexInit.KexAlgos[0] { - // The client sent a Kex message for the wrong algorithm, - // which we have to ignore. - if _, err := s.readPacket(); err != nil { - return err - } - } - - var H, K []byte - var hashFunc crypto.Hash - switch kexAlgo { - case kexAlgoDH14SHA1: - hashFunc = crypto.SHA1 - dhGroup14Once.Do(initDHGroup14) - H, K, err = s.kexDH(dhGroup14, hashFunc, &magics, hostKeyAlgo) - default: - err = errors.New("ssh: unexpected key exchange algorithm " + kexAlgo) - } - if err != nil { - return err - } - - if err = s.writePacket([]byte{msgNewKeys}); err != nil { - return err - } - if err = s.transport.writer.setupKeys(serverKeys, K, H, H, hashFunc); err != nil { - return err - } - if packet, err = s.readPacket(); err != nil { - return err - } - - if packet[0] != msgNewKeys { - return UnexpectedMessageError{msgNewKeys, packet[0]} - } - if err = s.transport.reader.setupKeys(clientKeys, K, H, H, hashFunc); err != nil { - return err - } - if packet, err = s.readPacket(); err != nil { - return err - } - - var serviceRequest serviceRequestMsg - if err = unmarshal(&serviceRequest, packet, msgServiceRequest); err != nil { - return err - } - if serviceRequest.Service != serviceUserAuth { - return errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") - } - serviceAccept := serviceAcceptMsg{ - Service: serviceUserAuth, - } - if err = s.writePacket(marshal(msgServiceAccept, serviceAccept)); err != nil { - return err - } - - if err = s.authenticate(H); err != nil { - return err - } - return nil -} - -func isAcceptableAlgo(algo string) bool { - return algo == hostAlgoRSA -} - -// testPubKey returns true if the given public key is acceptable for the user. -func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool { - if s.config.PublicKeyCallback == nil || !isAcceptableAlgo(algo) { - return false - } - - for _, c := range s.cachedPubKeys { - if c.user == user && c.algo == algo && bytes.Equal(c.pubKey, pubKey) { - return c.result - } - } - - result := s.config.PublicKeyCallback(user, algo, pubKey) - if len(s.cachedPubKeys) < maxCachedPubKeys { - c := cachedPubKey{ - user: user, - algo: algo, - pubKey: make([]byte, len(pubKey)), - result: result, - } - copy(c.pubKey, pubKey) - s.cachedPubKeys = append(s.cachedPubKeys, c) - } - - return result -} - -func (s *ServerConn) authenticate(H []byte) error { - var userAuthReq userAuthRequestMsg - var err error - var packet []byte - -userAuthLoop: - for { - if packet, err = s.readPacket(); err != nil { - return err - } - if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); err != nil { - return err - } - - if userAuthReq.Service != serviceSSH { - return errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) - } - - switch userAuthReq.Method { - case "none": - if s.config.NoClientAuth { - break userAuthLoop - } - case "password": - if s.config.PasswordCallback == nil { - break - } - payload := userAuthReq.Payload - if len(payload) < 1 || payload[0] != 0 { - return ParseError{msgUserAuthRequest} - } - payload = payload[1:] - password, payload, ok := parseString(payload) - if !ok || len(payload) > 0 { - return ParseError{msgUserAuthRequest} - } - - if s.config.PasswordCallback(userAuthReq.User, string(password)) { - break userAuthLoop - } - case "publickey": - if s.config.PublicKeyCallback == nil { - break - } - payload := userAuthReq.Payload - if len(payload) < 1 { - return ParseError{msgUserAuthRequest} - } - isQuery := payload[0] == 0 - payload = payload[1:] - algoBytes, payload, ok := parseString(payload) - if !ok { - return ParseError{msgUserAuthRequest} - } - algo := string(algoBytes) - - pubKey, payload, ok := parseString(payload) - if !ok { - return ParseError{msgUserAuthRequest} - } - if isQuery { - // The client can query if the given public key - // would be ok. - if len(payload) > 0 { - return ParseError{msgUserAuthRequest} - } - if s.testPubKey(userAuthReq.User, algo, pubKey) { - okMsg := userAuthPubKeyOkMsg{ - Algo: algo, - PubKey: string(pubKey), - } - if err = s.writePacket(marshal(msgUserAuthPubKeyOk, okMsg)); err != nil { - return err - } - continue userAuthLoop - } - } else { - sig, payload, ok := parseString(payload) - if !ok || len(payload) > 0 { - return ParseError{msgUserAuthRequest} - } - if !isAcceptableAlgo(algo) { - break - } - rsaSig, ok := parseRSASig(sig) - if !ok { - return ParseError{msgUserAuthRequest} - } - signedData := buildDataSignedForAuth(H, userAuthReq, algoBytes, pubKey) - switch algo { - case hostAlgoRSA: - hashFunc := crypto.SHA1 - h := hashFunc.New() - h.Write(signedData) - digest := h.Sum(nil) - rsaKey, ok := parseRSA(pubKey) - if !ok { - return ParseError{msgUserAuthRequest} - } - if rsa.VerifyPKCS1v15(rsaKey, hashFunc, digest, rsaSig) != nil { - return ParseError{msgUserAuthRequest} - } - default: - return errors.New("ssh: isAcceptableAlgo incorrect") - } - if s.testPubKey(userAuthReq.User, algo, pubKey) { - break userAuthLoop - } - } - } - - var failureMsg userAuthFailureMsg - if s.config.PasswordCallback != nil { - failureMsg.Methods = append(failureMsg.Methods, "password") - } - if s.config.PublicKeyCallback != nil { - failureMsg.Methods = append(failureMsg.Methods, "publickey") - } - - if len(failureMsg.Methods) == 0 { - return errors.New("ssh: no authentication methods configured but NoClientAuth is also false") - } - - if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil { - return err - } - } - - packet = []byte{msgUserAuthSuccess} - if err = s.writePacket(packet); err != nil { - return err - } - - return nil -} - -const defaultWindowSize = 32768 - -// Accept reads and processes messages on a ServerConn. It must be called -// in order to demultiplex messages to any resulting Channels. -func (s *ServerConn) Accept() (Channel, error) { - if s.err != nil { - return nil, s.err - } - - for { - packet, err := s.readPacket() - if err != nil { - - s.lock.Lock() - s.err = err - s.lock.Unlock() - - for _, c := range s.channels { - c.dead = true - c.handleData(nil) - } - - return nil, err - } - - switch packet[0] { - case msgChannelData: - if len(packet) < 9 { - // malformed data packet - return nil, ParseError{msgChannelData} - } - peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4]) - s.lock.Lock() - c, ok := s.channels[peersId] - if !ok { - s.lock.Unlock() - continue - } - if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 { - packet = packet[9:] - c.handleData(packet[:length]) - } - s.lock.Unlock() - default: - switch msg := decode(packet).(type) { - case *channelOpenMsg: - c := new(channel) - c.chanType = msg.ChanType - c.theirId = msg.PeersId - c.theirWindow = msg.PeersWindow - c.maxPacketSize = msg.MaxPacketSize - c.extraData = msg.TypeSpecificData - c.myWindow = defaultWindowSize - c.serverConn = s - c.cond = sync.NewCond(&c.lock) - c.pendingData = make([]byte, c.myWindow) - - s.lock.Lock() - c.myId = s.nextChanId - s.nextChanId++ - s.channels[c.myId] = c - s.lock.Unlock() - return c, nil - - case *channelRequestMsg: - s.lock.Lock() - c, ok := s.channels[msg.PeersId] - if !ok { - s.lock.Unlock() - continue - } - c.handlePacket(msg) - s.lock.Unlock() - - case *channelEOFMsg: - s.lock.Lock() - c, ok := s.channels[msg.PeersId] - if !ok { - s.lock.Unlock() - continue - } - c.handlePacket(msg) - s.lock.Unlock() - - case *channelCloseMsg: - s.lock.Lock() - c, ok := s.channels[msg.PeersId] - if !ok { - s.lock.Unlock() - continue - } - c.handlePacket(msg) - s.lock.Unlock() - - case *globalRequestMsg: - if msg.WantReply { - if err := s.writePacket([]byte{msgRequestFailure}); err != nil { - return nil, err - } - } - - case UnexpectedMessageError: - return nil, msg - case *disconnectMsg: - return nil, io.EOF - default: - // Unknown message. Ignore. - } - } - } - - panic("unreachable") -} - -// A Listener implements a network listener (net.Listener) for SSH connections. -type Listener struct { - listener net.Listener - config *ServerConfig -} - -// Accept waits for and returns the next incoming SSH connection. -// The receiver should call Handshake() in another goroutine -// to avoid blocking the accepter. -func (l *Listener) Accept() (*ServerConn, error) { - c, err := l.listener.Accept() - if err != nil { - return nil, err - } - conn := Server(c, l.config) - return conn, nil -} - -// Addr returns the listener's network address. -func (l *Listener) Addr() net.Addr { - return l.listener.Addr() -} - -// Close closes the listener. -func (l *Listener) Close() error { - return l.listener.Close() -} - -// Listen creates an SSH listener accepting connections on -// the given network address using net.Listen. -func Listen(network, addr string, config *ServerConfig) (*Listener, error) { - l, err := net.Listen(network, addr) - if err != nil { - return nil, err - } - return &Listener{ - l, - config, - }, nil -} diff --git a/libgo/go/exp/ssh/server_terminal.go b/libgo/go/exp/ssh/server_terminal.go deleted file mode 100644 index 708a9159ec8..00000000000 --- a/libgo/go/exp/ssh/server_terminal.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2011 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 ssh - -// A Terminal is capable of parsing and generating virtual terminal -// data from an SSH client. -type Terminal interface { - ReadLine() (line string, err error) - SetSize(x, y int) - Write([]byte) (int, error) -} - -// ServerTerminal contains the state for running a terminal that is capable of -// reading lines of input. -type ServerTerminal struct { - Term Terminal - Channel Channel -} - -// parsePtyRequest parses the payload of the pty-req message and extracts the -// dimensions of the terminal. See RFC 4254, section 6.2. -func parsePtyRequest(s []byte) (width, height int, ok bool) { - _, s, ok = parseString(s) - if !ok { - return - } - width32, s, ok := parseUint32(s) - if !ok { - return - } - height32, _, ok := parseUint32(s) - width = int(width32) - height = int(height32) - if width < 1 { - ok = false - } - if height < 1 { - ok = false - } - return -} - -func (ss *ServerTerminal) Write(buf []byte) (n int, err error) { - return ss.Term.Write(buf) -} - -// ReadLine returns a line of input from the terminal. -func (ss *ServerTerminal) ReadLine() (line string, err error) { - for { - if line, err = ss.Term.ReadLine(); err == nil { - return - } - - req, ok := err.(ChannelRequest) - if !ok { - return - } - - ok = false - switch req.Request { - case "pty-req": - var width, height int - width, height, ok = parsePtyRequest(req.Payload) - ss.Term.SetSize(width, height) - case "shell": - ok = true - if len(req.Payload) > 0 { - // We don't accept any commands, only the default shell. - ok = false - } - case "env": - ok = true - } - if req.WantReply { - ss.Channel.AckRequest(ok) - } - } - panic("unreachable") -} diff --git a/libgo/go/exp/ssh/session.go b/libgo/go/exp/ssh/session.go deleted file mode 100644 index ea4addbd50b..00000000000 --- a/libgo/go/exp/ssh/session.go +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright 2011 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 ssh - -// Session implements an interactive session described in -// "RFC 4254, section 6". - -import ( - "bytes" - "errors" - "fmt" - "io" - "io/ioutil" -) - -type Signal string - -// POSIX signals as listed in RFC 4254 Section 6.10. -const ( - SIGABRT Signal = "ABRT" - SIGALRM Signal = "ALRM" - SIGFPE Signal = "FPE" - SIGHUP Signal = "HUP" - SIGILL Signal = "ILL" - SIGINT Signal = "INT" - SIGKILL Signal = "KILL" - SIGPIPE Signal = "PIPE" - SIGQUIT Signal = "QUIT" - SIGSEGV Signal = "SEGV" - SIGTERM Signal = "TERM" - SIGUSR1 Signal = "USR1" - SIGUSR2 Signal = "USR2" -) - -var signals = map[Signal]int{ - SIGABRT: 6, - SIGALRM: 14, - SIGFPE: 8, - SIGHUP: 1, - SIGILL: 4, - SIGINT: 2, - SIGKILL: 9, - SIGPIPE: 13, - SIGQUIT: 3, - SIGSEGV: 11, - SIGTERM: 15, -} - -// A Session represents a connection to a remote command or shell. -type Session struct { - // Stdin specifies the remote process's standard input. - // If Stdin is nil, the remote process reads from an empty - // bytes.Buffer. - Stdin io.Reader - - // Stdout and Stderr specify the remote process's standard - // output and error. - // - // If either is nil, Run connects the corresponding file - // descriptor to an instance of ioutil.Discard. There is a - // fixed amount of buffering that is shared for the two streams. - // If either blocks it may eventually cause the remote - // command to block. - Stdout io.Writer - Stderr io.Writer - - *clientChan // the channel backing this session - - started bool // true once Start, Run or Shell is invoked. - copyFuncs []func() error - errors chan error // one send per copyFunc - - // true if pipe method is active - stdinpipe, stdoutpipe, stderrpipe bool -} - -// RFC 4254 Section 6.4. -type setenvRequest struct { - PeersId uint32 - Request string - WantReply bool - Name string - Value string -} - -// Setenv sets an environment variable that will be applied to any -// command executed by Shell or Run. -func (s *Session) Setenv(name, value string) error { - req := setenvRequest{ - PeersId: s.peersId, - Request: "env", - WantReply: true, - Name: name, - Value: value, - } - if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { - return err - } - return s.waitForResponse() -} - -// An empty mode list, see RFC 4254 Section 8. -var emptyModelist = "\x00" - -// RFC 4254 Section 6.2. -type ptyRequestMsg struct { - PeersId uint32 - Request string - WantReply bool - Term string - Columns uint32 - Rows uint32 - Width uint32 - Height uint32 - Modelist string -} - -// RequestPty requests the association of a pty with the session on the remote host. -func (s *Session) RequestPty(term string, h, w int) error { - req := ptyRequestMsg{ - PeersId: s.peersId, - Request: "pty-req", - WantReply: true, - Term: term, - Columns: uint32(w), - Rows: uint32(h), - Width: uint32(w * 8), - Height: uint32(h * 8), - Modelist: emptyModelist, - } - if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { - return err - } - return s.waitForResponse() -} - -// RFC 4254 Section 6.9. -type signalMsg struct { - PeersId uint32 - Request string - WantReply bool - Signal string -} - -// Signal sends the given signal to the remote process. -// sig is one of the SIG* constants. -func (s *Session) Signal(sig Signal) error { - req := signalMsg{ - PeersId: s.peersId, - Request: "signal", - WantReply: false, - Signal: string(sig), - } - return s.writePacket(marshal(msgChannelRequest, req)) -} - -// RFC 4254 Section 6.5. -type execMsg struct { - PeersId uint32 - Request string - WantReply bool - Command string -} - -// Start runs cmd on the remote host. Typically, the remote -// server passes cmd to the shell for interpretation. -// A Session only accepts one call to Run, Start or Shell. -func (s *Session) Start(cmd string) error { - if s.started { - return errors.New("ssh: session already started") - } - req := execMsg{ - PeersId: s.peersId, - Request: "exec", - WantReply: true, - Command: cmd, - } - if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { - return err - } - if err := s.waitForResponse(); err != nil { - return fmt.Errorf("ssh: could not execute command %s: %v", cmd, err) - } - return s.start() -} - -// Run runs cmd on the remote host. Typically, the remote -// server passes cmd to the shell for interpretation. -// A Session only accepts one call to Run, Start or Shell. -// -// The returned error is nil if the command runs, has no problems -// copying stdin, stdout, and stderr, and exits with a zero exit -// status. -// -// If the command fails to run or doesn't complete successfully, the -// error is of type *ExitError. Other error types may be -// returned for I/O problems. -func (s *Session) Run(cmd string) error { - err := s.Start(cmd) - if err != nil { - return err - } - return s.Wait() -} - -// Shell starts a login shell on the remote host. A Session only -// accepts one call to Run, Start or Shell. -func (s *Session) Shell() error { - if s.started { - return errors.New("ssh: session already started") - } - req := channelRequestMsg{ - PeersId: s.peersId, - Request: "shell", - WantReply: true, - } - if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { - return err - } - if err := s.waitForResponse(); err != nil { - return fmt.Errorf("ssh: cound not execute shell: %v", err) - } - return s.start() -} - -func (s *Session) waitForResponse() error { - msg := <-s.msg - switch msg.(type) { - case *channelRequestSuccessMsg: - return nil - case *channelRequestFailureMsg: - return errors.New("request failed") - } - return fmt.Errorf("unknown packet %T received: %v", msg, msg) -} - -func (s *Session) start() error { - s.started = true - - type F func(*Session) - for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { - setupFd(s) - } - - s.errors = make(chan error, len(s.copyFuncs)) - for _, fn := range s.copyFuncs { - go func(fn func() error) { - s.errors <- fn() - }(fn) - } - return nil -} - -// Wait waits for the remote command to exit. -// -// The returned error is nil if the command runs, has no problems -// copying stdin, stdout, and stderr, and exits with a zero exit -// status. -// -// If the command fails to run or doesn't complete successfully, the -// error is of type *ExitError. Other error types may be -// returned for I/O problems. -func (s *Session) Wait() error { - if !s.started { - return errors.New("ssh: session not started") - } - waitErr := s.wait() - - var copyError error - for _ = range s.copyFuncs { - if err := <-s.errors; err != nil && copyError == nil { - copyError = err - } - } - if waitErr != nil { - return waitErr - } - return copyError -} - -func (s *Session) wait() error { - wm := Waitmsg{status: -1} - - // Wait for msg channel to be closed before returning. - for msg := range s.msg { - switch msg := msg.(type) { - case *channelRequestMsg: - switch msg.Request { - case "exit-status": - d := msg.RequestSpecificData - wm.status = int(d[0])<<24 | int(d[1])<<16 | int(d[2])<<8 | int(d[3]) - case "exit-signal": - signal, rest, ok := parseString(msg.RequestSpecificData) - if !ok { - return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData) - } - wm.signal = safeString(string(signal)) - - // skip coreDumped bool - if len(rest) == 0 { - return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData) - } - rest = rest[1:] - - errmsg, rest, ok := parseString(rest) - if !ok { - return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData) - } - wm.msg = safeString(string(errmsg)) - - lang, _, ok := parseString(rest) - if !ok { - return fmt.Errorf("wait: could not parse request data: %v", msg.RequestSpecificData) - } - wm.lang = safeString(string(lang)) - default: - return fmt.Errorf("wait: unexpected channel request: %v", msg) - } - default: - return fmt.Errorf("wait: unexpected packet %T received: %v", msg, msg) - } - } - if wm.status == 0 { - return nil - } - if wm.status == -1 { - // exit-status was never sent from server - if wm.signal == "" { - return errors.New("wait: remote command exited without exit status or exit signal") - } - wm.status = 128 - if _, ok := signals[Signal(wm.signal)]; ok { - wm.status += signals[Signal(wm.signal)] - } - } - return &ExitError{wm} -} - -func (s *Session) stdin() { - if s.stdinpipe { - return - } - if s.Stdin == nil { - s.Stdin = new(bytes.Buffer) - } - s.copyFuncs = append(s.copyFuncs, func() error { - _, err := io.Copy(s.clientChan.stdin, s.Stdin) - if err1 := s.clientChan.stdin.Close(); err == nil { - err = err1 - } - return err - }) -} - -func (s *Session) stdout() { - if s.stdoutpipe { - return - } - if s.Stdout == nil { - s.Stdout = ioutil.Discard - } - s.copyFuncs = append(s.copyFuncs, func() error { - _, err := io.Copy(s.Stdout, s.clientChan.stdout) - return err - }) -} - -func (s *Session) stderr() { - if s.stderrpipe { - return - } - if s.Stderr == nil { - s.Stderr = ioutil.Discard - } - s.copyFuncs = append(s.copyFuncs, func() error { - _, err := io.Copy(s.Stderr, s.clientChan.stderr) - return err - }) -} - -// StdinPipe returns a pipe that will be connected to the -// remote command's standard input when the command starts. -func (s *Session) StdinPipe() (io.WriteCloser, error) { - if s.Stdin != nil { - return nil, errors.New("ssh: Stdin already set") - } - if s.started { - return nil, errors.New("ssh: StdinPipe after process started") - } - s.stdinpipe = true - return s.clientChan.stdin, nil -} - -// StdoutPipe returns a pipe that will be connected to the -// remote command's standard output when the command starts. -// There is a fixed amount of buffering that is shared between -// stdout and stderr streams. If the StdoutPipe reader is -// not serviced fast enought it may eventually cause the -// remote command to block. -func (s *Session) StdoutPipe() (io.Reader, error) { - if s.Stdout != nil { - return nil, errors.New("ssh: Stdout already set") - } - if s.started { - return nil, errors.New("ssh: StdoutPipe after process started") - } - s.stdoutpipe = true - return s.clientChan.stdout, nil -} - -// StderrPipe returns a pipe that will be connected to the -// remote command's standard error when the command starts. -// There is a fixed amount of buffering that is shared between -// stdout and stderr streams. If the StderrPipe reader is -// not serviced fast enought it may eventually cause the -// remote command to block. -func (s *Session) StderrPipe() (io.Reader, error) { - if s.Stderr != nil { - return nil, errors.New("ssh: Stderr already set") - } - if s.started { - return nil, errors.New("ssh: StderrPipe after process started") - } - s.stderrpipe = true - return s.clientChan.stderr, nil -} - -// TODO(dfc) add Output and CombinedOutput helpers - -// NewSession returns a new interactive session on the remote host. -func (c *ClientConn) NewSession() (*Session, error) { - ch := c.newChan(c.transport) - if err := c.writePacket(marshal(msgChannelOpen, channelOpenMsg{ - ChanType: "session", - PeersId: ch.id, - PeersWindow: 1 << 14, - MaxPacketSize: 1 << 15, // RFC 4253 6.1 - })); err != nil { - c.chanlist.remove(ch.id) - return nil, err - } - if err := ch.waitForChannelOpenResponse(); err != nil { - c.chanlist.remove(ch.id) - return nil, fmt.Errorf("ssh: unable to open session: %v", err) - } - return &Session{ - clientChan: ch, - }, nil -} - -// An ExitError reports unsuccessful completion of a remote command. -type ExitError struct { - Waitmsg -} - -func (e *ExitError) Error() string { - return e.Waitmsg.String() -} - -// Waitmsg stores the information about an exited remote command -// as reported by Wait. -type Waitmsg struct { - status int - signal string - msg string - lang string -} - -// ExitStatus returns the exit status of the remote command. -func (w Waitmsg) ExitStatus() int { - return w.status -} - -// Signal returns the exit signal of the remote command if -// it was terminated violently. -func (w Waitmsg) Signal() string { - return w.signal -} - -// Msg returns the exit message given by the remote command -func (w Waitmsg) Msg() string { - return w.msg -} - -// Lang returns the language tag. See RFC 3066 -func (w Waitmsg) Lang() string { - return w.lang -} - -func (w Waitmsg) String() string { - return fmt.Sprintf("Process exited with: %v. Reason was: %v (%v)", w.status, w.msg, w.signal) -} diff --git a/libgo/go/exp/ssh/session_test.go b/libgo/go/exp/ssh/session_test.go deleted file mode 100644 index 4a3d22bee04..00000000000 --- a/libgo/go/exp/ssh/session_test.go +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2011 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 ssh - -// Session tests. - -import ( - "bytes" - "exp/terminal" - "io" - "testing" -) - -type serverType func(*channel) - -// dial constructs a new test server and returns a *ClientConn. -func dial(handler serverType, t *testing.T) *ClientConn { - pw := password("tiger") - serverConfig.PasswordCallback = func(user, pass string) bool { - return user == "testuser" && pass == string(pw) - } - serverConfig.PublicKeyCallback = nil - - l, err := Listen("tcp", "127.0.0.1:0", serverConfig) - if err != nil { - t.Fatalf("unable to listen: %s", err) - } - go func() { - defer l.Close() - conn, err := l.Accept() - if err != nil { - t.Errorf("Unable to accept: %v", err) - return - } - defer conn.Close() - if err := conn.Handshake(); err != nil { - t.Errorf("Unable to handshake: %v", err) - return - } - for { - ch, err := conn.Accept() - if err == io.EOF { - return - } - if err != nil { - t.Errorf("Unable to accept incoming channel request: %v", err) - return - } - if ch.ChannelType() != "session" { - ch.Reject(UnknownChannelType, "unknown channel type") - continue - } - ch.Accept() - go handler(ch.(*channel)) - } - t.Log("done") - }() - - config := &ClientConfig{ - User: "testuser", - Auth: []ClientAuth{ - ClientAuthPassword(pw), - }, - } - - c, err := Dial("tcp", l.Addr().String(), config) - if err != nil { - t.Fatalf("unable to dial remote side: %s", err) - } - return c -} - -// Test a simple string is returned to session.Stdout. -func TestSessionShell(t *testing.T) { - conn := dial(shellHandler, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - stdout := new(bytes.Buffer) - session.Stdout = stdout - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - if err := session.Wait(); err != nil { - t.Fatalf("Remote command did not exit cleanly: %s", err) - } - actual := stdout.String() - if actual != "golang" { - t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual) - } -} - -// TODO(dfc) add support for Std{in,err}Pipe when the Server supports it. - -// Test a simple string is returned via StdoutPipe. -func TestSessionStdoutPipe(t *testing.T) { - conn := dial(shellHandler, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - stdout, err := session.StdoutPipe() - if err != nil { - t.Fatalf("Unable to request StdoutPipe(): %v", err) - } - var buf bytes.Buffer - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - done := make(chan bool, 1) - go func() { - if _, err := io.Copy(&buf, stdout); err != nil { - t.Errorf("Copy of stdout failed: %v", err) - } - done <- true - }() - if err := session.Wait(); err != nil { - t.Fatalf("Remote command did not exit cleanly: %s", err) - } - <-done - actual := buf.String() - if actual != "golang" { - t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual) - } -} - -// Test non-0 exit status is returned correctly. -func TestExitStatusNonZero(t *testing.T) { - conn := dial(exitStatusNonZeroHandler, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - err = session.Wait() - if err == nil { - t.Fatalf("expected command to fail but it didn't") - } - e, ok := err.(*ExitError) - if !ok { - t.Fatalf("expected *ExitError but got %T", err) - } - if e.ExitStatus() != 15 { - t.Fatalf("expected command to exit with 15 but got %s", e.ExitStatus()) - } -} - -// Test 0 exit status is returned correctly. -func TestExitStatusZero(t *testing.T) { - conn := dial(exitStatusZeroHandler, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - err = session.Wait() - if err != nil { - t.Fatalf("expected nil but got %s", err) - } -} - -// Test exit signal and status are both returned correctly. -func TestExitSignalAndStatus(t *testing.T) { - conn := dial(exitSignalAndStatusHandler, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - err = session.Wait() - if err == nil { - t.Fatalf("expected command to fail but it didn't") - } - e, ok := err.(*ExitError) - if !ok { - t.Fatalf("expected *ExitError but got %T", err) - } - if e.Signal() != "TERM" || e.ExitStatus() != 15 { - t.Fatalf("expected command to exit with signal TERM and status 15 but got signal %s and status %v", e.Signal(), e.ExitStatus()) - } -} - -// Test exit signal and status are both returned correctly. -func TestKnownExitSignalOnly(t *testing.T) { - conn := dial(exitSignalHandler, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - err = session.Wait() - if err == nil { - t.Fatalf("expected command to fail but it didn't") - } - e, ok := err.(*ExitError) - if !ok { - t.Fatalf("expected *ExitError but got %T", err) - } - if e.Signal() != "TERM" || e.ExitStatus() != 143 { - t.Fatalf("expected command to exit with signal TERM and status 143 but got signal %s and status %v", e.Signal(), e.ExitStatus()) - } -} - -// Test exit signal and status are both returned correctly. -func TestUnknownExitSignal(t *testing.T) { - conn := dial(exitSignalUnknownHandler, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - err = session.Wait() - if err == nil { - t.Fatalf("expected command to fail but it didn't") - } - e, ok := err.(*ExitError) - if !ok { - t.Fatalf("expected *ExitError but got %T", err) - } - if e.Signal() != "SYS" || e.ExitStatus() != 128 { - t.Fatalf("expected command to exit with signal SYS and status 128 but got signal %s and status %v", e.Signal(), e.ExitStatus()) - } -} - -// Test WaitMsg is not returned if the channel closes abruptly. -func TestExitWithoutStatusOrSignal(t *testing.T) { - conn := dial(exitWithoutSignalOrStatus, t) - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - t.Fatalf("Unable to request new session: %s", err) - } - defer session.Close() - if err := session.Shell(); err != nil { - t.Fatalf("Unable to execute command: %s", err) - } - err = session.Wait() - if err == nil { - t.Fatalf("expected command to fail but it didn't") - } - _, ok := err.(*ExitError) - if ok { - // you can't actually test for errors.errorString - // because it's not exported. - t.Fatalf("expected *errorString but got %T", err) - } -} - -type exitStatusMsg struct { - PeersId uint32 - Request string - WantReply bool - Status uint32 -} - -type exitSignalMsg struct { - PeersId uint32 - Request string - WantReply bool - Signal string - CoreDumped bool - Errmsg string - Lang string -} - -func newServerShell(ch *channel, prompt string) *ServerTerminal { - term := terminal.NewTerminal(ch, prompt) - return &ServerTerminal{ - Term: term, - Channel: ch, - } -} - -func exitStatusZeroHandler(ch *channel) { - defer ch.Close() - // this string is returned to stdout - shell := newServerShell(ch, "> ") - shell.ReadLine() - sendStatus(0, ch) -} - -func exitStatusNonZeroHandler(ch *channel) { - defer ch.Close() - shell := newServerShell(ch, "> ") - shell.ReadLine() - sendStatus(15, ch) -} - -func exitSignalAndStatusHandler(ch *channel) { - defer ch.Close() - shell := newServerShell(ch, "> ") - shell.ReadLine() - sendStatus(15, ch) - sendSignal("TERM", ch) -} - -func exitSignalHandler(ch *channel) { - defer ch.Close() - shell := newServerShell(ch, "> ") - shell.ReadLine() - sendSignal("TERM", ch) -} - -func exitSignalUnknownHandler(ch *channel) { - defer ch.Close() - shell := newServerShell(ch, "> ") - shell.ReadLine() - sendSignal("SYS", ch) -} - -func exitWithoutSignalOrStatus(ch *channel) { - defer ch.Close() - shell := newServerShell(ch, "> ") - shell.ReadLine() -} - -func shellHandler(ch *channel) { - defer ch.Close() - // this string is returned to stdout - shell := newServerShell(ch, "golang") - shell.ReadLine() - sendStatus(0, ch) -} - -func sendStatus(status uint32, ch *channel) { - msg := exitStatusMsg{ - PeersId: ch.theirId, - Request: "exit-status", - WantReply: false, - Status: status, - } - ch.serverConn.writePacket(marshal(msgChannelRequest, msg)) -} - -func sendSignal(signal string, ch *channel) { - sig := exitSignalMsg{ - PeersId: ch.theirId, - Request: "exit-signal", - WantReply: false, - Signal: signal, - CoreDumped: false, - Errmsg: "Process terminated", - Lang: "en-GB-oed", - } - ch.serverConn.writePacket(marshal(msgChannelRequest, sig)) -} diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go deleted file mode 100644 index e0c47bca1fc..00000000000 --- a/libgo/go/exp/ssh/tcpip.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "errors" - "fmt" - "io" - "net" - "time" -) - -// Dial initiates a connection to the addr from the remote host. -// addr is resolved using net.ResolveTCPAddr before connection. -// This could allow an observer to observe the DNS name of the -// remote host. Consider using ssh.DialTCP to avoid this. -func (c *ClientConn) Dial(n, addr string) (net.Conn, error) { - raddr, err := net.ResolveTCPAddr(n, addr) - if err != nil { - return nil, err - } - return c.DialTCP(n, nil, raddr) -} - -// DialTCP connects to the remote address raddr on the network net, -// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used -// as the local address for the connection. -func (c *ClientConn) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { - if laddr == nil { - laddr = &net.TCPAddr{ - IP: net.IPv4zero, - Port: 0, - } - } - ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) - if err != nil { - return nil, err - } - return &tcpchanconn{ - tcpchan: ch, - laddr: laddr, - raddr: raddr, - }, nil -} - -// RFC 4254 7.2 -type channelOpenDirectMsg struct { - ChanType string - PeersId uint32 - PeersWindow uint32 - MaxPacketSize uint32 - raddr string - rport uint32 - laddr string - lport uint32 -} - -// dial opens a direct-tcpip connection to the remote server. laddr and raddr are passed as -// strings and are expected to be resolveable at the remote end. -func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*tcpchan, error) { - ch := c.newChan(c.transport) - if err := c.writePacket(marshal(msgChannelOpen, channelOpenDirectMsg{ - ChanType: "direct-tcpip", - PeersId: ch.id, - PeersWindow: 1 << 14, - MaxPacketSize: 1 << 15, // RFC 4253 6.1 - raddr: raddr, - rport: uint32(rport), - laddr: laddr, - lport: uint32(lport), - })); err != nil { - c.chanlist.remove(ch.id) - return nil, err - } - if err := ch.waitForChannelOpenResponse(); err != nil { - c.chanlist.remove(ch.id) - return nil, fmt.Errorf("ssh: unable to open direct tcpip connection: %v", err) - } - return &tcpchan{ - clientChan: ch, - Reader: ch.stdout, - Writer: ch.stdin, - }, nil -} - -type tcpchan struct { - *clientChan // the backing channel - io.Reader - io.Writer -} - -// tcpchanconn fulfills the net.Conn interface without -// the tcpchan having to hold laddr or raddr directly. -type tcpchanconn struct { - *tcpchan - laddr, raddr net.Addr -} - -// LocalAddr returns the local network address. -func (t *tcpchanconn) LocalAddr() net.Addr { - return t.laddr -} - -// RemoteAddr returns the remote network address. -func (t *tcpchanconn) RemoteAddr() net.Addr { - return t.raddr -} - -// SetDeadline sets the read and write deadlines associated -// with the connection. -func (t *tcpchanconn) SetDeadline(deadline time.Time) error { - if err := t.SetReadDeadline(deadline); err != nil { - return err - } - return t.SetWriteDeadline(deadline) -} - -// SetReadDeadline sets the read deadline. -// A zero value for t means Read will not time out. -// After the deadline, the error from Read will implement net.Error -// with Timeout() == true. -func (t *tcpchanconn) SetReadDeadline(deadline time.Time) error { - return errors.New("ssh: tcpchan: deadline not supported") -} - -// SetWriteDeadline exists to satisfy the net.Conn interface -// but is not implemented by this type. It always returns an error. -func (t *tcpchanconn) SetWriteDeadline(deadline time.Time) error { - return errors.New("ssh: tcpchan: deadline not supported") -} diff --git a/libgo/go/exp/ssh/tcpip_func_test.go b/libgo/go/exp/ssh/tcpip_func_test.go deleted file mode 100644 index 261297241e9..00000000000 --- a/libgo/go/exp/ssh/tcpip_func_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2011 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 ssh - -// direct-tcpip functional tests - -import ( - "net" - "net/http" - "testing" -) - -func TestTCPIPHTTP(t *testing.T) { - if *sshuser == "" { - t.Log("ssh.user not defined, skipping test") - return - } - // google.com will generate at least one redirect, possibly three - // depending on your location. - doTest(t, "http://google.com") -} - -func TestTCPIPHTTPS(t *testing.T) { - if *sshuser == "" { - t.Log("ssh.user not defined, skipping test") - return - } - doTest(t, "https://encrypted.google.com/") -} - -func doTest(t *testing.T, url string) { - config := &ClientConfig{ - User: *sshuser, - Auth: []ClientAuth{ - ClientAuthPassword(password(*sshpass)), - }, - } - conn, err := Dial("tcp", "localhost:22", config) - if err != nil { - t.Fatalf("Unable to connect: %s", err) - } - defer conn.Close() - tr := &http.Transport{ - Dial: func(n, addr string) (net.Conn, error) { - return conn.Dial(n, addr) - }, - } - client := &http.Client{ - Transport: tr, - } - resp, err := client.Get(url) - if err != nil { - t.Fatalf("unable to proxy: %s", err) - } - // got a body without error - t.Log(resp) -} diff --git a/libgo/go/exp/ssh/transport.go b/libgo/go/exp/ssh/transport.go deleted file mode 100644 index e21bc4ba202..00000000000 --- a/libgo/go/exp/ssh/transport.go +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "bufio" - "crypto" - "crypto/cipher" - "crypto/hmac" - "crypto/sha1" - "crypto/subtle" - "errors" - "hash" - "io" - "net" - "sync" -) - -const ( - packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. - minPacketSize = 16 - maxPacketSize = 36000 - minPaddingSize = 4 // TODO(huin) should this be configurable? -) - -// filteredConn reduces the set of methods exposed when embeddeding -// a net.Conn inside ssh.transport. -// TODO(dfc) suggestions for a better name will be warmly received. -type filteredConn interface { - // Close closes the connection. - Close() error - - // LocalAddr returns the local network address. - LocalAddr() net.Addr - - // RemoteAddr returns the remote network address. - RemoteAddr() net.Addr -} - -// Types implementing packetWriter provide the ability to send packets to -// an SSH peer. -type packetWriter interface { - // Encrypt and send a packet of data to the remote peer. - writePacket(packet []byte) error -} - -// transport represents the SSH connection to the remote peer. -type transport struct { - reader - writer - - filteredConn -} - -// reader represents the incoming connection state. -type reader struct { - io.Reader - common -} - -// writer represnts the outgoing connection state. -type writer struct { - *sync.Mutex // protects writer.Writer from concurrent writes - *bufio.Writer - rand io.Reader - common -} - -// common represents the cipher state needed to process messages in a single -// direction. -type common struct { - seqNum uint32 - mac hash.Hash - cipher cipher.Stream - - cipherAlgo string - macAlgo string - compressionAlgo string -} - -// Read and decrypt a single packet from the remote peer. -func (r *reader) readOnePacket() ([]byte, error) { - var lengthBytes = make([]byte, 5) - var macSize uint32 - if _, err := io.ReadFull(r, lengthBytes); err != nil { - return nil, err - } - - r.cipher.XORKeyStream(lengthBytes, lengthBytes) - - if r.mac != nil { - r.mac.Reset() - seqNumBytes := []byte{ - byte(r.seqNum >> 24), - byte(r.seqNum >> 16), - byte(r.seqNum >> 8), - byte(r.seqNum), - } - r.mac.Write(seqNumBytes) - r.mac.Write(lengthBytes) - macSize = uint32(r.mac.Size()) - } - - length := uint32(lengthBytes[0])<<24 | uint32(lengthBytes[1])<<16 | uint32(lengthBytes[2])<<8 | uint32(lengthBytes[3]) - paddingLength := uint32(lengthBytes[4]) - - if length <= paddingLength+1 { - return nil, errors.New("invalid packet length") - } - if length > maxPacketSize { - return nil, errors.New("packet too large") - } - - packet := make([]byte, length-1+macSize) - if _, err := io.ReadFull(r, packet); err != nil { - return nil, err - } - mac := packet[length-1:] - r.cipher.XORKeyStream(packet, packet[:length-1]) - - if r.mac != nil { - r.mac.Write(packet[:length-1]) - if subtle.ConstantTimeCompare(r.mac.Sum(nil), mac) != 1 { - return nil, errors.New("ssh: MAC failure") - } - } - - r.seqNum++ - return packet[:length-paddingLength-1], nil -} - -// Read and decrypt next packet discarding debug and noop messages. -func (t *transport) readPacket() ([]byte, error) { - for { - packet, err := t.readOnePacket() - if err != nil { - return nil, err - } - if packet[0] != msgIgnore && packet[0] != msgDebug { - return packet, nil - } - } - panic("unreachable") -} - -// Encrypt and send a packet of data to the remote peer. -func (w *writer) writePacket(packet []byte) error { - w.Mutex.Lock() - defer w.Mutex.Unlock() - - paddingLength := packetSizeMultiple - (5+len(packet))%packetSizeMultiple - if paddingLength < 4 { - paddingLength += packetSizeMultiple - } - - length := len(packet) + 1 + paddingLength - lengthBytes := []byte{ - byte(length >> 24), - byte(length >> 16), - byte(length >> 8), - byte(length), - byte(paddingLength), - } - padding := make([]byte, paddingLength) - _, err := io.ReadFull(w.rand, padding) - if err != nil { - return err - } - - if w.mac != nil { - w.mac.Reset() - seqNumBytes := []byte{ - byte(w.seqNum >> 24), - byte(w.seqNum >> 16), - byte(w.seqNum >> 8), - byte(w.seqNum), - } - w.mac.Write(seqNumBytes) - w.mac.Write(lengthBytes) - w.mac.Write(packet) - w.mac.Write(padding) - } - - // TODO(dfc) lengthBytes, packet and padding should be - // subslices of a single buffer - w.cipher.XORKeyStream(lengthBytes, lengthBytes) - w.cipher.XORKeyStream(packet, packet) - w.cipher.XORKeyStream(padding, padding) - - if _, err := w.Write(lengthBytes); err != nil { - return err - } - if _, err := w.Write(packet); err != nil { - return err - } - if _, err := w.Write(padding); err != nil { - return err - } - - if w.mac != nil { - if _, err := w.Write(w.mac.Sum(nil)); err != nil { - return err - } - } - - if err := w.Flush(); err != nil { - return err - } - w.seqNum++ - return err -} - -// Send a message to the remote peer -func (t *transport) sendMessage(typ uint8, msg interface{}) error { - packet := marshal(typ, msg) - return t.writePacket(packet) -} - -func newTransport(conn net.Conn, rand io.Reader) *transport { - return &transport{ - reader: reader{ - Reader: bufio.NewReader(conn), - common: common{ - cipher: noneCipher{}, - }, - }, - writer: writer{ - Writer: bufio.NewWriter(conn), - rand: rand, - Mutex: new(sync.Mutex), - common: common{ - cipher: noneCipher{}, - }, - }, - filteredConn: conn, - } -} - -type direction struct { - ivTag []byte - keyTag []byte - macKeyTag []byte -} - -// TODO(dfc) can this be made a constant ? -var ( - serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} - clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} -) - -// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as -// described in RFC 4253, section 6.4. direction should either be serverKeys -// (to setup server->client keys) or clientKeys (for client->server keys). -func (c *common) setupKeys(d direction, K, H, sessionId []byte, hashFunc crypto.Hash) error { - cipherMode := cipherModes[c.cipherAlgo] - - macKeySize := 20 - - iv := make([]byte, cipherMode.ivSize) - key := make([]byte, cipherMode.keySize) - macKey := make([]byte, macKeySize) - - h := hashFunc.New() - generateKeyMaterial(iv, d.ivTag, K, H, sessionId, h) - generateKeyMaterial(key, d.keyTag, K, H, sessionId, h) - generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h) - - c.mac = truncatingMAC{12, hmac.New(sha1.New, macKey)} - - cipher, err := cipherMode.createCipher(key, iv) - if err != nil { - return err - } - - c.cipher = cipher - - return nil -} - -// generateKeyMaterial fills out with key material generated from tag, K, H -// and sessionId, as specified in RFC 4253, section 7.2. -func generateKeyMaterial(out, tag []byte, K, H, sessionId []byte, h hash.Hash) { - var digestsSoFar []byte - - for len(out) > 0 { - h.Reset() - h.Write(K) - h.Write(H) - - if len(digestsSoFar) == 0 { - h.Write(tag) - h.Write(sessionId) - } else { - h.Write(digestsSoFar) - } - - digest := h.Sum(nil) - n := copy(out, digest) - out = out[n:] - if len(out) > 0 { - digestsSoFar = append(digestsSoFar, digest...) - } - } -} - -// truncatingMAC wraps around a hash.Hash and truncates the output digest to -// a given size. -type truncatingMAC struct { - length int - hmac hash.Hash -} - -func (t truncatingMAC) Write(data []byte) (int, error) { - return t.hmac.Write(data) -} - -func (t truncatingMAC) Sum(in []byte) []byte { - out := t.hmac.Sum(in) - return out[:len(in)+t.length] -} - -func (t truncatingMAC) Reset() { - t.hmac.Reset() -} - -func (t truncatingMAC) Size() int { - return t.length -} - -func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } - -// maxVersionStringBytes is the maximum number of bytes that we'll accept as a -// version string. In the event that the client is talking a different protocol -// we need to set a limit otherwise we will keep using more and more memory -// while searching for the end of the version handshake. -const maxVersionStringBytes = 1024 - -// Read version string as specified by RFC 4253, section 4.2. -func readVersion(r io.Reader) ([]byte, error) { - versionString := make([]byte, 0, 64) - var ok bool - var buf [1]byte -forEachByte: - for len(versionString) < maxVersionStringBytes { - _, err := io.ReadFull(r, buf[:]) - if err != nil { - return nil, err - } - // The RFC says that the version should be terminated with \r\n - // but several SSH servers actually only send a \n. - if buf[0] == '\n' { - ok = true - break forEachByte - } - versionString = append(versionString, buf[0]) - } - - if !ok { - return nil, errors.New("ssh: failed to read version string") - } - - // There might be a '\r' on the end which we should remove. - if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { - versionString = versionString[:len(versionString)-1] - } - return versionString, nil -} diff --git a/libgo/go/exp/ssh/transport_test.go b/libgo/go/exp/ssh/transport_test.go deleted file mode 100644 index ab9177f0d11..00000000000 --- a/libgo/go/exp/ssh/transport_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2011 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 ssh - -import ( - "bufio" - "bytes" - "testing" -) - -func TestReadVersion(t *testing.T) { - buf := serverVersion - result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))) - if err != nil { - t.Errorf("readVersion didn't read version correctly: %s", err) - } - if !bytes.Equal(buf[:len(buf)-2], result) { - t.Error("version read did not match expected") - } -} - -func TestReadVersionWithJustLF(t *testing.T) { - var buf []byte - buf = append(buf, serverVersion...) - buf = buf[:len(buf)-1] - buf[len(buf)-1] = '\n' - result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))) - if err != nil { - t.Error("readVersion failed to handle just a \n") - } - if !bytes.Equal(buf[:len(buf)-1], result) { - t.Errorf("version read did not match expected: got %x, want %x", result, buf[:len(buf)-1]) - } -} - -func TestReadVersionTooLong(t *testing.T) { - buf := make([]byte, maxVersionStringBytes+1) - if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil { - t.Errorf("readVersion consumed %d bytes without error", len(buf)) - } -} - -func TestReadVersionWithoutCRLF(t *testing.T) { - buf := serverVersion - buf = buf[:len(buf)-1] - if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil { - t.Error("readVersion did not notice \\n was missing") - } -} |