Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runWithClient cannot be used to configure the client in the root Zone #828

Closed
brianquinlan opened this issue Nov 18, 2022 · 8 comments
Closed
Assignees
Labels
package:http type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@brianquinlan
Copy link
Collaborator

runWithClient is not sufficient for the Flutter use case.

Flutter sometimes invokes callbacks on the Root Zone and runWithClient cannot be used to set Client in that Zone.

@brianquinlan brianquinlan added type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) package:http labels Nov 18, 2022
@brianquinlan brianquinlan self-assigned this Nov 18, 2022
@natebosch
Copy link
Member

It makes me sad if we can't use Zones for the use case they fit best.

@brianquinlan
Copy link
Collaborator Author

Fixed in d434d42

@escamoteur
Copy link

@kevmoo while doing some intense testing with a network monitor I just had to find out that Flutter ignores the HttpClient that I provide with runWithClient in its NetworkImage with setting breakpoints and debugging I found out it uses this weird Httpclient implementation of the Flutter Engine
image

@brianquinlan
Copy link
Collaborator Author

@escamoteur You can look at flutter_http_example to see how you can plumb a package:http Client through a Flutter application - including using it to load images.

@escamoteur
Copy link

escamoteur commented Jun 25, 2024 via email

@escamoteur
Copy link

escamoteur commented Jun 25, 2024 via email

@brianquinlan
Copy link
Collaborator Author

I just checked your example, there you too use a different ImageProvider than the built in from Flutter.

That's correct. package:http_image_provider allows you to use a package:http-based Client with Image.

@escamoteur
Copy link

And that was my point, according to the documentation runWithClient should be enough to make Flutter use the HttpClient factory but it does not. The docs even press that it would work with Flutter (https://pub.dev/documentation/http/latest/http/runWithClient.html) So it's a bug and should be fixed or at least the docs should be updated.

Unfortunately, the package you used doesn't have a linked github repository which isn't really good for an official example. I would propose you just add an ImageProvider like the following (this here uses get_it instead of provider so you don't even have to pass the client to every Image widget) directly inside your demo project.

class HttpNetworkImage extends ImageProvider<HttpNetworkImage> {
  /// Creates an object that fetches the image at the given URL.
  const HttpNetworkImage(this.url, {this.scale = 1.0, this.headers});

  final String url;

  final double scale;

  final Map<String, String>? headers;

  @override
  Future<HttpNetworkImage> obtainKey(ImageConfiguration configuration) {
    return SynchronousFuture<HttpNetworkImage>(this);
  }

  @override
  ImageStreamCompleter loadImage(
      HttpNetworkImage key, ImageDecoderCallback decode) {
    // Ownership of this controller is handed off to [_loadAsync]; it is that
    // method's responsibility to close the controller's stream when the image
    // has been loaded or an error is thrown.

    return MultiFrameImageStreamCompleter(
      codec: _loadAsync(key, decode: decode),
      scale: key.scale,
      debugLabel: key.url,
      informationCollector: () => <DiagnosticsNode>[
        DiagnosticsProperty<ImageProvider>('Image provider', this),
        DiagnosticsProperty<HttpNetworkImage>('Image key', key),
      ],
    );
  }

  Future<ui.Codec> _loadAsync(
    HttpNetworkImage key, {
    required ImageDecoderCallback decode,
  }) async {
    try {
      assert(key == this);

      final Uri resolved = Uri.base.resolve(key.url);

      final response = await  GetIt.I<Client>().get(resolved, headers: headers);

      if (response.statusCode != HttpStatus.ok) {
        // The network may be only temporarily unavailable, or the file will be
        // added on the server later. Avoid having future calls to resolve
        // fail to check the network again.
        // await response.drain<List<int>>(<int>[]);
        throw NetworkImageLoadException(
            statusCode: response.statusCode, uri: resolved);
      }

      if (response.bodyBytes.isEmpty) {
        throw Exception('NetworkImage is an empty file: $resolved');
      }

      return decode(await ui.ImmutableBuffer.fromUint8List(response.bodyBytes));
    } catch (e) {
      // Depending on where the exception was thrown, the image cache may not
      // have had a chance to track the key in the cache at all.
      // Schedule a microtask to give the cache a chance to add the key.
      scheduleMicrotask(() {
        PaintingBinding.instance.imageCache.evict(key);
      });
      rethrow;
    }
  }

  @override
  bool operator ==(Object other) {
    if (other.runtimeType != runtimeType) {
      return false;
    }
    return other is HttpNetworkImage && other.url == url && other.scale == scale;
  }

  @override
  int get hashCode => Object.hash(url, scale);

  @override
  String toString() =>
      '${objectRuntimeType(this, 'NetworkImage')}("$url", scale: ${scale.toStringAsFixed(1)})';
}

natebosch added a commit that referenced this issue Jun 27, 2024
Towards #828

Add a section in the `runWithClient` doc that mentions HTTP requests
which _aren't_ affected by usage of this API - specifically requests
made through the SDK core libraries, or through instantiating specific
client implementations.
natebosch added a commit that referenced this issue Jun 27, 2024
Towards #828

Add a section in the `runWithClient` doc that mentions HTTP requests
which _aren't_ affected by usage of this API - specifically requests
made through the SDK core libraries, or through instantiating specific
client implementations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package:http type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

3 participants