Best K6 code snippet using html.Action
escape.go
Source:escape.go
...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) {...
page_actions_test.go
Source:page_actions_test.go
...12 "github.com/stretchr/testify/require"13 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"14 "github.com/projectdiscovery/nuclei/v2/pkg/types"15)16func TestActionNavigate(t *testing.T) {17 response := `18 <html>19 <head>20 <title>Nuclei Test Page</title>21 </head>22 <body>23 <h1>Nuclei Test</h1>24 </body>25 </html>`26 actions := []*Action{{ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}}, {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}}}27 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {28 require.Nil(t, err, "could not run page actions")29 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")30 })31}32func TestActionScript(t *testing.T) {33 response := `34 <html>35 <head>36 <title>Nuclei Test Page</title>37 </head>38 <body>Nuclei Test Page</body>39 <script>window.test = 'some-data';</script>40 </html>`41 timeout := 2 * time.Second42 t.Run("run-and-results", func(t *testing.T) {43 actions := []*Action{44 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},45 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},46 {ActionType: ActionTypeHolder{ActionType: ActionScript}, Name: "test", Data: map[string]string{"code": "window.test"}},47 }48 testHeadlessSimpleResponse(t, response, actions, timeout, func(page *Page, err error, out map[string]string) {49 require.Nil(t, err, "could not run page actions")50 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")51 require.Equal(t, "some-data", out["test"], "could not run js and get results correctly")52 })53 })54 t.Run("hook", func(t *testing.T) {55 actions := []*Action{56 {ActionType: ActionTypeHolder{ActionType: ActionScript}, Data: map[string]string{"code": "window.test = 'some-data';", "hook": "true"}},57 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},58 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},59 {ActionType: ActionTypeHolder{ActionType: ActionScript}, Name: "test", Data: map[string]string{"code": "window.test"}},60 }61 testHeadlessSimpleResponse(t, response, actions, timeout, func(page *Page, err error, out map[string]string) {62 require.Nil(t, err, "could not run page actions")63 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")64 require.Equal(t, "some-data", out["test"], "could not run js and get results correctly with js hook")65 })66 })67}68func TestActionClick(t *testing.T) {69 response := `70 <html>71 <head>72 <title>Nuclei Test Page</title>73 </head>74 <body>Nuclei Test Page</body>75 <button onclick='this.setAttribute("a", "ok")'>click me</button>76 </html>`77 actions := []*Action{78 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},79 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},80 {ActionType: ActionTypeHolder{ActionType: ActionClick}, Data: map[string]string{"selector": "button"}}, // Use css selector for clicking81 }82 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {83 require.Nil(t, err, "could not run page actions")84 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")85 el := page.Page().MustElement("button")86 val := el.MustAttribute("a")87 require.Equal(t, "ok", *val, "could not click button")88 })89}90func TestActionRightClick(t *testing.T) {91 response := `92 <html>93 <head>94 <title>Nuclei Test Page</title>95 </head>96 <body>Nuclei Test Page</body>97 <button id="test" onrightclick=''>click me</button>98 <script>99 elm = document.getElementById("test");100 elm.onmousedown = function(event) {101 if (event.which == 3) {102 elm.setAttribute("a", "ok")103 }104 }105 </script>106 </html>`107 actions := []*Action{108 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},109 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},110 {ActionType: ActionTypeHolder{ActionType: ActionRightClick}, Data: map[string]string{"selector": "button"}}, // Use css selector for clicking111 }112 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {113 require.Nil(t, err, "could not run page actions")114 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")115 el := page.Page().MustElement("button")116 val := el.MustAttribute("a")117 require.Equal(t, "ok", *val, "could not click button")118 })119}120func TestActionTextInput(t *testing.T) {121 response := `122 <html>123 <head>124 <title>Nuclei Test Page</title>125 </head>126 <body>Nuclei Test Page</body>127 <input type="text" onchange="this.setAttribute('event', 'input-change')">128 </html>`129 actions := []*Action{130 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},131 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},132 {ActionType: ActionTypeHolder{ActionType: ActionTextInput}, Data: map[string]string{"selector": "input", "value": "test"}},133 }134 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {135 require.Nil(t, err, "could not run page actions")136 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")137 el := page.Page().MustElement("input")138 val := el.MustAttribute("event")139 require.Equal(t, "input-change", *val, "could not get input change")140 require.Equal(t, "test", el.MustText(), "could not get input change value")141 })142}143func TestActionHeadersChange(t *testing.T) {144 actions := []*Action{145 {ActionType: ActionTypeHolder{ActionType: ActionSetHeader}, Data: map[string]string{"part": "request", "key": "Test", "value": "Hello"}},146 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},147 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},148 }149 handler := func(w http.ResponseWriter, r *http.Request) {150 if r.Header.Get("Test") == "Hello" {151 _, _ = fmt.Fprintln(w, `found`)152 }153 }154 testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {155 require.Nil(t, err, "could not run page actions")156 require.Equal(t, "found", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")157 })158}159func TestActionScreenshot(t *testing.T) {160 response := `161 <html>162 <head>163 <title>Nuclei Test Page</title>164 </head>165 <body>Nuclei Test Page</body>166 </html>`167 actions := []*Action{168 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},169 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},170 {ActionType: ActionTypeHolder{ActionType: ActionScreenshot}, Data: map[string]string{"to": "test"}},171 }172 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {173 require.Nil(t, err, "could not run page actions")174 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")175 el := page.Page()176 require.FileExists(t, "test.png", el, "could not get screenshot file")177 _ = os.Remove("test.png")178 })179}180func TestActionTimeInput(t *testing.T) {181 response := `182 <html>183 <head>184 <title>Nuclei Test Page</title>185 </head>186 <body>Nuclei Test Page</body>187 <input type="date">188 </html>`189 actions := []*Action{190 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},191 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},192 {ActionType: ActionTypeHolder{ActionType: ActionTimeInput}, Data: map[string]string{"selector": "input", "value": "2006-01-02T15:04:05Z"}},193 }194 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {195 require.Nil(t, err, "could not run page actions")196 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")197 el := page.Page().MustElement("input")198 require.Equal(t, "2006-01-02", el.MustText(), "could not get input time value")199 })200}201func TestActionSelectInput(t *testing.T) {202 response := `203 <html>204 <head>205 <title>Nuclei Test Page</title>206 </head>207 <body>208 <select name="test" id="test">209 <option value="test1">Test1</option>210 <option value="test2">Test2</option>211 </select>212 </body>213 </html>`214 actions := []*Action{215 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},216 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},217 {ActionType: ActionTypeHolder{ActionType: ActionSelectInput}, Data: map[string]string{"by": "x", "xpath": "//select[@id='test']", "value": "Test2", "selected": "true"}},218 }219 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {220 require.Nil(t, err, "could not run page actions")221 el := page.Page().MustElement("select")222 require.Equal(t, "Test2", el.MustText(), "could not get input change value")223 })224}225func TestActionFilesInput(t *testing.T) {226 response := `227 <html>228 <head>229 <title>Nuclei Test Page</title>230 </head>231 <body>Nuclei Test Page</body>232 <input type="file">233 </html>`234 actions := []*Action{235 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},236 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},237 {ActionType: ActionTypeHolder{ActionType: ActionFilesInput}, Data: map[string]string{"selector": "input", "value": "test1.pdf"}},238 }239 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {240 require.Nil(t, err, "could not run page actions")241 require.Equal(t, "Nuclei Test Page", page.Page().MustInfo().Title, "could not navigate correctly")242 el := page.Page().MustElement("input")243 require.Equal(t, "C:\\fakepath\\test1.pdf", el.MustText(), "could not get input file")244 })245}246func TestActionWaitLoad(t *testing.T) {247 response := `248 <html>249 <head>250 <title>Nuclei Test Page</title>251 </head>252 <button id="test">Wait for me!</button>253 <script>254 window.onload = () => document.querySelector('#test').style.color = 'red';255 </script>256 </html>`257 actions := []*Action{258 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},259 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},260 }261 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {262 require.Nil(t, err, "could not run page actions")263 el := page.Page().MustElement("button")264 style, attributeErr := el.Attribute("style")265 require.Nil(t, attributeErr)266 require.Equal(t, "color: red;", *style, "could not get color")267 })268}269func TestActionGetResource(t *testing.T) {270 response := `271 <html>272 <head>273 <title>Nuclei Test Page</title>274 </head>275 <body>276 <img id="test" src="https://nuclei.projectdiscovery.io/static/logo.png">277 </body>278 </html>`279 actions := []*Action{280 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},281 {ActionType: ActionTypeHolder{ActionType: ActionGetResource}, Data: map[string]string{"by": "x", "xpath": "//img[@id='test']"}, Name: "src"},282 }283 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {284 require.Nil(t, err, "could not run page actions")285 require.Equal(t, len(out["src"]), 3159, "could not find resource")286 })287}288func TestActionExtract(t *testing.T) {289 response := `290 <html>291 <head>292 <title>Nuclei Test Page</title>293 </head>294 <button id="test">Wait for me!</button>295 </html>`296 actions := []*Action{297 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},298 {ActionType: ActionTypeHolder{ActionType: ActionExtract}, Data: map[string]string{"by": "x", "xpath": "//button[@id='test']"}, Name: "extract"},299 }300 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {301 require.Nil(t, err, "could not run page actions")302 require.Equal(t, "Wait for me!", out["extract"], "could not extract text")303 })304}305func TestActionSetMethod(t *testing.T) {306 response := `307 <html>308 <head>309 <title>Nuclei Test Page</title>310 </head>311 </html>`312 actions := []*Action{313 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},314 {ActionType: ActionTypeHolder{ActionType: ActionSetMethod}, Data: map[string]string{"part": "x", "method": "SET"}},315 }316 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {317 require.Nil(t, err, "could not run page actions")318 require.Equal(t, "SET", page.rules[0].Args["method"], "could not find resource")319 })320}321func TestActionAddHeader(t *testing.T) {322 actions := []*Action{323 {ActionType: ActionTypeHolder{ActionType: ActionAddHeader}, Data: map[string]string{"part": "request", "key": "Test", "value": "Hello"}},324 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},325 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},326 }327 handler := func(w http.ResponseWriter, r *http.Request) {328 if r.Header.Get("Test") == "Hello" {329 _, _ = fmt.Fprintln(w, `found`)330 }331 }332 testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {333 require.Nil(t, err, "could not run page actions")334 require.Equal(t, "found", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")335 })336}337func TestActionDeleteHeader(t *testing.T) {338 actions := []*Action{339 {ActionType: ActionTypeHolder{ActionType: ActionAddHeader}, Data: map[string]string{"part": "request", "key": "Test1", "value": "Hello"}},340 {ActionType: ActionTypeHolder{ActionType: ActionAddHeader}, Data: map[string]string{"part": "request", "key": "Test2", "value": "World"}},341 {ActionType: ActionTypeHolder{ActionType: ActionDeleteHeader}, Data: map[string]string{"part": "request", "key": "Test2"}},342 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},343 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},344 }345 handler := func(w http.ResponseWriter, r *http.Request) {346 if r.Header.Get("Test1") == "Hello" && r.Header.Get("Test2") == "" {347 _, _ = fmt.Fprintln(w, `header deleted`)348 }349 }350 testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {351 require.Nil(t, err, "could not run page actions")352 require.Equal(t, "header deleted", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not delete header correctly")353 })354}355func TestActionSetBody(t *testing.T) {356 actions := []*Action{357 {ActionType: ActionTypeHolder{ActionType: ActionSetBody}, Data: map[string]string{"part": "request", "body": "hello"}},358 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},359 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},360 }361 handler := func(w http.ResponseWriter, r *http.Request) {362 body, _ := ioutil.ReadAll(r.Body)363 _, _ = fmt.Fprintln(w, string(body))364 }365 testHeadless(t, actions, 20*time.Second, handler, func(page *Page, err error, out map[string]string) {366 require.Nil(t, err, "could not run page actions")367 require.Equal(t, "hello", strings.ToLower(strings.TrimSpace(page.Page().MustElement("html").MustText())), "could not set header correctly")368 })369}370func TestActionKeyboard(t *testing.T) {371 response := `372 <html>373 <head>374 <title>Nuclei Test Page</title>375 </head>376 <body>377 <input type="text" name="test" id="test">378 </body>379 </html>`380 actions := []*Action{381 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},382 {ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},383 {ActionType: ActionTypeHolder{ActionType: ActionClick}, Data: map[string]string{"selector": "input"}},384 {ActionType: ActionTypeHolder{ActionType: ActionKeyboard}, Data: map[string]string{"keys": "Test2"}},385 }386 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {387 require.Nil(t, err, "could not run page actions")388 el := page.Page().MustElement("input")389 require.Equal(t, "Test2", el.MustText(), "could not get input change value")390 })391}392func TestActionSleep(t *testing.T) {393 response := `394 <html>395 <head>396 <title>Nuclei Test Page</title>397 </head>398 <button style="display:none" id="test">Wait for me!</button>399 <script>400 setTimeout(() => document.querySelector('#test').style.display = '', 1000);401 </script>402 </html>`403 actions := []*Action{404 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},405 {ActionType: ActionTypeHolder{ActionType: ActionSleep}, Data: map[string]string{"duration": "2"}},406 }407 testHeadlessSimpleResponse(t, response, actions, 20*time.Second, func(page *Page, err error, out map[string]string) {408 require.Nil(t, err, "could not run page actions")409 require.True(t, page.Page().MustElement("button").MustVisible(), "could not get button")410 })411}412func TestActionWaitVisible(t *testing.T) {413 response := `414 <html>415 <head>416 <title>Nuclei Test Page</title>417 </head>418 <button style="display:none" id="test">Wait for me!</button>419 <script>420 setTimeout(() => document.querySelector('#test').style.display = '', 1000);421 </script>422 </html>`423 actions := []*Action{424 {ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},425 {ActionType: ActionTypeHolder{ActionType: ActionWaitVisible}, Data: map[string]string{"by": "x", "xpath": "//button[@id='test']"}},426 }427 t.Run("wait for an element being visible", func(t *testing.T) {428 testHeadlessSimpleResponse(t, response, actions, 2*time.Second, func(page *Page, err error, out map[string]string) {429 require.Nil(t, err, "could not run page actions")430 page.Page().MustElement("button").MustVisible()431 })432 })433 t.Run("timeout because of element not visible", func(t *testing.T) {434 testHeadlessSimpleResponse(t, response, actions, time.Second/2, func(page *Page, err error, out map[string]string) {435 require.Error(t, err)436 require.Contains(t, err.Error(), "Element did not appear in the given amount of time")437 })438 })439}440func testHeadlessSimpleResponse(t *testing.T, response string, actions []*Action, timeout time.Duration, assert func(page *Page, pageErr error, out map[string]string)) {441 t.Helper()442 testHeadless(t, actions, timeout, func(w http.ResponseWriter, r *http.Request) {443 _, _ = fmt.Fprintln(w, response)444 }, assert)445}446func testHeadless(t *testing.T, actions []*Action, timeout time.Duration, handler func(w http.ResponseWriter, r *http.Request), assert func(page *Page, pageErr error, extractedData map[string]string)) {447 t.Helper()448 _ = protocolstate.Init(&types.Options{})449 browser, err := New(&types.Options{ShowBrowser: false})450 require.Nil(t, err, "could not create browser")451 defer browser.Close()452 instance, err := browser.NewInstance()453 require.Nil(t, err, "could not create browser instance")454 defer instance.Close()455 ts := httptest.NewServer(http.HandlerFunc(handler))456 defer ts.Close()457 parsed, err := url.Parse(ts.URL)458 require.Nil(t, err, "could not parse URL")459 extractedData, page, err := instance.Run(parsed, actions, timeout)460 assert(page, err, extractedData)...
apps_test.go
Source:apps_test.go
...63 found := man.FindIntent("PICK", "io.cozy.files")64 assert.Nil(t, found)65 man.Intents = []Intent{66 {67 Action: "PICK",68 Types: []string{"io.cozy.contacts", "io.cozy.calendars"},69 Href: "/pick",70 },71 {72 Action: "OPEN",73 Types: []string{"io.cozy.files", "image/gif"},74 Href: "/open",75 },76 {77 Action: "EDIT",78 Types: []string{"image/*"},79 Href: "/open",80 },81 }82 found = man.FindIntent("PICK", "io.cozy.files")83 assert.Nil(t, found)84 found = man.FindIntent("OPEN", "io.cozy.contacts")85 assert.Nil(t, found)86 found = man.FindIntent("PICK", "io.cozy.contacts")87 assert.NotNil(t, found)88 assert.Equal(t, "PICK", found.Action)89 found = man.FindIntent("OPEN", "io.cozy.files")90 assert.NotNil(t, found)91 assert.Equal(t, "OPEN", found.Action)92 found = man.FindIntent("open", "io.cozy.files")93 assert.NotNil(t, found)94 assert.Equal(t, "OPEN", found.Action)95 found = man.FindIntent("OPEN", "image/gif")96 assert.NotNil(t, found)97 assert.Equal(t, "OPEN", found.Action)98 found = man.FindIntent("EDIT", "image/gif")99 assert.NotNil(t, found)100 assert.Equal(t, "EDIT", found.Action)101 man.Intents = []Intent{102 {103 Action: "PICK",104 Href: "/pick",105 },106 }107 found = man.FindIntent("PICK", "io.cozy.files")108 assert.Nil(t, found)109}...
Action
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", handler)4 http.ListenAndServe(":8080", nil)5}6func handler(w http.ResponseWriter, r *http.Request) {7 fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))8}9import (10func main() {11 http.HandleFunc("/", handler)12 http.ListenAndServe(":8080", nil)13}14func handler(w http.ResponseWriter, r *http.Request) {15 t, _ := template.ParseFiles("index.html")16 t.Execute(w, nil)17}
Action
Using AI Code Generation
1func main() {2 http.HandleFunc("/", html.Action)3 http.ListenAndServe(":8080", nil)4}5func main() {6 http.HandleFunc("/", html.Action)7 http.ListenAndServe(":8080", nil)8}9func main() {10 http.HandleFunc("/", html.Action)11 http.ListenAndServe(":8080", nil)12}13func main() {14 http.HandleFunc("/", html.Action)15 http.ListenAndServe(":8080", nil)16}17func main() {18 http.HandleFunc("/", html.Action)19 http.ListenAndServe(":8080", nil)20}21func main() {22 http.HandleFunc("/", html.Action)23 http.ListenAndServe(":8080", nil)24}25func main() {26 http.HandleFunc("/", html.Action)27 http.ListenAndServe(":8080", nil)28}29func main() {30 http.HandleFunc("/", html.Action)31 http.ListenAndServe(":8080", nil)32}33func main() {34 http.HandleFunc("/", html.Action)35 http.ListenAndServe(":8080", nil)36}37func main() {38 http.HandleFunc("/", html.Action)39 http.ListenAndServe(":8080", nil)40}41func main() {42 http.HandleFunc("/", html.Action)43 http.ListenAndServe(":8080", nil)44}45func main() {46 http.HandleFunc("/", html.Action)47 http.ListenAndServe(":8080", nil)48}49func main() {50 http.HandleFunc("/", html.Action)51 http.ListenAndServe(":8080", nil)52}
Action
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {4 log.Println("request received")5 w.Header().Set("Content-Type", "text/html")6 w.Write([]byte(`7 })8 http.HandleFunc("/process", func(w http.ResponseWriter, r *http.Request) {9 log.Println("process request received")10 w.Header().Set("Content-Type", "text/html")11 name := r.FormValue("name")12 w.Write([]byte(`13 ` + html.EscapeString(name) + `14 })15 http.ListenAndServe(":8080", nil)16}17import (18type User struct {19}20func main() {21 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {22 log.Println("request received")23 w.Header().Set("Content-Type", "text/html")24 tmpl, err := template.ParseFiles("tmpl.html")25 if err != nil {26 panic(err)27 }28 user := User{29 }30 tmpl.Execute(w, user)31 })32 http.HandleFunc("/process", func(w http.ResponseWriter, r *http.Request) {33 log.Println("process request received")34 w.Header().Set("Content-Type", "text/html")35 tmpl, err := template.ParseFiles("tmpl.html")36 if err != nil {37 panic(err)38 }39 user := User{40 FirstName: r.FormValue("firstName"),41 LastName: r.FormValue("lastName"),42 }43 tmpl.Execute(w
Action
Using AI Code Generation
1import (2func main() {3}4import (5func main() {6 t, err := template.New("foo").Parse("{{.}}")7 if err != nil {8 panic(err)9 }10 err = t.Execute(os.Stdout, "<script>alert('you have been pwned')</script>")11 if err != nil {12 panic(err)13 }14}15import (16func main() {17 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {18 fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))19 })20 log.Fatal(http.ListenAndServe(":8080", nil))21}22import (23func main() {24 jar, err := cookiejar.New(nil)25 if err != nil {26 panic(err)27 }28 client := http.Client{29 }30 if err != nil {31 panic(err)32 }33}34import (35func main() {36 f, err := os.Open("file.txt")37 if err != nil {38 panic(err)39 }40 defer f.Close()41 fs := http.FileServer(http.File(f))42 log.Fatal(http.ListenAndServe(":8080", fs))43}44import (
Action
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {4 fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))5 })6 http.ListenAndServe(":8080", nil)7}8import (9func main() {10 http.HandleFunc("/", handler)11 http.ListenAndServe(":8080", nil)12}13func handler(w http.ResponseWriter, r *http.Request) {14 fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))15}16import (17func main() {18 http.HandleFunc("/", handler)19 http.ListenAndServe(":8080", nil)20}21func handler(w http.ResponseWriter, r *http.Request) {22 fmt.Fprintf(w, "Hello, %q", r.URL.Path)23}24import (25func main() {26 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {27 fmt.Fprintf(w, "Hello, %q", r.URL.Path)28 })29 http.ListenAndServe(":8080", nil)30}31import (
Action
Using AI Code Generation
1import (2func main() {3 fmt.Println(html.EscapeString(str))4}5import (6func main() {7 fmt.Println(html.EscapeString(str))8}9import (10func main() {11 fmt.Println(html.EscapeString(str))12}13import (14func main() {15 fmt.Println(html.EscapeString(str))16}17import (18func main() {19 fmt.Println(html.EscapeString(str))20}21import (22func main() {23 fmt.Println(html.EscapeString(str))24}25import (26func main() {27 fmt.Println(html.EscapeString(str))28}29import (30func main() {31 fmt.Println(html.EscapeString(str))32}
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!!