Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ jobs:
bash publish.sh lib-lang
bash publish.sh lib-lock
bash publish.sh lib-lock-redis
bash publish.sh lib-util-net
bash publish.sh lib-httpx
bash publish.sh lib-mail
bash publish.sh lib-node-id-redis
Expand All @@ -94,7 +95,6 @@ jobs:
bash publish.sh lib-util-string
bash publish.sh lib-util-time
bash publish.sh lib-util-tsid
bash publish.sh lib-util-net
bash publish.sh lib-pool
bash publish.sh lib-random
bash publish.sh lib-retry
Expand Down
23 changes: 12 additions & 11 deletions lib-httpx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Add the dependency to your `build.gradle`:

```gradle
dependencies {
implementation 'io.seqera:lib-httpx:2.6.0'
implementation 'io.seqera:lib-httpx:2.7.0'
}
```

Expand All @@ -25,7 +25,7 @@ dependencies {
- **Custom Token Storage**: Pluggable token store interface for distributed deployments (Redis, database, etc.)
- **WWW-Authenticate Support**: Automatic handling of HTTP authentication challenges (Basic and Bearer schemes)
- **Anonymous Authentication**: Fallback to anonymous authentication when credentials aren't provided
- **Proxy Support**: Authenticated forward-proxy support via `.proxy(...)`/`.authenticator(...)`, or an `HxProxyConfig` value applied with `.withProxyConfig(...)`
- **Proxy Support**: Authenticated forward-proxy support via `.proxy(...)`/`.authenticator(...)`, or an `io.seqera.util.net.ProxyConfig` (from `io.seqera:lib-util-net`) applied with `.withProxyConfig(...)`
- **Configurable**: Customizable retry policies, timeouts, token refresh, authentication settings, and cookie policies
- **Generic Integration**: Compatible with any `Retryable.Config` for flexible retry configuration
- **Thread-safe**: Safe for concurrent use with atomic token refresh coordination
Expand Down Expand Up @@ -403,16 +403,17 @@ HxClient client = HxClient.newBuilder()
.build();
```

For callers that resolve proxy settings themselves (host, port, optional credentials per protocol and
`NO_PROXY` entries), `HxProxyConfig` bundles them into a single value and produces the matching selector
and a proxy-only authenticator (credentials are supplied only for proxy authentication challenges, never
to origin servers). Apply it in one call with `.withProxyConfig(...)`:
For callers that resolve proxy settings themselves, `io.seqera.util.net.ProxyConfig` (from
`io.seqera:lib-util-net`, an `api` dependency of this library) bundles a proxy URI or the
`HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` environment variables into a single value and produces the matching
selector and a proxy-only authenticator (credentials are supplied only for proxy authentication
challenges, never to origin servers). Apply it in one call with `.withProxyConfig(...)`:

```java
HxProxyConfig proxy = HxProxyConfig.newBuilder()
.httpsProxy("proxy.example.com", 8080, "user", "pass")
.noProxy(List.of("internal.example.com"))
.build();
// prefer the explicit-credentials overload - it avoids having to percent-encode a password
// containing '@', ':' or '%' that would otherwise be embedded in the URI
ProxyConfig proxy = ProxyConfig.fromUri("http://proxy.example.com:8080", "user", "pass",
List.of("internal.example.com"));
HxClient client = HxClient.newBuilder()
.withProxyConfig(proxy) // no-op if proxy is null
.build();
Expand Down Expand Up @@ -469,7 +470,7 @@ HxClient client = HxClient.newBuilder()

- **`HxClient`**: Main HTTP client with retry, JWT, and WWW-Authenticate functionality
- **`HxConfig`**: Configuration builder with all available options
- **`HxProxyConfig`**: Forward-proxy settings (selector + proxy-only authenticator) assembled from explicit values via its builder
- **`io.seqera.util.net.ProxyConfig`** (from `io.seqera:lib-util-net`): Forward-proxy settings (selector + proxy-only authenticator) resolved from a URI or the environment, applied via `HxClient.Builder.withProxyConfig(...)`
- **`HxAuth`**: Interface for authentication credentials with stable identity across refreshes
- **`HxTokenStore`**: Interface for pluggable token storage (default: in-memory ConcurrentHashMap)
- **`HxTokenManager`**: Thread-safe JWT token lifecycle management with multi-session support
Expand Down
2 changes: 1 addition & 1 deletion lib-httpx/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.6.0
2.7.0
1 change: 1 addition & 0 deletions lib-httpx/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ version = "${project.file('VERSION').text.trim()}"

dependencies {
api project(':lib-retry')
api project(':lib-util-net')
implementation 'com.google.code.gson:gson:2.10.1'

testImplementation 'com.github.tomakehurst:wiremock:3.0.1'
Expand Down
17 changes: 17 additions & 0 deletions lib-httpx/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# lib-httpx changelog

2.7.0
- BREAKING (see note below): remove HxProxyConfig in favour of io.seqera.util.net.ProxyConfig
(io.seqera:lib-util-net), so the proxy selector / authenticator / no-proxy semantics live in a
single place shared with Wave and Nextflow
- HxClient.Builder.withProxyConfig now accepts an io.seqera.util.net.ProxyConfig; callers that built an
HxProxyConfig should resolve a ProxyConfig instead - its toProxySelector()/toAuthenticator() are
unchanged. For raw credentials prefer the explicit overload
ProxyConfig.fromUri(uri, user, pass, noProxy) over embedding them in the URI, so a password with
'@'/':'/'%' does not need percent-encoding; fromEnvironment(env) reads HTTP_PROXY/HTTPS_PROXY/NO_PROXY
- Note: HxProxyConfig could hold an http proxy without an https one (or vice versa); fromUri applies one
endpoint to both protocols, so asymmetric per-protocol config from explicit values is now only
expressible via fromEnvironment
- lib-httpx now depends on io.seqera:lib-util-net
- NOTE: this removes a public type, so it is source-incompatible for any caller of HxProxyConfig.
It is released as a minor (2.7.0) rather than a major because the only affected consumer is
Nextflow, which is migrated in lock-step; callers pinning <= 2.6.0 are unaffected.

2.6.0 - 12 Aug 2026
- Add HxClient.shouldRetryOnException(HttpRequest, Throwable) - the hook the retry policy now
consults - so a subclass can decide on the exception per request
Expand Down
22 changes: 12 additions & 10 deletions lib-httpx/src/main/java/io/seqera/http/HxClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import io.seqera.http.auth.AuthenticationChallenge;
import io.seqera.http.auth.AuthenticationScheme;
import io.seqera.http.auth.WwwAuthenticateParser;
import io.seqera.util.net.ProxyConfig;
import io.seqera.util.retry.Retryable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -1195,12 +1196,12 @@ public Builder version(HttpClient.Version version) {
* <p>The selector is forwarded to the inner {@link HttpClient.Builder} and is also
* inherited by the internal HTTP clients used for JWT token refresh and anonymous
* Bearer token retrieval. Proxy settings are never resolved from the environment
* automatically; supply them explicitly here (or via {@link #withProxyConfig(HxProxyConfig)}).
* automatically; supply them explicitly here (or via {@link #withProxyConfig(ProxyConfig)}).
*
* @param proxySelector the proxy selector to use
* @return this Builder instance
* @see HttpClient.Builder#proxy(ProxySelector)
* @see HxProxyConfig
* @see ProxyConfig
*/
public Builder proxy(ProxySelector proxySelector) {
this.proxySelector = proxySelector;
Expand All @@ -1220,29 +1221,30 @@ public Builder proxy(ProxySelector proxySelector) {
* {@link Authenticator#setDefault(Authenticator)} - proxy credentials only take effect
* when supplied via this method. For Basic proxy authentication of HTTPS traffic the JDK's
* {@code jdk.http.auth.tunneling.disabledSchemes} property must also be cleared - see
* {@link HxProxyConfig} for details.
* {@link ProxyConfig} for details.
*
* @param authenticator the authenticator providing credentials
* @return this Builder instance
* @see HttpClient.Builder#authenticator(Authenticator)
* @see HxProxyConfig#toAuthenticator()
* @see ProxyConfig#toAuthenticator()
*/
public Builder authenticator(Authenticator authenticator) {
this.proxyAuthenticator = authenticator;
return this;
}

/**
* Applies the proxy selector and authenticator carried by the given {@link HxProxyConfig},
* a convenience over calling {@link #proxy(ProxySelector)} and
* {@link #authenticator(Authenticator)} separately. A {@code null} config is a no-op, so
* callers can pass an optionally-resolved configuration directly.
* Applies the proxy selector and authenticator carried by the given
* {@link ProxyConfig} (from {@code io.seqera:lib-util-net}), a convenience over calling
* {@link #proxy(ProxySelector)} and {@link #authenticator(Authenticator)} separately. A
* {@code null} config is a no-op, so callers can pass an optionally-resolved configuration
* directly.
*
* @param config the proxy configuration to apply, or null for none
* @return this Builder instance
* @see HxProxyConfig
* @see ProxyConfig
*/
public Builder withProxyConfig(HxProxyConfig config) {
public Builder withProxyConfig(ProxyConfig config) {
if( config == null )
return this;
if( config.getHttpProxy() != null || config.getHttpsProxy() != null )
Expand Down
8 changes: 4 additions & 4 deletions lib-httpx/src/main/java/io/seqera/http/HxConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ public Builder withRefreshCookiePolicy(CookiePolicy policy) {
*
* @param proxySelector the proxy selector, or null to use the JVM default behaviour
* @return this builder instance for method chaining
* @see HxProxyConfig
* @see io.seqera.util.net.ProxyConfig
*/
public Builder proxySelector(ProxySelector proxySelector) {
this.proxySelector = proxySelector;
Expand All @@ -711,12 +711,12 @@ public Builder proxySelector(ProxySelector proxySelector) {
/**
* Sets the authenticator used to supply credentials to an authenticating forward proxy,
* applied to the main HTTP client and the internal token refresh clients. See
* {@link HxProxyConfig} for the {@code Authenticator.setDefault} and Basic-over-HTTPS
* tunnelling caveats.
* {@link io.seqera.util.net.ProxyConfig} for the {@code Authenticator.setDefault} and
* Basic-over-HTTPS tunnelling caveats.
*
* @param proxyAuthenticator the authenticator providing proxy credentials, or null for none
* @return this builder instance for method chaining
* @see HxProxyConfig#toAuthenticator()
* @see io.seqera.util.net.ProxyConfig#toAuthenticator()
*/
public Builder proxyAuthenticator(Authenticator proxyAuthenticator) {
this.proxyAuthenticator = proxyAuthenticator;
Expand Down
Loading
Loading