diff options
Diffstat (limited to 'src/pkg/html')
23 files changed, 0 insertions, 9471 deletions
| diff --git a/src/pkg/html/entity.go b/src/pkg/html/entity.go deleted file mode 100644 index af8a007ed..000000000 --- a/src/pkg/html/entity.go +++ /dev/null @@ -1,2253 +0,0 @@ -// 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/src/pkg/html/entity_test.go b/src/pkg/html/entity_test.go deleted file mode 100644 index b53f866fa..000000000 --- a/src/pkg/html/entity_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// 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/src/pkg/html/escape.go b/src/pkg/html/escape.go deleted file mode 100644 index dd5dfa7cd..000000000 --- a/src/pkg/html/escape.go +++ /dev/null @@ -1,250 +0,0 @@ -// 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 provides functions for escaping and unescaping HTML text. -package html - -import ( -	"bytes" -	"strings" -	"unicode/utf8" -) - -type writer interface { -	WriteString(string) (int, error) -} - -// 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 -} - -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 '\'': -			// "'" is shorter than "'" and apos was not in HTML until HTML5. -			esc = "'" -		case '<': -			esc = "<" -		case '>': -			esc = ">" -		case '"': -			// """ is shorter than """. -			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: <, >, &, ' and ". -// 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 -	} -	var buf bytes.Buffer -	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/src/pkg/html/escape_test.go b/src/pkg/html/escape_test.go deleted file mode 100644 index 2d7ad8ac2..000000000 --- a/src/pkg/html/escape_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2013 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" - -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‡", -	}, -	// Handle single ampersand. -	{ -		"copySingleAmpersand", -		"&", -		"&", -	}, -	// Handle ampersand followed by non-entity. -	{ -		"copyAmpersandNonEntity", -		"text &test", -		"text &test", -	}, -	// Handle "&#". -	{ -		"copyAmpersandHash", -		"text &#", -		"text &#", -	}, -} - -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=á`, -		`The special characters are: <, >, &, ' and "`, -	} -	for _, s := range ss { -		if got := UnescapeString(EscapeString(s)); got != s { -			t.Errorf("got %q want %q", got, s) -		} -	} -} diff --git a/src/pkg/html/template/attr.go b/src/pkg/html/template/attr.go deleted file mode 100644 index d65d34007..000000000 --- a/src/pkg/html/template/attr.go +++ /dev/null @@ -1,175 +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 template - -import ( -	"strings" -) - -// attrTypeMap[n] describes the value of the given attribute. -// If an attribute affects (or can mask) the encoding or interpretation of -// other content, or affects the contents, idempotency, or credentials of a -// network message, then the value in this map is contentTypeUnsafe. -// This map is derived from HTML5, specifically -// http://www.w3.org/TR/html5/Overview.html#attributes-1 -// as well as "%URI"-typed attributes from -// http://www.w3.org/TR/html4/index/attributes.html -var attrTypeMap = map[string]contentType{ -	"accept":          contentTypePlain, -	"accept-charset":  contentTypeUnsafe, -	"action":          contentTypeURL, -	"alt":             contentTypePlain, -	"archive":         contentTypeURL, -	"async":           contentTypeUnsafe, -	"autocomplete":    contentTypePlain, -	"autofocus":       contentTypePlain, -	"autoplay":        contentTypePlain, -	"background":      contentTypeURL, -	"border":          contentTypePlain, -	"checked":         contentTypePlain, -	"cite":            contentTypeURL, -	"challenge":       contentTypeUnsafe, -	"charset":         contentTypeUnsafe, -	"class":           contentTypePlain, -	"classid":         contentTypeURL, -	"codebase":        contentTypeURL, -	"cols":            contentTypePlain, -	"colspan":         contentTypePlain, -	"content":         contentTypeUnsafe, -	"contenteditable": contentTypePlain, -	"contextmenu":     contentTypePlain, -	"controls":        contentTypePlain, -	"coords":          contentTypePlain, -	"crossorigin":     contentTypeUnsafe, -	"data":            contentTypeURL, -	"datetime":        contentTypePlain, -	"default":         contentTypePlain, -	"defer":           contentTypeUnsafe, -	"dir":             contentTypePlain, -	"dirname":         contentTypePlain, -	"disabled":        contentTypePlain, -	"draggable":       contentTypePlain, -	"dropzone":        contentTypePlain, -	"enctype":         contentTypeUnsafe, -	"for":             contentTypePlain, -	"form":            contentTypeUnsafe, -	"formaction":      contentTypeURL, -	"formenctype":     contentTypeUnsafe, -	"formmethod":      contentTypeUnsafe, -	"formnovalidate":  contentTypeUnsafe, -	"formtarget":      contentTypePlain, -	"headers":         contentTypePlain, -	"height":          contentTypePlain, -	"hidden":          contentTypePlain, -	"high":            contentTypePlain, -	"href":            contentTypeURL, -	"hreflang":        contentTypePlain, -	"http-equiv":      contentTypeUnsafe, -	"icon":            contentTypeURL, -	"id":              contentTypePlain, -	"ismap":           contentTypePlain, -	"keytype":         contentTypeUnsafe, -	"kind":            contentTypePlain, -	"label":           contentTypePlain, -	"lang":            contentTypePlain, -	"language":        contentTypeUnsafe, -	"list":            contentTypePlain, -	"longdesc":        contentTypeURL, -	"loop":            contentTypePlain, -	"low":             contentTypePlain, -	"manifest":        contentTypeURL, -	"max":             contentTypePlain, -	"maxlength":       contentTypePlain, -	"media":           contentTypePlain, -	"mediagroup":      contentTypePlain, -	"method":          contentTypeUnsafe, -	"min":             contentTypePlain, -	"multiple":        contentTypePlain, -	"name":            contentTypePlain, -	"novalidate":      contentTypeUnsafe, -	// Skip handler names from -	// http://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects -	// since we have special handling in attrType. -	"open":        contentTypePlain, -	"optimum":     contentTypePlain, -	"pattern":     contentTypeUnsafe, -	"placeholder": contentTypePlain, -	"poster":      contentTypeURL, -	"profile":     contentTypeURL, -	"preload":     contentTypePlain, -	"pubdate":     contentTypePlain, -	"radiogroup":  contentTypePlain, -	"readonly":    contentTypePlain, -	"rel":         contentTypeUnsafe, -	"required":    contentTypePlain, -	"reversed":    contentTypePlain, -	"rows":        contentTypePlain, -	"rowspan":     contentTypePlain, -	"sandbox":     contentTypeUnsafe, -	"spellcheck":  contentTypePlain, -	"scope":       contentTypePlain, -	"scoped":      contentTypePlain, -	"seamless":    contentTypePlain, -	"selected":    contentTypePlain, -	"shape":       contentTypePlain, -	"size":        contentTypePlain, -	"sizes":       contentTypePlain, -	"span":        contentTypePlain, -	"src":         contentTypeURL, -	"srcdoc":      contentTypeHTML, -	"srclang":     contentTypePlain, -	"start":       contentTypePlain, -	"step":        contentTypePlain, -	"style":       contentTypeCSS, -	"tabindex":    contentTypePlain, -	"target":      contentTypePlain, -	"title":       contentTypePlain, -	"type":        contentTypeUnsafe, -	"usemap":      contentTypeURL, -	"value":       contentTypeUnsafe, -	"width":       contentTypePlain, -	"wrap":        contentTypePlain, -	"xmlns":       contentTypeURL, -} - -// attrType returns a conservative (upper-bound on authority) guess at the -// type of the named attribute. -func attrType(name string) contentType { -	name = strings.ToLower(name) -	if strings.HasPrefix(name, "data-") { -		// Strip data- so that custom attribute heuristics below are -		// widely applied. -		// Treat data-action as URL below. -		name = name[5:] -	} else if colon := strings.IndexRune(name, ':'); colon != -1 { -		if name[:colon] == "xmlns" { -			return contentTypeURL -		} -		// Treat svg:href and xlink:href as href below. -		name = name[colon+1:] -	} -	if t, ok := attrTypeMap[name]; ok { -		return t -	} -	// Treat partial event handler names as script. -	if strings.HasPrefix(name, "on") { -		return contentTypeJS -	} - -	// Heuristics to prevent "javascript:..." injection in custom -	// data attributes and custom attributes like g:tweetUrl. -	// http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes -	// "Custom data attributes are intended to store custom data -	//  private to the page or application, for which there are no -	//  more appropriate attributes or elements." -	// Developers seem to store URL content in data URLs that start -	// or end with "URI" or "URL". -	if strings.Contains(name, "src") || -		strings.Contains(name, "uri") || -		strings.Contains(name, "url") { -		return contentTypeURL -	} -	return contentTypePlain -} diff --git a/src/pkg/html/template/clone_test.go b/src/pkg/html/template/clone_test.go deleted file mode 100644 index e11bff2c5..000000000 --- a/src/pkg/html/template/clone_test.go +++ /dev/null @@ -1,188 +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 template - -import ( -	"bytes" -	"errors" -	"io/ioutil" -	"testing" -	"text/template/parse" -) - -func TestAddParseTree(t *testing.T) { -	root := Must(New("root").Parse(`{{define "a"}} {{.}} {{template "b"}} {{.}} "></a>{{end}}`)) -	tree, err := parse.Parse("t", `{{define "b"}}<a href="{{end}}`, "", "", nil, nil) -	if err != nil { -		t.Fatal(err) -	} -	added := Must(root.AddParseTree("b", tree["b"])) -	b := new(bytes.Buffer) -	err = added.ExecuteTemplate(b, "a", "1>0") -	if err != nil { -		t.Fatal(err) -	} -	if got, want := b.String(), ` 1>0 <a href=" 1%3e0 "></a>`; got != want { -		t.Errorf("got %q want %q", got, want) -	} -} - -func TestClone(t *testing.T) { -	// The {{.}} will be executed with data "<i>*/" in different contexts. -	// In the t0 template, it will be in a text context. -	// In the t1 template, it will be in a URL context. -	// In the t2 template, it will be in a JavaScript context. -	// In the t3 template, it will be in a CSS context. -	const tmpl = `{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}` -	b := new(bytes.Buffer) - -	// Create an incomplete template t0. -	t0 := Must(New("t0").Parse(tmpl)) - -	// Clone t0 as t1. -	t1 := Must(t0.Clone()) -	Must(t1.Parse(`{{define "lhs"}} <a href=" {{end}}`)) -	Must(t1.Parse(`{{define "rhs"}} "></a> {{end}}`)) - -	// Execute t1. -	b.Reset() -	if err := t1.ExecuteTemplate(b, "a", "<i>*/"); err != nil { -		t.Fatal(err) -	} -	if got, want := b.String(), ` <a href=" %3ci%3e*/ "></a> `; got != want { -		t.Errorf("t1: got %q want %q", got, want) -	} - -	// Clone t0 as t2. -	t2 := Must(t0.Clone()) -	Must(t2.Parse(`{{define "lhs"}} <p onclick="javascript: {{end}}`)) -	Must(t2.Parse(`{{define "rhs"}} "></p> {{end}}`)) - -	// Execute t2. -	b.Reset() -	if err := t2.ExecuteTemplate(b, "a", "<i>*/"); err != nil { -		t.Fatal(err) -	} -	if got, want := b.String(), ` <p onclick="javascript: "\u003ci\u003e*/" "></p> `; got != want { -		t.Errorf("t2: got %q want %q", got, want) -	} - -	// Clone t0 as t3, but do not execute t3 yet. -	t3 := Must(t0.Clone()) -	Must(t3.Parse(`{{define "lhs"}} <style> {{end}}`)) -	Must(t3.Parse(`{{define "rhs"}} </style> {{end}}`)) - -	// Complete t0. -	Must(t0.Parse(`{{define "lhs"}} ( {{end}}`)) -	Must(t0.Parse(`{{define "rhs"}} ) {{end}}`)) - -	// Clone t0 as t4. Redefining the "lhs" template should fail. -	t4 := Must(t0.Clone()) -	if _, err := t4.Parse(`{{define "lhs"}} FAIL {{end}}`); err == nil { -		t.Error(`redefine "lhs": got nil err want non-nil`) -	} - -	// Execute t0. -	b.Reset() -	if err := t0.ExecuteTemplate(b, "a", "<i>*/"); err != nil { -		t.Fatal(err) -	} -	if got, want := b.String(), ` ( <i>*/ ) `; got != want { -		t.Errorf("t0: got %q want %q", got, want) -	} - -	// Clone t0. This should fail, as t0 has already executed. -	if _, err := t0.Clone(); err == nil { -		t.Error(`t0.Clone(): got nil err want non-nil`) -	} - -	// Similarly, cloning sub-templates should fail. -	if _, err := t0.Lookup("a").Clone(); err == nil { -		t.Error(`t0.Lookup("a").Clone(): got nil err want non-nil`) -	} -	if _, err := t0.Lookup("lhs").Clone(); err == nil { -		t.Error(`t0.Lookup("lhs").Clone(): got nil err want non-nil`) -	} - -	// Execute t3. -	b.Reset() -	if err := t3.ExecuteTemplate(b, "a", "<i>*/"); err != nil { -		t.Fatal(err) -	} -	if got, want := b.String(), ` <style> ZgotmplZ </style> `; got != want { -		t.Errorf("t3: got %q want %q", got, want) -	} -} - -func TestTemplates(t *testing.T) { -	names := []string{"t0", "a", "lhs", "rhs"} -	// Some template definitions borrowed from TestClone. -	const tmpl = ` -		{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}} -		{{define "lhs"}} <a href=" {{end}} -		{{define "rhs"}} "></a> {{end}}` -	t0 := Must(New("t0").Parse(tmpl)) -	templates := t0.Templates() -	if len(templates) != len(names) { -		t.Errorf("expected %d templates; got %d", len(names), len(templates)) -	} -	for _, name := range names { -		found := false -		for _, tmpl := range templates { -			if name == tmpl.text.Name() { -				found = true -				break -			} -		} -		if !found { -			t.Error("could not find template", name) -		} -	} -} - -// This used to crash; http://golang.org/issue/3281 -func TestCloneCrash(t *testing.T) { -	t1 := New("all") -	Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`)) -	t1.Clone() -} - -// Ensure that this guarantee from the docs is upheld: -// "Further calls to Parse in the copy will add templates -// to the copy but not to the original." -func TestCloneThenParse(t *testing.T) { -	t0 := Must(New("t0").Parse(`{{define "a"}}{{template "embedded"}}{{end}}`)) -	t1 := Must(t0.Clone()) -	Must(t1.Parse(`{{define "embedded"}}t1{{end}}`)) -	if len(t0.Templates())+1 != len(t1.Templates()) { -		t.Error("adding a template to a clone added it to the original") -	} -	// double check that the embedded template isn't available in the original -	err := t0.ExecuteTemplate(ioutil.Discard, "a", nil) -	if err == nil { -		t.Error("expected 'no such template' error") -	} -} - -// https://code.google.com/p/go/issues/detail?id=5980 -func TestFuncMapWorksAfterClone(t *testing.T) { -	funcs := FuncMap{"customFunc": func() (string, error) { -		return "", errors.New("issue5980") -	}} - -	// get the expected error output (no clone) -	uncloned := Must(New("").Funcs(funcs).Parse("{{customFunc}}")) -	wantErr := uncloned.Execute(ioutil.Discard, nil) - -	// toClone must be the same as uncloned. It has to be recreated from scratch, -	// since cloning cannot occur after execution. -	toClone := Must(New("").Funcs(funcs).Parse("{{customFunc}}")) -	cloned := Must(toClone.Clone()) -	gotErr := cloned.Execute(ioutil.Discard, nil) - -	if wantErr.Error() != gotErr.Error() { -		t.Errorf("clone error message mismatch want %q got %q", wantErr, gotErr) -	} -} diff --git a/src/pkg/html/template/content.go b/src/pkg/html/template/content.go deleted file mode 100644 index 3715ed5c9..000000000 --- a/src/pkg/html/template/content.go +++ /dev/null @@ -1,136 +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 template - -import ( -	"fmt" -	"reflect" -) - -// Strings of content from a trusted source. -type ( -	// CSS encapsulates known safe content that matches any of: -	//   1. The CSS3 stylesheet production, such as `p { color: purple }`. -	//   2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`. -	//   3. CSS3 declaration productions, such as `color: red; margin: 2px`. -	//   4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`. -	// See http://www.w3.org/TR/css3-syntax/#parsing and -	// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style -	CSS string - -	// HTML encapsulates a known safe HTML document fragment. -	// It should not be used for HTML from a third-party, or HTML with -	// unclosed tags or comments. The outputs of a sound HTML sanitizer -	// and a template escaped by this package are fine for use with HTML. -	HTML string - -	// HTMLAttr encapsulates an HTML attribute from a trusted source, -	// for example, ` dir="ltr"`. -	HTMLAttr string - -	// JS encapsulates a known safe EcmaScript5 Expression, for example, -	// `(x + y * z())`. -	// Template authors are responsible for ensuring that typed expressions -	// do not break the intended precedence and that there is no -	// statement/expression ambiguity as when passing an expression like -	// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a -	// valid Program with a very different meaning. -	JS string - -	// JSStr encapsulates a sequence of characters meant to be embedded -	// between quotes in a JavaScript expression. -	// The string must match a series of StringCharacters: -	//   StringCharacter :: SourceCharacter but not `\` or LineTerminator -	//                    | EscapeSequence -	// Note that LineContinuations are not allowed. -	// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not. -	JSStr string - -	// URL encapsulates a known safe URL or URL substring (see RFC 3986). -	// A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()` -	// from a trusted source should go in the page, but by default dynamic -	// `javascript:` URLs are filtered out since they are a frequently -	// exploited injection vector. -	URL string -) - -type contentType uint8 - -const ( -	contentTypePlain contentType = iota -	contentTypeCSS -	contentTypeHTML -	contentTypeHTMLAttr -	contentTypeJS -	contentTypeJSStr -	contentTypeURL -	// contentTypeUnsafe is used in attr.go for values that affect how -	// embedded content and network messages are formed, vetted, -	// or interpreted; or which credentials network messages carry. -	contentTypeUnsafe -) - -// indirect returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil). -func indirect(a interface{}) interface{} { -	if a == nil { -		return nil -	} -	if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { -		// Avoid creating a reflect.Value if it's not a pointer. -		return a -	} -	v := reflect.ValueOf(a) -	for v.Kind() == reflect.Ptr && !v.IsNil() { -		v = v.Elem() -	} -	return v.Interface() -} - -var ( -	errorType       = reflect.TypeOf((*error)(nil)).Elem() -	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() -) - -// indirectToStringerOrError returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer -// or error, -func indirectToStringerOrError(a interface{}) interface{} { -	if a == nil { -		return nil -	} -	v := reflect.ValueOf(a) -	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { -		v = v.Elem() -	} -	return v.Interface() -} - -// stringify converts its arguments to a string and the type of the content. -// All pointers are dereferenced, as in the text/template package. -func stringify(args ...interface{}) (string, contentType) { -	if len(args) == 1 { -		switch s := indirect(args[0]).(type) { -		case string: -			return s, contentTypePlain -		case CSS: -			return string(s), contentTypeCSS -		case HTML: -			return string(s), contentTypeHTML -		case HTMLAttr: -			return string(s), contentTypeHTMLAttr -		case JS: -			return string(s), contentTypeJS -		case JSStr: -			return string(s), contentTypeJSStr -		case URL: -			return string(s), contentTypeURL -		} -	} -	for i, arg := range args { -		args[i] = indirectToStringerOrError(arg) -	} -	return fmt.Sprint(args...), contentTypePlain -} diff --git a/src/pkg/html/template/content_test.go b/src/pkg/html/template/content_test.go deleted file mode 100644 index 5f3ffe2d3..000000000 --- a/src/pkg/html/template/content_test.go +++ /dev/null @@ -1,280 +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 template - -import ( -	"bytes" -	"fmt" -	"strings" -	"testing" -) - -func TestTypedContent(t *testing.T) { -	data := []interface{}{ -		`<b> "foo%" O'Reilly &bar;`, -		CSS(`a[href =~ "//example.com"]#foo`), -		HTML(`Hello, <b>World</b> &tc!`), -		HTMLAttr(` dir="ltr"`), -		JS(`c && alert("Hello, World!");`), -		JSStr(`Hello, World & O'Reilly\x21`), -		URL(`greeting=H%69&addressee=(World)`), -	} - -	// For each content sensitive escaper, see how it does on -	// each of the typed strings above. -	tests := []struct { -		// A template containing a single {{.}}. -		input string -		want  []string -	}{ -		{ -			`<style>{{.}} { color: blue }</style>`, -			[]string{ -				`ZgotmplZ`, -				// Allowed but not escaped. -				`a[href =~ "//example.com"]#foo`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -			}, -		}, -		{ -			`<div style="{{.}}">`, -			[]string{ -				`ZgotmplZ`, -				// Allowed and HTML escaped. -				`a[href =~ "//example.com"]#foo`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -			}, -		}, -		{ -			`{{.}}`, -			[]string{ -				`<b> "foo%" O'Reilly &bar;`, -				`a[href =~ "//example.com"]#foo`, -				// Not escaped. -				`Hello, <b>World</b> &tc!`, -				` dir="ltr"`, -				`c && alert("Hello, World!");`, -				`Hello, World & O'Reilly\x21`, -				`greeting=H%69&addressee=(World)`, -			}, -		}, -		{ -			`<a{{.}}>`, -			[]string{ -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				// Allowed and HTML escaped. -				` dir="ltr"`, -				`ZgotmplZ`, -				`ZgotmplZ`, -				`ZgotmplZ`, -			}, -		}, -		{ -			`<a title={{.}}>`, -			[]string{ -				`<b> "foo%" O'Reilly &bar;`, -				`a[href =~ "//example.com"]#foo`, -				// Tags stripped, spaces escaped, entity not re-escaped. -				`Hello, World &tc!`, -				` dir="ltr"`, -				`c && alert("Hello, World!");`, -				`Hello, World & O'Reilly\x21`, -				`greeting=H%69&addressee=(World)`, -			}, -		}, -		{ -			`<a title='{{.}}'>`, -			[]string{ -				`<b> "foo%" O'Reilly &bar;`, -				`a[href =~ "//example.com"]#foo`, -				// Tags stripped, entity not re-escaped. -				`Hello, World &tc!`, -				` dir="ltr"`, -				`c && alert("Hello, World!");`, -				`Hello, World & O'Reilly\x21`, -				`greeting=H%69&addressee=(World)`, -			}, -		}, -		{ -			`<textarea>{{.}}</textarea>`, -			[]string{ -				`<b> "foo%" O'Reilly &bar;`, -				`a[href =~ "//example.com"]#foo`, -				// Angle brackets escaped to prevent injection of close tags, entity not re-escaped. -				`Hello, <b>World</b> &tc!`, -				` dir="ltr"`, -				`c && alert("Hello, World!");`, -				`Hello, World & O'Reilly\x21`, -				`greeting=H%69&addressee=(World)`, -			}, -		}, -		{ -			`<script>alert({{.}})</script>`, -			[]string{ -				`"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`, -				`"a[href =~ \"//example.com\"]#foo"`, -				`"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`, -				`" dir=\"ltr\""`, -				// Not escaped. -				`c && alert("Hello, World!");`, -				// Escape sequence not over-escaped. -				`"Hello, World & O'Reilly\x21"`, -				`"greeting=H%69\u0026addressee=(World)"`, -			}, -		}, -		{ -			`<button onclick="alert({{.}})">`, -			[]string{ -				`"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`, -				`"a[href =~ \"//example.com\"]#foo"`, -				`"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`, -				`" dir=\"ltr\""`, -				// Not JS escaped but HTML escaped. -				`c && alert("Hello, World!");`, -				// Escape sequence not over-escaped. -				`"Hello, World & O'Reilly\x21"`, -				`"greeting=H%69\u0026addressee=(World)"`, -			}, -		}, -		{ -			`<script>alert("{{.}}")</script>`, -			[]string{ -				`\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, -				`a[href =~ \x22\/\/example.com\x22]#foo`, -				`Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, -				` dir=\x22ltr\x22`, -				`c \x26\x26 alert(\x22Hello, World!\x22);`, -				// Escape sequence not over-escaped. -				`Hello, World \x26 O\x27Reilly\x21`, -				`greeting=H%69\x26addressee=(World)`, -			}, -		}, -		{ -			`<button onclick='alert("{{.}}")'>`, -			[]string{ -				`\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, -				`a[href =~ \x22\/\/example.com\x22]#foo`, -				`Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, -				` dir=\x22ltr\x22`, -				`c \x26\x26 alert(\x22Hello, World!\x22);`, -				// Escape sequence not over-escaped. -				`Hello, World \x26 O\x27Reilly\x21`, -				`greeting=H%69\x26addressee=(World)`, -			}, -		}, -		{ -			`<a href="?q={{.}}">`, -			[]string{ -				`%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`, -				`a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`, -				`Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, -				`%20dir%3d%22ltr%22`, -				`c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, -				`Hello%2c%20World%20%26%20O%27Reilly%5cx21`, -				// Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done. -				`greeting=H%69&addressee=%28World%29`, -			}, -		}, -		{ -			`<style>body { background: url('?img={{.}}') }</style>`, -			[]string{ -				`%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`, -				`a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`, -				`Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, -				`%20dir%3d%22ltr%22`, -				`c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, -				`Hello%2c%20World%20%26%20O%27Reilly%5cx21`, -				// Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done. -				`greeting=H%69&addressee=%28World%29`, -			}, -		}, -	} - -	for _, test := range tests { -		tmpl := Must(New("x").Parse(test.input)) -		pre := strings.Index(test.input, "{{.}}") -		post := len(test.input) - (pre + 5) -		var b bytes.Buffer -		for i, x := range data { -			b.Reset() -			if err := tmpl.Execute(&b, x); err != nil { -				t.Errorf("%q with %v: %s", test.input, x, err) -				continue -			} -			if want, got := test.want[i], b.String()[pre:b.Len()-post]; want != got { -				t.Errorf("%q with %v:\nwant\n\t%q,\ngot\n\t%q\n", test.input, x, want, got) -				continue -			} -		} -	} -} - -// Test that we print using the String method. Was issue 3073. -type stringer struct { -	v int -} - -func (s *stringer) String() string { -	return fmt.Sprintf("string=%d", s.v) -} - -type errorer struct { -	v int -} - -func (s *errorer) Error() string { -	return fmt.Sprintf("error=%d", s.v) -} - -func TestStringer(t *testing.T) { -	s := &stringer{3} -	b := new(bytes.Buffer) -	tmpl := Must(New("x").Parse("{{.}}")) -	if err := tmpl.Execute(b, s); err != nil { -		t.Fatal(err) -	} -	var expect = "string=3" -	if b.String() != expect { -		t.Errorf("expected %q got %q", expect, b.String()) -	} -	e := &errorer{7} -	b.Reset() -	if err := tmpl.Execute(b, e); err != nil { -		t.Fatal(err) -	} -	expect = "error=7" -	if b.String() != expect { -		t.Errorf("expected %q got %q", expect, b.String()) -	} -} - -// https://code.google.com/p/go/issues/detail?id=5982 -func TestEscapingNilNonemptyInterfaces(t *testing.T) { -	tmpl := Must(New("x").Parse("{{.E}}")) - -	got := new(bytes.Buffer) -	testData := struct{ E error }{} // any non-empty interface here will do; error is just ready at hand -	tmpl.Execute(got, testData) - -	// Use this data instead of just hard-coding "<nil>" to avoid -	// dependencies on the html escaper and the behavior of fmt w.r.t. nil. -	want := new(bytes.Buffer) -	data := struct{ E string }{E: fmt.Sprint(nil)} -	tmpl.Execute(want, data) - -	if !bytes.Equal(want.Bytes(), got.Bytes()) { -		t.Errorf("expected %q got %q", string(want.Bytes()), string(got.Bytes())) -	} -} diff --git a/src/pkg/html/template/context.go b/src/pkg/html/template/context.go deleted file mode 100644 index 59e794d68..000000000 --- a/src/pkg/html/template/context.go +++ /dev/null @@ -1,339 +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 template - -import ( -	"fmt" -) - -// context describes the state an HTML parser must be in when it reaches the -// portion of HTML produced by evaluating a particular template node. -// -// The zero value of type context is the start context for a template that -// produces an HTML fragment as defined at -// http://www.w3.org/TR/html5/syntax.html#the-end -// where the context element is null. -type context struct { -	state   state -	delim   delim -	urlPart urlPart -	jsCtx   jsCtx -	attr    attr -	element element -	err     *Error -} - -func (c context) String() string { -	return fmt.Sprintf("{%v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.attr, c.element, c.err) -} - -// eq reports whether two contexts are equal. -func (c context) eq(d context) bool { -	return c.state == d.state && -		c.delim == d.delim && -		c.urlPart == d.urlPart && -		c.jsCtx == d.jsCtx && -		c.attr == d.attr && -		c.element == d.element && -		c.err == d.err -} - -// mangle produces an identifier that includes a suffix that distinguishes it -// from template names mangled with different contexts. -func (c context) mangle(templateName string) string { -	// The mangled name for the default context is the input templateName. -	if c.state == stateText { -		return templateName -	} -	s := templateName + "$htmltemplate_" + c.state.String() -	if c.delim != 0 { -		s += "_" + c.delim.String() -	} -	if c.urlPart != 0 { -		s += "_" + c.urlPart.String() -	} -	if c.jsCtx != 0 { -		s += "_" + c.jsCtx.String() -	} -	if c.attr != 0 { -		s += "_" + c.attr.String() -	} -	if c.element != 0 { -		s += "_" + c.element.String() -	} -	return s -} - -// state describes a high-level HTML parser state. -// -// It bounds the top of the element stack, and by extension the HTML insertion -// mode, but also contains state that does not correspond to anything in the -// HTML5 parsing algorithm because a single token production in the HTML -// grammar may contain embedded actions in a template. For instance, the quoted -// HTML attribute produced by -//     <div title="Hello {{.World}}"> -// is a single token in HTML's grammar but in a template spans several nodes. -type state uint8 - -const ( -	// stateText is parsed character data. An HTML parser is in -	// this state when its parse position is outside an HTML tag, -	// directive, comment, and special element body. -	stateText state = iota -	// stateTag occurs before an HTML attribute or the end of a tag. -	stateTag -	// stateAttrName occurs inside an attribute name. -	// It occurs between the ^'s in ` ^name^ = value`. -	stateAttrName -	// stateAfterName occurs after an attr name has ended but before any -	// equals sign. It occurs between the ^'s in ` name^ ^= value`. -	stateAfterName -	// stateBeforeValue occurs after the equals sign but before the value. -	// It occurs between the ^'s in ` name =^ ^value`. -	stateBeforeValue -	// stateHTMLCmt occurs inside an <!-- HTML comment -->. -	stateHTMLCmt -	// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>) -	// as described at http://www.w3.org/TR/html5/syntax.html#elements-0 -	stateRCDATA -	// stateAttr occurs inside an HTML attribute whose content is text. -	stateAttr -	// stateURL occurs inside an HTML attribute whose content is a URL. -	stateURL -	// stateJS occurs inside an event handler or script element. -	stateJS -	// stateJSDqStr occurs inside a JavaScript double quoted string. -	stateJSDqStr -	// stateJSSqStr occurs inside a JavaScript single quoted string. -	stateJSSqStr -	// stateJSRegexp occurs inside a JavaScript regexp literal. -	stateJSRegexp -	// stateJSBlockCmt occurs inside a JavaScript /* block comment */. -	stateJSBlockCmt -	// stateJSLineCmt occurs inside a JavaScript // line comment. -	stateJSLineCmt -	// stateCSS occurs inside a <style> element or style attribute. -	stateCSS -	// stateCSSDqStr occurs inside a CSS double quoted string. -	stateCSSDqStr -	// stateCSSSqStr occurs inside a CSS single quoted string. -	stateCSSSqStr -	// stateCSSDqURL occurs inside a CSS double quoted url("..."). -	stateCSSDqURL -	// stateCSSSqURL occurs inside a CSS single quoted url('...'). -	stateCSSSqURL -	// stateCSSURL occurs inside a CSS unquoted url(...). -	stateCSSURL -	// stateCSSBlockCmt occurs inside a CSS /* block comment */. -	stateCSSBlockCmt -	// stateCSSLineCmt occurs inside a CSS // line comment. -	stateCSSLineCmt -	// stateError is an infectious error state outside any valid -	// HTML/CSS/JS construct. -	stateError -) - -var stateNames = [...]string{ -	stateText:        "stateText", -	stateTag:         "stateTag", -	stateAttrName:    "stateAttrName", -	stateAfterName:   "stateAfterName", -	stateBeforeValue: "stateBeforeValue", -	stateHTMLCmt:     "stateHTMLCmt", -	stateRCDATA:      "stateRCDATA", -	stateAttr:        "stateAttr", -	stateURL:         "stateURL", -	stateJS:          "stateJS", -	stateJSDqStr:     "stateJSDqStr", -	stateJSSqStr:     "stateJSSqStr", -	stateJSRegexp:    "stateJSRegexp", -	stateJSBlockCmt:  "stateJSBlockCmt", -	stateJSLineCmt:   "stateJSLineCmt", -	stateCSS:         "stateCSS", -	stateCSSDqStr:    "stateCSSDqStr", -	stateCSSSqStr:    "stateCSSSqStr", -	stateCSSDqURL:    "stateCSSDqURL", -	stateCSSSqURL:    "stateCSSSqURL", -	stateCSSURL:      "stateCSSURL", -	stateCSSBlockCmt: "stateCSSBlockCmt", -	stateCSSLineCmt:  "stateCSSLineCmt", -	stateError:       "stateError", -} - -func (s state) String() string { -	if int(s) < len(stateNames) { -		return stateNames[s] -	} -	return fmt.Sprintf("illegal state %d", int(s)) -} - -// isComment is true for any state that contains content meant for template -// authors & maintainers, not for end-users or machines. -func isComment(s state) bool { -	switch s { -	case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateCSSBlockCmt, stateCSSLineCmt: -		return true -	} -	return false -} - -// isInTag return whether s occurs solely inside an HTML tag. -func isInTag(s state) bool { -	switch s { -	case stateTag, stateAttrName, stateAfterName, stateBeforeValue, stateAttr: -		return true -	} -	return false -} - -// delim is the delimiter that will end the current HTML attribute. -type delim uint8 - -const ( -	// delimNone occurs outside any attribute. -	delimNone delim = iota -	// delimDoubleQuote occurs when a double quote (") closes the attribute. -	delimDoubleQuote -	// delimSingleQuote occurs when a single quote (') closes the attribute. -	delimSingleQuote -	// delimSpaceOrTagEnd occurs when a space or right angle bracket (>) -	// closes the attribute. -	delimSpaceOrTagEnd -) - -var delimNames = [...]string{ -	delimNone:          "delimNone", -	delimDoubleQuote:   "delimDoubleQuote", -	delimSingleQuote:   "delimSingleQuote", -	delimSpaceOrTagEnd: "delimSpaceOrTagEnd", -} - -func (d delim) String() string { -	if int(d) < len(delimNames) { -		return delimNames[d] -	} -	return fmt.Sprintf("illegal delim %d", int(d)) -} - -// urlPart identifies a part in an RFC 3986 hierarchical URL to allow different -// encoding strategies. -type urlPart uint8 - -const ( -	// urlPartNone occurs when not in a URL, or possibly at the start: -	// ^ in "^http://auth/path?k=v#frag". -	urlPartNone urlPart = iota -	// urlPartPreQuery occurs in the scheme, authority, or path; between the -	// ^s in "h^ttp://auth/path^?k=v#frag". -	urlPartPreQuery -	// urlPartQueryOrFrag occurs in the query portion between the ^s in -	// "http://auth/path?^k=v#frag^". -	urlPartQueryOrFrag -	// urlPartUnknown occurs due to joining of contexts both before and -	// after the query separator. -	urlPartUnknown -) - -var urlPartNames = [...]string{ -	urlPartNone:        "urlPartNone", -	urlPartPreQuery:    "urlPartPreQuery", -	urlPartQueryOrFrag: "urlPartQueryOrFrag", -	urlPartUnknown:     "urlPartUnknown", -} - -func (u urlPart) String() string { -	if int(u) < len(urlPartNames) { -		return urlPartNames[u] -	} -	return fmt.Sprintf("illegal urlPart %d", int(u)) -} - -// jsCtx determines whether a '/' starts a regular expression literal or a -// division operator. -type jsCtx uint8 - -const ( -	// jsCtxRegexp occurs where a '/' would start a regexp literal. -	jsCtxRegexp jsCtx = iota -	// jsCtxDivOp occurs where a '/' would start a division operator. -	jsCtxDivOp -	// jsCtxUnknown occurs where a '/' is ambiguous due to context joining. -	jsCtxUnknown -) - -func (c jsCtx) String() string { -	switch c { -	case jsCtxRegexp: -		return "jsCtxRegexp" -	case jsCtxDivOp: -		return "jsCtxDivOp" -	case jsCtxUnknown: -		return "jsCtxUnknown" -	} -	return fmt.Sprintf("illegal jsCtx %d", int(c)) -} - -// element identifies the HTML element when inside a start tag or special body. -// Certain HTML element (for example <script> and <style>) have bodies that are -// treated differently from stateText so the element type is necessary to -// transition into the correct context at the end of a tag and to identify the -// end delimiter for the body. -type element uint8 - -const ( -	// elementNone occurs outside a special tag or special element body. -	elementNone element = iota -	// elementScript corresponds to the raw text <script> element. -	elementScript -	// elementStyle corresponds to the raw text <style> element. -	elementStyle -	// elementTextarea corresponds to the RCDATA <textarea> element. -	elementTextarea -	// elementTitle corresponds to the RCDATA <title> element. -	elementTitle -) - -var elementNames = [...]string{ -	elementNone:     "elementNone", -	elementScript:   "elementScript", -	elementStyle:    "elementStyle", -	elementTextarea: "elementTextarea", -	elementTitle:    "elementTitle", -} - -func (e element) String() string { -	if int(e) < len(elementNames) { -		return elementNames[e] -	} -	return fmt.Sprintf("illegal element %d", int(e)) -} - -// attr identifies the most recent HTML attribute when inside a start tag. -type attr uint8 - -const ( -	// attrNone corresponds to a normal attribute or no attribute. -	attrNone attr = iota -	// attrScript corresponds to an event handler attribute. -	attrScript -	// attrStyle corresponds to the style attribute whose value is CSS. -	attrStyle -	// attrURL corresponds to an attribute whose value is a URL. -	attrURL -) - -var attrNames = [...]string{ -	attrNone:   "attrNone", -	attrScript: "attrScript", -	attrStyle:  "attrStyle", -	attrURL:    "attrURL", -} - -func (a attr) String() string { -	if int(a) < len(attrNames) { -		return attrNames[a] -	} -	return fmt.Sprintf("illegal attr %d", int(a)) -} diff --git a/src/pkg/html/template/css.go b/src/pkg/html/template/css.go deleted file mode 100644 index 634f183f7..000000000 --- a/src/pkg/html/template/css.go +++ /dev/null @@ -1,268 +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 template - -import ( -	"bytes" -	"fmt" -	"unicode" -	"unicode/utf8" -) - -// endsWithCSSKeyword reports whether b ends with an ident that -// case-insensitively matches the lower-case kw. -func endsWithCSSKeyword(b []byte, kw string) bool { -	i := len(b) - len(kw) -	if i < 0 { -		// Too short. -		return false -	} -	if i != 0 { -		r, _ := utf8.DecodeLastRune(b[:i]) -		if isCSSNmchar(r) { -			// Too long. -			return false -		} -	} -	// Many CSS keywords, such as "!important" can have characters encoded, -	// but the URI production does not allow that according to -	// http://www.w3.org/TR/css3-syntax/#TOK-URI -	// This does not attempt to recognize encoded keywords. For example, -	// given "\75\72\6c" and "url" this return false. -	return string(bytes.ToLower(b[i:])) == kw -} - -// isCSSNmchar reports whether rune is allowed anywhere in a CSS identifier. -func isCSSNmchar(r rune) bool { -	// Based on the CSS3 nmchar production but ignores multi-rune escape -	// sequences. -	// http://www.w3.org/TR/css3-syntax/#SUBTOK-nmchar -	return 'a' <= r && r <= 'z' || -		'A' <= r && r <= 'Z' || -		'0' <= r && r <= '9' || -		r == '-' || -		r == '_' || -		// Non-ASCII cases below. -		0x80 <= r && r <= 0xd7ff || -		0xe000 <= r && r <= 0xfffd || -		0x10000 <= r && r <= 0x10ffff -} - -// decodeCSS decodes CSS3 escapes given a sequence of stringchars. -// If there is no change, it returns the input, otherwise it returns a slice -// backed by a new array. -// http://www.w3.org/TR/css3-syntax/#SUBTOK-stringchar defines stringchar. -func decodeCSS(s []byte) []byte { -	i := bytes.IndexByte(s, '\\') -	if i == -1 { -		return s -	} -	// The UTF-8 sequence for a codepoint is never longer than 1 + the -	// number hex digits need to represent that codepoint, so len(s) is an -	// upper bound on the output length. -	b := make([]byte, 0, len(s)) -	for len(s) != 0 { -		i := bytes.IndexByte(s, '\\') -		if i == -1 { -			i = len(s) -		} -		b, s = append(b, s[:i]...), s[i:] -		if len(s) < 2 { -			break -		} -		// http://www.w3.org/TR/css3-syntax/#SUBTOK-escape -		// escape ::= unicode | '\' [#x20-#x7E#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF] -		if isHex(s[1]) { -			// http://www.w3.org/TR/css3-syntax/#SUBTOK-unicode -			//   unicode ::= '\' [0-9a-fA-F]{1,6} wc? -			j := 2 -			for j < len(s) && j < 7 && isHex(s[j]) { -				j++ -			} -			r := hexDecode(s[1:j]) -			if r > unicode.MaxRune { -				r, j = r/16, j-1 -			} -			n := utf8.EncodeRune(b[len(b):cap(b)], r) -			// The optional space at the end allows a hex -			// sequence to be followed by a literal hex. -			// string(decodeCSS([]byte(`\A B`))) == "\nB" -			b, s = b[:len(b)+n], skipCSSSpace(s[j:]) -		} else { -			// `\\` decodes to `\` and `\"` to `"`. -			_, n := utf8.DecodeRune(s[1:]) -			b, s = append(b, s[1:1+n]...), s[1+n:] -		} -	} -	return b -} - -// isHex reports whether the given character is a hex digit. -func isHex(c byte) bool { -	return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' -} - -// hexDecode decodes a short hex digit sequence: "10" -> 16. -func hexDecode(s []byte) rune { -	n := '\x00' -	for _, c := range s { -		n <<= 4 -		switch { -		case '0' <= c && c <= '9': -			n |= rune(c - '0') -		case 'a' <= c && c <= 'f': -			n |= rune(c-'a') + 10 -		case 'A' <= c && c <= 'F': -			n |= rune(c-'A') + 10 -		default: -			panic(fmt.Sprintf("Bad hex digit in %q", s)) -		} -	} -	return n -} - -// skipCSSSpace returns a suffix of c, skipping over a single space. -func skipCSSSpace(c []byte) []byte { -	if len(c) == 0 { -		return c -	} -	// wc ::= #x9 | #xA | #xC | #xD | #x20 -	switch c[0] { -	case '\t', '\n', '\f', ' ': -		return c[1:] -	case '\r': -		// This differs from CSS3's wc production because it contains a -		// probable spec error whereby wc contains all the single byte -		// sequences in nl (newline) but not CRLF. -		if len(c) >= 2 && c[1] == '\n' { -			return c[2:] -		} -		return c[1:] -	} -	return c -} - -// isCSSSpace reports whether b is a CSS space char as defined in wc. -func isCSSSpace(b byte) bool { -	switch b { -	case '\t', '\n', '\f', '\r', ' ': -		return true -	} -	return false -} - -// cssEscaper escapes HTML and CSS special characters using \<hex>+ escapes. -func cssEscaper(args ...interface{}) string { -	s, _ := stringify(args...) -	var b bytes.Buffer -	written := 0 -	for i, r := range s { -		var repl string -		switch r { -		case 0: -			repl = `\0` -		case '\t': -			repl = `\9` -		case '\n': -			repl = `\a` -		case '\f': -			repl = `\c` -		case '\r': -			repl = `\d` -		// Encode HTML specials as hex so the output can be embedded -		// in HTML attributes without further encoding. -		case '"': -			repl = `\22` -		case '&': -			repl = `\26` -		case '\'': -			repl = `\27` -		case '(': -			repl = `\28` -		case ')': -			repl = `\29` -		case '+': -			repl = `\2b` -		case '/': -			repl = `\2f` -		case ':': -			repl = `\3a` -		case ';': -			repl = `\3b` -		case '<': -			repl = `\3c` -		case '>': -			repl = `\3e` -		case '\\': -			repl = `\\` -		case '{': -			repl = `\7b` -		case '}': -			repl = `\7d` -		default: -			continue -		} -		b.WriteString(s[written:i]) -		b.WriteString(repl) -		written = i + utf8.RuneLen(r) -		if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) { -			b.WriteByte(' ') -		} -	} -	if written == 0 { -		return s -	} -	b.WriteString(s[written:]) -	return b.String() -} - -var expressionBytes = []byte("expression") -var mozBindingBytes = []byte("mozbinding") - -// cssValueFilter allows innocuous CSS values in the output including CSS -// quantities (10px or 25%), ID or class literals (#foo, .bar), keyword values -// (inherit, blue), and colors (#888). -// It filters out unsafe values, such as those that affect token boundaries, -// and anything that might execute scripts. -func cssValueFilter(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeCSS { -		return s -	} -	b, id := decodeCSS([]byte(s)), make([]byte, 0, 64) - -	// CSS3 error handling is specified as honoring string boundaries per -	// http://www.w3.org/TR/css3-syntax/#error-handling : -	//     Malformed declarations. User agents must handle unexpected -	//     tokens encountered while parsing a declaration by reading until -	//     the end of the declaration, while observing the rules for -	//     matching pairs of (), [], {}, "", and '', and correctly handling -	//     escapes. For example, a malformed declaration may be missing a -	//     property, colon (:) or value. -	// So we need to make sure that values do not have mismatched bracket -	// or quote characters to prevent the browser from restarting parsing -	// inside a string that might embed JavaScript source. -	for i, c := range b { -		switch c { -		case 0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}': -			return filterFailsafe -		case '-': -			// Disallow <!-- or -->. -			// -- should not appear in valid identifiers. -			if i != 0 && b[i-1] == '-' { -				return filterFailsafe -			} -		default: -			if c < 0x80 && isCSSNmchar(rune(c)) { -				id = append(id, c) -			} -		} -	} -	id = bytes.ToLower(id) -	if bytes.Index(id, expressionBytes) != -1 || bytes.Index(id, mozBindingBytes) != -1 { -		return filterFailsafe -	} -	return string(b) -} diff --git a/src/pkg/html/template/css_test.go b/src/pkg/html/template/css_test.go deleted file mode 100644 index a735638b0..000000000 --- a/src/pkg/html/template/css_test.go +++ /dev/null @@ -1,281 +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 template - -import ( -	"strconv" -	"strings" -	"testing" -) - -func TestEndsWithCSSKeyword(t *testing.T) { -	tests := []struct { -		css, kw string -		want    bool -	}{ -		{"", "url", false}, -		{"url", "url", true}, -		{"URL", "url", true}, -		{"Url", "url", true}, -		{"url", "important", false}, -		{"important", "important", true}, -		{"image-url", "url", false}, -		{"imageurl", "url", false}, -		{"image url", "url", true}, -	} -	for _, test := range tests { -		got := endsWithCSSKeyword([]byte(test.css), test.kw) -		if got != test.want { -			t.Errorf("want %t but got %t for css=%v, kw=%v", test.want, got, test.css, test.kw) -		} -	} -} - -func TestIsCSSNmchar(t *testing.T) { -	tests := []struct { -		rune rune -		want bool -	}{ -		{0, false}, -		{'0', true}, -		{'9', true}, -		{'A', true}, -		{'Z', true}, -		{'a', true}, -		{'z', true}, -		{'_', true}, -		{'-', true}, -		{':', false}, -		{';', false}, -		{' ', false}, -		{0x7f, false}, -		{0x80, true}, -		{0x1234, true}, -		{0xd800, false}, -		{0xdc00, false}, -		{0xfffe, false}, -		{0x10000, true}, -		{0x110000, false}, -	} -	for _, test := range tests { -		got := isCSSNmchar(test.rune) -		if got != test.want { -			t.Errorf("%q: want %t but got %t", string(test.rune), test.want, got) -		} -	} -} - -func TestDecodeCSS(t *testing.T) { -	tests := []struct { -		css, want string -	}{ -		{``, ``}, -		{`foo`, `foo`}, -		{`foo\`, `foo`}, -		{`foo\\`, `foo\`}, -		{`\`, ``}, -		{`\A`, "\n"}, -		{`\a`, "\n"}, -		{`\0a`, "\n"}, -		{`\00000a`, "\n"}, -		{`\000000a`, "\u0000a"}, -		{`\1234 5`, "\u1234" + "5"}, -		{`\1234\20 5`, "\u1234" + " 5"}, -		{`\1234\A 5`, "\u1234" + "\n5"}, -		{"\\1234\t5", "\u1234" + "5"}, -		{"\\1234\n5", "\u1234" + "5"}, -		{"\\1234\r\n5", "\u1234" + "5"}, -		{`\12345`, "\U00012345"}, -		{`\\`, `\`}, -		{`\\ `, `\ `}, -		{`\"`, `"`}, -		{`\'`, `'`}, -		{`\.`, `.`}, -		{`\. .`, `. .`}, -		{ -			`The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e  fox jumps\2028over the \3c canine class=\22lazy\22 \3e dog\3c/canine\3e`, -			"The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>", -		}, -	} -	for _, test := range tests { -		got1 := string(decodeCSS([]byte(test.css))) -		if got1 != test.want { -			t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.css, test.want, got1) -		} -		recoded := cssEscaper(got1) -		if got2 := string(decodeCSS([]byte(recoded))); got2 != test.want { -			t.Errorf("%q: escape & decode not dual for %q", test.css, recoded) -		} -	} -} - -func TestHexDecode(t *testing.T) { -	for i := 0; i < 0x200000; i += 101 /* coprime with 16 */ { -		s := strconv.FormatInt(int64(i), 16) -		if got := int(hexDecode([]byte(s))); got != i { -			t.Errorf("%s: want %d but got %d", s, i, got) -		} -		s = strings.ToUpper(s) -		if got := int(hexDecode([]byte(s))); got != i { -			t.Errorf("%s: want %d but got %d", s, i, got) -		} -	} -} - -func TestSkipCSSSpace(t *testing.T) { -	tests := []struct { -		css, want string -	}{ -		{"", ""}, -		{"foo", "foo"}, -		{"\n", ""}, -		{"\r\n", ""}, -		{"\r", ""}, -		{"\t", ""}, -		{" ", ""}, -		{"\f", ""}, -		{" foo", "foo"}, -		{"  foo", " foo"}, -		{`\20`, `\20`}, -	} -	for _, test := range tests { -		got := string(skipCSSSpace([]byte(test.css))) -		if got != test.want { -			t.Errorf("%q: want %q but got %q", test.css, test.want, got) -		} -	} -} - -func TestCSSEscaper(t *testing.T) { -	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" + -		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -		` !"#$%&'()*+,-./` + -		`0123456789:;<=>?` + -		`@ABCDEFGHIJKLMNO` + -		`PQRSTUVWXYZ[\]^_` + -		"`abcdefghijklmno" + -		"pqrstuvwxyz{|}~\x7f" + -		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E") - -	want := ("\\0\x01\x02\x03\x04\x05\x06\x07" + -		"\x08\\9 \\a\x0b\\c \\d\x0E\x0F" + -		"\x10\x11\x12\x13\x14\x15\x16\x17" + -		"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -		` !\22#$%\26\27\28\29*\2b,-.\2f ` + -		`0123456789\3a\3b\3c=\3e?` + -		`@ABCDEFGHIJKLMNO` + -		`PQRSTUVWXYZ[\\]^_` + -		"`abcdefghijklmno" + -		`pqrstuvwxyz\7b|\7d~` + "\u007f" + -		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E") - -	got := cssEscaper(input) -	if got != want { -		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got) -	} - -	got = string(decodeCSS([]byte(got))) -	if input != got { -		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", input, got) -	} -} - -func TestCSSValueFilter(t *testing.T) { -	tests := []struct { -		css, want string -	}{ -		{"", ""}, -		{"foo", "foo"}, -		{"0", "0"}, -		{"0px", "0px"}, -		{"-5px", "-5px"}, -		{"1.25in", "1.25in"}, -		{"+.33em", "+.33em"}, -		{"100%", "100%"}, -		{"12.5%", "12.5%"}, -		{".foo", ".foo"}, -		{"#bar", "#bar"}, -		{"corner-radius", "corner-radius"}, -		{"-moz-corner-radius", "-moz-corner-radius"}, -		{"#000", "#000"}, -		{"#48f", "#48f"}, -		{"#123456", "#123456"}, -		{"U+00-FF, U+980-9FF", "U+00-FF, U+980-9FF"}, -		{"color: red", "color: red"}, -		{"<!--", "ZgotmplZ"}, -		{"-->", "ZgotmplZ"}, -		{"<![CDATA[", "ZgotmplZ"}, -		{"]]>", "ZgotmplZ"}, -		{"</style", "ZgotmplZ"}, -		{`"`, "ZgotmplZ"}, -		{`'`, "ZgotmplZ"}, -		{"`", "ZgotmplZ"}, -		{"\x00", "ZgotmplZ"}, -		{"/* foo */", "ZgotmplZ"}, -		{"//", "ZgotmplZ"}, -		{"[href=~", "ZgotmplZ"}, -		{"expression(alert(1337))", "ZgotmplZ"}, -		{"-expression(alert(1337))", "ZgotmplZ"}, -		{"expression", "ZgotmplZ"}, -		{"Expression", "ZgotmplZ"}, -		{"EXPRESSION", "ZgotmplZ"}, -		{"-moz-binding", "ZgotmplZ"}, -		{"-expr\x00ession(alert(1337))", "ZgotmplZ"}, -		{`-expr\0ession(alert(1337))`, "ZgotmplZ"}, -		{`-express\69on(alert(1337))`, "ZgotmplZ"}, -		{`-express\69 on(alert(1337))`, "ZgotmplZ"}, -		{`-exp\72 ession(alert(1337))`, "ZgotmplZ"}, -		{`-exp\52 ession(alert(1337))`, "ZgotmplZ"}, -		{`-exp\000052 ession(alert(1337))`, "ZgotmplZ"}, -		{`-expre\0000073sion`, "-expre\x073sion"}, -		{`@import url evil.css`, "ZgotmplZ"}, -	} -	for _, test := range tests { -		got := cssValueFilter(test.css) -		if got != test.want { -			t.Errorf("%q: want %q but got %q", test.css, test.want, got) -		} -	} -} - -func BenchmarkCSSEscaper(b *testing.B) { -	for i := 0; i < b.N; i++ { -		cssEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>") -	} -} - -func BenchmarkCSSEscaperNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		cssEscaper("The quick, brown fox jumps over the lazy dog.") -	} -} - -func BenchmarkDecodeCSS(b *testing.B) { -	s := []byte(`The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e fox jumps\2028over the \3c canine class=\22lazy\22 \3edog\3c/canine\3e`) -	b.ResetTimer() -	for i := 0; i < b.N; i++ { -		decodeCSS(s) -	} -} - -func BenchmarkDecodeCSSNoSpecials(b *testing.B) { -	s := []byte("The quick, brown fox jumps over the lazy dog.") -	b.ResetTimer() -	for i := 0; i < b.N; i++ { -		decodeCSS(s) -	} -} - -func BenchmarkCSSValueFilter(b *testing.B) { -	for i := 0; i < b.N; i++ { -		cssValueFilter(`  e\78preS\0Sio/**/n(alert(1337))`) -	} -} - -func BenchmarkCSSValueFilterOk(b *testing.B) { -	for i := 0; i < b.N; i++ { -		cssValueFilter(`Times New Roman`) -	} -} diff --git a/src/pkg/html/template/doc.go b/src/pkg/html/template/doc.go deleted file mode 100644 index d422ada37..000000000 --- a/src/pkg/html/template/doc.go +++ /dev/null @@ -1,191 +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 template (html/template) implements data-driven templates for -generating HTML output safe against code injection. It provides the -same interface as package text/template and should be used instead of -text/template whenever the output is HTML. - -The documentation here focuses on the security features of the package. -For information about how to program the templates themselves, see the -documentation for text/template. - -Introduction - -This package wraps package text/template so you can share its template API -to parse and execute HTML templates safely. - -  tmpl, err := template.New("name").Parse(...) -  // Error checking elided -  err = tmpl.Execute(out, data) - -If successful, tmpl will now be injection-safe. Otherwise, err is an error -defined in the docs for ErrorCode. - -HTML templates treat data values as plain text which should be encoded so they -can be safely embedded in an HTML document. The escaping is contextual, so -actions can appear within JavaScript, CSS, and URI contexts. - -The security model used by this package assumes that template authors are -trusted, while Execute's data parameter is not. More details are -provided below. - -Example - -  import "text/template" -  ... -  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) -  err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>") - -produces - -  Hello, <script>alert('you have been pwned')</script>! - -but the contextual autoescaping in html/template - -  import "html/template" -  ... -  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) -  err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>") - -produces safe, escaped HTML output - -  Hello, <script>alert('you have been pwned')</script>! - - -Contexts - -This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing -functions to each simple action pipeline, so given the excerpt - -  <a href="/search?q={{.}}">{{.}}</a> - -At parse time each {{.}} is overwritten to add escaping functions as necessary. -In this case it becomes - -  <a href="/search?q={{. | urlquery}}">{{. | html}}</a> - - -Errors - -See the documentation of ErrorCode for details. - - -A fuller picture - -The rest of this package comment may be skipped on first reading; it includes -details necessary to understand escaping contexts and error messages. Most users -will not need to understand these details. - - -Contexts - -Assuming {{.}} is `O'Reilly: How are <i>you</i>?`, the table below shows -how {{.}} appears when used in the context to the left. - -  Context                          {{.}} After -  {{.}}                            O'Reilly: How are <i>you</i>? -  <a title='{{.}}'>                O'Reilly: How are you? -  <a href="/{{.}}">                O'Reilly: How are %3ci%3eyou%3c/i%3e? -  <a href="?q={{.}}">              O'Reilly%3a%20How%20are%3ci%3e...%3f -  <a onx='f("{{.}}")'>             O\x27Reilly: How are \x3ci\x3eyou...? -  <a onx='f({{.}})'>               "O\x27Reilly: How are \x3ci\x3eyou...?" -  <a onx='pattern = /{{.}}/;'>     O\x27Reilly: How are \x3ci\x3eyou...\x3f - -If used in an unsafe context, then the value might be filtered out: - -  Context                          {{.}} After -  <a href="{{.}}">                 #ZgotmplZ - -since "O'Reilly:" is not an allowed protocol like "http:". - - -If {{.}} is the innocuous word, `left`, then it can appear more widely, - -  Context                              {{.}} After -  {{.}}                                left -  <a title='{{.}}'>                    left -  <a href='{{.}}'>                     left -  <a href='/{{.}}'>                    left -  <a href='?dir={{.}}'>                left -  <a style="border-{{.}}: 4px">        left -  <a style="align: {{.}}">             left -  <a style="background: '{{.}}'>       left -  <a style="background: url('{{.}}')>  left -  <style>p.{{.}} {color:red}</style>   left - -Non-string values can be used in JavaScript contexts. -If {{.}} is - -  struct{A,B string}{ "foo", "bar" } - -in the escaped template - -  <script>var pair = {{.}};</script> - -then the template output is - -  <script>var pair = {"A": "foo", "B": "bar"};</script> - -See package json to understand how non-string content is marshalled for -embedding in JavaScript contexts. - - -Typed Strings - -By default, this package assumes that all pipelines produce a plain text string. -It adds escaping pipeline stages necessary to correctly and safely embed that -plain text string in the appropriate context. - -When a data value is not plain text, you can make sure it is not over-escaped -by marking it with its type. - -Types HTML, JS, URL, and others from content.go can carry safe content that is -exempted from escaping. - -The template - -  Hello, {{.}}! - -can be invoked with - -  tmpl.Execute(out, HTML(`<b>World</b>`)) - -to produce - -  Hello, <b>World</b>! - -instead of the - -  Hello, <b>World<b>! - -that would have been produced if {{.}} was a regular string. - - -Security Model - -http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition defines "safe" as used by this package. - -This package assumes that template authors are trusted, that Execute's data -parameter is not, and seeks to preserve the properties below in the face -of untrusted data: - -Structure Preservation Property: -"... when a template author writes an HTML tag in a safe templating language, -the browser will interpret the corresponding portion of the output as a tag -regardless of the values of untrusted data, and similarly for other structures -such as attribute boundaries and JS and CSS string boundaries." - -Code Effect Property: -"... only code specified by the template author should run as a result of -injecting the template output into a page and all code specified by the -template author should run as a result of the same." - -Least Surprise Property: -"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who -knows that contextual autoescaping happens should be able to look at a {{.}} -and correctly infer what sanitization happens." -*/ -package template diff --git a/src/pkg/html/template/error.go b/src/pkg/html/template/error.go deleted file mode 100644 index 46e49ccf8..000000000 --- a/src/pkg/html/template/error.go +++ /dev/null @@ -1,197 +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 template - -import ( -	"fmt" -) - -// Error describes a problem encountered during template Escaping. -type Error struct { -	// ErrorCode describes the kind of error. -	ErrorCode ErrorCode -	// Name is the name of the template in which the error was encountered. -	Name string -	// Line is the line number of the error in the template source or 0. -	Line int -	// Description is a human-readable description of the problem. -	Description string -} - -// ErrorCode is a code for a kind of error. -type ErrorCode int - -// We define codes for each error that manifests while escaping templates, but -// escaped templates may also fail at runtime. -// -// Output: "ZgotmplZ" -// Example: -//   <img src="{{.X}}"> -//   where {{.X}} evaluates to `javascript:...` -// Discussion: -//   "ZgotmplZ" is a special value that indicates that unsafe content reached a -//   CSS or URL context at runtime. The output of the example will be -//     <img src="#ZgotmplZ"> -//   If the data comes from a trusted source, use content types to exempt it -//   from filtering: URL(`javascript:...`). -const ( -	// OK indicates the lack of an error. -	OK ErrorCode = iota - -	// ErrAmbigContext: "... appears in an ambiguous URL context" -	// Example: -	//   <a href=" -	//      {{if .C}} -	//        /path/ -	//      {{else}} -	//        /search?q= -	//      {{end}} -	//      {{.X}} -	//   "> -	// Discussion: -	//   {{.X}} is in an ambiguous URL context since, depending on {{.C}}, -	//  it may be either a URL suffix or a query parameter. -	//   Moving {{.X}} into the condition removes the ambiguity: -	//   <a href="{{if .C}}/path/{{.X}}{{else}}/search?q={{.X}}"> -	ErrAmbigContext - -	// ErrBadHTML: "expected space, attr name, or end of tag, but got ...", -	//   "... in unquoted attr", "... in attribute name" -	// Example: -	//   <a href = /search?q=foo> -	//   <href=foo> -	//   <form na<e=...> -	//   <option selected< -	// Discussion: -	//   This is often due to a typo in an HTML element, but some runes -	//   are banned in tag names, attribute names, and unquoted attribute -	//   values because they can tickle parser ambiguities. -	//   Quoting all attributes is the best policy. -	ErrBadHTML - -	// ErrBranchEnd: "{{if}} branches end in different contexts" -	// Example: -	//   {{if .C}}<a href="{{end}}{{.X}} -	// Discussion: -	//   Package html/template statically examines each path through an -	//   {{if}}, {{range}}, or {{with}} to escape any following pipelines. -	//   The example is ambiguous since {{.X}} might be an HTML text node, -	//   or a URL prefix in an HTML attribute. The context of {{.X}} is -	//   used to figure out how to escape it, but that context depends on -	//   the run-time value of {{.C}} which is not statically known. -	// -	//   The problem is usually something like missing quotes or angle -	//   brackets, or can be avoided by refactoring to put the two contexts -	//   into different branches of an if, range or with. If the problem -	//   is in a {{range}} over a collection that should never be empty, -	//   adding a dummy {{else}} can help. -	ErrBranchEnd - -	// ErrEndContext: "... ends in a non-text context: ..." -	// Examples: -	//   <div -	//   <div title="no close quote> -	//   <script>f() -	// Discussion: -	//   Executed templates should produce a DocumentFragment of HTML. -	//   Templates that end without closing tags will trigger this error. -	//   Templates that should not be used in an HTML context or that -	//   produce incomplete Fragments should not be executed directly. -	// -	//   {{define "main"}} <script>{{template "helper"}}</script> {{end}} -	//   {{define "helper"}} document.write(' <div title=" ') {{end}} -	// -	//   "helper" does not produce a valid document fragment, so should -	//   not be Executed directly. -	ErrEndContext - -	// ErrNoSuchTemplate: "no such template ..." -	// Examples: -	//   {{define "main"}}<div {{template "attrs"}}>{{end}} -	//   {{define "attrs"}}href="{{.URL}}"{{end}} -	// Discussion: -	//   Package html/template looks through template calls to compute the -	//   context. -	//   Here the {{.URL}} in "attrs" must be treated as a URL when called -	//   from "main", but you will get this error if "attrs" is not defined -	//   when "main" is parsed. -	ErrNoSuchTemplate - -	// ErrOutputContext: "cannot compute output context for template ..." -	// Examples: -	//   {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}} -	// Discussion: -	//   A recursive template does not end in the same context in which it -	//   starts, and a reliable output context cannot be computed. -	//   Look for typos in the named template. -	//   If the template should not be called in the named start context, -	//   look for calls to that template in unexpected contexts. -	//   Maybe refactor recursive templates to not be recursive. -	ErrOutputContext - -	// ErrPartialCharset: "unfinished JS regexp charset in ..." -	// Example: -	//     <script>var pattern = /foo[{{.Chars}}]/</script> -	// Discussion: -	//   Package html/template does not support interpolation into regular -	//   expression literal character sets. -	ErrPartialCharset - -	// ErrPartialEscape: "unfinished escape sequence in ..." -	// Example: -	//   <script>alert("\{{.X}}")</script> -	// Discussion: -	//   Package html/template does not support actions following a -	//   backslash. -	//   This is usually an error and there are better solutions; for -	//   example -	//     <script>alert("{{.X}}")</script> -	//   should work, and if {{.X}} is a partial escape sequence such as -	//   "xA0", mark the whole sequence as safe content: JSStr(`\xA0`) -	ErrPartialEscape - -	// ErrRangeLoopReentry: "on range loop re-entry: ..." -	// Example: -	//   <script>var x = [{{range .}}'{{.}},{{end}}]</script> -	// Discussion: -	//   If an iteration through a range would cause it to end in a -	//   different context than an earlier pass, there is no single context. -	//   In the example, there is missing a quote, so it is not clear -	//   whether {{.}} is meant to be inside a JS string or in a JS value -	//   context.  The second iteration would produce something like -	// -	//     <script>var x = ['firstValue,'secondValue]</script> -	ErrRangeLoopReentry - -	// ErrSlashAmbig: '/' could start a division or regexp. -	// Example: -	//   <script> -	//     {{if .C}}var x = 1{{end}} -	//     /-{{.N}}/i.test(x) ? doThis : doThat(); -	//   </script> -	// Discussion: -	//   The example above could produce `var x = 1/-2/i.test(s)...` -	//   in which the first '/' is a mathematical division operator or it -	//   could produce `/-2/i.test(s)` in which the first '/' starts a -	//   regexp literal. -	//   Look for missing semicolons inside branches, and maybe add -	//   parentheses to make it clear which interpretation you intend. -	ErrSlashAmbig -) - -func (e *Error) Error() string { -	if e.Line != 0 { -		return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description) -	} else if e.Name != "" { -		return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description) -	} -	return "html/template: " + e.Description -} - -// errorf creates an error given a format string f and args. -// The template Name still needs to be supplied. -func errorf(k ErrorCode, line int, f string, args ...interface{}) *Error { -	return &Error{k, "", line, fmt.Sprintf(f, args...)} -} diff --git a/src/pkg/html/template/escape.go b/src/pkg/html/template/escape.go deleted file mode 100644 index 4e379828d..000000000 --- a/src/pkg/html/template/escape.go +++ /dev/null @@ -1,815 +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 template - -import ( -	"bytes" -	"fmt" -	"html" -	"io" -	"text/template" -	"text/template/parse" -) - -// escapeTemplates rewrites the named templates, which must be -// associated with t, to guarantee that the output of any of the named -// templates is properly escaped.  Names should include the names of -// all templates that might be Executed but need not include helper -// templates.  If no error is returned, then the named templates have -// been modified.  Otherwise the named templates have been rendered -// unusable. -func escapeTemplates(tmpl *Template, names ...string) error { -	e := newEscaper(tmpl) -	for _, name := range names { -		c, _ := e.escapeTree(context{}, name, 0) -		var err error -		if c.err != nil { -			err, c.err.Name = c.err, name -		} else if c.state != stateText { -			err = &Error{ErrEndContext, name, 0, fmt.Sprintf("ends in a non-text context: %v", c)} -		} -		if err != nil { -			// Prevent execution of unsafe templates. -			for _, name := range names { -				if t := tmpl.set[name]; t != nil { -					t.text.Tree = nil -					t.Tree = nil -				} -			} -			return err -		} -	} -	e.commit() -	for _, name := range names { -		if t := tmpl.set[name]; t != nil { -			t.escaped = true -			t.Tree = t.text.Tree -		} -	} -	return nil -} - -// funcMap maps command names to functions that render their inputs safe. -var funcMap = template.FuncMap{ -	"html_template_attrescaper":     attrEscaper, -	"html_template_commentescaper":  commentEscaper, -	"html_template_cssescaper":      cssEscaper, -	"html_template_cssvaluefilter":  cssValueFilter, -	"html_template_htmlnamefilter":  htmlNameFilter, -	"html_template_htmlescaper":     htmlEscaper, -	"html_template_jsregexpescaper": jsRegexpEscaper, -	"html_template_jsstrescaper":    jsStrEscaper, -	"html_template_jsvalescaper":    jsValEscaper, -	"html_template_nospaceescaper":  htmlNospaceEscaper, -	"html_template_rcdataescaper":   rcdataEscaper, -	"html_template_urlescaper":      urlEscaper, -	"html_template_urlfilter":       urlFilter, -	"html_template_urlnormalizer":   urlNormalizer, -} - -// equivEscapers matches contextual escapers to equivalent template builtins. -var equivEscapers = map[string]string{ -	"html_template_attrescaper":    "html", -	"html_template_htmlescaper":    "html", -	"html_template_nospaceescaper": "html", -	"html_template_rcdataescaper":  "html", -	"html_template_urlescaper":     "urlquery", -	"html_template_urlnormalizer":  "urlquery", -} - -// escaper collects type inferences about templates and changes needed to make -// templates injection safe. -type escaper struct { -	tmpl *Template -	// output[templateName] is the output context for a templateName that -	// has been mangled to include its input context. -	output map[string]context -	// derived[c.mangle(name)] maps to a template derived from the template -	// named name templateName for the start context c. -	derived map[string]*template.Template -	// called[templateName] is a set of called mangled template names. -	called map[string]bool -	// xxxNodeEdits are the accumulated edits to apply during commit. -	// Such edits are not applied immediately in case a template set -	// executes a given template in different escaping contexts. -	actionNodeEdits   map[*parse.ActionNode][]string -	templateNodeEdits map[*parse.TemplateNode]string -	textNodeEdits     map[*parse.TextNode][]byte -} - -// newEscaper creates a blank escaper for the given set. -func newEscaper(t *Template) *escaper { -	return &escaper{ -		t, -		map[string]context{}, -		map[string]*template.Template{}, -		map[string]bool{}, -		map[*parse.ActionNode][]string{}, -		map[*parse.TemplateNode]string{}, -		map[*parse.TextNode][]byte{}, -	} -} - -// filterFailsafe is an innocuous word that is emitted in place of unsafe values -// by sanitizer functions. It is not a keyword in any programming language, -// contains no special characters, is not empty, and when it appears in output -// it is distinct enough that a developer can find the source of the problem -// via a search engine. -const filterFailsafe = "ZgotmplZ" - -// escape escapes a template node. -func (e *escaper) escape(c context, n parse.Node) context { -	switch n := n.(type) { -	case *parse.ActionNode: -		return e.escapeAction(c, n) -	case *parse.IfNode: -		return e.escapeBranch(c, &n.BranchNode, "if") -	case *parse.ListNode: -		return e.escapeList(c, n) -	case *parse.RangeNode: -		return e.escapeBranch(c, &n.BranchNode, "range") -	case *parse.TemplateNode: -		return e.escapeTemplate(c, n) -	case *parse.TextNode: -		return e.escapeText(c, n) -	case *parse.WithNode: -		return e.escapeBranch(c, &n.BranchNode, "with") -	} -	panic("escaping " + n.String() + " is unimplemented") -} - -// escapeAction escapes an action template node. -func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { -	if len(n.Pipe.Decl) != 0 { -		// A local variable assignment, not an interpolation. -		return c -	} -	c = nudge(c) -	s := make([]string, 0, 3) -	switch c.state { -	case stateError: -		return c -	case stateURL, stateCSSDqStr, stateCSSSqStr, stateCSSDqURL, stateCSSSqURL, stateCSSURL: -		switch c.urlPart { -		case urlPartNone: -			s = append(s, "html_template_urlfilter") -			fallthrough -		case urlPartPreQuery: -			switch c.state { -			case stateCSSDqStr, stateCSSSqStr: -				s = append(s, "html_template_cssescaper") -			default: -				s = append(s, "html_template_urlnormalizer") -			} -		case urlPartQueryOrFrag: -			s = append(s, "html_template_urlescaper") -		case urlPartUnknown: -			return context{ -				state: stateError, -				err:   errorf(ErrAmbigContext, n.Line, "%s appears in an ambiguous URL context", n), -			} -		default: -			panic(c.urlPart.String()) -		} -	case stateJS: -		s = append(s, "html_template_jsvalescaper") -		// A slash after a value starts a div operator. -		c.jsCtx = jsCtxDivOp -	case stateJSDqStr, stateJSSqStr: -		s = append(s, "html_template_jsstrescaper") -	case stateJSRegexp: -		s = append(s, "html_template_jsregexpescaper") -	case stateCSS: -		s = append(s, "html_template_cssvaluefilter") -	case stateText: -		s = append(s, "html_template_htmlescaper") -	case stateRCDATA: -		s = append(s, "html_template_rcdataescaper") -	case stateAttr: -		// Handled below in delim check. -	case stateAttrName, stateTag: -		c.state = stateAttrName -		s = append(s, "html_template_htmlnamefilter") -	default: -		if isComment(c.state) { -			s = append(s, "html_template_commentescaper") -		} else { -			panic("unexpected state " + c.state.String()) -		} -	} -	switch c.delim { -	case delimNone: -		// No extra-escaping needed for raw text content. -	case delimSpaceOrTagEnd: -		s = append(s, "html_template_nospaceescaper") -	default: -		s = append(s, "html_template_attrescaper") -	} -	e.editActionNode(n, s) -	return c -} - -// allIdents returns the names of the identifiers under the Ident field of the node, -// which might be a singleton (Identifier) or a slice (Field). -func allIdents(node parse.Node) []string { -	switch node := node.(type) { -	case *parse.IdentifierNode: -		return []string{node.Ident} -	case *parse.FieldNode: -		return node.Ident -	} -	panic("unidentified node type in allIdents") -} - -// ensurePipelineContains ensures that the pipeline has commands with -// the identifiers in s in order. -// If the pipeline already has some of the sanitizers, do not interfere. -// For example, if p is (.X | html) and s is ["escapeJSVal", "html"] then it -// has one matching, "html", and one to insert, "escapeJSVal", to produce -// (.X | escapeJSVal | html). -func ensurePipelineContains(p *parse.PipeNode, s []string) { -	if len(s) == 0 { -		return -	} -	n := len(p.Cmds) -	// Find the identifiers at the end of the command chain. -	idents := p.Cmds -	for i := n - 1; i >= 0; i-- { -		if cmd := p.Cmds[i]; len(cmd.Args) != 0 { -			if _, ok := cmd.Args[0].(*parse.IdentifierNode); ok { -				continue -			} -		} -		idents = p.Cmds[i+1:] -	} -	dups := 0 -	for _, idNode := range idents { -		for _, ident := range allIdents(idNode.Args[0]) { -			if escFnsEq(s[dups], ident) { -				dups++ -				if dups == len(s) { -					return -				} -			} -		} -	} -	newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups) -	copy(newCmds, p.Cmds) -	// Merge existing identifier commands with the sanitizers needed. -	for _, idNode := range idents { -		pos := idNode.Args[0].Position() -		for _, ident := range allIdents(idNode.Args[0]) { -			i := indexOfStr(ident, s, escFnsEq) -			if i != -1 { -				for _, name := range s[:i] { -					newCmds = appendCmd(newCmds, newIdentCmd(name, pos)) -				} -				s = s[i+1:] -			} -		} -		newCmds = appendCmd(newCmds, idNode) -	} -	// Create any remaining sanitizers. -	for _, name := range s { -		newCmds = appendCmd(newCmds, newIdentCmd(name, p.Position())) -	} -	p.Cmds = newCmds -} - -// redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x) -// for all x. -var redundantFuncs = map[string]map[string]bool{ -	"html_template_commentescaper": { -		"html_template_attrescaper":    true, -		"html_template_nospaceescaper": true, -		"html_template_htmlescaper":    true, -	}, -	"html_template_cssescaper": { -		"html_template_attrescaper": true, -	}, -	"html_template_jsregexpescaper": { -		"html_template_attrescaper": true, -	}, -	"html_template_jsstrescaper": { -		"html_template_attrescaper": true, -	}, -	"html_template_urlescaper": { -		"html_template_urlnormalizer": true, -	}, -} - -// appendCmd appends the given command to the end of the command pipeline -// unless it is redundant with the last command. -func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode { -	if n := len(cmds); n != 0 { -		last, ok := cmds[n-1].Args[0].(*parse.IdentifierNode) -		next, _ := cmd.Args[0].(*parse.IdentifierNode) -		if ok && redundantFuncs[last.Ident][next.Ident] { -			return cmds -		} -	} -	return append(cmds, cmd) -} - -// indexOfStr is the first i such that eq(s, strs[i]) or -1 if s was not found. -func indexOfStr(s string, strs []string, eq func(a, b string) bool) int { -	for i, t := range strs { -		if eq(s, t) { -			return i -		} -	} -	return -1 -} - -// escFnsEq reports whether the two escaping functions are equivalent. -func escFnsEq(a, b string) bool { -	if e := equivEscapers[a]; e != "" { -		a = e -	} -	if e := equivEscapers[b]; e != "" { -		b = e -	} -	return a == b -} - -// newIdentCmd produces a command containing a single identifier node. -func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode { -	return &parse.CommandNode{ -		NodeType: parse.NodeCommand, -		Args:     []parse.Node{parse.NewIdentifier(identifier).SetPos(pos)}, -	} -} - -// nudge returns the context that would result from following empty string -// transitions from the input context. -// For example, parsing: -//     `<a href=` -// will end in context{stateBeforeValue, attrURL}, but parsing one extra rune: -//     `<a href=x` -// will end in context{stateURL, delimSpaceOrTagEnd, ...}. -// There are two transitions that happen when the 'x' is seen: -// (1) Transition from a before-value state to a start-of-value state without -//     consuming any character. -// (2) Consume 'x' and transition past the first value character. -// In this case, nudging produces the context after (1) happens. -func nudge(c context) context { -	switch c.state { -	case stateTag: -		// In `<foo {{.}}`, the action should emit an attribute. -		c.state = stateAttrName -	case stateBeforeValue: -		// In `<foo bar={{.}}`, the action is an undelimited value. -		c.state, c.delim, c.attr = attrStartStates[c.attr], delimSpaceOrTagEnd, attrNone -	case stateAfterName: -		// In `<foo bar {{.}}`, the action is an attribute name. -		c.state, c.attr = stateAttrName, attrNone -	} -	return c -} - -// join joins the two contexts of a branch template node. The result is an -// error context if either of the input contexts are error contexts, or if the -// the input contexts differ. -func join(a, b context, line int, nodeName string) context { -	if a.state == stateError { -		return a -	} -	if b.state == stateError { -		return b -	} -	if a.eq(b) { -		return a -	} - -	c := a -	c.urlPart = b.urlPart -	if c.eq(b) { -		// The contexts differ only by urlPart. -		c.urlPart = urlPartUnknown -		return c -	} - -	c = a -	c.jsCtx = b.jsCtx -	if c.eq(b) { -		// The contexts differ only by jsCtx. -		c.jsCtx = jsCtxUnknown -		return c -	} - -	// Allow a nudged context to join with an unnudged one. -	// This means that -	//   <p title={{if .C}}{{.}}{{end}} -	// ends in an unquoted value state even though the else branch -	// ends in stateBeforeValue. -	if c, d := nudge(a), nudge(b); !(c.eq(a) && d.eq(b)) { -		if e := join(c, d, line, nodeName); e.state != stateError { -			return e -		} -	} - -	return context{ -		state: stateError, -		err:   errorf(ErrBranchEnd, line, "{{%s}} branches end in different contexts: %v, %v", nodeName, a, b), -	} -} - -// escapeBranch escapes a branch template node: "if", "range" and "with". -func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context { -	c0 := e.escapeList(c, n.List) -	if nodeName == "range" && c0.state != stateError { -		// The "true" branch of a "range" node can execute multiple times. -		// We check that executing n.List once results in the same context -		// as executing n.List twice. -		c1, _ := e.escapeListConditionally(c0, n.List, nil) -		c0 = join(c0, c1, n.Line, nodeName) -		if c0.state == stateError { -			// Make clear that this is a problem on loop re-entry -			// since developers tend to overlook that branch when -			// debugging templates. -			c0.err.Line = n.Line -			c0.err.Description = "on range loop re-entry: " + c0.err.Description -			return c0 -		} -	} -	c1 := e.escapeList(c, n.ElseList) -	return join(c0, c1, n.Line, nodeName) -} - -// escapeList escapes a list template node. -func (e *escaper) escapeList(c context, n *parse.ListNode) context { -	if n == nil { -		return c -	} -	for _, m := range n.Nodes { -		c = e.escape(c, m) -	} -	return c -} - -// escapeListConditionally escapes a list node but only preserves edits and -// inferences in e if the inferences and output context satisfy filter. -// It returns the best guess at an output context, and the result of the filter -// which is the same as whether e was updated. -func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) { -	e1 := newEscaper(e.tmpl) -	// Make type inferences available to f. -	for k, v := range e.output { -		e1.output[k] = v -	} -	c = e1.escapeList(c, n) -	ok := filter != nil && filter(e1, c) -	if ok { -		// Copy inferences and edits from e1 back into e. -		for k, v := range e1.output { -			e.output[k] = v -		} -		for k, v := range e1.derived { -			e.derived[k] = v -		} -		for k, v := range e1.called { -			e.called[k] = v -		} -		for k, v := range e1.actionNodeEdits { -			e.editActionNode(k, v) -		} -		for k, v := range e1.templateNodeEdits { -			e.editTemplateNode(k, v) -		} -		for k, v := range e1.textNodeEdits { -			e.editTextNode(k, v) -		} -	} -	return c, ok -} - -// escapeTemplate escapes a {{template}} call node. -func (e *escaper) escapeTemplate(c context, n *parse.TemplateNode) context { -	c, name := e.escapeTree(c, n.Name, n.Line) -	if name != n.Name { -		e.editTemplateNode(n, name) -	} -	return c -} - -// escapeTree escapes the named template starting in the given context as -// necessary and returns its output context. -func (e *escaper) escapeTree(c context, name string, line int) (context, string) { -	// Mangle the template name with the input context to produce a reliable -	// identifier. -	dname := c.mangle(name) -	e.called[dname] = true -	if out, ok := e.output[dname]; ok { -		// Already escaped. -		return out, dname -	} -	t := e.template(name) -	if t == nil { -		// Two cases: The template exists but is empty, or has never been mentioned at -		// all. Distinguish the cases in the error messages. -		if e.tmpl.set[name] != nil { -			return context{ -				state: stateError, -				err:   errorf(ErrNoSuchTemplate, line, "%q is an incomplete or empty template", name), -			}, dname -		} -		return context{ -			state: stateError, -			err:   errorf(ErrNoSuchTemplate, line, "no such template %q", name), -		}, dname -	} -	if dname != name { -		// Use any template derived during an earlier call to escapeTemplate -		// with different top level templates, or clone if necessary. -		dt := e.template(dname) -		if dt == nil { -			dt = template.New(dname) -			dt.Tree = &parse.Tree{Name: dname, Root: t.Root.CopyList()} -			e.derived[dname] = dt -		} -		t = dt -	} -	return e.computeOutCtx(c, t), dname -} - -// computeOutCtx takes a template and its start context and computes the output -// context while storing any inferences in e. -func (e *escaper) computeOutCtx(c context, t *template.Template) context { -	// Propagate context over the body. -	c1, ok := e.escapeTemplateBody(c, t) -	if !ok { -		// Look for a fixed point by assuming c1 as the output context. -		if c2, ok2 := e.escapeTemplateBody(c1, t); ok2 { -			c1, ok = c2, true -		} -		// Use c1 as the error context if neither assumption worked. -	} -	if !ok && c1.state != stateError { -		return context{ -			state: stateError, -			// TODO: Find the first node with a line in t.text.Tree.Root -			err: errorf(ErrOutputContext, 0, "cannot compute output context for template %s", t.Name()), -		} -	} -	return c1 -} - -// escapeTemplateBody escapes the given template assuming the given output -// context, and returns the best guess at the output context and whether the -// assumption was correct. -func (e *escaper) escapeTemplateBody(c context, t *template.Template) (context, bool) { -	filter := func(e1 *escaper, c1 context) bool { -		if c1.state == stateError { -			// Do not update the input escaper, e. -			return false -		} -		if !e1.called[t.Name()] { -			// If t is not recursively called, then c1 is an -			// accurate output context. -			return true -		} -		// c1 is accurate if it matches our assumed output context. -		return c.eq(c1) -	} -	// We need to assume an output context so that recursive template calls -	// take the fast path out of escapeTree instead of infinitely recursing. -	// Naively assuming that the input context is the same as the output -	// works >90% of the time. -	e.output[t.Name()] = c -	return e.escapeListConditionally(c, t.Tree.Root, filter) -} - -// delimEnds maps each delim to a string of characters that terminate it. -var delimEnds = [...]string{ -	delimDoubleQuote: `"`, -	delimSingleQuote: "'", -	// Determined empirically by running the below in various browsers. -	// var div = document.createElement("DIV"); -	// for (var i = 0; i < 0x10000; ++i) { -	//   div.innerHTML = "<span title=x" + String.fromCharCode(i) + "-bar>"; -	//   if (div.getElementsByTagName("SPAN")[0].title.indexOf("bar") < 0) -	//     document.write("<p>U+" + i.toString(16)); -	// } -	delimSpaceOrTagEnd: " \t\n\f\r>", -} - -var doctypeBytes = []byte("<!DOCTYPE") - -// escapeText escapes a text template node. -func (e *escaper) escapeText(c context, n *parse.TextNode) context { -	s, written, i, b := n.Text, 0, 0, new(bytes.Buffer) -	for i != len(s) { -		c1, nread := contextAfterText(c, s[i:]) -		i1 := i + nread -		if c.state == stateText || c.state == stateRCDATA { -			end := i1 -			if c1.state != c.state { -				for j := end - 1; j >= i; j-- { -					if s[j] == '<' { -						end = j -						break -					} -				} -			} -			for j := i; j < end; j++ { -				if s[j] == '<' && !bytes.HasPrefix(bytes.ToUpper(s[j:]), doctypeBytes) { -					b.Write(s[written:j]) -					b.WriteString("<") -					written = j + 1 -				} -			} -		} else if isComment(c.state) && c.delim == delimNone { -			switch c.state { -			case stateJSBlockCmt: -				// http://es5.github.com/#x7.4: -				// "Comments behave like white space and are -				// discarded except that, if a MultiLineComment -				// contains a line terminator character, then -				// the entire comment is considered to be a -				// LineTerminator for purposes of parsing by -				// the syntactic grammar." -				if bytes.IndexAny(s[written:i1], "\n\r\u2028\u2029") != -1 { -					b.WriteByte('\n') -				} else { -					b.WriteByte(' ') -				} -			case stateCSSBlockCmt: -				b.WriteByte(' ') -			} -			written = i1 -		} -		if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone { -			// Preserve the portion between written and the comment start. -			cs := i1 - 2 -			if c1.state == stateHTMLCmt { -				// "<!--" instead of "/*" or "//" -				cs -= 2 -			} -			b.Write(s[written:cs]) -			written = i1 -		} -		if i == i1 && c.state == c1.state { -			panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:])) -		} -		c, i = c1, i1 -	} - -	if written != 0 && c.state != stateError { -		if !isComment(c.state) || c.delim != delimNone { -			b.Write(n.Text[written:]) -		} -		e.editTextNode(n, b.Bytes()) -	} -	return c -} - -// contextAfterText starts in context c, consumes some tokens from the front of -// s, then returns the context after those tokens and the unprocessed suffix. -func contextAfterText(c context, s []byte) (context, int) { -	if c.delim == delimNone { -		c1, i := tSpecialTagEnd(c, s) -		if i == 0 { -			// A special end tag (`</script>`) has been seen and -			// all content preceding it has been consumed. -			return c1, 0 -		} -		// Consider all content up to any end tag. -		return transitionFunc[c.state](c, s[:i]) -	} - -	i := bytes.IndexAny(s, delimEnds[c.delim]) -	if i == -1 { -		i = len(s) -	} -	if c.delim == delimSpaceOrTagEnd { -		// http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state -		// lists the runes below as error characters. -		// Error out because HTML parsers may differ on whether -		// "<a id= onclick=f("     ends inside id's or onclick's value, -		// "<a class=`foo "        ends inside a value, -		// "<a style=font:'Arial'" needs open-quote fixup. -		// IE treats '`' as a quotation character. -		if j := bytes.IndexAny(s[:i], "\"'<=`"); j >= 0 { -			return context{ -				state: stateError, -				err:   errorf(ErrBadHTML, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]), -			}, len(s) -		} -	} -	if i == len(s) { -		// Remain inside the attribute. -		// Decode the value so non-HTML rules can easily handle -		//     <button onclick="alert("Hi!")"> -		// without having to entity decode token boundaries. -		for u := []byte(html.UnescapeString(string(s))); len(u) != 0; { -			c1, i1 := transitionFunc[c.state](c, u) -			c, u = c1, u[i1:] -		} -		return c, len(s) -	} -	if c.delim != delimSpaceOrTagEnd { -		// Consume any quote. -		i++ -	} -	// On exiting an attribute, we discard all state information -	// except the state and element. -	return context{state: stateTag, element: c.element}, i -} - -// editActionNode records a change to an action pipeline for later commit. -func (e *escaper) editActionNode(n *parse.ActionNode, cmds []string) { -	if _, ok := e.actionNodeEdits[n]; ok { -		panic(fmt.Sprintf("node %s shared between templates", n)) -	} -	e.actionNodeEdits[n] = cmds -} - -// editTemplateNode records a change to a {{template}} callee for later commit. -func (e *escaper) editTemplateNode(n *parse.TemplateNode, callee string) { -	if _, ok := e.templateNodeEdits[n]; ok { -		panic(fmt.Sprintf("node %s shared between templates", n)) -	} -	e.templateNodeEdits[n] = callee -} - -// editTextNode records a change to a text node for later commit. -func (e *escaper) editTextNode(n *parse.TextNode, text []byte) { -	if _, ok := e.textNodeEdits[n]; ok { -		panic(fmt.Sprintf("node %s shared between templates", n)) -	} -	e.textNodeEdits[n] = text -} - -// commit applies changes to actions and template calls needed to contextually -// autoescape content and adds any derived templates to the set. -func (e *escaper) commit() { -	for name := range e.output { -		e.template(name).Funcs(funcMap) -	} -	for _, t := range e.derived { -		if _, err := e.tmpl.text.AddParseTree(t.Name(), t.Tree); err != nil { -			panic("error adding derived template") -		} -	} -	for n, s := range e.actionNodeEdits { -		ensurePipelineContains(n.Pipe, s) -	} -	for n, name := range e.templateNodeEdits { -		n.Name = name -	} -	for n, s := range e.textNodeEdits { -		n.Text = s -	} -} - -// template returns the named template given a mangled template name. -func (e *escaper) template(name string) *template.Template { -	t := e.tmpl.text.Lookup(name) -	if t == nil { -		t = e.derived[name] -	} -	return t -} - -// Forwarding functions so that clients need only import this package -// to reach the general escaping functions of text/template. - -// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b. -func HTMLEscape(w io.Writer, b []byte) { -	template.HTMLEscape(w, b) -} - -// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s. -func HTMLEscapeString(s string) string { -	return template.HTMLEscapeString(s) -} - -// HTMLEscaper returns the escaped HTML equivalent of the textual -// representation of its arguments. -func HTMLEscaper(args ...interface{}) string { -	return template.HTMLEscaper(args...) -} - -// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. -func JSEscape(w io.Writer, b []byte) { -	template.JSEscape(w, b) -} - -// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s. -func JSEscapeString(s string) string { -	return template.JSEscapeString(s) -} - -// JSEscaper returns the escaped JavaScript equivalent of the textual -// representation of its arguments. -func JSEscaper(args ...interface{}) string { -	return template.JSEscaper(args...) -} - -// URLQueryEscaper returns the escaped value of the textual representation of -// its arguments in a form suitable for embedding in a URL query. -func URLQueryEscaper(args ...interface{}) string { -	return template.URLQueryEscaper(args...) -} diff --git a/src/pkg/html/template/escape_test.go b/src/pkg/html/template/escape_test.go deleted file mode 100644 index 3ccf93ece..000000000 --- a/src/pkg/html/template/escape_test.go +++ /dev/null @@ -1,1692 +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 template - -import ( -	"bytes" -	"encoding/json" -	"fmt" -	"os" -	"strings" -	"testing" -	"text/template" -	"text/template/parse" -) - -type badMarshaler struct{} - -func (x *badMarshaler) MarshalJSON() ([]byte, error) { -	// Keys in valid JSON must be double quoted as must all strings. -	return []byte("{ foo: 'not quite valid JSON' }"), nil -} - -type goodMarshaler struct{} - -func (x *goodMarshaler) MarshalJSON() ([]byte, error) { -	return []byte(`{ "<foo>": "O'Reilly" }`), nil -} - -func TestEscape(t *testing.T) { -	data := struct { -		F, T    bool -		C, G, H string -		A, E    []string -		B, M    json.Marshaler -		N       int -		Z       *int -		W       HTML -	}{ -		F: false, -		T: true, -		C: "<Cincinatti>", -		G: "<Goodbye>", -		H: "<Hello>", -		A: []string{"<a>", "<b>"}, -		E: []string{}, -		N: 42, -		B: &badMarshaler{}, -		M: &goodMarshaler{}, -		Z: nil, -		W: HTML(`¡<b class="foo">Hello</b>, <textarea>O'World</textarea>!`), -	} -	pdata := &data - -	tests := []struct { -		name   string -		input  string -		output string -	}{ -		{ -			"if", -			"{{if .T}}Hello{{end}}, {{.C}}!", -			"Hello, <Cincinatti>!", -		}, -		{ -			"else", -			"{{if .F}}{{.H}}{{else}}{{.G}}{{end}}!", -			"<Goodbye>!", -		}, -		{ -			"overescaping1", -			"Hello, {{.C | html}}!", -			"Hello, <Cincinatti>!", -		}, -		{ -			"overescaping2", -			"Hello, {{html .C}}!", -			"Hello, <Cincinatti>!", -		}, -		{ -			"overescaping3", -			"{{with .C}}{{$msg := .}}Hello, {{$msg}}!{{end}}", -			"Hello, <Cincinatti>!", -		}, -		{ -			"assignment", -			"{{if $x := .H}}{{$x}}{{end}}", -			"<Hello>", -		}, -		{ -			"withBody", -			"{{with .H}}{{.}}{{end}}", -			"<Hello>", -		}, -		{ -			"withElse", -			"{{with .E}}{{.}}{{else}}{{.H}}{{end}}", -			"<Hello>", -		}, -		{ -			"rangeBody", -			"{{range .A}}{{.}}{{end}}", -			"<a><b>", -		}, -		{ -			"rangeElse", -			"{{range .E}}{{.}}{{else}}{{.H}}{{end}}", -			"<Hello>", -		}, -		{ -			"nonStringValue", -			"{{.T}}", -			"true", -		}, -		{ -			"constant", -			`<a href="/search?q={{"'a<b'"}}">`, -			`<a href="/search?q=%27a%3cb%27">`, -		}, -		{ -			"multipleAttrs", -			"<a b=1 c={{.H}}>", -			"<a b=1 c=<Hello>>", -		}, -		{ -			"urlStartRel", -			`<a href='{{"/foo/bar?a=b&c=d"}}'>`, -			`<a href='/foo/bar?a=b&c=d'>`, -		}, -		{ -			"urlStartAbsOk", -			`<a href='{{"http://example.com/foo/bar?a=b&c=d"}}'>`, -			`<a href='http://example.com/foo/bar?a=b&c=d'>`, -		}, -		{ -			"protocolRelativeURLStart", -			`<a href='{{"//example.com:8000/foo/bar?a=b&c=d"}}'>`, -			`<a href='//example.com:8000/foo/bar?a=b&c=d'>`, -		}, -		{ -			"pathRelativeURLStart", -			`<a href="{{"/javascript:80/foo/bar"}}">`, -			`<a href="/javascript:80/foo/bar">`, -		}, -		{ -			"dangerousURLStart", -			`<a href='{{"javascript:alert(%22pwned%22)"}}'>`, -			`<a href='#ZgotmplZ'>`, -		}, -		{ -			"dangerousURLStart2", -			`<a href='  {{"javascript:alert(%22pwned%22)"}}'>`, -			`<a href='  #ZgotmplZ'>`, -		}, -		{ -			"nonHierURL", -			`<a href={{"mailto:Muhammed \"The Greatest\" Ali <m.ali@example.com>"}}>`, -			`<a href=mailto:Muhammed%20%22The%20Greatest%22%20Ali%20%3cm.ali@example.com%3e>`, -		}, -		{ -			"urlPath", -			`<a href='http://{{"javascript:80"}}/foo'>`, -			`<a href='http://javascript:80/foo'>`, -		}, -		{ -			"urlQuery", -			`<a href='/search?q={{.H}}'>`, -			`<a href='/search?q=%3cHello%3e'>`, -		}, -		{ -			"urlFragment", -			`<a href='/faq#{{.H}}'>`, -			`<a href='/faq#%3cHello%3e'>`, -		}, -		{ -			"urlBranch", -			`<a href="{{if .F}}/foo?a=b{{else}}/bar{{end}}">`, -			`<a href="/bar">`, -		}, -		{ -			"urlBranchConflictMoot", -			`<a href="{{if .T}}/foo?a={{else}}/bar#{{end}}{{.C}}">`, -			`<a href="/foo?a=%3cCincinatti%3e">`, -		}, -		{ -			"jsStrValue", -			"<button onclick='alert({{.H}})'>", -			`<button onclick='alert("\u003cHello\u003e")'>`, -		}, -		{ -			"jsNumericValue", -			"<button onclick='alert({{.N}})'>", -			`<button onclick='alert( 42 )'>`, -		}, -		{ -			"jsBoolValue", -			"<button onclick='alert({{.T}})'>", -			`<button onclick='alert( true )'>`, -		}, -		{ -			"jsNilValue", -			"<button onclick='alert(typeof{{.Z}})'>", -			`<button onclick='alert(typeof null )'>`, -		}, -		{ -			"jsObjValue", -			"<button onclick='alert({{.A}})'>", -			`<button onclick='alert(["\u003ca\u003e","\u003cb\u003e"])'>`, -		}, -		{ -			"jsObjValueScript", -			"<script>alert({{.A}})</script>", -			`<script>alert(["\u003ca\u003e","\u003cb\u003e"])</script>`, -		}, -		{ -			"jsObjValueNotOverEscaped", -			"<button onclick='alert({{.A | html}})'>", -			`<button onclick='alert(["\u003ca\u003e","\u003cb\u003e"])'>`, -		}, -		{ -			"jsStr", -			"<button onclick='alert("{{.H}}")'>", -			`<button onclick='alert("\x3cHello\x3e")'>`, -		}, -		{ -			"badMarshaler", -			`<button onclick='alert(1/{{.B}}in numbers)'>`, -			`<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: invalid character 'f' looking for beginning of object key string */null in numbers)'>`, -		}, -		{ -			"jsMarshaler", -			`<button onclick='alert({{.M}})'>`, -			`<button onclick='alert({"\u003cfoo\u003e":"O'Reilly"})'>`, -		}, -		{ -			"jsStrNotUnderEscaped", -			"<button onclick='alert({{.C | urlquery}})'>", -			// URL escaped, then quoted for JS. -			`<button onclick='alert("%3CCincinatti%3E")'>`, -		}, -		{ -			"jsRe", -			`<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`, -			`<button onclick='alert(/foo\x2bbar/.test(""))'>`, -		}, -		{ -			"jsReBlank", -			`<script>alert(/{{""}}/.test(""));</script>`, -			`<script>alert(/(?:)/.test(""));</script>`, -		}, -		{ -			"jsReAmbigOk", -			`<script>{{if true}}var x = 1{{end}}</script>`, -			// The {if} ends in an ambiguous jsCtx but there is -			// no slash following so we shouldn't care. -			`<script>var x = 1</script>`, -		}, -		{ -			"styleBidiKeywordPassed", -			`<p style="dir: {{"ltr"}}">`, -			`<p style="dir: ltr">`, -		}, -		{ -			"styleBidiPropNamePassed", -			`<p style="border-{{"left"}}: 0; border-{{"right"}}: 1in">`, -			`<p style="border-left: 0; border-right: 1in">`, -		}, -		{ -			"styleExpressionBlocked", -			`<p style="width: {{"expression(alert(1337))"}}">`, -			`<p style="width: ZgotmplZ">`, -		}, -		{ -			"styleTagSelectorPassed", -			`<style>{{"p"}} { color: pink }</style>`, -			`<style>p { color: pink }</style>`, -		}, -		{ -			"styleIDPassed", -			`<style>p{{"#my-ID"}} { font: Arial }</style>`, -			`<style>p#my-ID { font: Arial }</style>`, -		}, -		{ -			"styleClassPassed", -			`<style>p{{".my_class"}} { font: Arial }</style>`, -			`<style>p.my_class { font: Arial }</style>`, -		}, -		{ -			"styleQuantityPassed", -			`<a style="left: {{"2em"}}; top: {{0}}">`, -			`<a style="left: 2em; top: 0">`, -		}, -		{ -			"stylePctPassed", -			`<table style=width:{{"100%"}}>`, -			`<table style=width:100%>`, -		}, -		{ -			"styleColorPassed", -			`<p style="color: {{"#8ff"}}; background: {{"#000"}}">`, -			`<p style="color: #8ff; background: #000">`, -		}, -		{ -			"styleObfuscatedExpressionBlocked", -			`<p style="width: {{"  e\\78preS\x00Sio/**/n(alert(1337))"}}">`, -			`<p style="width: ZgotmplZ">`, -		}, -		{ -			"styleMozBindingBlocked", -			`<p style="{{"-moz-binding(alert(1337))"}}: ...">`, -			`<p style="ZgotmplZ: ...">`, -		}, -		{ -			"styleObfuscatedMozBindingBlocked", -			`<p style="{{"  -mo\\7a-B\x00I/**/nding(alert(1337))"}}: ...">`, -			`<p style="ZgotmplZ: ...">`, -		}, -		{ -			"styleFontNameString", -			`<p style='font-family: "{{"Times New Roman"}}"'>`, -			`<p style='font-family: "Times New Roman"'>`, -		}, -		{ -			"styleFontNameString", -			`<p style='font-family: "{{"Times New Roman"}}", "{{"sans-serif"}}"'>`, -			`<p style='font-family: "Times New Roman", "sans-serif"'>`, -		}, -		{ -			"styleFontNameUnquoted", -			`<p style='font-family: {{"Times New Roman"}}'>`, -			`<p style='font-family: Times New Roman'>`, -		}, -		{ -			"styleURLQueryEncoded", -			`<p style="background: url(/img?name={{"O'Reilly Animal(1)<2>.png"}})">`, -			`<p style="background: url(/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png)">`, -		}, -		{ -			"styleQuotedURLQueryEncoded", -			`<p style="background: url('/img?name={{"O'Reilly Animal(1)<2>.png"}}')">`, -			`<p style="background: url('/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png')">`, -		}, -		{ -			"styleStrQueryEncoded", -			`<p style="background: '/img?name={{"O'Reilly Animal(1)<2>.png"}}'">`, -			`<p style="background: '/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png'">`, -		}, -		{ -			"styleURLBadProtocolBlocked", -			`<a style="background: url('{{"javascript:alert(1337)"}}')">`, -			`<a style="background: url('#ZgotmplZ')">`, -		}, -		{ -			"styleStrBadProtocolBlocked", -			`<a style="background: '{{"vbscript:alert(1337)"}}'">`, -			`<a style="background: '#ZgotmplZ'">`, -		}, -		{ -			"styleStrEncodedProtocolEncoded", -			`<a style="background: '{{"javascript\\3a alert(1337)"}}'">`, -			// The CSS string 'javascript\\3a alert(1337)' does not contains a colon. -			`<a style="background: 'javascript\\3a alert\28 1337\29 '">`, -		}, -		{ -			"styleURLGoodProtocolPassed", -			`<a style="background: url('{{"http://oreilly.com/O'Reilly Animals(1)<2>;{}.html"}}')">`, -			`<a style="background: url('http://oreilly.com/O%27Reilly%20Animals%281%29%3c2%3e;%7b%7d.html')">`, -		}, -		{ -			"styleStrGoodProtocolPassed", -			`<a style="background: '{{"http://oreilly.com/O'Reilly Animals(1)<2>;{}.html"}}'">`, -			`<a style="background: 'http\3a\2f\2foreilly.com\2fO\27Reilly Animals\28 1\29\3c 2\3e\3b\7b\7d.html'">`, -		}, -		{ -			"styleURLEncodedForHTMLInAttr", -			`<a style="background: url('{{"/search?img=foo&size=icon"}}')">`, -			`<a style="background: url('/search?img=foo&size=icon')">`, -		}, -		{ -			"styleURLNotEncodedForHTMLInCdata", -			`<style>body { background: url('{{"/search?img=foo&size=icon"}}') }</style>`, -			`<style>body { background: url('/search?img=foo&size=icon') }</style>`, -		}, -		{ -			"styleURLMixedCase", -			`<p style="background: URL(#{{.H}})">`, -			`<p style="background: URL(#%3cHello%3e)">`, -		}, -		{ -			"stylePropertyPairPassed", -			`<a style='{{"color: red"}}'>`, -			`<a style='color: red'>`, -		}, -		{ -			"styleStrSpecialsEncoded", -			`<a style="font-family: '{{"/**/'\";:// \\"}}', "{{"/**/'\";:// \\"}}"">`, -			`<a style="font-family: '\2f**\2f\27\22\3b\3a\2f\2f  \\', "\2f**\2f\27\22\3b\3a\2f\2f  \\"">`, -		}, -		{ -			"styleURLSpecialsEncoded", -			`<a style="border-image: url({{"/**/'\";:// \\"}}), url("{{"/**/'\";:// \\"}}"), url('{{"/**/'\";:// \\"}}'), 'http://www.example.com/?q={{"/**/'\";:// \\"}}''">`, -			`<a style="border-image: url(/**/%27%22;://%20%5c), url("/**/%27%22;://%20%5c"), url('/**/%27%22;://%20%5c'), 'http://www.example.com/?q=%2f%2a%2a%2f%27%22%3b%3a%2f%2f%20%5c''">`, -		}, -		{ -			"HTML comment", -			"<b>Hello, <!-- name of world -->{{.C}}</b>", -			"<b>Hello, <Cincinatti></b>", -		}, -		{ -			"HTML comment not first < in text node.", -			"<<!-- -->!--", -			"<!--", -		}, -		{ -			"HTML normalization 1", -			"a < b", -			"a < b", -		}, -		{ -			"HTML normalization 2", -			"a << b", -			"a << b", -		}, -		{ -			"HTML normalization 3", -			"a<<!-- --><!-- -->b", -			"a<b", -		}, -		{ -			"HTML doctype not normalized", -			"<!DOCTYPE html>Hello, World!", -			"<!DOCTYPE html>Hello, World!", -		}, -		{ -			"HTML doctype not case-insensitive", -			"<!doCtYPE htMl>Hello, World!", -			"<!doCtYPE htMl>Hello, World!", -		}, -		{ -			"No doctype injection", -			`<!{{"DOCTYPE"}}`, -			"<!DOCTYPE", -		}, -		{ -			"Split HTML comment", -			"<b>Hello, <!-- name of {{if .T}}city -->{{.C}}{{else}}world -->{{.W}}{{end}}</b>", -			"<b>Hello, <Cincinatti></b>", -		}, -		{ -			"JS line comment", -			"<script>for (;;) { if (c()) break// foo not a label\n" + -				"foo({{.T}});}</script>", -			"<script>for (;;) { if (c()) break\n" + -				"foo( true );}</script>", -		}, -		{ -			"JS multiline block comment", -			"<script>for (;;) { if (c()) break/* foo not a label\n" + -				" */foo({{.T}});}</script>", -			// Newline separates break from call. If newline -			// removed, then break will consume label leaving -			// code invalid. -			"<script>for (;;) { if (c()) break\n" + -				"foo( true );}</script>", -		}, -		{ -			"JS single-line block comment", -			"<script>for (;;) {\n" + -				"if (c()) break/* foo a label */foo;" + -				"x({{.T}});}</script>", -			// Newline separates break from call. If newline -			// removed, then break will consume label leaving -			// code invalid. -			"<script>for (;;) {\n" + -				"if (c()) break foo;" + -				"x( true );}</script>", -		}, -		{ -			"JS block comment flush with mathematical division", -			"<script>var a/*b*//c\nd</script>", -			"<script>var a /c\nd</script>", -		}, -		{ -			"JS mixed comments", -			"<script>var a/*b*///c\nd</script>", -			"<script>var a \nd</script>", -		}, -		{ -			"CSS comments", -			"<style>p// paragraph\n" + -				`{border: 1px/* color */{{"#00f"}}}</style>`, -			"<style>p\n" + -				"{border: 1px #00f}</style>", -		}, -		{ -			"JS attr block comment", -			`<a onclick="f(""); /* alert({{.H}}) */">`, -			// Attribute comment tests should pass if the comments -			// are successfully elided. -			`<a onclick="f(""); /* alert() */">`, -		}, -		{ -			"JS attr line comment", -			`<a onclick="// alert({{.G}})">`, -			`<a onclick="// alert()">`, -		}, -		{ -			"CSS attr block comment", -			`<a style="/* color: {{.H}} */">`, -			`<a style="/* color:  */">`, -		}, -		{ -			"CSS attr line comment", -			`<a style="// color: {{.G}}">`, -			`<a style="// color: ">`, -		}, -		{ -			"HTML substitution commented out", -			"<p><!-- {{.H}} --></p>", -			"<p></p>", -		}, -		{ -			"Comment ends flush with start", -			"<!--{{.}}--><script>/*{{.}}*///{{.}}\n</script><style>/*{{.}}*///{{.}}\n</style><a onclick='/*{{.}}*///{{.}}' style='/*{{.}}*///{{.}}'>", -			"<script> \n</script><style> \n</style><a onclick='/**///' style='/**///'>", -		}, -		{ -			"typed HTML in text", -			`{{.W}}`, -			`¡<b class="foo">Hello</b>, <textarea>O'World</textarea>!`, -		}, -		{ -			"typed HTML in attribute", -			`<div title="{{.W}}">`, -			`<div title="¡Hello, O'World!">`, -		}, -		{ -			"typed HTML in script", -			`<button onclick="alert({{.W}})">`, -			`<button onclick="alert("\u0026iexcl;\u003cb class=\"foo\"\u003eHello\u003c/b\u003e, \u003ctextarea\u003eO'World\u003c/textarea\u003e!")">`, -		}, -		{ -			"typed HTML in RCDATA", -			`<textarea>{{.W}}</textarea>`, -			`<textarea>¡<b class="foo">Hello</b>, <textarea>O'World</textarea>!</textarea>`, -		}, -		{ -			"range in textarea", -			"<textarea>{{range .A}}{{.}}{{end}}</textarea>", -			"<textarea><a><b></textarea>", -		}, -		{ -			"No tag injection", -			`{{"10$"}}<{{"script src,evil.org/pwnd.js"}}...`, -			`10$<script src,evil.org/pwnd.js...`, -		}, -		{ -			"No comment injection", -			`<{{"!--"}}`, -			`<!--`, -		}, -		{ -			"No RCDATA end tag injection", -			`<textarea><{{"/textarea "}}...</textarea>`, -			`<textarea></textarea ...</textarea>`, -		}, -		{ -			"optional attrs", -			`<img class="{{"iconClass"}}"` + -				`{{if .T}} id="{{"<iconId>"}}"{{end}}` + -				// Double quotes inside if/else. -				` src=` + -				`{{if .T}}"?{{"<iconPath>"}}"` + -				`{{else}}"images/cleardot.gif"{{end}}` + -				// Missing space before title, but it is not a -				// part of the src attribute. -				`{{if .T}}title="{{"<title>"}}"{{end}}` + -				// Quotes outside if/else. -				` alt="` + -				`{{if .T}}{{"<alt>"}}` + -				`{{else}}{{if .F}}{{"<title>"}}{{end}}` + -				`{{end}}"` + -				`>`, -			`<img class="iconClass" id="<iconId>" src="?%3ciconPath%3e"title="<title>" alt="<alt>">`, -		}, -		{ -			"conditional valueless attr name", -			`<input{{if .T}} checked{{end}} name=n>`, -			`<input checked name=n>`, -		}, -		{ -			"conditional dynamic valueless attr name 1", -			`<input{{if .T}} {{"checked"}}{{end}} name=n>`, -			`<input checked name=n>`, -		}, -		{ -			"conditional dynamic valueless attr name 2", -			`<input {{if .T}}{{"checked"}} {{end}}name=n>`, -			`<input checked name=n>`, -		}, -		{ -			"dynamic attribute name", -			`<img on{{"load"}}="alert({{"loaded"}})">`, -			// Treated as JS since quotes are inserted. -			`<img onload="alert("loaded")">`, -		}, -		{ -			"bad dynamic attribute name 1", -			// Allow checked, selected, disabled, but not JS or -			// CSS attributes. -			`<input {{"onchange"}}="{{"doEvil()"}}">`, -			`<input ZgotmplZ="doEvil()">`, -		}, -		{ -			"bad dynamic attribute name 2", -			`<div {{"sTyle"}}="{{"color: expression(alert(1337))"}}">`, -			`<div ZgotmplZ="color: expression(alert(1337))">`, -		}, -		{ -			"bad dynamic attribute name 3", -			// Allow title or alt, but not a URL. -			`<img {{"src"}}="{{"javascript:doEvil()"}}">`, -			`<img ZgotmplZ="javascript:doEvil()">`, -		}, -		{ -			"bad dynamic attribute name 4", -			// Structure preservation requires values to associate -			// with a consistent attribute. -			`<input checked {{""}}="Whose value am I?">`, -			`<input checked ZgotmplZ="Whose value am I?">`, -		}, -		{ -			"dynamic element name", -			`<h{{3}}><table><t{{"head"}}>...</h{{3}}>`, -			`<h3><table><thead>...</h3>`, -		}, -		{ -			"bad dynamic element name", -			// Dynamic element names are typically used to switch -			// between (thead, tfoot, tbody), (ul, ol), (th, td), -			// and other replaceable sets. -			// We do not currently easily support (ul, ol). -			// If we do change to support that, this test should -			// catch failures to filter out special tag names which -			// would violate the structure preservation property -- -			// if any special tag name could be substituted, then -			// the content could be raw text/RCDATA for some inputs -			// and regular HTML content for others. -			`<{{"script"}}>{{"doEvil()"}}</{{"script"}}>`, -			`<script>doEvil()</script>`, -		}, -	} - -	for _, test := range tests { -		tmpl := New(test.name) -		tmpl = Must(tmpl.Parse(test.input)) -		// Check for bug 6459: Tree field was not set in Parse. -		if tmpl.Tree != tmpl.text.Tree { -			t.Errorf("%s: tree not set properly", test.name) -			continue -		} -		b := new(bytes.Buffer) -		if err := tmpl.Execute(b, data); err != nil { -			t.Errorf("%s: template execution failed: %s", test.name, err) -			continue -		} -		if w, g := test.output, b.String(); w != g { -			t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) -			continue -		} -		b.Reset() -		if err := tmpl.Execute(b, pdata); err != nil { -			t.Errorf("%s: template execution failed for pointer: %s", test.name, err) -			continue -		} -		if w, g := test.output, b.String(); w != g { -			t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) -			continue -		} -		if tmpl.Tree != tmpl.text.Tree { -			t.Errorf("%s: tree mismatch", test.name) -			continue -		} -	} -} - -func TestEscapeSet(t *testing.T) { -	type dataItem struct { -		Children []*dataItem -		X        string -	} - -	data := dataItem{ -		Children: []*dataItem{ -			{X: "foo"}, -			{X: "<bar>"}, -			{ -				Children: []*dataItem{ -					{X: "baz"}, -				}, -			}, -		}, -	} - -	tests := []struct { -		inputs map[string]string -		want   string -	}{ -		// The trivial set. -		{ -			map[string]string{ -				"main": ``, -			}, -			``, -		}, -		// A template called in the start context. -		{ -			map[string]string{ -				"main": `Hello, {{template "helper"}}!`, -				// Not a valid top level HTML template. -				// "<b" is not a full tag. -				"helper": `{{"<World>"}}`, -			}, -			`Hello, <World>!`, -		}, -		// A template called in a context other than the start. -		{ -			map[string]string{ -				"main": `<a onclick='a = {{template "helper"}};'>`, -				// Not a valid top level HTML template. -				// "<b" is not a full tag. -				"helper": `{{"<a>"}}<b`, -			}, -			`<a onclick='a = "\u003ca\u003e"<b;'>`, -		}, -		// A recursive template that ends in its start context. -		{ -			map[string]string{ -				"main": `{{range .Children}}{{template "main" .}}{{else}}{{.X}} {{end}}`, -			}, -			`foo <bar> baz `, -		}, -		// A recursive helper template that ends in its start context. -		{ -			map[string]string{ -				"main":   `{{template "helper" .}}`, -				"helper": `{{if .Children}}<ul>{{range .Children}}<li>{{template "main" .}}</li>{{end}}</ul>{{else}}{{.X}}{{end}}`, -			}, -			`<ul><li>foo</li><li><bar></li><li><ul><li>baz</li></ul></li></ul>`, -		}, -		// Co-recursive templates that end in its start context. -		{ -			map[string]string{ -				"main":   `<blockquote>{{range .Children}}{{template "helper" .}}{{end}}</blockquote>`, -				"helper": `{{if .Children}}{{template "main" .}}{{else}}{{.X}}<br>{{end}}`, -			}, -			`<blockquote>foo<br><bar><br><blockquote>baz<br></blockquote></blockquote>`, -		}, -		// A template that is called in two different contexts. -		{ -			map[string]string{ -				"main":   `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`, -				"helper": `{{11}} of {{"<100>"}}`, -			}, -			`<button onclick="title='11 of \x3c100\x3e'; ...">11 of <100></button>`, -		}, -		// A non-recursive template that ends in a different context. -		// helper starts in jsCtxRegexp and ends in jsCtxDivOp. -		{ -			map[string]string{ -				"main":   `<script>var x={{template "helper"}}/{{"42"}};</script>`, -				"helper": "{{126}}", -			}, -			`<script>var x= 126 /"42";</script>`, -		}, -		// A recursive template that ends in a similar context. -		{ -			map[string]string{ -				"main":      `<script>var x=[{{template "countdown" 4}}];</script>`, -				"countdown": `{{.}}{{if .}},{{template "countdown" . | pred}}{{end}}`, -			}, -			`<script>var x=[ 4 , 3 , 2 , 1 , 0 ];</script>`, -		}, -		// A recursive template that ends in a different context. -		/* -			{ -				map[string]string{ -					"main":   `<a href="/foo{{template "helper" .}}">`, -					"helper": `{{if .Children}}{{range .Children}}{{template "helper" .}}{{end}}{{else}}?x={{.X}}{{end}}`, -				}, -				`<a href="/foo?x=foo?x=%3cbar%3e?x=baz">`, -			}, -		*/ -	} - -	// pred is a template function that returns the predecessor of a -	// natural number for testing recursive templates. -	fns := FuncMap{"pred": func(a ...interface{}) (interface{}, error) { -		if len(a) == 1 { -			if i, _ := a[0].(int); i > 0 { -				return i - 1, nil -			} -		} -		return nil, fmt.Errorf("undefined pred(%v)", a) -	}} - -	for _, test := range tests { -		source := "" -		for name, body := range test.inputs { -			source += fmt.Sprintf("{{define %q}}%s{{end}} ", name, body) -		} -		tmpl, err := New("root").Funcs(fns).Parse(source) -		if err != nil { -			t.Errorf("error parsing %q: %v", source, err) -			continue -		} -		var b bytes.Buffer - -		if err := tmpl.ExecuteTemplate(&b, "main", data); err != nil { -			t.Errorf("%q executing %v", err.Error(), tmpl.Lookup("main")) -			continue -		} -		if got := b.String(); test.want != got { -			t.Errorf("want\n\t%q\ngot\n\t%q", test.want, got) -		} -	} - -} - -func TestErrors(t *testing.T) { -	tests := []struct { -		input string -		err   string -	}{ -		// Non-error cases. -		{ -			"{{if .Cond}}<a>{{else}}<b>{{end}}", -			"", -		}, -		{ -			"{{if .Cond}}<a>{{end}}", -			"", -		}, -		{ -			"{{if .Cond}}{{else}}<b>{{end}}", -			"", -		}, -		{ -			"{{with .Cond}}<div>{{end}}", -			"", -		}, -		{ -			"{{range .Items}}<a>{{end}}", -			"", -		}, -		{ -			"<a href='/foo?{{range .Items}}&{{.K}}={{.V}}{{end}}'>", -			"", -		}, -		// Error cases. -		{ -			"{{if .Cond}}<a{{end}}", -			"z:1: {{if}} branches", -		}, -		{ -			"{{if .Cond}}\n{{else}}\n<a{{end}}", -			"z:1: {{if}} branches", -		}, -		{ -			// Missing quote in the else branch. -			`{{if .Cond}}<a href="foo">{{else}}<a href="bar>{{end}}`, -			"z:1: {{if}} branches", -		}, -		{ -			// Different kind of attribute: href implies a URL. -			"<a {{if .Cond}}href='{{else}}title='{{end}}{{.X}}'>", -			"z:1: {{if}} branches", -		}, -		{ -			"\n{{with .X}}<a{{end}}", -			"z:2: {{with}} branches", -		}, -		{ -			"\n{{with .X}}<a>{{else}}<a{{end}}", -			"z:2: {{with}} branches", -		}, -		{ -			"{{range .Items}}<a{{end}}", -			`z:1: on range loop re-entry: "<" in attribute name: "<a"`, -		}, -		{ -			"\n{{range .Items}} x='<a{{end}}", -			"z:2: on range loop re-entry: {{range}} branches", -		}, -		{ -			"<a b=1 c={{.H}}", -			"z: ends in a non-text context: {stateAttr delimSpaceOrTagEnd", -		}, -		{ -			"<script>foo();", -			"z: ends in a non-text context: {stateJS", -		}, -		{ -			`<a href="{{if .F}}/foo?a={{else}}/bar/{{end}}{{.H}}">`, -			"z:1: {{.H}} appears in an ambiguous URL context", -		}, -		{ -			`<a onclick="alert('Hello \`, -			`unfinished escape sequence in JS string: "Hello \\"`, -		}, -		{ -			`<a onclick='alert("Hello\, World\`, -			`unfinished escape sequence in JS string: "Hello\\, World\\"`, -		}, -		{ -			`<a onclick='alert(/x+\`, -			`unfinished escape sequence in JS string: "x+\\"`, -		}, -		{ -			`<a onclick="/foo[\]/`, -			`unfinished JS regexp charset: "foo[\\]/"`, -		}, -		{ -			// It is ambiguous whether 1.5 should be 1\.5 or 1.5. -			// Either `var x = 1/- 1.5 /i.test(x)` -			// where `i.test(x)` is a method call of reference i, -			// or `/-1\.5/i.test(x)` which is a method call on a -			// case insensitive regular expression. -			`<script>{{if false}}var x = 1{{end}}/-{{"1.5"}}/i.test(x)</script>`, -			`'/' could start a division or regexp: "/-"`, -		}, -		{ -			`{{template "foo"}}`, -			"z:1: no such template \"foo\"", -		}, -		{ -			`<div{{template "y"}}>` + -				// Illegal starting in stateTag but not in stateText. -				`{{define "y"}} foo<b{{end}}`, -			`"<" in attribute name: " foo<b"`, -		}, -		{ -			`<script>reverseList = [{{template "t"}}]</script>` + -				// Missing " after recursive call. -				`{{define "t"}}{{if .Tail}}{{template "t" .Tail}}{{end}}{{.Head}}",{{end}}`, -			`: cannot compute output context for template t$htmltemplate_stateJS_elementScript`, -		}, -		{ -			`<input type=button value=onclick=>`, -			`html/template:z: "=" in unquoted attr: "onclick="`, -		}, -		{ -			`<input type=button value= onclick=>`, -			`html/template:z: "=" in unquoted attr: "onclick="`, -		}, -		{ -			`<input type=button value= 1+1=2>`, -			`html/template:z: "=" in unquoted attr: "1+1=2"`, -		}, -		{ -			"<a class=`foo>", -			"html/template:z: \"`\" in unquoted attr: \"`foo\"", -		}, -		{ -			`<a style=font:'Arial'>`, -			`html/template:z: "'" in unquoted attr: "font:'Arial'"`, -		}, -		{ -			`<a=foo>`, -			`: expected space, attr name, or end of tag, but got "=foo>"`, -		}, -	} - -	for _, test := range tests { -		buf := new(bytes.Buffer) -		tmpl, err := New("z").Parse(test.input) -		if err != nil { -			t.Errorf("input=%q: unexpected parse error %s\n", test.input, err) -			continue -		} -		err = tmpl.Execute(buf, nil) -		var got string -		if err != nil { -			got = err.Error() -		} -		if test.err == "" { -			if got != "" { -				t.Errorf("input=%q: unexpected error %q", test.input, got) -			} -			continue -		} -		if strings.Index(got, test.err) == -1 { -			t.Errorf("input=%q: error\n\t%q\ndoes not contain expected string\n\t%q", test.input, got, test.err) -			continue -		} -	} -} - -func TestEscapeText(t *testing.T) { -	tests := []struct { -		input  string -		output context -	}{ -		{ -			``, -			context{}, -		}, -		{ -			`Hello, World!`, -			context{}, -		}, -		{ -			// An orphaned "<" is OK. -			`I <3 Ponies!`, -			context{}, -		}, -		{ -			`<a`, -			context{state: stateTag}, -		}, -		{ -			`<a `, -			context{state: stateTag}, -		}, -		{ -			`<a>`, -			context{state: stateText}, -		}, -		{ -			`<a href`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a on`, -			context{state: stateAttrName, attr: attrScript}, -		}, -		{ -			`<a href `, -			context{state: stateAfterName, attr: attrURL}, -		}, -		{ -			`<a style  =  `, -			context{state: stateBeforeValue, attr: attrStyle}, -		}, -		{ -			`<a href=`, -			context{state: stateBeforeValue, attr: attrURL}, -		}, -		{ -			`<a href=x`, -			context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a href=x `, -			context{state: stateTag}, -		}, -		{ -			`<a href=>`, -			context{state: stateText}, -		}, -		{ -			`<a href=x>`, -			context{state: stateText}, -		}, -		{ -			`<a href ='`, -			context{state: stateURL, delim: delimSingleQuote}, -		}, -		{ -			`<a href=''`, -			context{state: stateTag}, -		}, -		{ -			`<a href= "`, -			context{state: stateURL, delim: delimDoubleQuote}, -		}, -		{ -			`<a href=""`, -			context{state: stateTag}, -		}, -		{ -			`<a title="`, -			context{state: stateAttr, delim: delimDoubleQuote}, -		}, -		{ -			`<a HREF='http:`, -			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a Href='/`, -			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a href='"`, -			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a href="'`, -			context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a href=''`, -			context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a href=""`, -			context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a href=""`, -			context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a href="`, -			context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery}, -		}, -		{ -			`<img alt="1">`, -			context{state: stateText}, -		}, -		{ -			`<img alt="1>"`, -			context{state: stateTag}, -		}, -		{ -			`<img alt="1>">`, -			context{state: stateText}, -		}, -		{ -			`<input checked type="checkbox"`, -			context{state: stateTag}, -		}, -		{ -			`<a onclick="`, -			context{state: stateJS, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="//foo`, -			context{state: stateJSLineCmt, delim: delimDoubleQuote}, -		}, -		{ -			"<a onclick='//\n", -			context{state: stateJS, delim: delimSingleQuote}, -		}, -		{ -			"<a onclick='//\r\n", -			context{state: stateJS, delim: delimSingleQuote}, -		}, -		{ -			"<a onclick='//\u2028", -			context{state: stateJS, delim: delimSingleQuote}, -		}, -		{ -			`<a onclick="/*`, -			context{state: stateJSBlockCmt, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="/*/`, -			context{state: stateJSBlockCmt, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="/**/`, -			context{state: stateJS, delim: delimDoubleQuote}, -		}, -		{ -			`<a onkeypress=""`, -			context{state: stateJSDqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick='"foo"`, -			context{state: stateJS, delim: delimSingleQuote, jsCtx: jsCtxDivOp}, -		}, -		{ -			`<a onclick='foo'`, -			context{state: stateJS, delim: delimSpaceOrTagEnd, jsCtx: jsCtxDivOp}, -		}, -		{ -			`<a onclick='foo`, -			context{state: stateJSSqStr, delim: delimSpaceOrTagEnd}, -		}, -		{ -			`<a onclick=""foo'`, -			context{state: stateJSDqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="'foo"`, -			context{state: stateJSSqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<A ONCLICK="'`, -			context{state: stateJSSqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="/`, -			context{state: stateJSRegexp, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="'foo'`, -			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, -		}, -		{ -			`<a onclick="'foo\'`, -			context{state: stateJSSqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="'foo\'`, -			context{state: stateJSSqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="/foo/`, -			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, -		}, -		{ -			`<script>/foo/ /=`, -			context{state: stateJS, element: elementScript}, -		}, -		{ -			`<a onclick="1 /foo`, -			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, -		}, -		{ -			`<a onclick="1 /*c*/ /foo`, -			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, -		}, -		{ -			`<a onclick="/foo[/]`, -			context{state: stateJSRegexp, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="/foo\/`, -			context{state: stateJSRegexp, delim: delimDoubleQuote}, -		}, -		{ -			`<a onclick="/foo/`, -			context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, -		}, -		{ -			`<input checked style="`, -			context{state: stateCSS, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="//`, -			context{state: stateCSSLineCmt, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="//</script>`, -			context{state: stateCSSLineCmt, delim: delimDoubleQuote}, -		}, -		{ -			"<a style='//\n", -			context{state: stateCSS, delim: delimSingleQuote}, -		}, -		{ -			"<a style='//\r", -			context{state: stateCSS, delim: delimSingleQuote}, -		}, -		{ -			`<a style="/*`, -			context{state: stateCSSBlockCmt, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="/*/`, -			context{state: stateCSSBlockCmt, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="/**/`, -			context{state: stateCSS, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="background: '`, -			context{state: stateCSSSqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="background: "`, -			context{state: stateCSSDqStr, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="background: '/foo?img=`, -			context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag}, -		}, -		{ -			`<a style="background: '/`, -			context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a style="background: url("/`, -			context{state: stateCSSDqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a style="background: url('/`, -			context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a style="background: url('/)`, -			context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a style="background: url('/ `, -			context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a style="background: url(/`, -			context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, -		}, -		{ -			`<a style="background: url( `, -			context{state: stateCSSURL, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="background: url( /image?name=`, -			context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag}, -		}, -		{ -			`<a style="background: url(x)`, -			context{state: stateCSS, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="background: url('x'`, -			context{state: stateCSS, delim: delimDoubleQuote}, -		}, -		{ -			`<a style="background: url( x `, -			context{state: stateCSS, delim: delimDoubleQuote}, -		}, -		{ -			`<!-- foo`, -			context{state: stateHTMLCmt}, -		}, -		{ -			`<!-->`, -			context{state: stateHTMLCmt}, -		}, -		{ -			`<!--->`, -			context{state: stateHTMLCmt}, -		}, -		{ -			`<!-- foo -->`, -			context{state: stateText}, -		}, -		{ -			`<script`, -			context{state: stateTag, element: elementScript}, -		}, -		{ -			`<script `, -			context{state: stateTag, element: elementScript}, -		}, -		{ -			`<script src="foo.js" `, -			context{state: stateTag, element: elementScript}, -		}, -		{ -			`<script src='foo.js' `, -			context{state: stateTag, element: elementScript}, -		}, -		{ -			`<script type=text/javascript `, -			context{state: stateTag, element: elementScript}, -		}, -		{ -			`<script>foo`, -			context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript}, -		}, -		{ -			`<script>foo</script>`, -			context{state: stateText}, -		}, -		{ -			`<script>foo</script><!--`, -			context{state: stateHTMLCmt}, -		}, -		{ -			`<script>document.write("<p>foo</p>");`, -			context{state: stateJS, element: elementScript}, -		}, -		{ -			`<script>document.write("<p>foo<\/script>");`, -			context{state: stateJS, element: elementScript}, -		}, -		{ -			`<script>document.write("<script>alert(1)</script>");`, -			context{state: stateText}, -		}, -		{ -			`<Script>`, -			context{state: stateJS, element: elementScript}, -		}, -		{ -			`<SCRIPT>foo`, -			context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript}, -		}, -		{ -			`<textarea>value`, -			context{state: stateRCDATA, element: elementTextarea}, -		}, -		{ -			`<textarea>value</TEXTAREA>`, -			context{state: stateText}, -		}, -		{ -			`<textarea name=html><b`, -			context{state: stateRCDATA, element: elementTextarea}, -		}, -		{ -			`<title>value`, -			context{state: stateRCDATA, element: elementTitle}, -		}, -		{ -			`<style>value`, -			context{state: stateCSS, element: elementStyle}, -		}, -		{ -			`<a xlink:href`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a xmlns`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a xmlns:foo`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a xmlnsxyz`, -			context{state: stateAttrName}, -		}, -		{ -			`<a data-url`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a data-iconUri`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a data-urlItem`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a g:`, -			context{state: stateAttrName}, -		}, -		{ -			`<a g:url`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a g:iconUri`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a g:urlItem`, -			context{state: stateAttrName, attr: attrURL}, -		}, -		{ -			`<a g:value`, -			context{state: stateAttrName}, -		}, -		{ -			`<a svg:style='`, -			context{state: stateCSS, delim: delimSingleQuote}, -		}, -		{ -			`<svg:font-face`, -			context{state: stateTag}, -		}, -		{ -			`<svg:a svg:onclick="`, -			context{state: stateJS, delim: delimDoubleQuote}, -		}, -	} - -	for _, test := range tests { -		b, e := []byte(test.input), newEscaper(nil) -		c := e.escapeText(context{}, &parse.TextNode{NodeType: parse.NodeText, Text: b}) -		if !test.output.eq(c) { -			t.Errorf("input %q: want context\n\t%v\ngot\n\t%v", test.input, test.output, c) -			continue -		} -		if test.input != string(b) { -			t.Errorf("input %q: text node was modified: want %q got %q", test.input, test.input, b) -			continue -		} -	} -} - -func TestEnsurePipelineContains(t *testing.T) { -	tests := []struct { -		input, output string -		ids           []string -	}{ -		{ -			"{{.X}}", -			".X", -			[]string{}, -		}, -		{ -			"{{.X | html}}", -			".X | html", -			[]string{}, -		}, -		{ -			"{{.X}}", -			".X | html", -			[]string{"html"}, -		}, -		{ -			"{{.X | html}}", -			".X | html | urlquery", -			[]string{"urlquery"}, -		}, -		{ -			"{{.X | html | urlquery}}", -			".X | html | urlquery", -			[]string{"urlquery"}, -		}, -		{ -			"{{.X | html | urlquery}}", -			".X | html | urlquery", -			[]string{"html", "urlquery"}, -		}, -		{ -			"{{.X | html | urlquery}}", -			".X | html | urlquery", -			[]string{"html"}, -		}, -		{ -			"{{.X | urlquery}}", -			".X | html | urlquery", -			[]string{"html", "urlquery"}, -		}, -		{ -			"{{.X | html | print}}", -			".X | urlquery | html | print", -			[]string{"urlquery", "html"}, -		}, -		{ -			"{{($).X | html | print}}", -			"($).X | urlquery | html | print", -			[]string{"urlquery", "html"}, -		}, -	} -	for i, test := range tests { -		tmpl := template.Must(template.New("test").Parse(test.input)) -		action, ok := (tmpl.Tree.Root.Nodes[0].(*parse.ActionNode)) -		if !ok { -			t.Errorf("#%d: First node is not an action: %s", i, test.input) -			continue -		} -		pipe := action.Pipe -		ensurePipelineContains(pipe, test.ids) -		got := pipe.String() -		if got != test.output { -			t.Errorf("#%d: %s, %v: want\n\t%s\ngot\n\t%s", i, test.input, test.ids, test.output, got) -		} -	} -} - -func TestEscapeErrorsNotIgnorable(t *testing.T) { -	var b bytes.Buffer -	tmpl, _ := New("dangerous").Parse("<a") -	err := tmpl.Execute(&b, nil) -	if err == nil { -		t.Errorf("Expected error") -	} else if b.Len() != 0 { -		t.Errorf("Emitted output despite escaping failure") -	} -} - -func TestEscapeSetErrorsNotIgnorable(t *testing.T) { -	var b bytes.Buffer -	tmpl, err := New("root").Parse(`{{define "t"}}<a{{end}}`) -	if err != nil { -		t.Errorf("failed to parse set: %q", err) -	} -	err = tmpl.ExecuteTemplate(&b, "t", nil) -	if err == nil { -		t.Errorf("Expected error") -	} else if b.Len() != 0 { -		t.Errorf("Emitted output despite escaping failure") -	} -} - -func TestRedundantFuncs(t *testing.T) { -	inputs := []interface{}{ -		"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" + -			"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -			` !"#$%&'()*+,-./` + -			`0123456789:;<=>?` + -			`@ABCDEFGHIJKLMNO` + -			`PQRSTUVWXYZ[\]^_` + -			"`abcdefghijklmno" + -			"pqrstuvwxyz{|}~\x7f" + -			"\u00A0\u0100\u2028\u2029\ufeff\ufdec\ufffd\uffff\U0001D11E" + -			"&%22\\", -		CSS(`a[href =~ "//example.com"]#foo`), -		HTML(`Hello, <b>World</b> &tc!`), -		HTMLAttr(` dir="ltr"`), -		JS(`c && alert("Hello, World!");`), -		JSStr(`Hello, World & O'Reilly\x21`), -		URL(`greeting=H%69&addressee=(World)`), -	} - -	for n0, m := range redundantFuncs { -		f0 := funcMap[n0].(func(...interface{}) string) -		for n1 := range m { -			f1 := funcMap[n1].(func(...interface{}) string) -			for _, input := range inputs { -				want := f0(input) -				if got := f1(want); want != got { -					t.Errorf("%s %s with %T %q: want\n\t%q,\ngot\n\t%q", n0, n1, input, input, want, got) -				} -			} -		} -	} -} - -func TestIndirectPrint(t *testing.T) { -	a := 3 -	ap := &a -	b := "hello" -	bp := &b -	bpp := &bp -	tmpl := Must(New("t").Parse(`{{.}}`)) -	var buf bytes.Buffer -	err := tmpl.Execute(&buf, ap) -	if err != nil { -		t.Errorf("Unexpected error: %s", err) -	} else if buf.String() != "3" { -		t.Errorf(`Expected "3"; got %q`, buf.String()) -	} -	buf.Reset() -	err = tmpl.Execute(&buf, bpp) -	if err != nil { -		t.Errorf("Unexpected error: %s", err) -	} else if buf.String() != "hello" { -		t.Errorf(`Expected "hello"; got %q`, buf.String()) -	} -} - -// This is a test for issue 3272. -func TestEmptyTemplate(t *testing.T) { -	page := Must(New("page").ParseFiles(os.DevNull)) -	if err := page.ExecuteTemplate(os.Stdout, "page", "nothing"); err == nil { -		t.Fatal("expected error") -	} -} - -type Issue7379 int - -func (Issue7379) SomeMethod(x int) string { -	return fmt.Sprintf("<%d>", x) -} - -// This is a test for issue 7379: type assertion error caused panic, and then -// the code to handle the panic breaks escaping. It's hard to see the second -// problem once the first is fixed, but its fix is trivial so we let that go. See -// the discussion for issue 7379. -func TestPipeToMethodIsEscaped(t *testing.T) { -	tmpl := Must(New("x").Parse("<html>{{0 | .SomeMethod}}</html>\n")) -	tryExec := func() string { -		defer func() { -			panicValue := recover() -			if panicValue != nil { -				t.Errorf("panicked: %v\n", panicValue) -			} -		}() -		var b bytes.Buffer -		tmpl.Execute(&b, Issue7379(0)) -		return b.String() -	} -	for i := 0; i < 3; i++ { -		str := tryExec() -		const expect = "<html><0></html>\n" -		if str != expect { -			t.Errorf("expected %q got %q", expect, str) -		} -	} -} - -func BenchmarkEscapedExecute(b *testing.B) { -	tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`)) -	var buf bytes.Buffer -	b.ResetTimer() -	for i := 0; i < b.N; i++ { -		tmpl.Execute(&buf, "foo & 'bar' & baz") -		buf.Reset() -	} -} diff --git a/src/pkg/html/template/html.go b/src/pkg/html/template/html.go deleted file mode 100644 index 9c069efd1..000000000 --- a/src/pkg/html/template/html.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 template - -import ( -	"bytes" -	"fmt" -	"strings" -	"unicode/utf8" -) - -// htmlNospaceEscaper escapes for inclusion in unquoted attribute values. -func htmlNospaceEscaper(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeHTML { -		return htmlReplacer(stripTags(s), htmlNospaceNormReplacementTable, false) -	} -	return htmlReplacer(s, htmlNospaceReplacementTable, false) -} - -// attrEscaper escapes for inclusion in quoted attribute values. -func attrEscaper(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeHTML { -		return htmlReplacer(stripTags(s), htmlNormReplacementTable, true) -	} -	return htmlReplacer(s, htmlReplacementTable, true) -} - -// rcdataEscaper escapes for inclusion in an RCDATA element body. -func rcdataEscaper(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeHTML { -		return htmlReplacer(s, htmlNormReplacementTable, true) -	} -	return htmlReplacer(s, htmlReplacementTable, true) -} - -// htmlEscaper escapes for inclusion in HTML text. -func htmlEscaper(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeHTML { -		return s -	} -	return htmlReplacer(s, htmlReplacementTable, true) -} - -// htmlReplacementTable contains the runes that need to be escaped -// inside a quoted attribute value or in a text node. -var htmlReplacementTable = []string{ -	// http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state -	// U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT -	// CHARACTER character to the current attribute's value. -	// " -	// and similarly -	// http://www.w3.org/TR/html5/syntax.html#before-attribute-value-state -	0:    "\uFFFD", -	'"':  """, -	'&':  "&", -	'\'': "'", -	'+':  "+", -	'<':  "<", -	'>':  ">", -} - -// htmlNormReplacementTable is like htmlReplacementTable but without '&' to -// avoid over-encoding existing entities. -var htmlNormReplacementTable = []string{ -	0:    "\uFFFD", -	'"':  """, -	'\'': "'", -	'+':  "+", -	'<':  "<", -	'>':  ">", -} - -// htmlNospaceReplacementTable contains the runes that need to be escaped -// inside an unquoted attribute value. -// The set of runes escaped is the union of the HTML specials and -// those determined by running the JS below in browsers: -// <div id=d></div> -// <script>(function () { -// var a = [], d = document.getElementById("d"), i, c, s; -// for (i = 0; i < 0x10000; ++i) { -//   c = String.fromCharCode(i); -//   d.innerHTML = "<span title=" + c + "lt" + c + "></span>" -//   s = d.getElementsByTagName("SPAN")[0]; -//   if (!s || s.title !== c + "lt" + c) { a.push(i.toString(16)); } -// } -// document.write(a.join(", ")); -// })()</script> -var htmlNospaceReplacementTable = []string{ -	0:    "�", -	'\t': "	", -	'\n': "
", -	'\v': "", -	'\f': "", -	'\r': "
", -	' ':  " ", -	'"':  """, -	'&':  "&", -	'\'': "'", -	'+':  "+", -	'<':  "<", -	'=':  "=", -	'>':  ">", -	// A parse error in the attribute value (unquoted) and -	// before attribute value states. -	// Treated as a quoting character by IE. -	'`': "`", -} - -// htmlNospaceNormReplacementTable is like htmlNospaceReplacementTable but -// without '&' to avoid over-encoding existing entities. -var htmlNospaceNormReplacementTable = []string{ -	0:    "�", -	'\t': "	", -	'\n': "
", -	'\v': "", -	'\f': "", -	'\r': "
", -	' ':  " ", -	'"':  """, -	'\'': "'", -	'+':  "+", -	'<':  "<", -	'=':  "=", -	'>':  ">", -	// A parse error in the attribute value (unquoted) and -	// before attribute value states. -	// Treated as a quoting character by IE. -	'`': "`", -} - -// htmlReplacer returns s with runes replaced according to replacementTable -// and when badRunes is true, certain bad runes are allowed through unescaped. -func htmlReplacer(s string, replacementTable []string, badRunes bool) string { -	written, b := 0, new(bytes.Buffer) -	for i, r := range s { -		if int(r) < len(replacementTable) { -			if repl := replacementTable[r]; len(repl) != 0 { -				b.WriteString(s[written:i]) -				b.WriteString(repl) -				// Valid as long as replacementTable doesn't -				// include anything above 0x7f. -				written = i + utf8.RuneLen(r) -			} -		} else if badRunes { -			// No-op. -			// IE does not allow these ranges in unquoted attrs. -		} else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff { -			fmt.Fprintf(b, "%s&#x%x;", s[written:i], r) -			written = i + utf8.RuneLen(r) -		} -	} -	if written == 0 { -		return s -	} -	b.WriteString(s[written:]) -	return b.String() -} - -// stripTags takes a snippet of HTML and returns only the text content. -// For example, `<b>¡Hi!</b> <script>...</script>` -> `¡Hi! `. -func stripTags(html string) string { -	var b bytes.Buffer -	s, c, i, allText := []byte(html), context{}, 0, true -	// Using the transition funcs helps us avoid mangling -	// `<div title="1>2">` or `I <3 Ponies!`. -	for i != len(s) { -		if c.delim == delimNone { -			st := c.state -			// Use RCDATA instead of parsing into JS or CSS styles. -			if c.element != elementNone && !isInTag(st) { -				st = stateRCDATA -			} -			d, nread := transitionFunc[st](c, s[i:]) -			i1 := i + nread -			if c.state == stateText || c.state == stateRCDATA { -				// Emit text up to the start of the tag or comment. -				j := i1 -				if d.state != c.state { -					for j1 := j - 1; j1 >= i; j1-- { -						if s[j1] == '<' { -							j = j1 -							break -						} -					} -				} -				b.Write(s[i:j]) -			} else { -				allText = false -			} -			c, i = d, i1 -			continue -		} -		i1 := i + bytes.IndexAny(s[i:], delimEnds[c.delim]) -		if i1 < i { -			break -		} -		if c.delim != delimSpaceOrTagEnd { -			// Consume any quote. -			i1++ -		} -		c, i = context{state: stateTag, element: c.element}, i1 -	} -	if allText { -		return html -	} else if c.state == stateText || c.state == stateRCDATA { -		b.Write(s[i:]) -	} -	return b.String() -} - -// htmlNameFilter accepts valid parts of an HTML attribute or tag name or -// a known-safe HTML attribute. -func htmlNameFilter(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeHTMLAttr { -		return s -	} -	if len(s) == 0 { -		// Avoid violation of structure preservation. -		// <input checked {{.K}}={{.V}}>. -		// Without this, if .K is empty then .V is the value of -		// checked, but otherwise .V is the value of the attribute -		// named .K. -		return filterFailsafe -	} -	s = strings.ToLower(s) -	if t := attrType(s); t != contentTypePlain { -		// TODO: Split attr and element name part filters so we can whitelist -		// attributes. -		return filterFailsafe -	} -	for _, r := range s { -		switch { -		case '0' <= r && r <= '9': -		case 'a' <= r && r <= 'z': -		default: -			return filterFailsafe -		} -	} -	return s -} - -// commentEscaper returns the empty string regardless of input. -// Comment content does not correspond to any parsed structure or -// human-readable content, so the simplest and most secure policy is to drop -// content interpolated into comments. -// This approach is equally valid whether or not static comment content is -// removed from the template. -func commentEscaper(args ...interface{}) string { -	return "" -} diff --git a/src/pkg/html/template/html_test.go b/src/pkg/html/template/html_test.go deleted file mode 100644 index b9b970387..000000000 --- a/src/pkg/html/template/html_test.go +++ /dev/null @@ -1,94 +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 template - -import ( -	"html" -	"strings" -	"testing" -) - -func TestHTMLNospaceEscaper(t *testing.T) { -	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" + -		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -		` !"#$%&'()*+,-./` + -		`0123456789:;<=>?` + -		`@ABCDEFGHIJKLMNO` + -		`PQRSTUVWXYZ[\]^_` + -		"`abcdefghijklmno" + -		"pqrstuvwxyz{|}~\x7f" + -		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E") - -	want := ("�\x01\x02\x03\x04\x05\x06\x07" + -		"\x08	

