Line data Source code
1 : import 'dart:async';
2 : import 'dart:convert';
3 : import 'package:http_parser/http_parser.dart';
4 : import 'utils.dart';
5 :
6 : // ignore: uri_does_not_exist
7 : import 'multipart_file_stub.dart'
8 : // ignore: uri_does_not_exist
9 : if (dart.library.io) 'multipart_file_io.dart';
10 :
11 : /// A file to be uploaded as part of a [MultipartRequest]. This doesn't need to
12 : /// correspond to a physical file.
13 : ///
14 : /// MultipartFile is based on stream, and a stream can be read only once,
15 : /// so the same MultipartFile can't be read multiple times.
16 : class MultipartFile {
17 : /// The size of the file in bytes. This must be known in advance, even if this
18 : /// file is created from a [ByteStream].
19 : final int length;
20 :
21 : /// The basename of the file. May be null.
22 : final String filename;
23 :
24 : /// The content-type of the file. Defaults to `application/octet-stream`.
25 : final MediaType contentType;
26 :
27 : /// The stream that will emit the file's contents.
28 : final Stream<List<int>> _stream;
29 :
30 : /// Whether [finalize] has been called.
31 2 : bool get isFinalized => _isFinalized;
32 : bool _isFinalized = false;
33 :
34 : /// Creates a new [MultipartFile] from a chunked [Stream] of bytes. The length
35 : /// of the file in bytes must be known in advance. If it's not, read the data
36 : /// from the stream and use [MultipartFile.fromBytes] instead.
37 : ///
38 : /// [contentType] currently defaults to `application/octet-stream`, but in the
39 : /// future may be inferred from [filename].
40 1 : MultipartFile(
41 : Stream<List<int>> stream,
42 : this.length, {
43 : this.filename,
44 : MediaType contentType,
45 : }) : _stream = stream,
46 1 : contentType = contentType ?? MediaType('application', 'octet-stream');
47 :
48 : /// Creates a new [MultipartFile] from a byte array.
49 : ///
50 : /// [contentType] currently defaults to `application/octet-stream`, but in the
51 : /// future may be inferred from [filename].
52 1 : factory MultipartFile.fromBytes(
53 : List<int> value, {
54 : String filename,
55 : MediaType contentType,
56 : }) {
57 2 : var stream = Stream.fromIterable([value]);
58 1 : return MultipartFile(
59 : stream,
60 1 : value.length,
61 : filename: filename,
62 : contentType: contentType,
63 : );
64 : }
65 :
66 : /// Creates a new [MultipartFile] from a string.
67 : ///
68 : /// The encoding to use when translating [value] into bytes is taken from
69 : /// [contentType] if it has a charset set. Otherwise, it defaults to UTF-8.
70 : /// [contentType] currently defaults to `text/plain; charset=utf-8`, but in
71 : /// the future may be inferred from [filename].
72 1 : factory MultipartFile.fromString(
73 : String value, {
74 : String filename,
75 : MediaType contentType,
76 : }) {
77 1 : contentType ??= MediaType('text', 'plain');
78 3 : var encoding = encodingForCharset(contentType.parameters['charset'], utf8);
79 3 : contentType = contentType.change(parameters: {'charset': encoding.name});
80 :
81 1 : return MultipartFile.fromBytes(
82 1 : encoding.encode(value),
83 : filename: filename,
84 : contentType: contentType,
85 : );
86 : }
87 :
88 : /// Creates a new [MultipartFile] from a path to a file on disk.
89 : ///
90 : /// [filename] defaults to the basename of [filePath]. [contentType] currently
91 : /// defaults to `application/octet-stream`, but in the future may be inferred
92 : /// from [filename].
93 : ///
94 : /// Throws an [UnsupportedError] if `dart:io` isn't supported in this
95 : /// environment.
96 1 : static Future<MultipartFile> fromFile(
97 : String filePath, {
98 : String filename,
99 : MediaType contentType,
100 : }) =>
101 1 : multipartFileFromPath(
102 : filePath,
103 : filename: filename,
104 : contentType: contentType,
105 : );
106 :
107 1 : static MultipartFile fromFileSync(
108 : String filePath, {
109 : String filename,
110 : MediaType contentType,
111 : }) =>
112 1 : multipartFileFromPathSync(
113 : filePath,
114 : filename: filename,
115 : contentType: contentType,
116 : );
117 :
118 1 : Stream<List<int>> finalize() {
119 1 : if (isFinalized) {
120 0 : throw StateError("Can't finalize a finalized MultipartFile.");
121 : }
122 1 : _isFinalized = true;
123 1 : return _stream;
124 : }
125 : }
|