request.dart
2.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import '../http.dart';
import '../multipart/form_data.dart';
class Request<T> {
  /// Headers attach to this [Request]
  final Map<String, String> headers;
  /// The [Uri] from request
  final Uri url;
  final Decoder<T> decoder;
  /// The Http Method from this [Request]
  /// ex: `GET`,`POST`,`PUT`,`DELETE`
  final String method;
  final int contentLength;
  /// The BodyBytesStream of body from this [Request]
  final BodyBytesStream bodyBytes;
  /// When true, the client will follow redirects to resolves this [Request]
  final bool followRedirects;
  /// The maximum number of redirects if [followRedirects] is true.
  final int maxRedirects;
  final bool persistentConnection;
  final FormData files;
  const Request._({
    @required this.method,
    @required this.bodyBytes,
    @required this.url,
    @required this.headers,
    @required this.contentLength,
    @required this.followRedirects,
    @required this.maxRedirects,
    @required this.files,
    @required this.persistentConnection,
    @required this.decoder,
  });
  factory Request({
    @required Uri url,
    @required String method,
    @required Map<String, String> headers,
    BodyBytesStream bodyBytes,
    bool followRedirects = true,
    int maxRedirects = 4,
    int contentLength,
    FormData files,
    bool persistentConnection = true,
    Decoder<T> decoder,
  }) {
    assert(url != null);
    assert(method != null);
    assert(followRedirects != null);
    if (followRedirects) {
      assert(maxRedirects != null);
      assert(maxRedirects > 0);
    }
    return Request._(
      url: url,
      method: method,
      bodyBytes: bodyBytes ??= BodyBytesStream.fromBytes(const []),
      headers: Map.from(headers ??= <String, String>{}),
      followRedirects: followRedirects,
      maxRedirects: maxRedirects,
      contentLength: contentLength,
      files: files,
      persistentConnection: persistentConnection,
      decoder: decoder,
    );
  }
}
class BodyBytesStream extends StreamView<List<int>> {
  BodyBytesStream(Stream<List<int>> stream) : super(stream);
  factory BodyBytesStream.fromBytes(List<int> bytes) =>
      BodyBytesStream(Stream.fromIterable([bytes]));
  Future<Uint8List> toBytes() {
    var completer = Completer<Uint8List>();
    var sink = ByteConversionSink.withCallback(
      (bytes) => completer.complete(
        Uint8List.fromList(bytes),
      ),
    );
    listen(sink.add,
        onError: completer.completeError,
        onDone: sink.close,
        cancelOnError: true);
    return completer.future;
  }
  Future<String> bytesToString([Encoding encoding = utf8]) =>
      encoding.decodeStream(this);
}