Skip to content

feat: add kernel browsers curl command#146

Merged
rgarcia merged 4 commits intomainfrom
raf/browser-curl-cli
Apr 29, 2026
Merged

feat: add kernel browsers curl command#146
rgarcia merged 4 commits intomainfrom
raf/browser-curl-cli

Conversation

@rgarcia
Copy link
Copy Markdown
Contributor

@rgarcia rgarcia commented Apr 9, 2026

Summary

Adds a curl-like kernel browsers curl command for making HTTP requests through a browser session's Chrome network stack. Requests inherit the browser's TLS fingerprint, cookies, proxy configuration, and browser headers, and responses are streamed directly through the SDK browser HTTP client wrapper around /curl/raw.

/curl/raw follows redirects automatically in Chromium, so this command documents that behavior rather than exposing -L.

Usage

# Simple GET
kernel browsers curl $ID https://example.com

# POST JSON through the browser session
kernel browsers curl $ID https://api.example.com \
  -H "Content-Type: application/json" \
  -d '{"key":"val"}'

# Include response headers and write headers + body to a file
kernel browsers curl $ID -i -o page.html https://example.com

# Dump headers separately from the response body
kernel browsers curl $ID -D headers.txt -o body.html https://example.com

# Fetch headers only
kernel browsers curl $ID -I https://example.com

# Fail on HTTP errors without printing the response body
kernel browsers curl $ID -f https://example.com/missing

# Print curl-style metrics after completion
kernel browsers curl $ID -o body.html -w 'status=%{http_code} bytes=%{size_download}\n' https://example.com

Flags

Flag Description
-X, --request HTTP method (default: GET; defaults to POST when --data is set)
-H, --header HTTP header, repeatable ("Key: Value" format)
-d, --data Request body
--data-file Read request body from file
--max-time Maximum time allowed for the request in seconds (default: 30)
-o, --output Write response body to file
-I, --head Fetch headers only
-i, --include Include response headers in output
-D, --dump-header Write received headers to file (use - for stdout)
-w, --write-out Output text after completion; supports %{http_code}, %{response_code}, %{time_total}, %{size_download}
-f, --fail Fail with no body output on HTTP errors
-s, --silent Suppress progress output

Implementation notes

  • Uses github.com/kernel/kernel-go-sdk v0.51.0 and Browsers.HTTPClient(sessionID) to route requests through /curl/raw.
  • Always streams the proxied response directly; there is no JSON envelope mode.
  • Redirects are followed automatically by Chromium and currently cannot be disabled.
  • Root command error handling now writes CLI errors to stderr, which keeps --fail and timeout output closer to curl behavior.

Test plan

  • make test && make build
  • Production smoke: create browser, run kernel browsers curl <id> https://example.com, delete browser
  • Compare actual curl vs kernel browsers curl for body output, -i, -o, -i -o, and -d
  • Compare -I, -D, -w, -f, and --max-time
  • Verify /curl/raw follows redirects automatically while plain curl does not without -L

Note

Medium Risk
Introduces new HTTP execution paths and modifies global error output behavior; while scoped to a new subcommand, it changes stdout/stderr expectations and request/response streaming semantics.

Overview
Adds a new kernel browsers curl <session-id> <url> command that makes HTTP requests through the browser session’s SDK-provided HTTPClient, supporting curl-like flags for method/headers/body (incl. --data-file), timeouts, output-to-file, header inclusion/dumping, --write-out metrics, --fail, and --silent.

Updates root error handling to support “silent” command errors (suppress diagnostics while still exiting non-zero) and to ensure CLI errors are written to fang’s error stream (stderr), keeping stdout clean for response bodies. Documentation and examples in README.md are updated, and new unit tests cover request shaping, output/header behaviors, write-out expansion, fail mode, and silent error wrapping.

Reviewed by Cursor Bugbot for commit db97766. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread cmd/browsers.go Outdated
Comment thread cmd/browsers.go
@firetiger-agent
Copy link
Copy Markdown

I'll monitor the rollout of the new kernel browsers curl command. This change adds CLI functionality for making HTTP requests through browser sessions, supporting both standard and streaming/raw modes.

