Skip to content

Restore HTTP.Exceptions as a deprecating compat shim + migration note - #1315

Merged
quinnj merged 1 commit into
JuliaWeb:masterfrom
mathieu17g:fix/exceptions-submodule-shim
Jun 23, 2026
Merged

Restore HTTP.Exceptions as a deprecating compat shim + migration note#1315
quinnj merged 1 commit into
JuliaWeb:masterfrom
mathieu17g:fix/exceptions-submodule-shim

Conversation

@mathieu17g

Copy link
Copy Markdown
Contributor

Implements the deprecating HTTP.Exceptions shim and migration note discussed in #1314 (context and prevalence there).

src/HTTP.jl re-adds HTTP.Exceptions as a thin deprecated submodule forwarding the four relocated types to their top-level names:

module Exceptions
    import ..HTTP
    Base.@deprecate_binding HTTPError    HTTP.HTTPError    false
    Base.@deprecate_binding StatusError  HTTP.StatusError  false
    Base.@deprecate_binding ConnectError HTTP.ConnectError false
    Base.@deprecate_binding TimeoutError HTTP.TimeoutError false
end

So catch … isa HTTP.Exceptions.StatusError resolves again, forwarding to HTTP.StatusError with a --depwarn=yes warning — same mechanism as the existing @deprecate escape escapeuri, and like it, untested.

