fire_http 0.0.1 copy "fire_http: ^0.0.1" to clipboard
fire_http: ^0.0.1 copied to clipboard

outdated

A client of HTTP/1.1 or HTTP/2.

example/main.dart

// ignore_for_file: avoid_print

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

import 'package:fire_http/fire_http.dart';
import 'package:http/http.dart';
import 'package:http_parser/http_parser.dart';
import 'package:mime/mime.dart' as mime;

Future<void> main(List<String> arguments) async {
  // the host of client
  const host = 'https://catfact.ninja';
  // the path of request
  const path = '/fact';
  // create HttpClient with HTTP/1.1
  final client1 = HttpClient(client: Http1Client(), headers: {}, host: host);
  // create HttpClient with HTTP/2
  final client2 = HttpClient(client: Http2Client(), headers: {}, host: host);

  // request with HTTP/1.1 Client
  final resClient1 = await client1.get(path);
  // request with HTTP/2 Client
  final resClient2 = await client2.get(path);

  // print all responses
  print('\n====== FIRE HTTP =====\n');
  print('=> response Client1: \n${(resClient1 as Response).body}\n');
  print('=> response Client2: \n${(resClient2 as Response).body}');
}

/// [HttpClient] is a sample Client Wrapper that can be
/// used to [Http1Client] or [Http2Client]
class HttpClient {
  // client for the app server
  BaseHttpClient client;
  // client for outside of app server
  BaseHttpClient? clientOutsideAppServer;
  // specific host of the client
  String host;
  // to set the required headers
  Map<String, String> headers;

  HttpClient({
    required this.client,
    required this.host,
    required this.headers,
  }) : super() {
    // auto set up the client
    setUpClient(clientParam: client);
  }
  // constant of error code: certificate already registered
  static const _tlsCertAlreadyRegisteredErrorCode = 184549481;

  /// [setUpClient] to set up the client anytime
  void setUpClient({
    required BaseHttpClient clientParam,
  }) {
    final newClient = clientParam.setUp(
      // set null, since use this free url
      securityContext: null,
      // securityContext: SecurityContext(),
    );
    clientOutsideAppServer = newClient;
    client = newClient;
  }

  /// [setUpCertPinning] to set up the certificate pinning anytime
  void setUpCertPinning({
    required String certBase64,
    String? certAltBase64,
  }) {
    final securityContext = SecurityContext();

// set up the securityContext with the certBase64 and certAltBase64
    void setUpCert(String cert) {
      final certBytes = base64Decode(cert);
      try {
        securityContext.setTrustedCertificatesBytes(certBytes);
      } catch (e) {
        // return nothing when certificate already registered
        if (e is TlsException &&
            e.osError?.errorCode == _tlsCertAlreadyRegisteredErrorCode) {
          // Cert already registered, so ignore the error.
          return;
        }
        rethrow;
      }
    }

    setUpCert(certBase64);
    if (certAltBase64 != null) {
      setUpCert(certAltBase64);
    }
    final newClient = client.setUp(
      securityContext: securityContext,
    );
    client = newClient;
    clientOutsideAppServer = newClient;
  }

// parse the path with host
  Uri getParsedUrl(String path) => Uri.parse('$host$path');

// generate required request headers
  Map<String, String> generateRequestHeader([
    Map<String, String> overrideHeader = const {},
  ]) {
    return {
      ...headers,
      ...overrideHeader,
    };
  }

  ///
  /// Sends an HTTP GET request to the given URL.
  ///
  Future<dynamic> get(
    String path, {
    Map<String, String> overrideHeader = const {},
  }) async {
    final allHeaders = generateRequestHeader(overrideHeader);
    final parsedUrl = getParsedUrl(path);

    final response = await client.get(parsedUrl, headers: allHeaders);

    return response;
  }