What I'll watch for:

  • Traffic appearing on the new /browsers/{id}/curl and /browsers/{id}/curl/raw API endpoints (confirms backend is deployed and users are adopting)
  • Authentication failures, especially on the raw endpoint which handles auth differently than the SDK path
  • Error rates compared to similar browser endpoints like /browsers/{id}/playwright/execute
  • Latency distributions to ensure requests complete within the 30s default timeout

This is a low-risk change since it's a CLI-only addition that depends on existing API endpoints. The main thing to watch is whether the backend /browsers/{id}/curl* routes are deployed and working. I'll post updates as the deployment progresses.

View agent

@kernel-internal
Copy link
Copy Markdown
Contributor

kernel-internal Bot commented Apr 10, 2026

🔧 CI Fix Available
I've pushed a fix for the CI failure.

👉 Click here to create a PR with the fix

Comment thread go.mod Outdated
Comment thread cmd/browsers.go Outdated
Comment thread cmd/browsers.go
Comment thread cmd/browsers.go
Comment thread cmd/browsers.go
Comment thread cmd/browsers.go
Comment thread cmd/browsers.go
@rgarcia rgarcia force-pushed the raf/browser-curl-cli branch from 06c1cdf to 811df1e Compare April 28, 2026 18:41
Comment thread cmd/browsers.go
// Seed the SDK's browser route cache before constructing the raw curl client.
if _, err := b.browsers.Get(ctx, in.Identifier, kernel.BrowserGetParams{}); err != nil {
return curlError(in, util.CleanedUpSdkError{Err: err})
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might want to consider a local disk cache of this since this is super inefficient

Comment thread cmd/browsers.go
@rgarcia rgarcia requested a review from ulziibay-kernel April 29, 2026 15:49
Comment thread cmd/browsers.go
httpClient.Timeout = in.MaxTime
}

req, err := http.NewRequestWithContext(ctx, method, in.URL, bodyReader)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we verify that /curl/raw doesn't forward Go's default User-Agent / Accept-Encoding as browser request headers when the user didn't specify them?

The CLI builds a normal Go http.Request and sends it through the SDK HTTPClient; Go's transport can add defaults like User-Agent: Go-http-client/1.1, and the raw endpoint appears to forward non-hop-by-hop headers into the Chromium forward proxy. If the Chromium proxy honors those forwarded headers, this could override the browser's UA/default headers even though the command is documented as inheriting browser headers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressing upstream in chromium

@rgarcia rgarcia force-pushed the raf/browser-curl-cli branch from fb182e7 to db97766 Compare April 29, 2026 20:51
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues. You can view the agent here.

Reviewed by Cursor Bugbot for commit db97766. Configure here.

Comment thread cmd/browsers.go
}
if body != "" && !hasCurlHeader(headers, "Content-Type") {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go default headers leak through browser proxy

High Severity

When no User-Agent header is explicitly provided by the user, Go's http.Transport automatically injects User-Agent: Go-http-client/1.1 into the outgoing request. Since /curl/raw appears to forward non-hop-by-hop headers into the Chromium forward proxy, this Go default will override the browser's natural User-Agent, defeating the core purpose of routing requests through Chrome's network stack for TLS fingerprint and header inheritance. The same concern applies to Accept-Encoding: gzip. The request construction here doesn't prevent these Go defaults from being added.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit db97766. Configure here.

Comment thread cmd/browsers.go
if in.Head {
method = "HEAD"
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty data file doesn't default method to POST

Low Severity

The method inference checks body != "" to decide whether to default to POST, but the PR documents "defaults to POST when --data is set." When --data-file points to an empty file, readCurlBody returns "", so the method stays GET despite the user explicitly requesting a data upload. Checking in.DataFile != "" alongside the body content would fix the --data-file case.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit db97766. Configure here.

@rgarcia rgarcia merged commit 55a2b93 into main Apr 29, 2026
8 checks passed
@rgarcia rgarcia deleted the raf/browser-curl-cli branch April 29, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants