Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cancel ongoing file upload sent with http.MultipartRequest() in Flutter?

I'm trying to add cancel functionality to file upload in my Flutter app. I'm currently using http.MultipartRequest() from http package to upload the file. I've tried wrapping the upload with CancelableOperation but it only cancels the internal process within my Flutter app and the file still gets uploaded successfully to my Firebase Storage server.

I read the README.md on http package about using http.Client() and closing it after the http request is completed. I'm thinking about using http.Client() to upload the file and then closing it with the http.Client().close() to cancel the http request.

But, I haven't found the right way to upload file with http.Client yet. I browsed about it on Google and stackoverflow but all the posts recommend using http.MultipartRequest(). One of the posts

So, my questions are: 1. Is it possible to cancel upload file sent with http.MultipartRequest() from http package in Flutter? 2. Am I in the right track with trying to use http.Client() ? Or is there any better way to do this? 3. If using http.Client() is the only way, then can you please show me how to upload file with http.Client()? since it only has post() and no multipartrequest().

Sorry for the long text. Please help. Thanks!

like image 640
Natasha S Avatar asked Jan 02 '23 11:01

Natasha S


1 Answers

Package http uses HTTPClient under the hood. It wraps that underlying client in an IOClient. Most of http's methods (like get and post) allow you to pass in your own client, but the MultipartRequest doesn't (it creates one for each request).

The easiest solution seems to be to subclass it.

import 'dart:async';
import 'dart:io';

import 'package:http/http.dart' as http;

class CloseableMultipartRequest extends http.MultipartRequest {
  http.IOClient client = http.IOClient(HttpClient());

  CloseableMultipartRequest(String method, Uri uri) : super(method, uri);

  void close() => client.close();

  @override
  Future<http.StreamedResponse> send() async {
    try {
      var response = await client.send(this);
      var stream = onDone(response.stream, client.close);
      return new http.StreamedResponse(
        new http.ByteStream(stream),
        response.statusCode,
        contentLength: response.contentLength,
        request: response.request,
        headers: response.headers,
        isRedirect: response.isRedirect,
        persistentConnection: response.persistentConnection,
        reasonPhrase: response.reasonPhrase,
      );
    } catch (_) {
      client.close();
      rethrow;
    }
  }

  Stream<T> onDone<T>(Stream<T> stream, void onDone()) =>
      stream.transform(new StreamTransformer.fromHandlers(handleDone: (sink) {
        sink.close();
        onDone();
      }));
}
like image 76
Richard Heap Avatar answered Jan 10 '23 19:01

Richard Heap