RequestError, @try, and current_exceptions_to_string are not reinstated; the migration note covers them (RequestError has no drop-in — the underlying exception propagates and isrecoverable classifies it, #1310).

docs/src/guides/migration-1x.md gains an "Exceptions" section (Before/After for StatusError and RequestError) and a Final-Checklist line.

Closes #1314.

Re-add HTTP.Exceptions as a thin deprecated submodule forwarding HTTPError,
StatusError, ConnectError and TimeoutError to the canonical top-level names via
Base.@deprecate_binding (as the existing escape -> escapeuri), so downstream
`catch ... isa HTTP.Exceptions.StatusError` keeps working with a deprecation
warning. RequestError, @Try and current_exceptions_to_string are not reinstated;
the migration guide documents them (RequestError has no drop-in -- the underlying
exception propagates and isrecoverable classifies it).

Closes JuliaWeb#1314.
@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.17%. Comparing base (9e830d9) to head (2e44ce5).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1315      +/-   ##
==========================================
- Coverage   87.32%   87.17%   -0.16%     
==========================================
  Files          29       29              
  Lines       11326    11326              
==========================================
- Hits         9890     9873      -17     
- Misses       1436     1453      +17     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mathieu17g

Copy link
Copy Markdown
Contributor Author

The codecov/project -0.16% is an indirect drop in http2_server.jl's non-deterministic error/RST paths (base 10 coverage sessions vs this PR's 5; codecov/patch green; this PR's files untracked) — a re-run should re-aggregate and clear it.

@quinnj quinnj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM; thanks!

@quinnj
quinnj merged commit a1eb82b into JuliaWeb:master Jun 23, 2026
7 of 8 checks passed
krynju added a commit to krynju/AWS.jl that referenced this pull request Jun 25, 2026
`_HTTP_V2 = !isdefined(HTTP, :Exceptions)` is no longer reliable: HTTP 2.x
re-adds `HTTP.Exceptions` as a deprecating compat shim (JuliaWeb/HTTP.jl#1315),
so on a 2.x release carrying that shim the flag would flip to `false` and AWS.jl
would silently run its 1.x code paths on HTTP 2. Switch to `pkgversion(HTTP) >= 2`
(with an `HTTP.EmptyBody` feature-detection fallback for Julia < 1.9 — a genuine
2.x-only type that is not shimmed back).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
krynju added a commit to krynju/AWSS3.jl that referenced this pull request Jun 25, 2026
The `isdir` test picked the `StatusError` constructor via
`isdefined(AWS.HTTP, :Exceptions)`. HTTP 2.x re-adds `HTTP.Exceptions` as a
deprecating compat shim (JuliaWeb/HTTP.jl#1315), so on such a release the test
would take the 1.x branch and call the removed 4-arg
`StatusError(status, method, target, response)` constructor → MethodError.
Key off `HTTP.EmptyBody` (a genuine 2.x-only type that is not shimmed) instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
krynju added a commit to JuliaComputing/GitForge.jl that referenced this pull request Jun 25, 2026
`_HTTP_V2 = !isdefined(HTTP, :Header)` keys off a removed binding's absence,
which is fragile: HTTP.jl 2.x has re-added other removed bindings as deprecating
shims (e.g. HTTP.Exceptions, JuliaWeb/HTTP.jl#1315), so a future Header shim
would silently flip the flag. Use `pkgversion(HTTP) >= 2`, falling back to a
genuine 2.x-only type (`HTTP.EmptyBody`) when pkgversion is unavailable
(Julia < 1.9).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nkottary added a commit to JuliaWeb/GitForge.jl that referenced this pull request Jun 29, 2026
* Update HTTP.jl to 2.4.0

* Fix compatibility with HTTP.jl 2.x API

- Replace HTTP.Header[] with Pair{String,String}[]; the HTTP.Header
  type alias was removed from the public API in HTTP.jl 2.0.
- Replace HTTP.StatusError(status, method, url, resp) with
  HTTP.StatusError(resp); the v2 StatusError struct has only
  (status, response) fields and no longer takes method/url arguments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix remaining HTTP.jl 2.x test failures

Replace HTTP.Header[] with Pair{String,String}[] since HTTP.Header was
removed in HTTP.jl 2.x. Drop the !isempty(out) verbose log assertion
since HTTP.jl 2.x prints verbose output directly to stdout rather than
through Julia's logging system, making it uncapturable by TestLogger.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Drop Julia 1.6 support

HTTP.jl 2.x requires Julia 1.7+, so Julia 1.6 can no longer resolve
the dependency. Remove 1.6 from the CI matrix and bump the julia compat
bound to 1.7 accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove docs/Manifest.toml from version control

Add it to .gitignore so it is generated fresh during CI via
Pkg.instantiate(), avoiding stale pinned dependencies (e.g. the
TimeZones build failure on current Julia).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add missing docstrings to docs

19 documented symbols were not referenced in the manual, causing
makedocs to error with :missing_docs. Add them across three areas:
- API endpoints: get_branches, delete_branch, create_repo (owner/repo
  variant), subscribe/unsubscribe_from_pull_request, groups,
  list_issues, list_pipeline_schedules, and all pull request comment
  CRUD functions
- Bitbucket section: Bitbucket module, BitbucketAPI, RenderedPullRequestMarkup
- Internals: constructfield, write(::FieldContext, ...), @forge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Bump version 0.4.4 -> 0.5.0

Dropping Julia 1.6 support and requiring HTTP.jl 2.x are both breaking
changes for existing users, warranting a minor version bump under
Julia's pre-1.0 conventions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add dual HTTP.jl 1.x/2.x support; bump version to 0.4.5

Widen HTTP compat from "2.4.0" to "1.10, 2" so the package resolves on
both HTTP 1.x and 2.x. The sole API incompatibility was the HTTP.StatusError
constructor (4-arg in 1.x, 1-arg in 2.x); this is guarded by a module-level
_HTTP_V2 constant derived from isdefined(HTTP, :Header) (works on Julia 1.6+).
Also fixes the pre-existing broken 2-arg HTTP.StatusError call in Bitbucket
pagination and replaces removed HTTP.status/HTTP.body accessor functions with
direct field access (compatible with both versions).

Restore Julia 1.6 to Project.toml compat and CI matrix: HTTP 1.x supports 1.6,
so users on 1.6 will resolve HTTP 1.x and the conditional paths handle the rest.

Version bump 0.5.0 → 0.4.5: dual-version support is additive, not breaking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* detect HTTP 2.x by package version, not HTTP.Header absence

`_HTTP_V2 = !isdefined(HTTP, :Header)` keys off a removed binding's absence,
which is fragile: HTTP.jl 2.x has re-added other removed bindings as deprecating
shims (e.g. HTTP.Exceptions, JuliaWeb/HTTP.jl#1315), so a future Header shim
would silently flip the flag. Use `pkgversion(HTTP) >= 2`, falling back to a
genuine 2.x-only type (`HTTP.EmptyBody`) when pkgversion is unavailable
(Julia < 1.9).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: detect HTTP 2.x era via binding-owned VERSION

`HTTP.VERSION` only exists from HTTP.jl 2.0 on; under 1.x it resolves to the `VERSION` re-exported from `Base` (the Julia version). Guard with `Base.binding_module` before comparing, and bound to the 2.x line (`v"2" <= VERSION < v"3"`) so a future HTTP 3 isn't treated as 2.x. Replaces the prior version-detection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix http compat

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: krynju <krystian.gulinski@juliahub.com>
tanmaykm pushed a commit to krynju/AWS.jl that referenced this pull request Aug 7, 2026
* Support HTTP.jl 2.x alongside 1.x

HTTP.jl 2.0 is a breaking release. Add a compatibility layer so AWS.jl
works on both 1.x and 2.x, selected at load time via a feature flag.

Client-side changes (src/utilities/http_compat.jl + call sites):
- `StatusError` constructor changed from (status, method, target, response)
  to (status, response).
- `RequestError`, `iserror`, `isbytes`, `resource`, and the `HTTP.Exceptions`
  submodule were removed; use `HTTP.isrecoverable` and local shims.
- Response bodies are buffered as bytes (no `IOBuffer` bodies), header names
  are canonicalized, and connection timeouts surface as `TimeoutError`
  rather than `ConnectError`.

Drop the GitHub.jl dependency: it pins HTTP < 2 and was used only by the
API-generation tooling. Its three REST calls (authenticate/tree/blob) are
reimplemented over HTTP + JSON.

Tests updated to construct version-appropriate exceptions/bodies. The IMDS
mock no longer replicates HTTP.jl's private retry internals (which differ
across versions) and instead honors only the retry_check path IMDS relies on.

Verified: unit suite passes under both HTTP 1.11 and HTTP 2.4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Restore GitHub.jl dependency for API generation

Bring GitHub.jl back as a dependency and revert the API-generation tooling
to use it (the hand-rolled GitHub REST shim from the HTTP 2 work is removed).
This keeps all the HTTP.jl 1.x/2.x client compatibility from the parent branch
while using GitHub.jl for `parse_aws_metadata`.

Note: registered GitHub.jl (v5) still pins HTTP < 2, so with this dependency
the resolver currently selects HTTP 1.x. Once GitHub.jl publishes a release
with HTTP 1+2 support, HTTP 2 resolves without further changes (widen the
`GitHub` compat bound if that support arrives in a new major version).

Verified: unit suite passes (HTTP 1.11 + GitHub.jl).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Use a single HTTP-version flag across tests

The test helpers gated their HTTP 1.x/2.x branches on an inline
`isdefined(HTTP, :Exceptions)`, duplicating the detection that
`AWS._HTTP_V2` already centralizes. Reference the package flag instead so
version detection has a single source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* IMDS: treat HTTP.TimeoutError as a hop-limit (TTL) rejection on HTTP 2.x

The IMDSv2 token PUT runs with `retry=false`; a hop-limit rejection manifests
as a read timeout. On HTTP.jl 2.x that read-deadline timeout can surface as an
`HTTP.TimeoutError` (the same way connection timeouts do — `is_connection_exception`
already handles that), not only as a bare `ETIMEDOUT` `IOError`. Without this,
`is_ttl_expired_exception` returns false, the IMDSv1 fallback is skipped, and the
token fetch hard-fails in hop-limited (container) environments. Match
`HTTP.TimeoutError` in the 2.x branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* http_compat: detect HTTP 2.x by version, not the Exceptions submodule

`_HTTP_V2 = !isdefined(HTTP, :Exceptions)` is no longer reliable: HTTP 2.x
re-adds `HTTP.Exceptions` as a deprecating compat shim (JuliaWeb/HTTP.jl#1315),
so on a 2.x release carrying that shim the flag would flip to `false` and AWS.jl
would silently run its 1.x code paths on HTTP 2. Switch to `pkgversion(HTTP) >= 2`
(with an `HTTP.EmptyBody` feature-detection fallback for Julia < 1.9 — a genuine
2.x-only type that is not shimmed back).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: detect HTTP 2.x era via binding-owned VERSION

`HTTP.VERSION` only exists from HTTP.jl 2.0 on; under 1.x it resolves to the `VERSION` re-exported from `Base` (the Julia version). Guard with `Base.binding_module` before comparing, and bound to the 2.x line (`v"2" <= VERSION < v"3"`) so a future HTTP 3 isn't treated as 2.x. Replaces the prior version-detection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* CI: test against HTTP.jl 1.x and 2.x

Add an `http` matrix axis that pins HTTP.jl to the selected major before
running tests (the pin survives `Pkg.test`'s re-resolve), so both code paths
are exercised. HTTP.jl 2 requires Julia >= 1.10, so the "min" Julia version is
excluded from the HTTP 2 leg.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* CI: pin HTTP before buildpkg, matching Onda.jl pattern

Address review feedback (PR JuliaCloud#775): move the HTTP.jl pin ahead of
`julia-buildpkg` so instantiation and precompilation happen once at the pinned
version rather than resolving the latest and then downgrading, and pass the
package UUID explicitly. Mirrors the multi-version-dependency CI approach used
in Onda.jl that the reviewer referenced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix HTTP 2.x behavior regressions found in review

Code review of the HTTP 1/2 compatibility layer surfaced several cases where
the 2.x shims diverged from 1.x semantics:

- IMDS: on 2.x every `TimeoutError` was classified as both a connection
  failure and a hop-limit rejection, with the connection check winning, making
  the IMDSv1 hop-limit fallback (issues JuliaCloud#654/JuliaCloud#649) unreachable. Discriminate
  on `TimeoutError.operation`: connect/tls_handshake phases are connection
  failures, read-phase timeouts are hop-limit rejections — the predicates are
  now disjoint. The same phase logic prevents `_is_connection_failure` from
  swallowing read timeouts from a reachable ECS credentials endpoint.
- `_http_iserror` treated redirect statuses as errors, breaking the S3
  wrong-region redirect re-sign flow on the Downloads backend. Mirror 1.x
  `HTTP.iserror` exactly.
- HTTPBackend's retry check no longer retried transient timeouts on 2.x
  (`HTTP.isrecoverable` returns false for `TimeoutError`). Include
  connect-phase timeouts via `_is_connection_failure` and read-phase timeouts
  in `_is_recoverable_request_error`, matching 1.x's RequestError semantics.
- On 2.x, `showerror` of a `StatusError` whose response has no request crashed
  in HTTP.jl, masking the real error. The `_statuserror` shim now attaches a
  minimal request when the response carries none.
- The Downloads backend's synthetic response used `UInt8[]` as the body, which
  1.x `HTTP.isbytes` classifies as inline, silently dropping
  `AWSException.streamed_body`. New `_streamed_body_placeholder()` shim
  restores the streamed marker per version, and tests now reuse it instead of
  duplicating the conditional.
- Restore `HTTP.resource` semantics (e.g. empty path => "/") via a
  `_resource` shim instead of a hand-rolled target string.

Unit suite passes on HTTP 1.11 (668) and HTTP 2.5.5 (672, including new
phase-discrimination tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* IMDS: own the 401 token-refresh retry instead of delegating to HTTP.jl

`IMDS.request` relied on the `retry_check`/`retry_delays` keywords to refresh
an expired IMDSv2 token on a 401 and retry. HTTP.jl 2.x accepts those keywords
for backwards compatibility but ignores them, so on 2.x the 401 propagated to
the caller instead of transparently refreshing the token.

Move the refresh-and-retry-once loop into `IMDS.request` itself and pass
`retry=false`, giving identical single-attempt-per-call semantics on both
HTTP.jl majors.

The test mock previously reimplemented the retry keywords via `Base.retry`,
which is exactly what masked this: it honored `retry_check` even though the
real 2.x client does not. The mock now performs one attempt per call, like the
real client, so the refresh retry is exercised through the actual code path —
the existing request-count assertions pass unchanged.

Unit suite passes on HTTP 1.11 (668) and HTTP 2.5.5 (672); the 2.x
"retry_delays ... no longer supported" deprecation warning is gone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* CI: skip the HTTP pin on the min Julia job

The hard pin of HTTP to 1.11.0 made the `Pkg.develop(TestPkg)` in the test
suite unresolvable on Julia 1.8: HTTP 1.11 needs ConcurrentUtilities >= 2.4,
but with stdlibs fixed at v0.0.0 on Julia < 1.9 the Sockets compat caps
ConcurrentUtilities at 2.2.1, and a pin cannot be moved by any resolve tier.

Julia 1.8 can only resolve HTTP 1.x regardless (HTTP 2 requires Julia >=
1.10), so the pin adds no coverage on the min job — skip it there, matching
the conditional pin pattern in Onda.jl's CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
krynju added a commit to krynju/AWSS3.jl that referenced this pull request Aug 10, 2026
* Add HTTP.jl 2.0 compat

Bump HTTP compat to "1, 2". src/ only uses HTTP.header, whose
signature is unchanged in 2.0. The one breaking usage is in tests:
StatusError moved out of the Exceptions submodule and its constructor
changed from (status, method, target, response) to (status, response).
Construct it version-aware via isdefined(AWS.HTTP, :Exceptions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: detect HTTP 2.x by EmptyBody, not the Exceptions submodule

The `isdir` test picked the `StatusError` constructor via
`isdefined(AWS.HTTP, :Exceptions)`. HTTP 2.x re-adds `HTTP.Exceptions` as a
deprecating compat shim (JuliaWeb/HTTP.jl#1315), so on such a release the test
would take the 1.x branch and call the removed 4-arg
`StatusError(status, method, target, response)` constructor → MethodError.
Key off `HTTP.EmptyBody` (a genuine 2.x-only type that is not shimmed) instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: detect HTTP 2.x era via binding-owned VERSION const

`HTTP.VERSION` only exists from HTTP.jl 2.0 on; under 1.x it resolves to the `VERSION` re-exported from `Base` (the Julia version). Guard with `Base.binding_module` before comparing, and bound to the 2.x line (`v"2" <= VERSION < v"3"`) so a future HTTP 3 isn't treated as 2.x. Replaces the prior version-detection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: case-insensitive get_robust_case for HTTP.jl 2.x headers

HTTP.jl 2.x canonicalizes response header names, so S3's `ETag` header
arrives as `Etag`. get_robust_case only tried the lowercase (`etag`) and
verbatim (`ETag`) spellings, so the canonicalized `Etag` missed both and
threw `KeyError: key "ETag" not found` from s3_upload_part, breaking every
multipart upload under HTTP.jl 2.x.

Fall back to a full case-insensitive scan before throwing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: test against HTTP.jl 1.x and 2.x

Add an `http` dimension to the CI matrix and pin HTTP.jl to the matrix major
before instantiation, so both code paths are actually exercised. Without the
pin the resolver selects HTTP 1.x, leaving the 2.x path untested.

Fix two tests that only pass on HTTP 1.x: HTTP.jl 2.x canonicalizes response
header names, so `s3_get_meta` returns `X-Amz-Meta-Foo`/`Etag` rather than the
spellings S3 sends. Look those up via `get_robust_case`, and extend its unit
test with a case that exercises the case-insensitive scan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* add

* ci: drop archived actions-oidc-debugger step

`github/actions-oidc-debugger` was archived in September 2025. Its Dockerfile
pins `apk add go=$(cat .go-version)-r0`, which no longer resolves against
Alpine 3.22's repos (musl has moved to -r12), so the image build fails and
takes down every matrix job before Julia is installed.

The step is purely diagnostic; role assumption via
`aws-actions/configure-aws-credentials` is unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

HTTP.Exceptions submodule removed in 2.x — restore as a (deprecating) compat shim, or document it?

2 participants