Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 7 additions & 19 deletions internal/js/modules/k6/browser/common/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ type Connection struct {
onTargetAttachedToTarget func(*target.EventAttachedToTarget) bool
}

var globalPool = new(sync.Pool) //nolint:gochecknoglobals

// NewConnection creates a new browser.
func NewConnection(
ctx context.Context,
Expand All @@ -155,6 +157,7 @@ func NewConnection(
TLSClientConfig: tlsConfig,
WriteBufferSize: wsWriteBufferSize,
ReadBufferSize: wsWriteBufferSize,
WriteBufferPool: globalPool,
}

ctx, cancelCtx := context.WithCancel(ctx)
Expand Down Expand Up @@ -331,16 +334,14 @@ func (c *Connection) findTargetIDForLog(id target.SessionID) target.ID {
func (c *Connection) recvLoop() {
c.logger.Debugf("Connection:recvLoop", "wsURL:%q", c.wsURL)
for {
_, buf, err := c.conn.ReadMessage()
_, reader, err := c.conn.NextReader()
if err != nil {
c.handleIOError(err)
return
}

c.logger.Tracef("cdp:recv", "<- %s", buf)

var msg cdproto.Message
err = jsonv2.Unmarshal(buf, &msg, defaultJSONV2Options)
err = jsonv2.UnmarshalRead(reader, &msg, defaultJSONV2Options)
if err != nil {
select {
case c.errorCh <- err:
Expand Down Expand Up @@ -541,26 +542,13 @@ func (c *Connection) sendLoop() {
for {
select {
case msg := <-c.sendCh:
buf, err := jsonv2.Marshal(msg, defaultJSONV2Options)
if err != nil {
sid := msg.SessionID
tid := c.findTargetIDForLog(sid)
select {
case c.errorCh <- err:
c.logger.Debugf("Connection:sendLoop:c.errorCh <- err", "sid:%v tid:%v wsURL:%q err:%v", sid, tid, c.wsURL, err)
case <-c.done:
c.logger.Debugf("Connection:sendLoop:<-c.done", "sid:%v tid:%v wsURL:%q", sid, tid, c.wsURL)
return
}
}

c.logger.Tracef("cdp:send", "-> %s", buf)
writer, err := c.conn.NextWriter(websocket.TextMessage)
if err != nil {
c.handleIOError(err)
return
}
if _, err := writer.Write(buf); err != nil {
err = jsonv2.MarshalWrite(writer, msg, defaultJSONV2Options)
if err != nil {
c.handleIOError(err)
return
}
Expand Down
20 changes: 6 additions & 14 deletions internal/js/modules/k6/browser/common/execution_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
_ "embed"
"errors"
"fmt"
"regexp"
"sync"

"go.k6.io/k6/internal/js/modules/k6/browser/log"
Expand All @@ -22,8 +21,6 @@ const evaluationScriptURL = "__xk6_browser_evaluation_script__"
// This error code originates from chromium.
const devToolsServerErrorCode = -32000

var sourceURLRegex = regexp.MustCompile(`^(?s)[\040\t]*//[@#] sourceURL=\s*(\S*?)\s*$`)

type executionWorld string

const (
Expand Down Expand Up @@ -177,7 +174,7 @@ func (e *ExecutionContext) eval(
}

if !opts.forceCallable {
if !sourceURLRegex.Match([]byte(js)) {
if !hasSourceURL(js) {
js += "\n" + suffix
}

Expand Down Expand Up @@ -255,6 +252,10 @@ func (e *ExecutionContext) eval(
//go:embed js/injected_script.js
var injectedScriptSource string

//nolint:gochecknoglobals
var injectedScriptSourceWithSourceURL = `(() => {` + injectedScriptSource + `; return new InjectedScript();})()` +
"\n//# sourceURL=" + evaluationScriptURL

// getInjectedScript returns a JS handle to the injected script of helper functions.
func (e *ExecutionContext) getInjectedScript(apiCtx context.Context) (JSHandleAPI, error) {
e.logger.Debugf(
Expand All @@ -270,19 +271,10 @@ func (e *ExecutionContext) getInjectedScript(apiCtx context.Context) (JSHandleAP
}
e.isMutex.RUnlock()

var (
suffix = `//# sourceURL=` + evaluationScriptURL
source = `(() => {` + injectedScriptSource + `; return new InjectedScript();})()`
expression = source
expressionWithSourceURL = expression
)
if !sourceURLRegex.Match([]byte(expression)) {
expressionWithSourceURL = expression + "\n" + suffix
}
handle, err := e.eval(
apiCtx,
evalOptions{forceCallable: false, returnByValue: false},
expressionWithSourceURL,
injectedScriptSourceWithSourceURL,
)
if err != nil {
return nil, err
Expand Down
24 changes: 24 additions & 0 deletions internal/js/modules/k6/browser/common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"errors"
"fmt"
"math"
"regexp"
"slices"
"strings"
"time"

cdpruntime "github.com/chromedp/cdproto/runtime"
Expand Down Expand Up @@ -278,3 +280,25 @@ func (rm RegExMatcher) Match(pattern, s string) (bool, error) {
}
return m(s)
}

var sourceURLRegex = regexp.MustCompile(`(?s)[\040\t]*//[@#] sourceURL=\s*(\S*?)\s*$`)

func hasSourceURL(js string) bool {
lastNotEmptyIndex := strings.LastIndexFunc(js, func(r rune) bool {
switch r {
case '\n', '\r', ' ', '\t':
return false
default:
return true
}
})
lastNewLineBeforeLastLineIndex := 0 // default to going through the whole string
if lastNotEmptyIndex != -1 { // if there are no new lines - go through the whole string
lastNewLineBeforeLastLineIndex = strings.LastIndex(js[:lastNotEmptyIndex], "\n")
if lastNewLineBeforeLastLineIndex == -1 { // reset to zero again
lastNewLineBeforeLastLineIndex = 0
}
}

return sourceURLRegex.MatchString(js[lastNewLineBeforeLastLineIndex:])
}
33 changes: 33 additions & 0 deletions internal/js/modules/k6/browser/common/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,36 @@ func TestConvertArgument(t *testing.T) {
require.Empty(t, arg.UnserializableValue)
})
}

func TestHasSourceURL(t *testing.T) {
t.Parallel()

cases := map[string]struct {
js string
result bool
}{
"empty": {
js: "",
result: false,
},
"simple": {
js: "something;\n//# sourceURL=somethingher",
result: true,
},
"simple without": {
js: "something",
result: false,
},
"only sourceURL": {
js: "//# sourceURL=somethinghere",
result: true,
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
t.Parallel()
require.Equal(t, c.result, hasSourceURL(c.js))
})
}
}
Loading