Skip to content

Send a default User-Agent, as the JDK does - #40

Merged
yogthos merged 1 commit into
mainfrom
default-user-agent
Oct 15, 2026
Merged

yogthos merged 1 commit into
mainfrom
default-user-agent

Conversation

@yogthos

@yogthos yogthos commented Oct 15, 2026

Copy link
Copy Markdown
Member

A request whose caller sets no User-Agent goes out with none. The JDK always names itself:

  • HttpURLConnection sends Java/<version>, after the http.agent property when that is set.
  • java.net.http sends Java-http-client/<version>.

Sending nothing isn't neutral. A CDN in front of an API commonly answers a request without a User-Agent with a 403 challenge page. Nous Research's inference API does this, so an OpenAI-style client that works on the JVM got an HTML 403 under jolt. I checked with curl: no User-Agent gets 403, and any User-Agent at all gets 200.

Change

Both shims now name jolt the same way, using jolt's version (from jolt.host/jolt-version) since this isn't the JDK:

  • Jolt/<version> through HttpURLConnection, and so through jolt.http-client and clj-http-lite. It comes after http.agent when that is set, as on the JDK.
  • Jolt-http-client/<version> through java.net.http.

A User-Agent the caller sets, in any letter case, is sent instead. The header is added in core/with-user-agent at the point the request is written. So getRequestProperty("User-Agent") still answers null when unset, as on the JDK, and babashka.http-client's own User-Agent is untouched.

Tests

  • core-test: the two defaults, and that a caller's own wins whatever its case.
  • New user-agent-test: what the server receives through both shims, via a /user-agent echo route on the test server.

Local runs, all passing:

Suite Tests Assertions
test 108 349
bhctest 57 195
tlstest 15 35
wstest 17 79
timeouttest 16 32

A request whose caller set no User-Agent went out with none. The JDK always
names itself: HttpURLConnection as Java/<version> (after the http.agent
property when set) and java.net.http as Java-http-client/<version>. Sending
nothing isn't neutral: a CDN in front of an API commonly answers a request
with no User-Agent with a 403 challenge page. Nous Research's inference API
does, so an OpenAI-style client that works on the JVM got an HTML 403 under
jolt.

Both shims now name jolt the same way, with jolt's version since this isn't
the JDK: Jolt/<version> through HttpURLConnection (so jolt.http-client and
clj-http-lite), after http.agent when set, and Jolt-http-client/<version>
through java.net.http. A User-Agent the caller sets, in any case, is sent
instead. It is added where the request is written, so getRequestProperty
still answers null for it, as on the JDK.

core-test pins the defaults and that a caller's own wins; user-agent-test
checks what the server receives through both shims, via a /user-agent echo
route on the test server.
@yogthos
yogthos merged commit 5a9706e into main Oct 15, 2026
2 checks passed
@yogthos
yogthos deleted the default-user-agent branch October 15, 2026 22:37
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.

1 participant