@@ -27,8 +27,19 @@ class Fetch {
2727 return MediaType .parse (mime ?? 'application/octet-stream' );
2828 }
2929
30- StorageException _handleError (dynamic error, StackTrace stack, Uri ? url) {
30+ StorageException _handleError (
31+ dynamic error,
32+ StackTrace stack,
33+ Uri ? url,
34+ FetchOptions ? options,
35+ ) {
3136 if (error is http.Response ) {
37+ if (options? .noResolveJson == true ) {
38+ return StorageException (
39+ error.body.isEmpty ? error.reasonPhrase ?? '' : error.body,
40+ statusCode: '${error .statusCode }' ,
41+ );
42+ }
3243 try {
3344 final data = json.decode (error.body) as Map <String , dynamic >;
3445
@@ -79,7 +90,7 @@ class Fetch {
7990 return _handleResponse (streamedResponse, options);
8091 }
8192
82- Future <dynamic > _handleMultipartRequest (
93+ Future <dynamic > _handleFileRequest (
8394 String method,
8495 String url,
8596 File file,
@@ -88,7 +99,6 @@ class Fetch {
8899 int retryAttempts,
89100 StorageRetryController ? retryController,
90101 ) async {
91- final headers = options? .headers ?? {};
92102 final contentType = fileOptions.contentType != null
93103 ? MediaType .parse (fileOptions.contentType! )
94104 : _parseMediaType (file.path);
@@ -98,31 +108,15 @@ class Fetch {
98108 filename: file.path,
99109 contentType: contentType,
100110 );
101- final request = http.MultipartRequest (method, Uri .parse (url))
102- ..headers.addAll (headers)
103- ..files.add (multipartFile)
104- ..fields['cacheControl' ] = fileOptions.cacheControl
105- ..headers['x-upsert' ] = fileOptions.upsert.toString ();
106-
107- final http.StreamedResponse streamedResponse;
108- final r = RetryOptions (maxAttempts: (retryAttempts + 1 ));
109- var attempts = 0 ;
110- streamedResponse = await r.retry< http.StreamedResponse > (
111- () async {
112- attempts++ ;
113- _log.finest ('Request: attempt: $attempts $method $url $headers ' );
114- if (httpClient != null ) {
115- return httpClient! .send (request);
116- } else {
117- return request.send ();
118- }
119- },
120- retryIf: (error) =>
121- retryController? .cancelled != true &&
122- (error is ClientException || error is TimeoutException ),
111+ return _handleMultipartRequest (
112+ method,
113+ url,
114+ multipartFile,
115+ fileOptions,
116+ options,
117+ retryAttempts,
118+ retryController,
123119 );
124-
125- return _handleResponse (streamedResponse, options);
126120 }
127121
128122 Future <dynamic > _handleBinaryFileRequest (
@@ -134,7 +128,6 @@ class Fetch {
134128 int retryAttempts,
135129 StorageRetryController ? retryController,
136130 ) async {
137- final headers = options? .headers ?? {};
138131 final contentType = fileOptions.contentType != null
139132 ? MediaType .parse (fileOptions.contentType! )
140133 : _parseMediaType (url);
@@ -145,11 +138,38 @@ class Fetch {
145138 filename: '' ,
146139 contentType: contentType,
147140 );
141+ return _handleMultipartRequest (
142+ method,
143+ url,
144+ multipartFile,
145+ fileOptions,
146+ options,
147+ retryAttempts,
148+ retryController,
149+ );
150+ }
151+
152+ Future <dynamic > _handleMultipartRequest (
153+ String method,
154+ String url,
155+ MultipartFile multipartFile,
156+ FileOptions fileOptions,
157+ FetchOptions ? options,
158+ int retryAttempts,
159+ StorageRetryController ? retryController,
160+ ) async {
161+ final headers = options? .headers ?? {};
148162 final request = http.MultipartRequest (method, Uri .parse (url))
149163 ..headers.addAll (headers)
150164 ..files.add (multipartFile)
151165 ..fields['cacheControl' ] = fileOptions.cacheControl
152166 ..headers['x-upsert' ] = fileOptions.upsert.toString ();
167+ if (fileOptions.metadata != null ) {
168+ request.fields['metadata' ] = json.encode (fileOptions.metadata);
169+ }
170+ if (fileOptions.headers != null ) {
171+ request.headers.addAll (fileOptions.headers! );
172+ }
153173
154174 final http.StreamedResponse streamedResponse;
155175 final r = RetryOptions (maxAttempts: (retryAttempts + 1 ));
@@ -185,10 +205,24 @@ class Fetch {
185205 return jsonBody;
186206 }
187207 } else {
188- throw _handleError (response, StackTrace .current, response.request? .url);
208+ throw _handleError (
209+ response,
210+ StackTrace .current,
211+ response.request? .url,
212+ options,
213+ );
189214 }
190215 }
191216
217+ Future <dynamic > head (String url, {FetchOptions ? options}) async {
218+ return _handleRequest (
219+ 'HEAD' ,
220+ url,
221+ null ,
222+ FetchOptions (headers: options? .headers, noResolveJson: true ),
223+ );
224+ }
225+
192226 Future <dynamic > get (String url, {FetchOptions ? options}) async {
193227 return _handleRequest ('GET' , url, null , options);
194228 }
@@ -225,8 +259,15 @@ class Fetch {
225259 required int retryAttempts,
226260 required StorageRetryController ? retryController,
227261 }) async {
228- return _handleMultipartRequest ('POST' , url, file, fileOptions, options,
229- retryAttempts, retryController);
262+ return _handleFileRequest (
263+ 'POST' ,
264+ url,
265+ file,
266+ fileOptions,
267+ options,
268+ retryAttempts,
269+ retryController,
270+ );
230271 }
231272
232273 Future <dynamic > putFile (
@@ -237,7 +278,7 @@ class Fetch {
237278 required int retryAttempts,
238279 required StorageRetryController ? retryController,
239280 }) async {
240- return _handleMultipartRequest (
281+ return _handleFileRequest (
241282 'PUT' ,
242283 url,
243284 file,
0 commit comments