  ///
  /// Sends an HTTP POST request to the given URL.
  ///
  Future<dynamic> post(
    String path,
    dynamic data, {
    Map<String, String> overrideHeader = const {},
  }) async {
    final allHeaders = generateRequestHeader(overrideHeader);
    final parsedUrl = getParsedUrl(path);

    final encodedBody = utf8.encode(jsonEncode(data as Map<String, String>));

    final response = await client.post(
      parsedUrl,
      headers: allHeaders,
      body: encodedBody,
    );

    print('HTTP response\n'
        'Method: POST\n'
        'Url: $parsedUrl\n'
        'Code: ${response.statusCode}\n'
        'Data: ${response.body}');

    return response;
  }

  ///
  /// Sends an HTTP PATCH request to the given URL.
  ///
  Future<dynamic> patch(
    String path,
    dynamic data, {
    Map<String, String> overrideHeader = const {},
  }) async {
    final allHeaders = generateRequestHeader(overrideHeader);
    final parsedUrl = getParsedUrl(path);

    final encodedBody = utf8.encode(jsonEncode(data as Map<String, String>));

    final response = await client.patch(
      parsedUrl,
      headers: allHeaders,
      body: encodedBody,
    );

    return response;
  }

  ///
  /// Sends an HTTP PUT request to the given URL.
  ///
  Future<dynamic> put(
    String path,
    dynamic data, {
    Map<String, String> overrideHeader = const {},
  }) async {
    final allHeaders = generateRequestHeader(overrideHeader);
    final parsedUrl = getParsedUrl(path);
    final encodedBody = utf8.encode(jsonEncode(data as Map<String, String>));

    final response = await client.put(
      parsedUrl,
      headers: allHeaders,
      body: encodedBody,
    );

    print('HTTP response\n'
        'Method: PUT\n'
        'Url: $parsedUrl\n'
        'Data: ${response.body}');

    return response;
  }

  ///
  /// Sends an HTTP DELETE request to the given URL.
  ///
  Future<dynamic> delete(
    String path, {
    Map<String, String> overrideHeader = const {},
    dynamic body,
  }) async {
    final allHeaders = generateRequestHeader(overrideHeader);
    final parsedUrl = getParsedUrl(path);
    final encodedBody = utf8.encode(jsonEncode(body as Map<String, String>));

    final response = await client.delete(
      parsedUrl,
      headers: allHeaders,
      body: encodedBody,
    );

    print('HTTP response\n'
        'Method: DELETE\n'
        'Url: $parsedUrl\n'
        'Data: ${response.body}');

    return response;
  }

  ///
  /// Sends an HTTP GET request to the given URL to download file.
  ///
  Future<Response> downloadFile(
    String path, {
    Map<String, String> overrideHeader = const {},
  }) async {
    final allHeaders = generateRequestHeader(overrideHeader);
    final parsedUrl = getParsedUrl(path);

    final response = await client.get(
      parsedUrl,
      headers: allHeaders,
    );

    return response;
  }

  ///
  /// Sends an HTTP request to the given URL to upload file.
  ///
  Future<dynamic> uploadFile(
    String path,
    Map<String, File> mapFile,
    Map<String, dynamic> data, {
    Map<String, String> overrideHeader = const {},
    HttpMethodType method = HttpMethodType.post,
    Completer<Stream<double>>? uploadProgressCompleter,
    Completer<Stream<double>>? downloadProgressCompleter,
    dynamic signPayload = 'null',
  }) async {
    final parsedUrl = getParsedUrl(path);
    final Map<String, String> inputHeaders = {
      ...overrideHeader,
      HttpConstants.accept: HttpConstants.jsonContentType,
      HttpConstants.contentType: HttpConstants.multiPartFormDataType,
      HttpConstants.authorization: headers[HttpConstants.authorization] ?? '',
    };
    final allHeaders = generateRequestHeader(inputHeaders);

    final request = MultipartRequest(
      HttpMethod(type: method).toString(),
      parsedUrl,
    );

    data.forEach((key, value) => request.fields[key] = value);
    request.headers.addAll(allHeaders);

    for (final element in mapFile.entries) {
      final mimeTypeData = mime.lookupMimeType(
        element.value.path,
        headerBytes: [0xFF, 0xD8],
      )?.split('/');
      final field = await element.value.readAsBytes();
      final multiPartFile = MultipartFile.fromBytes(
        element.key,
        field,
        filename: element.value.path.split('/').last,
        contentType: MediaType(mimeTypeData![0], mimeTypeData[1]),
      );
      request.files.add(multiPartFile);
    }

    final streamResponse = await client
        .send(
      request,
      uploadStreamCompleter: uploadProgressCompleter,
    )
        .then((value) {
      if (downloadProgressCompleter != null) {
        /// Invoke onDownloadStreamCreated callback
        /// to give download progress stream to caller
        final responseLength = value.contentLength ?? 0;
        int downloadDataCount = 0;

        final downloadStream = value.stream.transform<double>(
          StreamTransformer.fromHandlers(
            handleData: (data, sink) {
              downloadDataCount += data.length;
              sink.add(downloadDataCount / responseLength);
            },
            handleError: (error, stack, sink) {
              sink.addError(error, stack);
            },
            handleDone: (sink) {
              sink.close();
            },
          ),
        );
        downloadProgressCompleter.complete(downloadStream);
      }
      return value;
    });

    return Response.fromStream(streamResponse);
  }

  ///
  /// Sends an HTTP GET request to the given URL to
  /// download file outside our server.
  ///
  Future<dynamic> downloadFileFromOtherServer(
    String url, {
    Map<String, String> overrideHeader = const {},
  }) async {
    final requestHeader = generateRequestHeader(overrideHeader);
    final uri = Uri.parse(url);

    final response = await clientOutsideAppServer!.get(
      uri,
      headers: requestHeader,
    );

    return response;
  }

  /// Function to create HTTP request
  /// with upload and download stream completer.
  /// So caller can pass the completer
  /// to get stream they want
  Future<dynamic> streamedRequest({
    required HttpMethodType method,
    required String path,
    Map<String, dynamic>? body,
    Map<String, String> overrideHeader = const {},
    Completer<Stream<double>>? uploadProgressCompleter,
    Completer<Stream<double>>? downloadProgressCompleter,
  }) async {
    final allHeaders = generateRequestHeader(overrideHeader);

    final request = StreamedRequest(
      HttpMethod(type: method).toString(),
      getParsedUrl(path),
    )..headers.addAll(allHeaders);

    final stringifyJson = body != null ? jsonEncode(body) : 'null';
    request.contentLength = stringifyJson.length;

    await Stream.fromIterable(stringifyJson.split(''))
        .transform(utf8.encoder)
        .transform<double>(
          StreamTransformer.fromHandlers(
            handleData: (data, sink) {
              request.sink.add(data);
            },
            handleError: (error, stack, sink) {
              request.sink.addError(error, stack);
              sink.addError(error, stack);
            },
            handleDone: (sink) {
              request.sink.close();
              sink.close();
            },
          ),
        )
        .toList();

    final streamResponse = await client
        .send(
      request,
      uploadStreamCompleter: uploadProgressCompleter,
    )
        .then((value) async {
      if (downloadProgressCompleter != null) {
        /// Invoke onDownloadStreamCreated callback
        /// to give download progress stream to caller
        final responseLength = value.contentLength ?? 0;
        int downloadDataCount = 0;

        final downloadStream = value.stream.transform<double>(
          StreamTransformer.fromHandlers(
            handleData: (data, sink) {
              downloadDataCount += data.length;
              sink.add(downloadDataCount / responseLength);
            },
            handleError: (error, stack, sink) {
              sink.addError(error, stack);
            },
            handleDone: (sink) {
              sink.close();
            },
          ),
        );
        downloadProgressCompleter.complete(downloadStream);
      }
      return value;
    });

    return Response.fromStream(streamResponse);
  }
}
1
likes
0
points
28
downloads

Publisher

unverified uploader

Weekly Downloads

A client of HTTP/1.1 or HTTP/2.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

http, http2

More

Packages that depend on fire_http