\x0E\x0F" + -		"\x10\x11\x12\x13\x14\x15\x16\x17" + -		"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -		` !"#$%&'()*+,-./` + -		`0123456789:;<=>?` + -		`@ABCDEFGHIJKLMNO` + -		`PQRSTUVWXYZ[\]^_` + -		``abcdefghijklmno` + -		`pqrstuvwxyz{|}~` + "\u007f" + -		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E") - -	got := htmlNospaceEscaper(input) -	if got != want { -		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got) -	} - -	got, want = html.UnescapeString(got), strings.Replace(input, "\x00", "\ufffd", 1) -	if want != got { -		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got) -	} -} - -func TestStripTags(t *testing.T) { -	tests := []struct { -		input, want string -	}{ -		{"", ""}, -		{"Hello, World!", "Hello, World!"}, -		{"foo&bar", "foo&bar"}, -		{`Hello <a href="www.example.com/">World</a>!`, "Hello World!"}, -		{"Foo <textarea>Bar</textarea> Baz", "Foo Bar Baz"}, -		{"Foo <!-- Bar --> Baz", "Foo  Baz"}, -		{"<", "<"}, -		{"foo < bar", "foo < bar"}, -		{`Foo<script type="text/javascript">alert(1337)</script>Bar`, "FooBar"}, -		{`Foo<div title="1>2">Bar`, "FooBar"}, -		{`I <3 Ponies!`, `I <3 Ponies!`}, -		{`<script>foo()</script>`, ``}, -	} - -	for _, test := range tests { -		if got := stripTags(test.input); got != test.want { -			t.Errorf("%q: want %q, got %q", test.input, test.want, got) -		} -	} -} - -func BenchmarkHTMLNospaceEscaper(b *testing.B) { -	for i := 0; i < b.N; i++ { -		htmlNospaceEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>") -	} -} - -func BenchmarkHTMLNospaceEscaperNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		htmlNospaceEscaper("The_quick,_brown_fox_jumps_over_the_lazy_dog.") -	} -} - -func BenchmarkStripTags(b *testing.B) { -	for i := 0; i < b.N; i++ { -		stripTags("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>") -	} -} - -func BenchmarkStripTagsNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		stripTags("The quick, brown fox jumps over the lazy dog.") -	} -} diff --git a/src/pkg/html/template/js.go b/src/pkg/html/template/js.go deleted file mode 100644 index 999a61ed0..000000000 --- a/src/pkg/html/template/js.go +++ /dev/null @@ -1,362 +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 template - -import ( -	"bytes" -	"encoding/json" -	"fmt" -	"reflect" -	"strings" -	"unicode/utf8" -) - -// nextJSCtx returns the context that determines whether a slash after the -// given run of tokens starts a regular expression instead of a division -// operator: / or /=. -// -// This assumes that the token run does not include any string tokens, comment -// tokens, regular expression literal tokens, or division operators. -// -// This fails on some valid but nonsensical JavaScript programs like -// "x = ++/foo/i" which is quite different than "x++/foo/i", but is not known to -// fail on any known useful programs. It is based on the draft -// JavaScript 2.0 lexical grammar and requires one token of lookbehind: -// http://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html -func nextJSCtx(s []byte, preceding jsCtx) jsCtx { -	s = bytes.TrimRight(s, "\t\n\f\r \u2028\u2029") -	if len(s) == 0 { -		return preceding -	} - -	// All cases below are in the single-byte UTF-8 group. -	switch c, n := s[len(s)-1], len(s); c { -	case '+', '-': -		// ++ and -- are not regexp preceders, but + and - are whether -		// they are used as infix or prefix operators. -		start := n - 1 -		// Count the number of adjacent dashes or pluses. -		for start > 0 && s[start-1] == c { -			start-- -		} -		if (n-start)&1 == 1 { -			// Reached for trailing minus signs since "---" is the -			// same as "-- -". -			return jsCtxRegexp -		} -		return jsCtxDivOp -	case '.': -		// Handle "42." -		if n != 1 && '0' <= s[n-2] && s[n-2] <= '9' { -			return jsCtxDivOp -		} -		return jsCtxRegexp -	// Suffixes for all punctuators from section 7.7 of the language spec -	// that only end binary operators not handled above. -	case ',', '<', '>', '=', '*', '%', '&', '|', '^', '?': -		return jsCtxRegexp -	// Suffixes for all punctuators from section 7.7 of the language spec -	// that are prefix operators not handled above. -	case '!', '~': -		return jsCtxRegexp -	// Matches all the punctuators from section 7.7 of the language spec -	// that are open brackets not handled above. -	case '(', '[': -		return jsCtxRegexp -	// Matches all the punctuators from section 7.7 of the language spec -	// that precede expression starts. -	case ':', ';', '{': -		return jsCtxRegexp -	// CAVEAT: the close punctuators ('}', ']', ')') precede div ops and -	// are handled in the default except for '}' which can precede a -	// division op as in -	//    ({ valueOf: function () { return 42 } } / 2 -	// which is valid, but, in practice, developers don't divide object -	// literals, so our heuristic works well for code like -	//    function () { ... }  /foo/.test(x) && sideEffect(); -	// The ')' punctuator can precede a regular expression as in -	//     if (b) /foo/.test(x) && ... -	// but this is much less likely than -	//     (a + b) / c -	case '}': -		return jsCtxRegexp -	default: -		// Look for an IdentifierName and see if it is a keyword that -		// can precede a regular expression. -		j := n -		for j > 0 && isJSIdentPart(rune(s[j-1])) { -			j-- -		} -		if regexpPrecederKeywords[string(s[j:])] { -			return jsCtxRegexp -		} -	} -	// Otherwise is a punctuator not listed above, or -	// a string which precedes a div op, or an identifier -	// which precedes a div op. -	return jsCtxDivOp -} - -// regexpPrecederKeywords is a set of reserved JS keywords that can precede a -// regular expression in JS source. -var regexpPrecederKeywords = map[string]bool{ -	"break":      true, -	"case":       true, -	"continue":   true, -	"delete":     true, -	"do":         true, -	"else":       true, -	"finally":    true, -	"in":         true, -	"instanceof": true, -	"return":     true, -	"throw":      true, -	"try":        true, -	"typeof":     true, -	"void":       true, -} - -var jsonMarshalType = reflect.TypeOf((*json.Marshaler)(nil)).Elem() - -// indirectToJSONMarshaler returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil) or an implementation of json.Marshal. -func indirectToJSONMarshaler(a interface{}) interface{} { -	v := reflect.ValueOf(a) -	for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Ptr && !v.IsNil() { -		v = v.Elem() -	} -	return v.Interface() -} - -// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has -// neither side-effects nor free variables outside (NaN, Infinity). -func jsValEscaper(args ...interface{}) string { -	var a interface{} -	if len(args) == 1 { -		a = indirectToJSONMarshaler(args[0]) -		switch t := a.(type) { -		case JS: -			return string(t) -		case JSStr: -			// TODO: normalize quotes. -			return `"` + string(t) + `"` -		case json.Marshaler: -			// Do not treat as a Stringer. -		case fmt.Stringer: -			a = t.String() -		} -	} else { -		for i, arg := range args { -			args[i] = indirectToJSONMarshaler(arg) -		} -		a = fmt.Sprint(args...) -	} -	// TODO: detect cycles before calling Marshal which loops infinitely on -	// cyclic data. This may be an unacceptable DoS risk. - -	b, err := json.Marshal(a) -	if err != nil { -		// Put a space before comment so that if it is flush against -		// a division operator it is not turned into a line comment: -		//     x/{{y}} -		// turning into -		//     x//* error marshalling y: -		//          second line of error message */null -		return fmt.Sprintf(" /* %s */null ", strings.Replace(err.Error(), "*/", "* /", -1)) -	} - -	// TODO: maybe post-process output to prevent it from containing -	// "<!--", "-->", "<![CDATA[", "]]>", or "</script" -	// in case custom marshallers produce output containing those. - -	// TODO: Maybe abbreviate \u00ab to \xab to produce more compact output. -	if len(b) == 0 { -		// In, `x=y/{{.}}*z` a json.Marshaler that produces "" should -		// not cause the output `x=y/*z`. -		return " null " -	} -	first, _ := utf8.DecodeRune(b) -	last, _ := utf8.DecodeLastRune(b) -	var buf bytes.Buffer -	// Prevent IdentifierNames and NumericLiterals from running into -	// keywords: in, instanceof, typeof, void -	pad := isJSIdentPart(first) || isJSIdentPart(last) -	if pad { -		buf.WriteByte(' ') -	} -	written := 0 -	// Make sure that json.Marshal escapes codepoints U+2028 & U+2029 -	// so it falls within the subset of JSON which is valid JS. -	for i := 0; i < len(b); { -		rune, n := utf8.DecodeRune(b[i:]) -		repl := "" -		if rune == 0x2028 { -			repl = `\u2028` -		} else if rune == 0x2029 { -			repl = `\u2029` -		} -		if repl != "" { -			buf.Write(b[written:i]) -			buf.WriteString(repl) -			written = i + n -		} -		i += n -	} -	if buf.Len() != 0 { -		buf.Write(b[written:]) -		if pad { -			buf.WriteByte(' ') -		} -		b = buf.Bytes() -	} -	return string(b) -} - -// jsStrEscaper produces a string that can be included between quotes in -// JavaScript source, in JavaScript embedded in an HTML5 <script> element, -// or in an HTML5 event handler attribute such as onclick. -func jsStrEscaper(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeJSStr { -		return replace(s, jsStrNormReplacementTable) -	} -	return replace(s, jsStrReplacementTable) -} - -// jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression -// specials so the result is treated literally when included in a regular -// expression literal. /foo{{.X}}bar/ matches the string "foo" followed by -// the literal text of {{.X}} followed by the string "bar". -func jsRegexpEscaper(args ...interface{}) string { -	s, _ := stringify(args...) -	s = replace(s, jsRegexpReplacementTable) -	if s == "" { -		// /{{.X}}/ should not produce a line comment when .X == "". -		return "(?:)" -	} -	return s -} - -// replace replaces each rune r of s with replacementTable[r], provided that -// r < len(replacementTable). If replacementTable[r] is the empty string then -// no replacement is made. -// It also replaces runes U+2028 and U+2029 with the raw strings `\u2028` and -// `\u2029`. -func replace(s string, replacementTable []string) string { -	var b bytes.Buffer -	written := 0 -	for i, r := range s { -		var repl string -		switch { -		case int(r) < len(replacementTable) && replacementTable[r] != "": -			repl = replacementTable[r] -		case r == '\u2028': -			repl = `\u2028` -		case r == '\u2029': -			repl = `\u2029` -		default: -			continue -		} -		b.WriteString(s[written:i]) -		b.WriteString(repl) -		written = i + utf8.RuneLen(r) -	} -	if written == 0 { -		return s -	} -	b.WriteString(s[written:]) -	return b.String() -} - -var jsStrReplacementTable = []string{ -	0:    `\0`, -	'\t': `\t`, -	'\n': `\n`, -	'\v': `\x0b`, // "\v" == "v" on IE 6. -	'\f': `\f`, -	'\r': `\r`, -	// Encode HTML specials as hex so the output can be embedded -	// in HTML attributes without further encoding. -	'"':  `\x22`, -	'&':  `\x26`, -	'\'': `\x27`, -	'+':  `\x2b`, -	'/':  `\/`, -	'<':  `\x3c`, -	'>':  `\x3e`, -	'\\': `\\`, -} - -// jsStrNormReplacementTable is like jsStrReplacementTable but does not -// overencode existing escapes since this table has no entry for `\`. -var jsStrNormReplacementTable = []string{ -	0:    `\0`, -	'\t': `\t`, -	'\n': `\n`, -	'\v': `\x0b`, // "\v" == "v" on IE 6. -	'\f': `\f`, -	'\r': `\r`, -	// Encode HTML specials as hex so the output can be embedded -	// in HTML attributes without further encoding. -	'"':  `\x22`, -	'&':  `\x26`, -	'\'': `\x27`, -	'+':  `\x2b`, -	'/':  `\/`, -	'<':  `\x3c`, -	'>':  `\x3e`, -} - -var jsRegexpReplacementTable = []string{ -	0:    `\0`, -	'\t': `\t`, -	'\n': `\n`, -	'\v': `\x0b`, // "\v" == "v" on IE 6. -	'\f': `\f`, -	'\r': `\r`, -	// Encode HTML specials as hex so the output can be embedded -	// in HTML attributes without further encoding. -	'"':  `\x22`, -	'$':  `\$`, -	'&':  `\x26`, -	'\'': `\x27`, -	'(':  `\(`, -	')':  `\)`, -	'*':  `\*`, -	'+':  `\x2b`, -	'-':  `\-`, -	'.':  `\.`, -	'/':  `\/`, -	'<':  `\x3c`, -	'>':  `\x3e`, -	'?':  `\?`, -	'[':  `\[`, -	'\\': `\\`, -	']':  `\]`, -	'^':  `\^`, -	'{':  `\{`, -	'|':  `\|`, -	'}':  `\}`, -} - -// isJSIdentPart reports whether the given rune is a JS identifier part. -// It does not handle all the non-Latin letters, joiners, and combining marks, -// but it does handle every codepoint that can occur in a numeric literal or -// a keyword. -func isJSIdentPart(r rune) bool { -	switch { -	case r == '$': -		return true -	case '0' <= r && r <= '9': -		return true -	case 'A' <= r && r <= 'Z': -		return true -	case r == '_': -		return true -	case 'a' <= r && r <= 'z': -		return true -	} -	return false -} diff --git a/src/pkg/html/template/js_test.go b/src/pkg/html/template/js_test.go deleted file mode 100644 index 311e1d2c4..000000000 --- a/src/pkg/html/template/js_test.go +++ /dev/null @@ -1,401 +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 template - -import ( -	"bytes" -	"math" -	"strings" -	"testing" -) - -func TestNextJsCtx(t *testing.T) { -	tests := []struct { -		jsCtx jsCtx -		s     string -	}{ -		// Statement terminators precede regexps. -		{jsCtxRegexp, ";"}, -		// This is not airtight. -		//     ({ valueOf: function () { return 1 } } / 2) -		// is valid JavaScript but in practice, devs do not do this. -		// A block followed by a statement starting with a RegExp is -		// much more common: -		//     while (x) {...} /foo/.test(x) || panic() -		{jsCtxRegexp, "}"}, -		// But member, call, grouping, and array expression terminators -		// precede div ops. -		{jsCtxDivOp, ")"}, -		{jsCtxDivOp, "]"}, -		// At the start of a primary expression, array, or expression -		// statement, expect a regexp. -		{jsCtxRegexp, "("}, -		{jsCtxRegexp, "["}, -		{jsCtxRegexp, "{"}, -		// Assignment operators precede regexps as do all exclusively -		// prefix and binary operators. -		{jsCtxRegexp, "="}, -		{jsCtxRegexp, "+="}, -		{jsCtxRegexp, "*="}, -		{jsCtxRegexp, "*"}, -		{jsCtxRegexp, "!"}, -		// Whether the + or - is infix or prefix, it cannot precede a -		// div op. -		{jsCtxRegexp, "+"}, -		{jsCtxRegexp, "-"}, -		// An incr/decr op precedes a div operator. -		// This is not airtight. In (g = ++/h/i) a regexp follows a -		// pre-increment operator, but in practice devs do not try to -		// increment or decrement regular expressions. -		// (g++/h/i) where ++ is a postfix operator on g is much more -		// common. -		{jsCtxDivOp, "--"}, -		{jsCtxDivOp, "++"}, -		{jsCtxDivOp, "x--"}, -		// When we have many dashes or pluses, then they are grouped -		// left to right. -		{jsCtxRegexp, "x---"}, // A postfix -- then a -. -		// return followed by a slash returns the regexp literal or the -		// slash starts a regexp literal in an expression statement that -		// is dead code. -		{jsCtxRegexp, "return"}, -		{jsCtxRegexp, "return "}, -		{jsCtxRegexp, "return\t"}, -		{jsCtxRegexp, "return\n"}, -		{jsCtxRegexp, "return\u2028"}, -		// Identifiers can be divided and cannot validly be preceded by -		// a regular expressions. Semicolon insertion cannot happen -		// between an identifier and a regular expression on a new line -		// because the one token lookahead for semicolon insertion has -		// to conclude that it could be a div binary op and treat it as -		// such. -		{jsCtxDivOp, "x"}, -		{jsCtxDivOp, "x "}, -		{jsCtxDivOp, "x\t"}, -		{jsCtxDivOp, "x\n"}, -		{jsCtxDivOp, "x\u2028"}, -		{jsCtxDivOp, "preturn"}, -		// Numbers precede div ops. -		{jsCtxDivOp, "0"}, -		// Dots that are part of a number are div preceders. -		{jsCtxDivOp, "0."}, -	} - -	for _, test := range tests { -		if nextJSCtx([]byte(test.s), jsCtxRegexp) != test.jsCtx { -			t.Errorf("want %s got %q", test.jsCtx, test.s) -		} -		if nextJSCtx([]byte(test.s), jsCtxDivOp) != test.jsCtx { -			t.Errorf("want %s got %q", test.jsCtx, test.s) -		} -	} - -	if nextJSCtx([]byte("   "), jsCtxRegexp) != jsCtxRegexp { -		t.Error("Blank tokens") -	} - -	if nextJSCtx([]byte("   "), jsCtxDivOp) != jsCtxDivOp { -		t.Error("Blank tokens") -	} -} - -func TestJSValEscaper(t *testing.T) { -	tests := []struct { -		x  interface{} -		js string -	}{ -		{int(42), " 42 "}, -		{uint(42), " 42 "}, -		{int16(42), " 42 "}, -		{uint16(42), " 42 "}, -		{int32(-42), " -42 "}, -		{uint32(42), " 42 "}, -		{int16(-42), " -42 "}, -		{uint16(42), " 42 "}, -		{int64(-42), " -42 "}, -		{uint64(42), " 42 "}, -		{uint64(1) << 53, " 9007199254740992 "}, -		// ulp(1 << 53) > 1 so this loses precision in JS -		// but it is still a representable integer literal. -		{uint64(1)<<53 + 1, " 9007199254740993 "}, -		{float32(1.0), " 1 "}, -		{float32(-1.0), " -1 "}, -		{float32(0.5), " 0.5 "}, -		{float32(-0.5), " -0.5 "}, -		{float32(1.0) / float32(256), " 0.00390625 "}, -		{float32(0), " 0 "}, -		{math.Copysign(0, -1), " -0 "}, -		{float64(1.0), " 1 "}, -		{float64(-1.0), " -1 "}, -		{float64(0.5), " 0.5 "}, -		{float64(-0.5), " -0.5 "}, -		{float64(0), " 0 "}, -		{math.Copysign(0, -1), " -0 "}, -		{"", `""`}, -		{"foo", `"foo"`}, -		// Newlines. -		{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, -		// "\v" == "v" on IE 6 so use "\x0b" instead. -		{"\t\x0b", `"\u0009\u000b"`}, -		{struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, -		{[]interface{}{}, "[]"}, -		{[]interface{}{42, "foo", nil}, `[42,"foo",null]`}, -		{[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`}, -		{"<!--", `"\u003c!--"`}, -		{"-->", `"--\u003e"`}, -		{"<![CDATA[", `"\u003c![CDATA["`}, -		{"]]>", `"]]\u003e"`}, -		{"</script", `"\u003c/script"`}, -		{"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E" -	} - -	for _, test := range tests { -		if js := jsValEscaper(test.x); js != test.js { -			t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js) -		} -		// Make sure that escaping corner cases are not broken -		// by nesting. -		a := []interface{}{test.x} -		want := "[" + strings.TrimSpace(test.js) + "]" -		if js := jsValEscaper(a); js != want { -			t.Errorf("%+v: want\n\t%q\ngot\n\t%q", a, want, js) -		} -	} -} - -func TestJSStrEscaper(t *testing.T) { -	tests := []struct { -		x   interface{} -		esc string -	}{ -		{"", ``}, -		{"foo", `foo`}, -		{"\u0000", `\0`}, -		{"\t", `\t`}, -		{"\n", `\n`}, -		{"\r", `\r`}, -		{"\u2028", `\u2028`}, -		{"\u2029", `\u2029`}, -		{"\\", `\\`}, -		{"\\n", `\\n`}, -		{"foo\r\nbar", `foo\r\nbar`}, -		// Preserve attribute boundaries. -		{`"`, `\x22`}, -		{`'`, `\x27`}, -		// Allow embedding in HTML without further escaping. -		{`&`, `\x26amp;`}, -		// Prevent breaking out of text node and element boundaries. -		{"</script>", `\x3c\/script\x3e`}, -		{"<![CDATA[", `\x3c![CDATA[`}, -		{"]]>", `]]\x3e`}, -		// http://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span -		//   "The text in style, script, title, and textarea elements -		//   must not have an escaping text span start that is not -		//   followed by an escaping text span end." -		// Furthermore, spoofing an escaping text span end could lead -		// to different interpretation of a </script> sequence otherwise -		// masked by the escaping text span, and spoofing a start could -		// allow regular text content to be interpreted as script -		// allowing script execution via a combination of a JS string -		// injection followed by an HTML text injection. -		{"<!--", `\x3c!--`}, -		{"-->", `--\x3e`}, -		// From http://code.google.com/p/doctype/wiki/ArticleUtf7 -		{"+ADw-script+AD4-alert(1)+ADw-/script+AD4-", -			`\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`, -		}, -		// Invalid UTF-8 sequence -		{"foo\xA0bar", "foo\xA0bar"}, -		// Invalid unicode scalar value. -		{"foo\xed\xa0\x80bar", "foo\xed\xa0\x80bar"}, -	} - -	for _, test := range tests { -		esc := jsStrEscaper(test.x) -		if esc != test.esc { -			t.Errorf("%q: want %q got %q", test.x, test.esc, esc) -		} -	} -} - -func TestJSRegexpEscaper(t *testing.T) { -	tests := []struct { -		x   interface{} -		esc string -	}{ -		{"", `(?:)`}, -		{"foo", `foo`}, -		{"\u0000", `\0`}, -		{"\t", `\t`}, -		{"\n", `\n`}, -		{"\r", `\r`}, -		{"\u2028", `\u2028`}, -		{"\u2029", `\u2029`}, -		{"\\", `\\`}, -		{"\\n", `\\n`}, -		{"foo\r\nbar", `foo\r\nbar`}, -		// Preserve attribute boundaries. -		{`"`, `\x22`}, -		{`'`, `\x27`}, -		// Allow embedding in HTML without further escaping. -		{`&`, `\x26amp;`}, -		// Prevent breaking out of text node and element boundaries. -		{"</script>", `\x3c\/script\x3e`}, -		{"<![CDATA[", `\x3c!\[CDATA\[`}, -		{"]]>", `\]\]\x3e`}, -		// Escaping text spans. -		{"<!--", `\x3c!\-\-`}, -		{"-->", `\-\-\x3e`}, -		{"*", `\*`}, -		{"+", `\x2b`}, -		{"?", `\?`}, -		{"[](){}", `\[\]\(\)\{\}`}, -		{"$foo|x.y", `\$foo\|x\.y`}, -		{"x^y", `x\^y`}, -	} - -	for _, test := range tests { -		esc := jsRegexpEscaper(test.x) -		if esc != test.esc { -			t.Errorf("%q: want %q got %q", test.x, test.esc, esc) -		} -	} -} - -func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) { -	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" + -		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -		` !"#$%&'()*+,-./` + -		`0123456789:;<=>?` + -		`@ABCDEFGHIJKLMNO` + -		`PQRSTUVWXYZ[\]^_` + -		"`abcdefghijklmno" + -		"pqrstuvwxyz{|}~\x7f" + -		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E") - -	tests := []struct { -		name    string -		escaper func(...interface{}) string -		escaped string -	}{ -		{ -			"jsStrEscaper", -			jsStrEscaper, -			"\\0\x01\x02\x03\x04\x05\x06\x07" + -				"\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + -				"\x10\x11\x12\x13\x14\x15\x16\x17" + -				"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -				` !\x22#$%\x26\x27()*\x2b,-.\/` + -				`0123456789:;\x3c=\x3e?` + -				`@ABCDEFGHIJKLMNO` + -				`PQRSTUVWXYZ[\\]^_` + -				"`abcdefghijklmno" + -				"pqrstuvwxyz{|}~\x7f" + -				"\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E", -		}, -		{ -			"jsRegexpEscaper", -			jsRegexpEscaper, -			"\\0\x01\x02\x03\x04\x05\x06\x07" + -				"\x08\\t\\n\\x0b\\f\\r\x0E\x0F" + -				"\x10\x11\x12\x13\x14\x15\x16\x17" + -				"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -				` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` + -				`0123456789:;\x3c=\x3e\?` + -				`@ABCDEFGHIJKLMNO` + -				`PQRSTUVWXYZ\[\\\]\^_` + -				"`abcdefghijklmno" + -				`pqrstuvwxyz\{\|\}~` + "\u007f" + -				"\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E", -		}, -	} - -	for _, test := range tests { -		if s := test.escaper(input); s != test.escaped { -			t.Errorf("%s once: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s) -			continue -		} - -		// Escape it rune by rune to make sure that any -		// fast-path checking does not break escaping. -		var buf bytes.Buffer -		for _, c := range input { -			buf.WriteString(test.escaper(string(c))) -		} - -		if s := buf.String(); s != test.escaped { -			t.Errorf("%s rune-wise: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s) -			continue -		} -	} -} - -func BenchmarkJSValEscaperWithNum(b *testing.B) { -	for i := 0; i < b.N; i++ { -		jsValEscaper(3.141592654) -	} -} - -func BenchmarkJSValEscaperWithStr(b *testing.B) { -	for i := 0; i < b.N; i++ { -		jsValEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>") -	} -} - -func BenchmarkJSValEscaperWithStrNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		jsValEscaper("The quick, brown fox jumps over the lazy dog") -	} -} - -func BenchmarkJSValEscaperWithObj(b *testing.B) { -	o := struct { -		S string -		N int -	}{ -		"The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>\u2028", -		42, -	} -	for i := 0; i < b.N; i++ { -		jsValEscaper(o) -	} -} - -func BenchmarkJSValEscaperWithObjNoSpecials(b *testing.B) { -	o := struct { -		S string -		N int -	}{ -		"The quick, brown fox jumps over the lazy dog", -		42, -	} -	for i := 0; i < b.N; i++ { -		jsValEscaper(o) -	} -} - -func BenchmarkJSStrEscaperNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		jsStrEscaper("The quick, brown fox jumps over the lazy dog.") -	} -} - -func BenchmarkJSStrEscaper(b *testing.B) { -	for i := 0; i < b.N; i++ { -		jsStrEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>") -	} -} - -func BenchmarkJSRegexpEscaperNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		jsRegexpEscaper("The quick, brown fox jumps over the lazy dog") -	} -} - -func BenchmarkJSRegexpEscaper(b *testing.B) { -	for i := 0; i < b.N; i++ { -		jsRegexpEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>") -	} -} diff --git a/src/pkg/html/template/template.go b/src/pkg/html/template/template.go deleted file mode 100644 index d38965897..000000000 --- a/src/pkg/html/template/template.go +++ /dev/null @@ -1,381 +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 template - -import ( -	"fmt" -	"io" -	"io/ioutil" -	"path/filepath" -	"sync" -	"text/template" -	"text/template/parse" -) - -// Template is a specialized Template from "text/template" that produces a safe -// HTML document fragment. -type Template struct { -	escaped bool -	// We could embed the text/template field, but it's safer not to because -	// we need to keep our version of the name space and the underlying -	// template's in sync. -	text *template.Template -	// The underlying template's parse tree, updated to be HTML-safe. -	Tree       *parse.Tree -	*nameSpace // common to all associated templates -} - -// nameSpace is the data structure shared by all templates in an association. -type nameSpace struct { -	mu  sync.Mutex -	set map[string]*Template -} - -// Templates returns a slice of the templates associated with t, including t -// itself. -func (t *Template) Templates() []*Template { -	ns := t.nameSpace -	ns.mu.Lock() -	defer ns.mu.Unlock() -	// Return a slice so we don't expose the map. -	m := make([]*Template, 0, len(ns.set)) -	for _, v := range ns.set { -		m = append(m, v) -	} -	return m -} - -// escape escapes all associated templates. -func (t *Template) escape() error { -	t.nameSpace.mu.Lock() -	defer t.nameSpace.mu.Unlock() -	if !t.escaped { -		if err := escapeTemplates(t, t.Name()); err != nil { -			return err -		} -		t.escaped = true -	} -	return nil -} - -// Execute applies a parsed template to the specified data object, -// writing the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel. -func (t *Template) Execute(wr io.Writer, data interface{}) error { -	if err := t.escape(); err != nil { -		return err -	} -	return t.text.Execute(wr, data) -} - -// ExecuteTemplate applies the template associated with t that has the given -// name to the specified data object and writes the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel. -func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { -	tmpl, err := t.lookupAndEscapeTemplate(name) -	if err != nil { -		return err -	} -	return tmpl.text.Execute(wr, data) -} - -// lookupAndEscapeTemplate guarantees that the template with the given name -// is escaped, or returns an error if it cannot be. It returns the named -// template. -func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) { -	t.nameSpace.mu.Lock() -	defer t.nameSpace.mu.Unlock() -	tmpl = t.set[name] -	if tmpl == nil { -		return nil, fmt.Errorf("html/template: %q is undefined", name) -	} -	if tmpl.text.Tree == nil || tmpl.text.Root == nil { -		return nil, fmt.Errorf("html/template: %q is an incomplete template", name) -	} -	if t.text.Lookup(name) == nil { -		panic("html/template internal error: template escaping out of sync") -	} -	if tmpl != nil && !tmpl.escaped { -		err = escapeTemplates(tmpl, name) -	} -	return tmpl, err -} - -// Parse parses a string into a template. Nested template definitions -// will be associated with the top-level template t. Parse may be -// called multiple times to parse definitions of templates to associate -// with t. It is an error if a resulting template is non-empty (contains -// content other than template definitions) and would replace a -// non-empty template with the same name.  (In multiple calls to Parse -// with the same receiver template, only one call can contain text -// other than space, comments, and template definitions.) -func (t *Template) Parse(src string) (*Template, error) { -	t.nameSpace.mu.Lock() -	t.escaped = false -	t.nameSpace.mu.Unlock() -	ret, err := t.text.Parse(src) -	if err != nil { -		return nil, err -	} -	// In general, all the named templates might have changed underfoot. -	// Regardless, some new ones may have been defined. -	// The template.Template set has been updated; update ours. -	t.nameSpace.mu.Lock() -	defer t.nameSpace.mu.Unlock() -	for _, v := range ret.Templates() { -		name := v.Name() -		tmpl := t.set[name] -		if tmpl == nil { -			tmpl = t.new(name) -		} -		// Restore our record of this text/template to its unescaped original state. -		tmpl.escaped = false -		tmpl.text = v -		tmpl.Tree = v.Tree -	} -	return t, nil -} - -// AddParseTree creates a new template with the name and parse tree -// and associates it with t. -// -// It returns an error if t has already been executed. -func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { -	t.nameSpace.mu.Lock() -	defer t.nameSpace.mu.Unlock() -	if t.escaped { -		return nil, fmt.Errorf("html/template: cannot AddParseTree to %q after it has executed", t.Name()) -	} -	text, err := t.text.AddParseTree(name, tree) -	if err != nil { -		return nil, err -	} -	ret := &Template{ -		false, -		text, -		text.Tree, -		t.nameSpace, -	} -	t.set[name] = ret -	return ret, nil -} - -// Clone returns a duplicate of the template, including all associated -// templates. The actual representation is not copied, but the name space of -// associated templates is, so further calls to Parse in the copy will add -// templates to the copy but not to the original. Clone can be used to prepare -// common templates and use them with variant definitions for other templates -// by adding the variants after the clone is made. -// -// It returns an error if t has already been executed. -func (t *Template) Clone() (*Template, error) { -	t.nameSpace.mu.Lock() -	defer t.nameSpace.mu.Unlock() -	if t.escaped { -		return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) -	} -	textClone, err := t.text.Clone() -	if err != nil { -		return nil, err -	} -	ret := &Template{ -		false, -		textClone, -		textClone.Tree, -		&nameSpace{ -			set: make(map[string]*Template), -		}, -	} -	for _, x := range textClone.Templates() { -		name := x.Name() -		src := t.set[name] -		if src == nil || src.escaped { -			return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) -		} -		x.Tree = x.Tree.Copy() -		ret.set[name] = &Template{ -			false, -			x, -			x.Tree, -			ret.nameSpace, -		} -	} -	return ret, nil -} - -// New allocates a new HTML template with the given name. -func New(name string) *Template { -	tmpl := &Template{ -		false, -		template.New(name), -		nil, -		&nameSpace{ -			set: make(map[string]*Template), -		}, -	} -	tmpl.set[name] = tmpl -	return tmpl -} - -// New allocates a new HTML template associated with the given one -// and with the same delimiters. The association, which is transitive, -// allows one template to invoke another with a {{template}} action. -func (t *Template) New(name string) *Template { -	t.nameSpace.mu.Lock() -	defer t.nameSpace.mu.Unlock() -	return t.new(name) -} - -// new is the implementation of New, without the lock. -func (t *Template) new(name string) *Template { -	tmpl := &Template{ -		false, -		t.text.New(name), -		nil, -		t.nameSpace, -	} -	tmpl.set[name] = tmpl -	return tmpl -} - -// Name returns the name of the template. -func (t *Template) Name() string { -	return t.text.Name() -} - -// FuncMap is the type of the map defining the mapping from names to -// functions. Each function must have either a single return value, or two -// return values of which the second has type error. In that case, if the -// second (error) argument evaluates to non-nil during execution, execution -// terminates and Execute returns that error. FuncMap has the same base type -// as FuncMap in "text/template", copied here so clients need not import -// "text/template". -type FuncMap map[string]interface{} - -// Funcs adds the elements of the argument map to the template's function map. -// It panics if a value in the map is not a function with appropriate return -// type. However, it is legal to overwrite elements of the map. The return -// value is the template, so calls can be chained. -func (t *Template) Funcs(funcMap FuncMap) *Template { -	t.text.Funcs(template.FuncMap(funcMap)) -	return t -} - -// Delims sets the action delimiters to the specified strings, to be used in -// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template -// definitions will inherit the settings. An empty delimiter stands for the -// corresponding default: {{ or }}. -// The return value is the template, so calls can be chained. -func (t *Template) Delims(left, right string) *Template { -	t.text.Delims(left, right) -	return t -} - -// Lookup returns the template with the given name that is associated with t, -// or nil if there is no such template. -func (t *Template) Lookup(name string) *Template { -	t.nameSpace.mu.Lock() -	defer t.nameSpace.mu.Unlock() -	return t.set[name] -} - -// Must is a helper that wraps a call to a function returning (*Template, error) -// and panics if the error is non-nil. It is intended for use in variable initializations -// such as -//	var t = template.Must(template.New("name").Parse("html")) -func Must(t *Template, err error) *Template { -	if err != nil { -		panic(err) -	} -	return t -} - -// ParseFiles creates a new Template and parses the template definitions from -// the named files. The returned template's name will have the (base) name and -// (parsed) contents of the first file. There must be at least one file. -// If an error occurs, parsing stops and the returned *Template is nil. -func ParseFiles(filenames ...string) (*Template, error) { -	return parseFiles(nil, filenames...) -} - -// ParseFiles parses the named files and associates the resulting templates with -// t. If an error occurs, parsing stops and the returned template is nil; -// otherwise it is t. There must be at least one file. -func (t *Template) ParseFiles(filenames ...string) (*Template, error) { -	return parseFiles(t, filenames...) -} - -// parseFiles is the helper for the method and function. If the argument -// template is nil, it is created from the first file. -func parseFiles(t *Template, filenames ...string) (*Template, error) { -	if len(filenames) == 0 { -		// Not really a problem, but be consistent. -		return nil, fmt.Errorf("html/template: no files named in call to ParseFiles") -	} -	for _, filename := range filenames { -		b, err := ioutil.ReadFile(filename) -		if err != nil { -			return nil, err -		} -		s := string(b) -		name := filepath.Base(filename) -		// First template becomes return value if not already defined, -		// and we use that one for subsequent New calls to associate -		// all the templates together. Also, if this file has the same name -		// as t, this file becomes the contents of t, so -		//  t, err := New(name).Funcs(xxx).ParseFiles(name) -		// works. Otherwise we create a new template associated with t. -		var tmpl *Template -		if t == nil { -			t = New(name) -		} -		if name == t.Name() { -			tmpl = t -		} else { -			tmpl = t.New(name) -		} -		_, err = tmpl.Parse(s) -		if err != nil { -			return nil, err -		} -	} -	return t, nil -} - -// ParseGlob creates a new Template and parses the template definitions from the -// files identified by the pattern, which must match at least one file. The -// returned template will have the (base) name and (parsed) contents of the -// first file matched by the pattern. ParseGlob is equivalent to calling -// ParseFiles with the list of files matched by the pattern. -func ParseGlob(pattern string) (*Template, error) { -	return parseGlob(nil, pattern) -} - -// ParseGlob parses the template definitions in the files identified by the -// pattern and associates the resulting templates with t. The pattern is -// processed by filepath.Glob and must match at least one file. ParseGlob is -// equivalent to calling t.ParseFiles with the list of files matched by the -// pattern. -func (t *Template) ParseGlob(pattern string) (*Template, error) { -	return parseGlob(t, pattern) -} - -// parseGlob is the implementation of the function and method ParseGlob. -func parseGlob(t *Template, pattern string) (*Template, error) { -	filenames, err := filepath.Glob(pattern) -	if err != nil { -		return nil, err -	} -	if len(filenames) == 0 { -		return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern) -	} -	return parseFiles(t, filenames...) -} diff --git a/src/pkg/html/template/transition.go b/src/pkg/html/template/transition.go deleted file mode 100644 index 7f30a7ab8..000000000 --- a/src/pkg/html/template/transition.go +++ /dev/null @@ -1,550 +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 template - -import ( -	"bytes" -	"strings" -) - -// transitionFunc is the array of context transition functions for text nodes. -// A transition function takes a context and template text input, and returns -// the updated context and the number of bytes consumed from the front of the -// input. -var transitionFunc = [...]func(context, []byte) (context, int){ -	stateText:        tText, -	stateTag:         tTag, -	stateAttrName:    tAttrName, -	stateAfterName:   tAfterName, -	stateBeforeValue: tBeforeValue, -	stateHTMLCmt:     tHTMLCmt, -	stateRCDATA:      tSpecialTagEnd, -	stateAttr:        tAttr, -	stateURL:         tURL, -	stateJS:          tJS, -	stateJSDqStr:     tJSDelimited, -	stateJSSqStr:     tJSDelimited, -	stateJSRegexp:    tJSDelimited, -	stateJSBlockCmt:  tBlockCmt, -	stateJSLineCmt:   tLineCmt, -	stateCSS:         tCSS, -	stateCSSDqStr:    tCSSStr, -	stateCSSSqStr:    tCSSStr, -	stateCSSDqURL:    tCSSStr, -	stateCSSSqURL:    tCSSStr, -	stateCSSURL:      tCSSStr, -	stateCSSBlockCmt: tBlockCmt, -	stateCSSLineCmt:  tLineCmt, -	stateError:       tError, -} - -var commentStart = []byte("<!--") -var commentEnd = []byte("-->") - -// tText is the context transition function for the text state. -func tText(c context, s []byte) (context, int) { -	k := 0 -	for { -		i := k + bytes.IndexByte(s[k:], '<') -		if i < k || i+1 == len(s) { -			return c, len(s) -		} else if i+4 <= len(s) && bytes.Equal(commentStart, s[i:i+4]) { -			return context{state: stateHTMLCmt}, i + 4 -		} -		i++ -		end := false -		if s[i] == '/' { -			if i+1 == len(s) { -				return c, len(s) -			} -			end, i = true, i+1 -		} -		j, e := eatTagName(s, i) -		if j != i { -			if end { -				e = elementNone -			} -			// We've found an HTML tag. -			return context{state: stateTag, element: e}, j -		} -		k = j -	} -} - -var elementContentType = [...]state{ -	elementNone:     stateText, -	elementScript:   stateJS, -	elementStyle:    stateCSS, -	elementTextarea: stateRCDATA, -	elementTitle:    stateRCDATA, -} - -// tTag is the context transition function for the tag state. -func tTag(c context, s []byte) (context, int) { -	// Find the attribute name. -	i := eatWhiteSpace(s, 0) -	if i == len(s) { -		return c, len(s) -	} -	if s[i] == '>' { -		return context{ -			state:   elementContentType[c.element], -			element: c.element, -		}, i + 1 -	} -	j, err := eatAttrName(s, i) -	if err != nil { -		return context{state: stateError, err: err}, len(s) -	} -	state, attr := stateTag, attrNone -	if i == j { -		return context{ -			state: stateError, -			err:   errorf(ErrBadHTML, 0, "expected space, attr name, or end of tag, but got %q", s[i:]), -		}, len(s) -	} -	switch attrType(string(s[i:j])) { -	case contentTypeURL: -		attr = attrURL -	case contentTypeCSS: -		attr = attrStyle -	case contentTypeJS: -		attr = attrScript -	} -	if j == len(s) { -		state = stateAttrName -	} else { -		state = stateAfterName -	} -	return context{state: state, element: c.element, attr: attr}, j -} - -// tAttrName is the context transition function for stateAttrName. -func tAttrName(c context, s []byte) (context, int) { -	i, err := eatAttrName(s, 0) -	if err != nil { -		return context{state: stateError, err: err}, len(s) -	} else if i != len(s) { -		c.state = stateAfterName -	} -	return c, i -} - -// tAfterName is the context transition function for stateAfterName. -func tAfterName(c context, s []byte) (context, int) { -	// Look for the start of the value. -	i := eatWhiteSpace(s, 0) -	if i == len(s) { -		return c, len(s) -	} else if s[i] != '=' { -		// Occurs due to tag ending '>', and valueless attribute. -		c.state = stateTag -		return c, i -	} -	c.state = stateBeforeValue -	// Consume the "=". -	return c, i + 1 -} - -var attrStartStates = [...]state{ -	attrNone:   stateAttr, -	attrScript: stateJS, -	attrStyle:  stateCSS, -	attrURL:    stateURL, -} - -// tBeforeValue is the context transition function for stateBeforeValue. -func tBeforeValue(c context, s []byte) (context, int) { -	i := eatWhiteSpace(s, 0) -	if i == len(s) { -		return c, len(s) -	} -	// Find the attribute delimiter. -	delim := delimSpaceOrTagEnd -	switch s[i] { -	case '\'': -		delim, i = delimSingleQuote, i+1 -	case '"': -		delim, i = delimDoubleQuote, i+1 -	} -	c.state, c.delim, c.attr = attrStartStates[c.attr], delim, attrNone -	return c, i -} - -// tHTMLCmt is the context transition function for stateHTMLCmt. -func tHTMLCmt(c context, s []byte) (context, int) { -	if i := bytes.Index(s, commentEnd); i != -1 { -		return context{}, i + 3 -	} -	return c, len(s) -} - -// specialTagEndMarkers maps element types to the character sequence that -// case-insensitively signals the end of the special tag body. -var specialTagEndMarkers = [...]string{ -	elementScript:   "</script", -	elementStyle:    "</style", -	elementTextarea: "</textarea", -	elementTitle:    "</title", -} - -// tSpecialTagEnd is the context transition function for raw text and RCDATA -// element states. -func tSpecialTagEnd(c context, s []byte) (context, int) { -	if c.element != elementNone { -		if i := strings.Index(strings.ToLower(string(s)), specialTagEndMarkers[c.element]); i != -1 { -			return context{}, i -		} -	} -	return c, len(s) -} - -// tAttr is the context transition function for the attribute state. -func tAttr(c context, s []byte) (context, int) { -	return c, len(s) -} - -// tURL is the context transition function for the URL state. -func tURL(c context, s []byte) (context, int) { -	if bytes.IndexAny(s, "#?") >= 0 { -		c.urlPart = urlPartQueryOrFrag -	} else if len(s) != eatWhiteSpace(s, 0) && c.urlPart == urlPartNone { -		// HTML5 uses "Valid URL potentially surrounded by spaces" for -		// attrs: http://www.w3.org/TR/html5/index.html#attributes-1 -		c.urlPart = urlPartPreQuery -	} -	return c, len(s) -} - -// tJS is the context transition function for the JS state. -func tJS(c context, s []byte) (context, int) { -	i := bytes.IndexAny(s, `"'/`) -	if i == -1 { -		// Entire input is non string, comment, regexp tokens. -		c.jsCtx = nextJSCtx(s, c.jsCtx) -		return c, len(s) -	} -	c.jsCtx = nextJSCtx(s[:i], c.jsCtx) -	switch s[i] { -	case '"': -		c.state, c.jsCtx = stateJSDqStr, jsCtxRegexp -	case '\'': -		c.state, c.jsCtx = stateJSSqStr, jsCtxRegexp -	case '/': -		switch { -		case i+1 < len(s) && s[i+1] == '/': -			c.state, i = stateJSLineCmt, i+1 -		case i+1 < len(s) && s[i+1] == '*': -			c.state, i = stateJSBlockCmt, i+1 -		case c.jsCtx == jsCtxRegexp: -			c.state = stateJSRegexp -		case c.jsCtx == jsCtxDivOp: -			c.jsCtx = jsCtxRegexp -		default: -			return context{ -				state: stateError, -				err:   errorf(ErrSlashAmbig, 0, "'/' could start a division or regexp: %.32q", s[i:]), -			}, len(s) -		} -	default: -		panic("unreachable") -	} -	return c, i + 1 -} - -// tJSDelimited is the context transition function for the JS string and regexp -// states. -func tJSDelimited(c context, s []byte) (context, int) { -	specials := `\"` -	switch c.state { -	case stateJSSqStr: -		specials = `\'` -	case stateJSRegexp: -		specials = `\/[]` -	} - -	k, inCharset := 0, false -	for { -		i := k + bytes.IndexAny(s[k:], specials) -		if i < k { -			break -		} -		switch s[i] { -		case '\\': -			i++ -			if i == len(s) { -				return context{ -					state: stateError, -					err:   errorf(ErrPartialEscape, 0, "unfinished escape sequence in JS string: %q", s), -				}, len(s) -			} -		case '[': -			inCharset = true -		case ']': -			inCharset = false -		default: -			// end delimiter -			if !inCharset { -				c.state, c.jsCtx = stateJS, jsCtxDivOp -				return c, i + 1 -			} -		} -		k = i + 1 -	} - -	if inCharset { -		// This can be fixed by making context richer if interpolation -		// into charsets is desired. -		return context{ -			state: stateError, -			err:   errorf(ErrPartialCharset, 0, "unfinished JS regexp charset: %q", s), -		}, len(s) -	} - -	return c, len(s) -} - -var blockCommentEnd = []byte("*/") - -// tBlockCmt is the context transition function for /*comment*/ states. -func tBlockCmt(c context, s []byte) (context, int) { -	i := bytes.Index(s, blockCommentEnd) -	if i == -1 { -		return c, len(s) -	} -	switch c.state { -	case stateJSBlockCmt: -		c.state = stateJS -	case stateCSSBlockCmt: -		c.state = stateCSS -	default: -		panic(c.state.String()) -	} -	return c, i + 2 -} - -// tLineCmt is the context transition function for //comment states. -func tLineCmt(c context, s []byte) (context, int) { -	var lineTerminators string -	var endState state -	switch c.state { -	case stateJSLineCmt: -		lineTerminators, endState = "\n\r\u2028\u2029", stateJS -	case stateCSSLineCmt: -		lineTerminators, endState = "\n\f\r", stateCSS -		// Line comments are not part of any published CSS standard but -		// are supported by the 4 major browsers. -		// This defines line comments as -		//     LINECOMMENT ::= "//" [^\n\f\d]* -		// since http://www.w3.org/TR/css3-syntax/#SUBTOK-nl defines -		// newlines: -		//     nl ::= #xA | #xD #xA | #xD | #xC -	default: -		panic(c.state.String()) -	} - -	i := bytes.IndexAny(s, lineTerminators) -	if i == -1 { -		return c, len(s) -	} -	c.state = endState -	// Per section 7.4 of EcmaScript 5 : http://es5.github.com/#x7.4 -	// "However, the LineTerminator at the end of the line is not -	// considered to be part of the single-line comment; it is -	// recognized separately by the lexical grammar and becomes part -	// of the stream of input elements for the syntactic grammar." -	return c, i -} - -// tCSS is the context transition function for the CSS state. -func tCSS(c context, s []byte) (context, int) { -	// CSS quoted strings are almost never used except for: -	// (1) URLs as in background: "/foo.png" -	// (2) Multiword font-names as in font-family: "Times New Roman" -	// (3) List separators in content values as in inline-lists: -	//    <style> -	//    ul.inlineList { list-style: none; padding:0 } -	//    ul.inlineList > li { display: inline } -	//    ul.inlineList > li:before { content: ", " } -	//    ul.inlineList > li:first-child:before { content: "" } -	//    </style> -	//    <ul class=inlineList><li>One<li>Two<li>Three</ul> -	// (4) Attribute value selectors as in a[href="http://example.com/"] -	// -	// We conservatively treat all strings as URLs, but make some -	// allowances to avoid confusion. -	// -	// In (1), our conservative assumption is justified. -	// In (2), valid font names do not contain ':', '?', or '#', so our -	// conservative assumption is fine since we will never transition past -	// urlPartPreQuery. -	// In (3), our protocol heuristic should not be tripped, and there -	// should not be non-space content after a '?' or '#', so as long as -	// we only %-encode RFC 3986 reserved characters we are ok. -	// In (4), we should URL escape for URL attributes, and for others we -	// have the attribute name available if our conservative assumption -	// proves problematic for real code. - -	k := 0 -	for { -		i := k + bytes.IndexAny(s[k:], `("'/`) -		if i < k { -			return c, len(s) -		} -		switch s[i] { -		case '(': -			// Look for url to the left. -			p := bytes.TrimRight(s[:i], "\t\n\f\r ") -			if endsWithCSSKeyword(p, "url") { -				j := len(s) - len(bytes.TrimLeft(s[i+1:], "\t\n\f\r ")) -				switch { -				case j != len(s) && s[j] == '"': -					c.state, j = stateCSSDqURL, j+1 -				case j != len(s) && s[j] == '\'': -					c.state, j = stateCSSSqURL, j+1 -				default: -					c.state = stateCSSURL -				} -				return c, j -			} -		case '/': -			if i+1 < len(s) { -				switch s[i+1] { -				case '/': -					c.state = stateCSSLineCmt -					return c, i + 2 -				case '*': -					c.state = stateCSSBlockCmt -					return c, i + 2 -				} -			} -		case '"': -			c.state = stateCSSDqStr -			return c, i + 1 -		case '\'': -			c.state = stateCSSSqStr -			return c, i + 1 -		} -		k = i + 1 -	} -} - -// tCSSStr is the context transition function for the CSS string and URL states. -func tCSSStr(c context, s []byte) (context, int) { -	var endAndEsc string -	switch c.state { -	case stateCSSDqStr, stateCSSDqURL: -		endAndEsc = `\"` -	case stateCSSSqStr, stateCSSSqURL: -		endAndEsc = `\'` -	case stateCSSURL: -		// Unquoted URLs end with a newline or close parenthesis. -		// The below includes the wc (whitespace character) and nl. -		endAndEsc = "\\\t\n\f\r )" -	default: -		panic(c.state.String()) -	} - -	k := 0 -	for { -		i := k + bytes.IndexAny(s[k:], endAndEsc) -		if i < k { -			c, nread := tURL(c, decodeCSS(s[k:])) -			return c, k + nread -		} -		if s[i] == '\\' { -			i++ -			if i == len(s) { -				return context{ -					state: stateError, -					err:   errorf(ErrPartialEscape, 0, "unfinished escape sequence in CSS string: %q", s), -				}, len(s) -			} -		} else { -			c.state = stateCSS -			return c, i + 1 -		} -		c, _ = tURL(c, decodeCSS(s[:i+1])) -		k = i + 1 -	} -} - -// tError is the context transition function for the error state. -func tError(c context, s []byte) (context, int) { -	return c, len(s) -} - -// eatAttrName returns the largest j such that s[i:j] is an attribute name. -// It returns an error if s[i:] does not look like it begins with an -// attribute name, such as encountering a quote mark without a preceding -// equals sign. -func eatAttrName(s []byte, i int) (int, *Error) { -	for j := i; j < len(s); j++ { -		switch s[j] { -		case ' ', '\t', '\n', '\f', '\r', '=', '>': -			return j, nil -		case '\'', '"', '<': -			// These result in a parse warning in HTML5 and are -			// indicative of serious problems if seen in an attr -			// name in a template. -			return -1, errorf(ErrBadHTML, 0, "%q in attribute name: %.32q", s[j:j+1], s) -		default: -			// No-op. -		} -	} -	return len(s), nil -} - -var elementNameMap = map[string]element{ -	"script":   elementScript, -	"style":    elementStyle, -	"textarea": elementTextarea, -	"title":    elementTitle, -} - -// asciiAlpha reports whether c is an ASCII letter. -func asciiAlpha(c byte) bool { -	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' -} - -// asciiAlphaNum reports whether c is an ASCII letter or digit. -func asciiAlphaNum(c byte) bool { -	return asciiAlpha(c) || '0' <= c && c <= '9' -} - -// eatTagName returns the largest j such that s[i:j] is a tag name and the tag type. -func eatTagName(s []byte, i int) (int, element) { -	if i == len(s) || !asciiAlpha(s[i]) { -		return i, elementNone -	} -	j := i + 1 -	for j < len(s) { -		x := s[j] -		if asciiAlphaNum(x) { -			j++ -			continue -		} -		// Allow "x-y" or "x:y" but not "x-", "-y", or "x--y". -		if (x == ':' || x == '-') && j+1 < len(s) && asciiAlphaNum(s[j+1]) { -			j += 2 -			continue -		} -		break -	} -	return j, elementNameMap[strings.ToLower(string(s[i:j]))] -} - -// eatWhiteSpace returns the largest j such that s[i:j] is white space. -func eatWhiteSpace(s []byte, i int) int { -	for j := i; j < len(s); j++ { -		switch s[j] { -		case ' ', '\t', '\n', '\f', '\r': -			// No-op. -		default: -			return j -		} -	} -	return len(s) -} diff --git a/src/pkg/html/template/url.go b/src/pkg/html/template/url.go deleted file mode 100644 index 2ca76bf38..000000000 --- a/src/pkg/html/template/url.go +++ /dev/null @@ -1,105 +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 template - -import ( -	"bytes" -	"fmt" -	"strings" -) - -// urlFilter returns its input unless it contains an unsafe protocol in which -// case it defangs the entire URL. -func urlFilter(args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeURL { -		return s -	} -	if i := strings.IndexRune(s, ':'); i >= 0 && strings.IndexRune(s[:i], '/') < 0 { -		protocol := strings.ToLower(s[:i]) -		if protocol != "http" && protocol != "https" && protocol != "mailto" { -			return "#" + filterFailsafe -		} -	} -	return s -} - -// urlEscaper produces an output that can be embedded in a URL query. -// The output can be embedded in an HTML attribute without further escaping. -func urlEscaper(args ...interface{}) string { -	return urlProcessor(false, args...) -} - -// urlEscaper normalizes URL content so it can be embedded in a quote-delimited -// string or parenthesis delimited url(...). -// The normalizer does not encode all HTML specials. Specifically, it does not -// encode '&' so correct embedding in an HTML attribute requires escaping of -// '&' to '&'. -func urlNormalizer(args ...interface{}) string { -	return urlProcessor(true, args...) -} - -// urlProcessor normalizes (when norm is true) or escapes its input to produce -// a valid hierarchical or opaque URL part. -func urlProcessor(norm bool, args ...interface{}) string { -	s, t := stringify(args...) -	if t == contentTypeURL { -		norm = true -	} -	var b bytes.Buffer -	written := 0 -	// The byte loop below assumes that all URLs use UTF-8 as the -	// content-encoding. This is similar to the URI to IRI encoding scheme -	// defined in section 3.1 of  RFC 3987, and behaves the same as the -	// EcmaScript builtin encodeURIComponent. -	// It should not cause any misencoding of URLs in pages with -	// Content-type: text/html;charset=UTF-8. -	for i, n := 0, len(s); i < n; i++ { -		c := s[i] -		switch c { -		// Single quote and parens are sub-delims in RFC 3986, but we -		// escape them so the output can be embedded in single -		// quoted attributes and unquoted CSS url(...) constructs. -		// Single quotes are reserved in URLs, but are only used in -		// the obsolete "mark" rule in an appendix in RFC 3986 -		// so can be safely encoded. -		case '!', '#', '$', '&', '*', '+', ',', '/', ':', ';', '=', '?', '@', '[', ']': -			if norm { -				continue -			} -		// Unreserved according to RFC 3986 sec 2.3 -		// "For consistency, percent-encoded octets in the ranges of -		// ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), -		// period (%2E), underscore (%5F), or tilde (%7E) should not be -		// created by URI producers -		case '-', '.', '_', '~': -			continue -		case '%': -			// When normalizing do not re-encode valid escapes. -			if norm && i+2 < len(s) && isHex(s[i+1]) && isHex(s[i+2]) { -				continue -			} -		default: -			// Unreserved according to RFC 3986 sec 2.3 -			if 'a' <= c && c <= 'z' { -				continue -			} -			if 'A' <= c && c <= 'Z' { -				continue -			} -			if '0' <= c && c <= '9' { -				continue -			} -		} -		b.WriteString(s[written:i]) -		fmt.Fprintf(&b, "%%%02x", c) -		written = i + 1 -	} -	if written == 0 { -		return s -	} -	b.WriteString(s[written:]) -	return b.String() -} diff --git a/src/pkg/html/template/url_test.go b/src/pkg/html/template/url_test.go deleted file mode 100644 index 5182e9d79..000000000 --- a/src/pkg/html/template/url_test.go +++ /dev/null @@ -1,112 +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 template - -import ( -	"testing" -) - -func TestURLNormalizer(t *testing.T) { -	tests := []struct { -		url, want string -	}{ -		{"", ""}, -		{ -			"http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag", -			"http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag", -		}, -		{" ", "%20"}, -		{"%7c", "%7c"}, -		{"%7C", "%7C"}, -		{"%2", "%252"}, -		{"%", "%25"}, -		{"%z", "%25z"}, -		{"/foo|bar/%5c\u1234", "/foo%7cbar/%5c%e1%88%b4"}, -	} -	for _, test := range tests { -		if got := urlNormalizer(test.url); test.want != got { -			t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.url, test.want, got) -		} -		if test.want != urlNormalizer(test.want) { -			t.Errorf("not idempotent: %q", test.want) -		} -	} -} - -func TestURLFilters(t *testing.T) { -	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" + -		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + -		` !"#$%&'()*+,-./` + -		`0123456789:;<=>?` + -		`@ABCDEFGHIJKLMNO` + -		`PQRSTUVWXYZ[\]^_` + -		"`abcdefghijklmno" + -		"pqrstuvwxyz{|}~\x7f" + -		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E") - -	tests := []struct { -		name    string -		escaper func(...interface{}) string -		escaped string -	}{ -		{ -			"urlEscaper", -			urlEscaper, -			"%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" + -				"%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" + -				"%20%21%22%23%24%25%26%27%28%29%2a%2b%2c-.%2f" + -				"0123456789%3a%3b%3c%3d%3e%3f" + -				"%40ABCDEFGHIJKLMNO" + -				"PQRSTUVWXYZ%5b%5c%5d%5e_" + -				"%60abcdefghijklmno" + -				"pqrstuvwxyz%7b%7c%7d~%7f" + -				"%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e", -		}, -		{ -			"urlNormalizer", -			urlNormalizer, -			"%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" + -				"%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" + -				"%20!%22#$%25&%27%28%29*+,-./" + -				"0123456789:;%3c=%3e?" + -				"@ABCDEFGHIJKLMNO" + -				"PQRSTUVWXYZ[%5c]%5e_" + -				"%60abcdefghijklmno" + -				"pqrstuvwxyz%7b%7c%7d~%7f" + -				"%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e", -		}, -	} - -	for _, test := range tests { -		if s := test.escaper(input); s != test.escaped { -			t.Errorf("%s: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s) -			continue -		} -	} -} - -func BenchmarkURLEscaper(b *testing.B) { -	for i := 0; i < b.N; i++ { -		urlEscaper("http://example.com:80/foo?q=bar%20&baz=x+y#frag") -	} -} - -func BenchmarkURLEscaperNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		urlEscaper("TheQuickBrownFoxJumpsOverTheLazyDog.") -	} -} - -func BenchmarkURLNormalizer(b *testing.B) { -	for i := 0; i < b.N; i++ { -		urlNormalizer("The quick brown fox jumps over the lazy dog.\n") -	} -} - -func BenchmarkURLNormalizerNoSpecials(b *testing.B) { -	for i := 0; i < b.N; i++ { -		urlNormalizer("http://example.com:80/foo?q=bar%20&baz=x+y#frag") -	} -} | 
