-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
multipart_file.dart
143 lines (129 loc) · 4.42 KB
/
multipart_file.dart
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import 'dart:async';
import 'dart:convert';
import 'package:http_parser/http_parser.dart';
import 'utils.dart';
import 'multipart_file/io_multipart_file.dart'
if (dart.library.html) 'multipart_file/browser_multipart_file.dart';
/// A file to be uploaded as part of a [MultipartRequest]. This doesn't need to
/// correspond to a physical file.
///
/// MultipartFile is based on stream, and a stream can be read only once,
/// so the same MultipartFile can't be read multiple times.
class MultipartFile {
/// The size of the file in bytes. This must be known in advance, even if this
/// file is created from a [ByteStream].
final int length;
/// The basename of the file. May be null.
final String? filename;
/// The additional headers the file has. May be null.
final Map<String, List<String>>? headers;
/// The content-type of the file. Defaults to `application/octet-stream`.
final MediaType? contentType;
/// The stream that will emit the file's contents.
final Stream<List<int>> _stream;
/// Whether [finalize] has been called.
bool get isFinalized => _isFinalized;
bool _isFinalized = false;
/// Creates a new [MultipartFile] from a chunked [Stream] of bytes. The length
/// of the file in bytes must be known in advance. If it's not, read the data
/// from the stream and use [MultipartFile.fromBytes] instead.
///
/// [contentType] currently defaults to `application/octet-stream`, but in the
/// future may be inferred from [filename].
MultipartFile(
Stream<List<int>> stream,
this.length, {
this.filename,
MediaType? contentType,
Map<String, List<String>>? headers,
}) : _stream = stream,
headers = caseInsensitiveKeyMap(headers),
contentType = contentType ?? MediaType('application', 'octet-stream');
/// Creates a new [MultipartFile] from a byte array.
///
/// [contentType] currently defaults to `application/octet-stream`, but in the
/// future may be inferred from [filename].
factory MultipartFile.fromBytes(
List<int> value, {
String? filename,
MediaType? contentType,
final Map<String, List<String>>? headers,
}) {
final stream = Stream.fromIterable([value]);
return MultipartFile(
stream,
value.length,
filename: filename,
contentType: contentType,
headers: headers,
);
}
/// Creates a new [MultipartFile] from a string.
///
/// The encoding to use when translating [value] into bytes is taken from
/// [contentType] if it has a charset set. Otherwise, it defaults to UTF-8.
/// [contentType] currently defaults to `text/plain; charset=utf-8`, but in
/// the future may be inferred from [filename].
factory MultipartFile.fromString(
String value, {
String? filename,
MediaType? contentType,
final Map<String, List<String>>? headers,
}) {
contentType ??= MediaType('text', 'plain');
final encoding = encodingForCharset(
contentType.parameters['charset'],
utf8,
);
contentType = contentType.change(parameters: {'charset': encoding.name});
return MultipartFile.fromBytes(
encoding.encode(value),
filename: filename,
contentType: contentType,
headers: headers,
);
}
/// Creates a new [MultipartFile] from a path to a file on disk.
///
/// [filename] defaults to the basename of [filePath]. [contentType] currently
/// defaults to `application/octet-stream`, but in the future may be inferred
/// from [filename].
///
/// Throws an [UnsupportedError] if `dart:io` isn't supported in this
/// environment.
static Future<MultipartFile> fromFile(
String filePath, {
String? filename,
MediaType? contentType,
final Map<String, List<String>>? headers,
}) =>
multipartFileFromPath(
filePath,
filename: filename,
contentType: contentType,
headers: headers,
);
static MultipartFile fromFileSync(
String filePath, {
String? filename,
MediaType? contentType,
final Map<String, List<String>>? headers,
}) =>
multipartFileFromPathSync(
filePath,
filename: filename,
contentType: contentType,
headers: headers,
);
Stream<List<int>> finalize() {
if (isFinalized) {
throw StateError(
'The MultipartFile has already been finalized. '
'This typically means you are using '
'the same MultipartFile in repeated requests.',
);
}
_isFinalized = true;
return _stream;
}
}