Skip to content

Avoid URISyntaxException for common bad input in HttpURLConnection URLs (draft) - #12693

Draft
dougqh wants to merge 1 commit into
masterfrom
dougqh/lenient-url-to-uri
Draft

dougqh wants to merge 1 commit into
masterfrom
dougqh/lenient-url-to-uri

Conversation

@dougqh

@dougqh dougqh commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

What Does This Do

Draft / jumping-off point, expect to iterate.

Stops HttpURLConnection requests with common bad-input URLs from throwing and reporting a URISyntaxException on every request.

java.net.URL accepts strings that java.net.URI rejects. HttpUrlConnectionDecorator.url and UrlConnectionDecorator.onURL called URL.toURI(), so each such request threw, was caught in HttpClientDecorator.onRequest ("Error tagging url"), and ended up with no http.url, no peer host/port, and no path-based resource name.

  • Adds URIUtils.toURI(URL), which percent-encodes only what java.net.URI rejects before parsing: a space or control character, any of " < > \ ^ { | }, [or]in the **path** (they stay legal in the query, fragment and an IPv6 host), a%not followed by two hex digits, and a second#`. Non-ASCII letters are kept; non-ASCII spaces/controls are encoded as UTF-8.
  • Well-formed URLs are converted exactly as url.toURI() would, and return the same String with no extra allocation.
  • Anything else URI rejects still throws URISyntaxException, so existing catch blocks behave as before.
  • HttpUrlConnectionDecorator.url and UrlConnectionDecorator.onURL now use it.
  • Adds URIUtilsToURITest (JUnit 5, 17 cases): repaired inputs, unchanged well-formed inputs (compared with url.toURI()), non-ASCII handling, and a case that must still throw.

Motivation

Three Error Tracking issues are this same failure through different entry points: 7eb5eb3c (HttpURLConnection.getInputStream), 80a09d2a (HttpURLConnection.connect, currently IGNORED with no recorded reason) and 7d87bb46 (commons-httpclient, not touched here). Together they are about 200k events a day (all tracer versions; reports aggregate repeats, so the real throw count is higher), and 80a09d2a is still ~28% on 1.65.1 / 1.66.0, so upgrading does not make it go away. A latch is the wrong tool because the failure is per URL, so the fix makes the failing case cheap instead of skipping it. Related: APMLP-1881 (guarded safeParse) and APMLP-1884 (input-rate breaker and per-site counters).

Additional Notes

  • No benchmark included. The claim is that a repaired URL costs less than a thrown and caught URISyntaxException plus the lost tags; that is reasoned, not measured. A JMH comparing the three paths (well-formed, repaired, throwing) would be a good addition before this leaves draft.
  • Behavior change to be aware of: requests that used to get no URL tags now get them, built from the repaired URI. http.url and the SSRF check see the percent-encoded form, and URI.getPath() decodes back to the original characters.
  • Possible iterations:
    • The pathStart / path-end scan runs on every call and is only needed when the string has a [ or ]; computing it lazily would make the clean path a single pass (techdebt noted this; perf-review did not consider it worth flagging).
    • Other toURI() callers were not touched: OkHttpClientDecorator (okhttp-2.2, request.url().toURI()), and commons-httpclient (new URI(httpMethod.getURI().toString()), a different source type).
    • The structural alternative is a client-side URIDataAdapter (already used by ~20 server decorators) so that nothing goes through the strict java.net.URI.
  • java.net.URL already rejects malformed authorities at construction, so URI failures after the repair should be rare; the "still throws" test uses the multi-argument URL constructor, which does not validate the host.
  • SpotBugs and Spotless pass on internal-api and agent-bootstrap. CI has not run.

Contributor Checklist

Jira ticket: N/A

🤖 Generated with Claude Code

java.net.URL accepts strings that java.net.URI rejects (a space, |, {}, [] in
the path, a stray % or a second #). HttpUrlConnectionDecorator and
UrlConnectionDecorator called URL.toURI(), so every such request threw and
reported a URISyntaxException and lost its http.url, peer and path-based
resource tags.

Add URIUtils.toURI(URL), which percent-encodes only the offending characters
before parsing. Well-formed URLs go through unchanged and without extra
allocation.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@dougqh dougqh added type: bug fix Bug fix comp: core Tracer core tag: no release notes Changes to exclude from release notes tag: ai generated Largely based on code generated by an AI or LLM labels Sep 29, 2026
@datadog-prod-us1-3

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.03 s 14.05 s [-1.1%; +0.8%] (no difference)
startup:insecure-bank:tracing:Agent 12.98 s 13.02 s [-0.9%; +0.4%] (no difference)
startup:petclinic:appsec:Agent 17.05 s 16.89 s [+0.0%; +1.9%] (maybe worse)
startup:petclinic:iast:Agent 16.31 s 17.04 s [-8.5%; -0.1%] (maybe better)
startup:petclinic:profiling:Agent 16.63 s 16.93 s [-3.0%; -0.5%] (maybe better)
startup:petclinic:sca:Agent 16.96 s 16.84 s [-0.3%; +1.7%] (no difference)
startup:petclinic:tracing:Agent 16.23 s 16.19 s [-0.7%; +1.1%] (no difference)

Commit: 41cfd9ea · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM tag: no release notes Changes to exclude from release notes type: bug fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant