Line data Source code
1 : import 'dart:io';
2 :
3 : import 'package:agattp/src/agattp_config.dart';
4 : import 'package:agattp/src/agattp_method.dart';
5 : import 'package:agattp/src/agattp_request.dart';
6 : import 'package:agattp/src/agattp_response.dart';
7 : import 'package:agattp/src/agattp_utils.dart';
8 : import 'package:agattp/src/native/agattp_response.dart';
9 :
10 : /// A concrete implementation of the Request interface that implements the
11 : /// request using Flutter's native HttpClientRequest and HttpClientResponse
12 : /// classes
13 : class AgattpRequest<T, R extends AgattpResponse>
14 : implements AgattpRequestInterface<T, R> {
15 : @override
16 : final AgattpConfig config;
17 :
18 2 : AgattpRequest(this.config);
19 :
20 2 : R _makeResponse(HttpClientResponse response, String body) {
21 : // (R is AgattpJsonResponse) doesn't work here, we need this workaround,
22 : // purely because "R" is ambiguous - do you mean the generic Type template
23 : // argument, or the value that resides in "R" at runtime? Instantiating a
24 : // list like this will work around this by removing the second possibility,
25 : // forcing the cast check to work properly.
26 : // https://github.com/dart-lang/sdk/issues/43390
27 : // ignore: always_specify_types
28 4 : return <R>[] is List<AgattpJsonResponse>
29 2 : ? AgattpJsonResponseNative<T>(response, body) as R
30 1 : : AgattpResponseNative(response, body) as R;
31 : }
32 :
33 2 : @override
34 : Future<R> send({
35 : required AgattpMethod method,
36 : required Uri uri,
37 : required Duration? timeout,
38 : required String? body,
39 : Map<String, String> headers = const <String, String>{},
40 : }) async {
41 4 : final HttpClient client = HttpClient()..badCertificateCallback =
42 4 : config.badCertificateCallback;
43 :
44 : final HttpClientRequest request = await switch (method) {
45 4 : AgattpMethod.get => client.getUrl(uri),
46 2 : AgattpMethod.post => client.postUrl(uri),
47 2 : AgattpMethod.put => client.putUrl(uri),
48 2 : AgattpMethod.delete => client.deleteUrl(uri),
49 2 : AgattpMethod.head => client.headUrl(uri),
50 2 : AgattpMethod.patch => client.patchUrl(uri),
51 : };
52 :
53 6 : request.followRedirects = config.followRedirects;
54 :
55 2 : final Map<String, String> newHeaders = Utils.headers(
56 : headers,
57 4 : config.headerKeyCase,
58 : );
59 :
60 4 : for (final MapEntry<String, String> entry in newHeaders.entries) {
61 8 : request.headers.set(entry.key, entry.value, preserveHeaderCase: true);
62 : }
63 :
64 : if (body != null) {
65 1 : request.write(body);
66 : }
67 :
68 4 : final HttpClientResponse response = await request.close().timeout(
69 4 : timeout ?? config.timeout,
70 : );
71 :
72 : final String responseBody =
73 10 : await response.transform(config.encoding.decoder).join();
74 :
75 2 : final R agattpResponse = _makeResponse(response, responseBody);
76 :
77 6 : client.close(force: config.forceClose);
78 :
79 : return agattpResponse;
80 : }
81 : }
|