cfug / cfug/dio

[native_dio_adapter] ConversionLayerAdapter silently drops proxy, badCertificateCallback, and persistentConnection config

Open
#2,607 0 comments 0 reactions 1 assignee View on GitHub

@AlexV525 is already working on this.

Since Sep 7, 2026.

e: performance p: native_dio_adapter platform: io s: bug
Dominant language
Dart
Stars
12.8k
Forks
1.6k
PR merge metrics
No merged PRs in 30d

Description

Package

native_dio_adapter

Version

1.8.0

Operating-System

Android, iOS, MacOS

Adapter

NativeAdapter

Output of flutter doctor -v

Dart Version

No response

Steps to Reproduce
  1. Configure a Dio instance with the default IOHttpClientAdapter and set a proxy (RequestOptions/HttpClient.findProxy) and a badCertificateCallback that accepts a specific self-signed cert. Confirm both work end to end (e.g. traffic visibly routes through the proxy; the self-signed endpoint succeeds).
  2. Swap the adapter to NativeAdapter(...) with no other code changes.
  3. Re-run the exact same requests against the same proxy and self-signed endpoint.
// Before: works
dio.httpClientAdapter = IOHttpClientAdapter(
  createHttpClient: () => HttpClient()
    ..findProxy = (uri) => 'PROXY 127.0.0.1:8888'
    ..badCertificateCallback = (cert, host, port) => true,
);

// After: proxy and cert override silently stop applying
dio.httpClientAdapter = NativeAdapter(
  createCronetEngine: () => CronetEngine.build(),
  createCupertinoConfiguration: () => URLSessionConfiguration.defaultSessionConfiguration(),
);
Expected Result

Switching adapters should either (a) preserve proxy and certificate-override behavior, or (b) fail loudly (throw / assert / log a warning) so the app doesn't silently start talking to the real endpoint without the proxy or start rejecting/accepting certs differently than configured.

Actual Result

Both settings silently stop having any effect — no exception, no log, no UnsupportedError. Confirmed by reading plugins/native_dio_adapter/lib/src/conversion_layer_adapter.dart, method _fromOptionsAndStream: it reads and forwards headers, followRedirects, maxRedirects, and the request body stream, but has no code path that reads any proxy-related field off RequestOptions, nor any bridge for a certificate-override callback. persistentConnection is also read by RequestOptions but is not forwarded to the constructed http.Request even though http.BaseRequest.persistentConnection exists and compatibility_layer's equivalent conversion function already does forward it (plugins/compatibility_layer/lib/src/conversion_layer_adapter.dart, ..persistentConnection = options.persistentConnection).

This is a silent capability regression on adapter swap, not a documented limitation — users who rely on proxy or self-signed-cert testing setups (very common in a CI/QA environment) get no signal that these stopped working.

Solution Brainstorm (proposed fix)

Split into three independently landable pieces:

  1. persistentConnection — trivial, no upstream dependency. Add one line in _fromOptionsAndStream:

    request.persistentConnection = options.persistentConnection;
    
  2. badCertificateCallback — needs an upstream hook first. cronet_http's CronetEngine.build does not currently expose a per-request or per-engine "accept this certificate" callback comparable to dart:io's HttpClient.badCertificateCallback; cupertino_http's NSURLSession is validated by the system trust store with no Dart-side override point at all. Concretely:

    • For the Cronet path, this needs a feature request against cronet_http first (expose a certificate-verification callback on CronetEngine), then NativeAdapter/ConversionLayerAdapter can thread options → that callback.
    • For the Cupertino path, this is a platform limitation with no code-level fix available; the right deliverable here is documentation — NativeAdapter's doc comment and README should explicitly state "self-signed/private-CA certificates are not supported via CupertinoAdapter; fall back to IOHttpClientAdapter for that scenario," so users don't discover this by a silent failure in production.
  3. Proxy — likely also needs an upstream hook. Neither cronet_http nor cupertino_http expose a documented way to set proxy configuration per-request; both platforms currently rely on system-level proxy settings being picked up transparently by CronetEngine/URLSessionConfiguration. If that's the intended behavior, it should be stated explicitly in NativeAdapter's doc comment (it currently is not); if per-request/explicit proxy configuration is wanted, that's a feature request against the two upstream http packages, not something native_dio_adapter can add on its own.

Given (2) and (3) require upstream API additions, the immediately actionable, no-dependency part of this issue is (1) plus updating NativeAdapter's doc comment to explicitly list proxy and certificate-override as not supported / silently ignored, until upstream hooks land.

Additional context

Related, separate but adjacent robustness gap in the same package: plugins/native_dio_adapter/lib/src/cronet_fallback_adapter.dart's isCronetProviderUnavailableMessage detects "all Cronet providers disabled" purely by message.contains(cronetProvidersDisabledMessage) against JThrowable.message. This is a Java exception-message substring match with no structural type check; if a future Cronet/Play Services release changes that message text, the fallback silently stops firing and requests fail with the raw JNI exception instead of falling back to the configured HttpClientAdapter. Happy to file this as its own issue if preferred, since it's a distinct failure mode (fallback-detection fragility) from the silent-config-drop problem above — flagging here for visibility since it was found during the same audit pass.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.