Best K6 code snippet using html.Name
escape.go
Source:escape.go
...19 e := newEscaper(tmpl)20 c, _ := e.escapeTree(context{}, node, name, 0)21 var err error22 if c.err != nil {23 err, c.err.Name = c.err, name24 } else if c.state != stateText {25 err = &Error{ErrEndContext, nil, name, 0, fmt.Sprintf("ends in a non-text context: %v", c)}26 }27 if err != nil {28 // Prevent execution of unsafe templates.29 if t := tmpl.set[name]; t != nil {30 t.escapeErr = err31 t.text.Tree = nil32 t.Tree = nil33 }34 return err35 }36 e.commit()37 if t := tmpl.set[name]; t != nil {38 t.escapeErr = escapeOK39 t.Tree = t.text.Tree40 }41 return nil42}43// funcMap maps command names to functions that render their inputs safe.44var funcMap = template.FuncMap{45 "_html_template_attrescaper": attrEscaper,46 "_html_template_commentescaper": commentEscaper,47 "_html_template_cssescaper": cssEscaper,48 "_html_template_cssvaluefilter": cssValueFilter,49 "_html_template_htmlnamefilter": htmlNameFilter,50 "_html_template_htmlescaper": htmlEscaper,51 "_html_template_jsregexpescaper": jsRegexpEscaper,52 "_html_template_jsstrescaper": jsStrEscaper,53 "_html_template_jsvalescaper": jsValEscaper,54 "_html_template_nospaceescaper": htmlNospaceEscaper,55 "_html_template_rcdataescaper": rcdataEscaper,56 "_html_template_urlescaper": urlEscaper,57 "_html_template_urlfilter": urlFilter,58 "_html_template_urlnormalizer": urlNormalizer,59}60// equivEscapers matches contextual escapers to equivalent template builtins.61var equivEscapers = map[string]string{62 "_html_template_attrescaper": "html",63 "_html_template_htmlescaper": "html",64 "_html_template_nospaceescaper": "html",65 "_html_template_rcdataescaper": "html",66 "_html_template_urlescaper": "urlquery",67 "_html_template_urlnormalizer": "urlquery",68}69// escaper collects type inferences about templates and changes needed to make70// templates injection safe.71type escaper struct {72 tmpl *Template73 // output[templateName] is the output context for a templateName that74 // has been mangled to include its input context.75 output map[string]context76 // derived[c.mangle(name)] maps to a template derived from the template77 // named name templateName for the start context c.78 derived map[string]*template.Template79 // called[templateName] is a set of called mangled template names.80 called map[string]bool81 // xxxNodeEdits are the accumulated edits to apply during commit.82 // Such edits are not applied immediately in case a template set83 // executes a given template in different escaping contexts.84 actionNodeEdits map[*parse.ActionNode][]string85 templateNodeEdits map[*parse.TemplateNode]string86 textNodeEdits map[*parse.TextNode][]byte87}88// newEscaper creates a blank escaper for the given set.89func newEscaper(t *Template) *escaper {90 return &escaper{91 t,92 map[string]context{},93 map[string]*template.Template{},94 map[string]bool{},95 map[*parse.ActionNode][]string{},96 map[*parse.TemplateNode]string{},97 map[*parse.TextNode][]byte{},98 }99}100// filterFailsafe is an innocuous word that is emitted in place of unsafe values101// by sanitizer functions. It is not a keyword in any programming language,102// contains no special characters, is not empty, and when it appears in output103// it is distinct enough that a developer can find the source of the problem104// via a search engine.105const filterFailsafe = "ZgotmplZ"106// escape escapes a template node.107func (e *escaper) escape(c context, n parse.Node) context {108 switch n := n.(type) {109 case *parse.ActionNode:110 return e.escapeAction(c, n)111 case *parse.IfNode:112 return e.escapeBranch(c, &n.BranchNode, "if")113 case *parse.ListNode:114 return e.escapeList(c, n)115 case *parse.RangeNode:116 return e.escapeBranch(c, &n.BranchNode, "range")117 case *parse.TemplateNode:118 return e.escapeTemplate(c, n)119 case *parse.TextNode:120 return e.escapeText(c, n)121 case *parse.WithNode:122 return e.escapeBranch(c, &n.BranchNode, "with")123 }124 panic("escaping " + n.String() + " is unimplemented")125}126// escapeAction escapes an action template node.127func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {128 if len(n.Pipe.Decl) != 0 {129 // A local variable assignment, not an interpolation.130 return c131 }132 c = nudge(c)133 s := make([]string, 0, 3)134 switch c.state {135 case stateError:136 return c137 case stateURL, stateCSSDqStr, stateCSSSqStr, stateCSSDqURL, stateCSSSqURL, stateCSSURL:138 switch c.urlPart {139 case urlPartNone:140 s = append(s, "_html_template_urlfilter")141 fallthrough142 case urlPartPreQuery:143 switch c.state {144 case stateCSSDqStr, stateCSSSqStr:145 s = append(s, "_html_template_cssescaper")146 default:147 s = append(s, "_html_template_urlnormalizer")148 }149 case urlPartQueryOrFrag:150 s = append(s, "_html_template_urlescaper")151 case urlPartUnknown:152 return context{153 state: stateError,154 err: errorf(ErrAmbigContext, n, n.Line, "%s appears in an ambiguous URL context", n),155 }156 default:157 panic(c.urlPart.String())158 }159 case stateJS:160 s = append(s, "_html_template_jsvalescaper")161 // A slash after a value starts a div operator.162 c.jsCtx = jsCtxDivOp163 case stateJSDqStr, stateJSSqStr:164 s = append(s, "_html_template_jsstrescaper")165 case stateJSRegexp:166 s = append(s, "_html_template_jsregexpescaper")167 case stateCSS:168 s = append(s, "_html_template_cssvaluefilter")169 case stateText:170 s = append(s, "_html_template_htmlescaper")171 case stateRCDATA:172 s = append(s, "_html_template_rcdataescaper")173 case stateAttr:174 // Handled below in delim check.175 case stateAttrName, stateTag:176 c.state = stateAttrName177 s = append(s, "_html_template_htmlnamefilter")178 default:179 if isComment(c.state) {180 s = append(s, "_html_template_commentescaper")181 } else {182 panic("unexpected state " + c.state.String())183 }184 }185 switch c.delim {186 case delimNone:187 // No extra-escaping needed for raw text content.188 case delimSpaceOrTagEnd:189 s = append(s, "_html_template_nospaceescaper")190 default:191 s = append(s, "_html_template_attrescaper")192 }193 e.editActionNode(n, s)194 return c195}196// allIdents returns the names of the identifiers under the Ident field of the node,197// which might be a singleton (Identifier) or a slice (Field or Chain).198func allIdents(node parse.Node) []string {199 switch node := node.(type) {200 case *parse.IdentifierNode:201 return []string{node.Ident}202 case *parse.FieldNode:203 return node.Ident204 case *parse.ChainNode:205 return node.Field206 }207 return nil208}209// ensurePipelineContains ensures that the pipeline has commands with210// the identifiers in s in order.211// If the pipeline already has some of the sanitizers, do not interfere.212// For example, if p is (.X | html) and s is ["escapeJSVal", "html"] then it213// has one matching, "html", and one to insert, "escapeJSVal", to produce214// (.X | escapeJSVal | html).215func ensurePipelineContains(p *parse.PipeNode, s []string) {216 if len(s) == 0 {217 return218 }219 n := len(p.Cmds)220 // Find the identifiers at the end of the command chain.221 idents := p.Cmds222 for i := n - 1; i >= 0; i-- {223 if cmd := p.Cmds[i]; len(cmd.Args) != 0 {224 if _, ok := cmd.Args[0].(*parse.IdentifierNode); ok {225 continue226 }227 }228 idents = p.Cmds[i+1:]229 }230 dups := 0231 for _, idNode := range idents {232 for _, ident := range allIdents(idNode.Args[0]) {233 if escFnsEq(s[dups], ident) {234 dups++235 if dups == len(s) {236 return237 }238 }239 }240 }241 newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups)242 copy(newCmds, p.Cmds)243 // Merge existing identifier commands with the sanitizers needed.244 for _, idNode := range idents {245 pos := idNode.Args[0].Position()246 for _, ident := range allIdents(idNode.Args[0]) {247 i := indexOfStr(ident, s, escFnsEq)248 if i != -1 {249 for _, name := range s[:i] {250 newCmds = appendCmd(newCmds, newIdentCmd(name, pos))251 }252 s = s[i+1:]253 }254 }255 newCmds = appendCmd(newCmds, idNode)256 }257 // Create any remaining sanitizers.258 for _, name := range s {259 newCmds = appendCmd(newCmds, newIdentCmd(name, p.Position()))260 }261 p.Cmds = newCmds262}263// redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x)264// for all x.265var redundantFuncs = map[string]map[string]bool{266 "_html_template_commentescaper": {267 "_html_template_attrescaper": true,268 "_html_template_nospaceescaper": true,269 "_html_template_htmlescaper": true,270 },271 "_html_template_cssescaper": {272 "_html_template_attrescaper": true,273 },274 "_html_template_jsregexpescaper": {275 "_html_template_attrescaper": true,276 },277 "_html_template_jsstrescaper": {278 "_html_template_attrescaper": true,279 },280 "_html_template_urlescaper": {281 "_html_template_urlnormalizer": true,282 },283}284// appendCmd appends the given command to the end of the command pipeline285// unless it is redundant with the last command.286func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode {287 if n := len(cmds); n != 0 {288 last, okLast := cmds[n-1].Args[0].(*parse.IdentifierNode)289 next, okNext := cmd.Args[0].(*parse.IdentifierNode)290 if okLast && okNext && redundantFuncs[last.Ident][next.Ident] {291 return cmds292 }293 }294 return append(cmds, cmd)295}296// indexOfStr is the first i such that eq(s, strs[i]) or -1 if s was not found.297func indexOfStr(s string, strs []string, eq func(a, b string) bool) int {298 for i, t := range strs {299 if eq(s, t) {300 return i301 }302 }303 return -1304}305// escFnsEq reports whether the two escaping functions are equivalent.306func escFnsEq(a, b string) bool {307 if e := equivEscapers[a]; e != "" {308 a = e309 }310 if e := equivEscapers[b]; e != "" {311 b = e312 }313 return a == b314}315// newIdentCmd produces a command containing a single identifier node.316func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode {317 return &parse.CommandNode{318 NodeType: parse.NodeCommand,319 Args: []parse.Node{parse.NewIdentifier(identifier).SetTree(nil).SetPos(pos)}, // TODO: SetTree.320 }321}322// nudge returns the context that would result from following empty string323// transitions from the input context.324// For example, parsing:325// `<a href=`326// will end in context{stateBeforeValue, attrURL}, but parsing one extra rune:327// `<a href=x`328// will end in context{stateURL, delimSpaceOrTagEnd, ...}.329// There are two transitions that happen when the 'x' is seen:330// (1) Transition from a before-value state to a start-of-value state without331// consuming any character.332// (2) Consume 'x' and transition past the first value character.333// In this case, nudging produces the context after (1) happens.334func nudge(c context) context {335 switch c.state {336 case stateTag:337 // In `<foo {{.}}`, the action should emit an attribute.338 c.state = stateAttrName339 case stateBeforeValue:340 // In `<foo bar={{.}}`, the action is an undelimited value.341 c.state, c.delim, c.attr = attrStartStates[c.attr], delimSpaceOrTagEnd, attrNone342 case stateAfterName:343 // In `<foo bar {{.}}`, the action is an attribute name.344 c.state, c.attr = stateAttrName, attrNone345 }346 return c347}348// join joins the two contexts of a branch template node. The result is an349// error context if either of the input contexts are error contexts, or if the350// the input contexts differ.351func join(a, b context, node parse.Node, nodeName string) context {352 if a.state == stateError {353 return a354 }355 if b.state == stateError {356 return b357 }358 if a.eq(b) {359 return a360 }361 c := a362 c.urlPart = b.urlPart363 if c.eq(b) {364 // The contexts differ only by urlPart.365 c.urlPart = urlPartUnknown366 return c367 }368 c = a369 c.jsCtx = b.jsCtx370 if c.eq(b) {371 // The contexts differ only by jsCtx.372 c.jsCtx = jsCtxUnknown373 return c374 }375 // Allow a nudged context to join with an unnudged one.376 // This means that377 // <p title={{if .C}}{{.}}{{end}}378 // ends in an unquoted value state even though the else branch379 // ends in stateBeforeValue.380 if c, d := nudge(a), nudge(b); !(c.eq(a) && d.eq(b)) {381 if e := join(c, d, node, nodeName); e.state != stateError {382 return e383 }384 }385 return context{386 state: stateError,387 err: errorf(ErrBranchEnd, node, 0, "{{%s}} branches end in different contexts: %v, %v", nodeName, a, b),388 }389}390// escapeBranch escapes a branch template node: "if", "range" and "with".391func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context {392 c0 := e.escapeList(c, n.List)393 if nodeName == "range" && c0.state != stateError {394 // The "true" branch of a "range" node can execute multiple times.395 // We check that executing n.List once results in the same context396 // as executing n.List twice.397 c1, _ := e.escapeListConditionally(c0, n.List, nil)398 c0 = join(c0, c1, n, nodeName)399 if c0.state == stateError {400 // Make clear that this is a problem on loop re-entry401 // since developers tend to overlook that branch when402 // debugging templates.403 c0.err.Line = n.Line404 c0.err.Description = "on range loop re-entry: " + c0.err.Description405 return c0406 }407 }408 c1 := e.escapeList(c, n.ElseList)409 return join(c0, c1, n, nodeName)410}411// escapeList escapes a list template node.412func (e *escaper) escapeList(c context, n *parse.ListNode) context {413 if n == nil {414 return c415 }416 for _, m := range n.Nodes {417 c = e.escape(c, m)418 }419 return c420}421// escapeListConditionally escapes a list node but only preserves edits and422// inferences in e if the inferences and output context satisfy filter.423// It returns the best guess at an output context, and the result of the filter424// which is the same as whether e was updated.425func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) {426 e1 := newEscaper(e.tmpl)427 // Make type inferences available to f.428 for k, v := range e.output {429 e1.output[k] = v430 }431 c = e1.escapeList(c, n)432 ok := filter != nil && filter(e1, c)433 if ok {434 // Copy inferences and edits from e1 back into e.435 for k, v := range e1.output {436 e.output[k] = v437 }438 for k, v := range e1.derived {439 e.derived[k] = v440 }441 for k, v := range e1.called {442 e.called[k] = v443 }444 for k, v := range e1.actionNodeEdits {445 e.editActionNode(k, v)446 }447 for k, v := range e1.templateNodeEdits {448 e.editTemplateNode(k, v)449 }450 for k, v := range e1.textNodeEdits {451 e.editTextNode(k, v)452 }453 }454 return c, ok455}456// escapeTemplate escapes a {{template}} call node.457func (e *escaper) escapeTemplate(c context, n *parse.TemplateNode) context {458 c, name := e.escapeTree(c, n, n.Name, n.Line)459 if name != n.Name {460 e.editTemplateNode(n, name)461 }462 return c463}464// escapeTree escapes the named template starting in the given context as465// necessary and returns its output context.466func (e *escaper) escapeTree(c context, node parse.Node, name string, line int) (context, string) {467 // Mangle the template name with the input context to produce a reliable468 // identifier.469 dname := c.mangle(name)470 e.called[dname] = true471 if out, ok := e.output[dname]; ok {472 // Already escaped.473 return out, dname474 }475 t := e.template(name)476 if t == nil {477 // Two cases: The template exists but is empty, or has never been mentioned at478 // all. Distinguish the cases in the error messages.479 if e.tmpl.set[name] != nil {480 return context{481 state: stateError,482 err: errorf(ErrNoSuchTemplate, node, line, "%q is an incomplete or empty template", name),483 }, dname484 }485 return context{486 state: stateError,487 err: errorf(ErrNoSuchTemplate, node, line, "no such template %q", name),488 }, dname489 }490 if dname != name {491 // Use any template derived during an earlier call to escapeTemplate492 // with different top level templates, or clone if necessary.493 dt := e.template(dname)494 if dt == nil {495 dt = template.New(dname)496 dt.Tree = &parse.Tree{Name: dname, Root: t.Root.CopyList()}497 e.derived[dname] = dt498 }499 t = dt500 }501 return e.computeOutCtx(c, t), dname502}503// computeOutCtx takes a template and its start context and computes the output504// context while storing any inferences in e.505func (e *escaper) computeOutCtx(c context, t *template.Template) context {506 // Propagate context over the body.507 c1, ok := e.escapeTemplateBody(c, t)508 if !ok {509 // Look for a fixed point by assuming c1 as the output context.510 if c2, ok2 := e.escapeTemplateBody(c1, t); ok2 {511 c1, ok = c2, true512 }513 // Use c1 as the error context if neither assumption worked.514 }515 if !ok && c1.state != stateError {516 return context{517 state: stateError,518 err: errorf(ErrOutputContext, t.Tree.Root, 0, "cannot compute output context for template %s", t.Name()),519 }520 }521 return c1522}523// escapeTemplateBody escapes the given template assuming the given output524// context, and returns the best guess at the output context and whether the525// assumption was correct.526func (e *escaper) escapeTemplateBody(c context, t *template.Template) (context, bool) {527 filter := func(e1 *escaper, c1 context) bool {528 if c1.state == stateError {529 // Do not update the input escaper, e.530 return false531 }532 if !e1.called[t.Name()] {533 // If t is not recursively called, then c1 is an534 // accurate output context.535 return true536 }537 // c1 is accurate if it matches our assumed output context.538 return c.eq(c1)539 }540 // We need to assume an output context so that recursive template calls541 // take the fast path out of escapeTree instead of infinitely recursing.542 // Naively assuming that the input context is the same as the output543 // works >90% of the time.544 e.output[t.Name()] = c545 return e.escapeListConditionally(c, t.Tree.Root, filter)546}547// delimEnds maps each delim to a string of characters that terminate it.548var delimEnds = [...]string{549 delimDoubleQuote: `"`,550 delimSingleQuote: "'",551 // Determined empirically by running the below in various browsers.552 // var div = document.createElement("DIV");553 // for (var i = 0; i < 0x10000; ++i) {554 // div.innerHTML = "<span title=x" + String.fromCharCode(i) + "-bar>";555 // if (div.getElementsByTagName("SPAN")[0].title.indexOf("bar") < 0)556 // document.write("<p>U+" + i.toString(16));557 // }558 delimSpaceOrTagEnd: " \t\n\f\r>",559}560var doctypeBytes = []byte("<!DOCTYPE")561// escapeText escapes a text template node.562func (e *escaper) escapeText(c context, n *parse.TextNode) context {563 s, written, i, b := n.Text, 0, 0, new(bytes.Buffer)564 for i != len(s) {565 c1, nread := contextAfterText(c, s[i:])566 i1 := i + nread567 if c.state == stateText || c.state == stateRCDATA {568 end := i1569 if c1.state != c.state {570 for j := end - 1; j >= i; j-- {571 if s[j] == '<' {572 end = j573 break574 }575 }576 }577 for j := i; j < end; j++ {578 if s[j] == '<' && !bytes.HasPrefix(bytes.ToUpper(s[j:]), doctypeBytes) {579 b.Write(s[written:j])580 b.WriteString("<")581 written = j + 1582 }583 }584 } else if isComment(c.state) && c.delim == delimNone {585 switch c.state {586 case stateJSBlockCmt:587 // http://es5.github.com/#x7.4:588 // "Comments behave like white space and are589 // discarded except that, if a MultiLineComment590 // contains a line terminator character, then591 // the entire comment is considered to be a592 // LineTerminator for purposes of parsing by593 // the syntactic grammar."594 if bytes.IndexAny(s[written:i1], "\n\r\u2028\u2029") != -1 {595 b.WriteByte('\n')596 } else {597 b.WriteByte(' ')598 }599 case stateCSSBlockCmt:600 b.WriteByte(' ')601 }602 written = i1603 }604 if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone {605 // Preserve the portion between written and the comment start.606 cs := i1 - 2607 if c1.state == stateHTMLCmt {608 // "<!--" instead of "/*" or "//"609 cs -= 2610 }611 b.Write(s[written:cs])612 written = i1613 }614 if i == i1 && c.state == c1.state {615 panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:]))616 }617 c, i = c1, i1618 }619 if written != 0 && c.state != stateError {620 if !isComment(c.state) || c.delim != delimNone {621 b.Write(n.Text[written:])622 }623 e.editTextNode(n, b.Bytes())624 }625 return c626}627// contextAfterText starts in context c, consumes some tokens from the front of628// s, then returns the context after those tokens and the unprocessed suffix.629func contextAfterText(c context, s []byte) (context, int) {630 if c.delim == delimNone {631 c1, i := tSpecialTagEnd(c, s)632 if i == 0 {633 // A special end tag (`</script>`) has been seen and634 // all content preceding it has been consumed.635 return c1, 0636 }637 // Consider all content up to any end tag.638 return transitionFunc[c.state](c, s[:i])639 }640 i := bytes.IndexAny(s, delimEnds[c.delim])641 if i == -1 {642 i = len(s)643 }644 if c.delim == delimSpaceOrTagEnd {645 // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state646 // lists the runes below as error characters.647 // Error out because HTML parsers may differ on whether648 // "<a id= onclick=f(" ends inside id's or onclick's value,649 // "<a class=`foo " ends inside a value,650 // "<a style=font:'Arial'" needs open-quote fixup.651 // IE treats '`' as a quotation character.652 if j := bytes.IndexAny(s[:i], "\"'<=`"); j >= 0 {653 return context{654 state: stateError,655 err: errorf(ErrBadHTML, nil, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]),656 }, len(s)657 }658 }659 if i == len(s) {660 // Remain inside the attribute.661 // Decode the value so non-HTML rules can easily handle662 // <button onclick="alert("Hi!")">663 // without having to entity decode token boundaries.664 for u := []byte(html.UnescapeString(string(s))); len(u) != 0; {665 c1, i1 := transitionFunc[c.state](c, u)666 c, u = c1, u[i1:]667 }668 return c, len(s)669 }670 if c.delim != delimSpaceOrTagEnd {671 // Consume any quote.672 i++673 }674 // On exiting an attribute, we discard all state information675 // except the state and element.676 return context{state: stateTag, element: c.element}, i677}678// editActionNode records a change to an action pipeline for later commit.679func (e *escaper) editActionNode(n *parse.ActionNode, cmds []string) {680 if _, ok := e.actionNodeEdits[n]; ok {681 panic(fmt.Sprintf("node %s shared between templates", n))682 }683 e.actionNodeEdits[n] = cmds684}685// editTemplateNode records a change to a {{template}} callee for later commit.686func (e *escaper) editTemplateNode(n *parse.TemplateNode, callee string) {687 if _, ok := e.templateNodeEdits[n]; ok {688 panic(fmt.Sprintf("node %s shared between templates", n))689 }690 e.templateNodeEdits[n] = callee691}692// editTextNode records a change to a text node for later commit.693func (e *escaper) editTextNode(n *parse.TextNode, text []byte) {694 if _, ok := e.textNodeEdits[n]; ok {695 panic(fmt.Sprintf("node %s shared between templates", n))696 }697 e.textNodeEdits[n] = text698}699// commit applies changes to actions and template calls needed to contextually700// autoescape content and adds any derived templates to the set.701func (e *escaper) commit() {702 for name := range e.output {703 e.template(name).Funcs(funcMap)704 }705 for _, t := range e.derived {706 if _, err := e.tmpl.text.AddParseTree(t.Name(), t.Tree); err != nil {707 panic("error adding derived template")708 }709 }710 for n, s := range e.actionNodeEdits {711 ensurePipelineContains(n.Pipe, s)712 }713 for n, name := range e.templateNodeEdits {714 n.Name = name715 }716 for n, s := range e.textNodeEdits {717 n.Text = s718 }719}720// template returns the named template given a mangled template name.721func (e *escaper) template(name string) *template.Template {722 t := e.tmpl.text.Lookup(name)723 if t == nil {724 t = e.derived[name]725 }726 return t727}728// Forwarding functions so that clients need only import this package...
mediatype_test.go
Source:mediatype_test.go
1// Copyright 2010 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4package mime5import (6 "reflect"7 "testing"8)9func TestConsumeToken(t *testing.T) {10 tests := [...][3]string{11 {"foo bar", "foo", " bar"},12 {"bar", "bar", ""},13 {"", "", ""},14 {" foo", "", " foo"},15 }16 for _, test := range tests {17 token, rest := consumeToken(test[0])18 expectedToken := test[1]19 expectedRest := test[2]20 if token != expectedToken {21 t.Errorf("expected to consume token '%s', not '%s' from '%s'",22 expectedToken, token, test[0])23 } else if rest != expectedRest {24 t.Errorf("expected to have left '%s', not '%s' after reading token '%s' from '%s'",25 expectedRest, rest, token, test[0])26 }27 }28}29func TestConsumeValue(t *testing.T) {30 tests := [...][3]string{31 {"foo bar", "foo", " bar"},32 {"bar", "bar", ""},33 {" bar ", "", " bar "},34 {`"My value"end`, "My value", "end"},35 {`"My value" end`, "My value", " end"},36 {`"\\" rest`, "\\", " rest"},37 {`"My \" value"end`, "My \" value", "end"},38 {`"\" rest`, "", `"\" rest`},39 }40 for _, test := range tests {41 value, rest := consumeValue(test[0])42 expectedValue := test[1]43 expectedRest := test[2]44 if value != expectedValue {45 t.Errorf("expected to consume value [%s], not [%s] from [%s]",46 expectedValue, value, test[0])47 } else if rest != expectedRest {48 t.Errorf("expected to have left [%s], not [%s] after reading value [%s] from [%s]",49 expectedRest, rest, value, test[0])50 }51 }52}53func TestConsumeMediaParam(t *testing.T) {54 tests := [...][4]string{55 {" ; foo=bar", "foo", "bar", ""},56 {"; foo=bar", "foo", "bar", ""},57 {";foo=bar", "foo", "bar", ""},58 {";FOO=bar", "foo", "bar", ""},59 {`;foo="bar"`, "foo", "bar", ""},60 {`;foo="bar"; `, "foo", "bar", "; "},61 {`;foo="bar"; foo=baz`, "foo", "bar", "; foo=baz"},62 {` ; boundary=----CUT;`, "boundary", "----CUT", ";"},63 {` ; key=value; blah="value";name="foo" `, "key", "value", `; blah="value";name="foo" `},64 {`; blah="value";name="foo" `, "blah", "value", `;name="foo" `},65 {`;name="foo" `, "name", "foo", ` `},66 }67 for _, test := range tests {68 param, value, rest := consumeMediaParam(test[0])69 expectedParam := test[1]70 expectedValue := test[2]71 expectedRest := test[3]72 if param != expectedParam {73 t.Errorf("expected to consume param [%s], not [%s] from [%s]",74 expectedParam, param, test[0])75 } else if value != expectedValue {76 t.Errorf("expected to consume value [%s], not [%s] from [%s]",77 expectedValue, value, test[0])78 } else if rest != expectedRest {79 t.Errorf("expected to have left [%s], not [%s] after reading [%s/%s] from [%s]",80 expectedRest, rest, param, value, test[0])81 }82 }83}84type mediaTypeTest struct {85 in string86 t string87 p map[string]string88}89func TestParseMediaType(t *testing.T) {90 // Convenience map initializer91 m := func(s ...string) map[string]string {92 sm := make(map[string]string)93 for i := 0; i < len(s); i += 2 {94 sm[s[i]] = s[i+1]95 }96 return sm97 }98 nameFoo := map[string]string{"name": "foo"}99 tests := []mediaTypeTest{100 {`form-data; name="foo"`, "form-data", nameFoo},101 {` form-data ; name=foo`, "form-data", nameFoo},102 {`FORM-DATA;name="foo"`, "form-data", nameFoo},103 {` FORM-DATA ; name="foo"`, "form-data", nameFoo},104 {` FORM-DATA ; name="foo"`, "form-data", nameFoo},105 {`form-data; key=value; blah="value";name="foo" `,106 "form-data",107 m("key", "value", "blah", "value", "name", "foo")},108 {`foo; key=val1; key=the-key-appears-again-which-is-bogus`,109 "", m()},110 // From RFC 2231:111 {`application/x-stuff; title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A`,112 "application/x-stuff",113 m("title", "This is ***fun***")},114 {`message/external-body; access-type=URL; ` +115 `URL*0="ftp://";` +116 `URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"`,117 "message/external-body",118 m("access-type", "URL",119 "url", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")},120 {`application/x-stuff; ` +121 `title*0*=us-ascii'en'This%20is%20even%20more%20; ` +122 `title*1*=%2A%2A%2Afun%2A%2A%2A%20; ` +123 `title*2="isn't it!"`,124 "application/x-stuff",125 m("title", "This is even more ***fun*** isn't it!")},126 // Tests from http://greenbytes.de/tech/tc2231/127 // TODO(bradfitz): add the rest of the tests from that site.128 {`attachment; filename="f\oo.html"`,129 "attachment",130 m("filename", "foo.html")},131 {`attachment; filename="\"quoting\" tested.html"`,132 "attachment",133 m("filename", `"quoting" tested.html`)},134 {`attachment; filename="Here's a semicolon;.html"`,135 "attachment",136 m("filename", "Here's a semicolon;.html")},137 {`attachment; foo="\"\\";filename="foo.html"`,138 "attachment",139 m("foo", "\"\\", "filename", "foo.html")},140 {`attachment; filename=foo.html`,141 "attachment",142 m("filename", "foo.html")},143 {`attachment; filename=foo.html ;`,144 "attachment",145 m("filename", "foo.html")},146 {`attachment; filename='foo.html'`,147 "attachment",148 m("filename", "'foo.html'")},149 {`attachment; filename="foo-%41.html"`,150 "attachment",151 m("filename", "foo-%41.html")},152 {`attachment; filename="foo-%\41.html"`,153 "attachment",154 m("filename", "foo-%41.html")},155 {`filename=foo.html`,156 "", m()},157 {`x=y; filename=foo.html`,158 "", m()},159 {`"foo; filename=bar;baz"; filename=qux`,160 "", m()},161 {`inline; attachment; filename=foo.html`,162 "", m()},163 {`attachment; filename="foo.html".txt`,164 "", m()},165 {`attachment; filename="bar`,166 "", m()},167 {`attachment; creation-date="Wed, 12 Feb 1997 16:29:51 -0500"`,168 "attachment",169 m("creation-date", "Wed, 12 Feb 1997 16:29:51 -0500")},170 {`foobar`, "foobar", m()},171 {`attachment; filename* =UTF-8''foo-%c3%a4.html`,172 "attachment",173 m("filename", "foo-ä.html")},174 {`attachment; filename*=UTF-8''A-%2541.html`,175 "attachment",176 m("filename", "A-%41.html")},177 {`attachment; filename*0="foo."; filename*1="html"`,178 "attachment",179 m("filename", "foo.html")},180 {`attachment; filename*0*=UTF-8''foo-%c3%a4; filename*1=".html"`,181 "attachment",182 m("filename", "foo-ä.html")},183 {`attachment; filename*0="foo"; filename*01="bar"`,184 "attachment",185 m("filename", "foo")},186 {`attachment; filename*0="foo"; filename*2="bar"`,187 "attachment",188 m("filename", "foo")},189 {`attachment; filename*1="foo"; filename*2="bar"`,190 "attachment", m()},191 {`attachment; filename*1="bar"; filename*0="foo"`,192 "attachment",193 m("filename", "foobar")},194 {`attachment; filename="foo-ae.html"; filename*=UTF-8''foo-%c3%a4.html`,195 "attachment",196 m("filename", "foo-ä.html")},197 {`attachment; filename*=UTF-8''foo-%c3%a4.html; filename="foo-ae.html"`,198 "attachment",199 m("filename", "foo-ä.html")},200 // Browsers also just send UTF-8 directly without RFC 2231,201 // at least when the source page is served with UTF-8.202 {`form-data; firstname="ÐÑÑд"; lastname="ФиÑпаÑÑик"`,203 "form-data",204 m("firstname", "ÐÑÑд", "lastname", "ФиÑпаÑÑик")},205 // Empty string used to be mishandled.206 {`foo; bar=""`, "foo", m("bar", "")},207 }208 for _, test := range tests {209 mt, params, err := ParseMediaType(test.in)210 if err != nil {211 if test.t != "" {212 t.Errorf("for input %q, unexpected error: %v", test.in, err)213 continue214 }215 continue216 }217 if g, e := mt, test.t; g != e {218 t.Errorf("for input %q, expected type %q, got %q",219 test.in, e, g)220 continue221 }222 if len(params) == 0 && len(test.p) == 0 {223 continue224 }225 if !reflect.DeepEqual(params, test.p) {226 t.Errorf("for input %q, wrong params.\n"+227 "expected: %#v\n"+228 " got: %#v",229 test.in, test.p, params)230 }231 }232}233type badMediaTypeTest struct {234 in string235 err string236}237var badMediaTypeTests = []badMediaTypeTest{238 {"bogus ;=========", "mime: invalid media parameter"},239 {"bogus/<script>alert</script>", "mime: expected token after slash"},240 {"bogus/bogus<script>alert</script>", "mime: unexpected content after media subtype"},241}242func TestParseMediaTypeBogus(t *testing.T) {243 for _, tt := range badMediaTypeTests {244 mt, params, err := ParseMediaType(tt.in)245 if err == nil {246 t.Errorf("ParseMediaType(%q) = nil error; want parse error", tt.in)247 continue248 }249 if err.Error() != tt.err {250 t.Errorf("ParseMediaType(%q) = err %q; want %q", tt.in, err.Error(), tt.err)251 }252 if params != nil {253 t.Errorf("ParseMediaType(%q): got non-nil params on error", tt.in)254 }255 if mt != "" {256 t.Errorf("ParseMediaType(%q): got non-empty media type string on error", tt.in)257 }258 }259}260type formatTest struct {261 typ string262 params map[string]string263 want string264}265var formatTests = []formatTest{266 {"noslash", map[string]string{"X": "Y"}, "noslash; x=Y"}, // e.g. Content-Disposition values (RFC 2183); issue 11289267 {"foo bar/baz", nil, ""},268 {"foo/bar baz", nil, ""},269 {"foo/BAR", nil, "foo/bar"},270 {"foo/BAR", map[string]string{"X": "Y"}, "foo/bar; x=Y"},271 {"foo/BAR", map[string]string{"space": "With space"}, `foo/bar; space="With space"`},272 {"foo/BAR", map[string]string{"quote": `With "quote`}, `foo/bar; quote="With \"quote"`},273 {"foo/BAR", map[string]string{"bslash": `With \backslash`}, `foo/bar; bslash="With \\backslash"`},274 {"foo/BAR", map[string]string{"both": `With \backslash and "quote`}, `foo/bar; both="With \\backslash and \"quote"`},275 {"foo/BAR", map[string]string{"": "empty attribute"}, ""},276 {"foo/BAR", map[string]string{"bad attribute": "baz"}, ""},277 {"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, ""},278 {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"},279 {"foo/bar", map[string]string{"0": "'", "9": "'"}, "foo/bar; 0='; 9='"},280 {"foo", map[string]string{"bar": ""}, `foo; bar=""`},281}282func TestFormatMediaType(t *testing.T) {283 for i, tt := range formatTests {284 got := FormatMediaType(tt.typ, tt.params)285 if got != tt.want {286 t.Errorf("%d. FormatMediaType(%q, %v) = %q; want %q", i, tt.typ, tt.params, got, tt.want)287 }288 }289}...
html.go
Source:html.go
...7)8func init() {9 Register("html", parseHTML)10}11func parseHTML(ctx *Context, fileName string, lineno int, text string) (Elem, error) {12 p := strings.Fields(text)13 if len(p) != 2 {14 return nil, errors.New("invalid .html args")15 }16 name := filepath.Join(filepath.Dir(fileName), p[1])17 b, err := ctx.ReadFile(name)18 if err != nil {19 return nil, err20 }21 return HTML{text, template.HTML(b)}, nil22}23type HTML struct {24 Cmd string // original command from present source25 template.HTML26}27func (s HTML) PresentCmd() string { return s.Cmd }28func (s HTML) TemplateName() string { return "html" }...
Name
Using AI Code Generation
1import (2func main() {3 doc, err := html.Parse(os.Stdin)4 if err != nil {5 fmt.Fprintf(os.Stderr, "findlinks1: %v\n", err)6 os.Exit(1)7 }8 for _, link := range visit(nil, doc) {9 fmt.Println(link)10 }11}12func visit(links []string, n *html.Node) []string {13 if n.Type == html.ElementNode {14 links = append(links, n.Data)15 }16 for c := n.FirstChild; c != nil; c = c.NextSibling {17 links = visit(links, c)18 }19}
Name
Using AI Code Generation
1import (2func main() {3 doc, err := html.Parse(os.Stdin)4 if err != nil {5 log.Fatal(err)6 }7 for _, link := range visit(nil, doc) {8 fmt.Println(link)9 }10}11func visit(links []string, n *html.Node) []string {12 if n.Type == html.ElementNode && n.Data == "a" {13 for _, a := range n.Attr {14 if a.Key == "href" {15 links = append(links, a.Val)16 }17 }18 }19 for c := n.FirstChild; c != nil; c = c.NextSibling {20 links = visit(links, c)21 }22}
Name
Using AI Code Generation
1import (2func main() {3 doc, err := html.Parse(os.Stdin)4 if err != nil {5 fmt.Fprintf(os.Stderr, "findlink1: %v\n", err)6 os.Exit(1)7 }8 for _, link := range visit(nil, doc) {9 fmt.Println(link)10 }11}12func visit(links []string, n *html.Node) []string {13 if n.Type == html.ElementNode && n.Data == "a" {14 for _, a := range n.Attr {15 fmt.Println(a.Key)16 if a.Key == "href" {17 links = append(links, a.Val)18 fmt.Println(a.Key, a.Val)19 }20 }21 }22 if n.FirstChild != nil {23 links = visit(links, n.FirstChild)24 }25 if n.NextSibling != nil {26 links = visit(links, n.NextSibling)27 }28}29import (30func main() {31 doc, err := html.Parse(os.Stdin)32 if err != nil {33 fmt.Fprintf(os.Stderr, "findlink2: %v\n", err)34 os.Exit(1)35 }36 for _, link := range visit(nil, doc) {37 fmt.Println(link)38 }39}40func visit(links []string, n *html.Node) []string {41 if n.Type == html.ElementNode && n.Data == "a" {42 for _, a := range n.Attr {43 fmt.Println(a.Key)44 if a.Key == "href" {45 links = append(links, a.Val)46 fmt.Println(a.Key, a.Val)47 }48 }49 }50 if n.FirstChild != nil {51 links = visit(links, n.FirstChild)52 }53 if n.NextSibling != nil {54 links = visit(links, n.NextSibling)55 }56}57import (58func main() {59 doc, err := html.Parse(os.Stdin)60 if err != nil {61 fmt.Fprintf(os.Stderr, "findlink
Name
Using AI Code Generation
1import (2func main() {3 doc, err := html.Parse(os.Stdin)4 if err != nil {5 fmt.Fprintf(os.Stderr, "findLinks1:%v\n", err)6 os.Exit(1)7 }8 for _, link := range visit(nil, doc) {9 fmt.Println(link)10 }11}12func visit(links []string, n *html.Node) []string {13 }14 }15 }16 }17}
Name
Using AI Code Generation
1import (2func main() {3 resp, err := http.Get(url)4 if err != nil {5 fmt.Fprintf(os.Stderr, "error: %v\n", err)6 os.Exit(1)7 }8 doc, err := html.Parse(resp.Body)9 if err != nil {10 fmt.Fprintf(os.Stderr, "error: %v\n", err)11 os.Exit(1)12 }13 forEachNode(doc, startElement, endElement)14}15func forEachNode(n *html.Node, pre, post func(n *html.Node, w io.Writer)) {16 if pre != nil {17 pre(n, os.Stdout)18 }19 for c := n.FirstChild; c != nil; c = c.NextSibling {20 forEachNode(c, pre, post)21 }22 if post != nil {23 post(n, os.Stdout)24 }25}26func startElement(n *html.Node, w io.Writer) {27 if n.Type == html.ElementNode {28 fmt.Fprintf(w, "<%s", n.Data)29 for _, a := range n.Attr {30 fmt.Fprintf(w, " %s='%s'", a.Key, a.Val)31 }32 if n.FirstChild == nil {33 fmt.Fprintf(w, "/>\n")34 } else {35 fmt.Fprintf(w, ">\n")36 }37 } else if n.Type == html.TextNode {38 text := strings.TrimSpace(n.Data)39 if text != "" {40 fmt.Fprintf(w, "%s\n", text)41 }42 }43}44func endElement(n *html.Node, w io.Writer) {45 if n.Type == html.ElementNode && n.FirstChild != nil {46 fmt.Fprintf(w, "</%s>\n", n.Data)47 }48}
Name
Using AI Code Generation
1import (2func main() {3 page, _ := ioutil.ReadAll(res.Body)4 res.Body.Close()5 doc, _ := html.Parse(string(page))6 fmt.Println(doc.FirstChild.Data)7}
Name
Using AI Code Generation
1import (2func main() {3 if err != nil {4 fmt.Println("Error: ", err)5 os.Exit(1)6 }7 io.Copy(os.Stdout, resp.Body)8}
Name
Using AI Code Generation
1import (2func main() {3 fmt.Println(resp.Status)4 fmt.Println(resp.Header.Get("Content-Type"))5 fmt.Println(resp.Header.Get("Date"))6 fmt.Println(resp.Header.Get("Server"))7 fmt.Println(resp.Header.Get("Last-Modified"))8 fmt.Println(resp.Header.Get("Content-Length"))9 fmt.Println(resp.Header.Get("Cache-Control"))10 fmt.Println(resp.Header.Get("Expires"))11 fmt.Println(resp.Header.Get("Content-Encoding"))12 fmt.Println(resp.Header.Get("X-Frame-Options"))13 fmt.Println(resp.Header.Get("X-XSS-Protection"))14 fmt.Println(resp.Header.Get("X-Content-Type-Options"))15 fmt.Println(resp.Header.Get("Alt-Svc"))16 fmt.Println(resp.Header.Get("Accept-Ranges"))17 fmt.Println(resp.Header.Get("Vary"))18 fmt.Println(resp.Header.Get("Transfer-Encoding"))19}
Name
Using AI Code Generation
1import (2func main() {3 doc, err := html.Parse(s)4 if err != nil {5 log.Fatal(err)6 }7 fmt.Println(doc.FirstChild.Data)8 fmt.Println(doc.FirstChild.NextSibling.Data)9 fmt.Println(doc.FirstChild.NextSibling.NextSibling.Data)10 fmt.Println(doc.FirstChild.NextSibling.NextSibling.FirstChild.Data)11 fmt.Println(doc.FirstChild.NextSibling.NextSibling.FirstChild.NextSibling.Data)12 fmt.Println(doc.FirstChild.NextSibling.NextSibling.FirstChild.NextSibling.NextSibling.Data)13}
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!