@@ -25,8 +25,12 @@ class Fetch {
2525 return MediaType .parse (mime ?? 'application/octet-stream' );
2626 }
2727
28- StorageException _handleError (dynamic error, StackTrace stack) {
29- if (error is http.Response ) {
28+ StorageException _handleError (
29+ dynamic error,
30+ StackTrace stack,
31+ FetchOptions ? options,
32+ ) {
33+ if (error is http.Response && ! (options? .noResolveJson == true )) {
3034 try {
3135 final data = json.decode (error.body) as Map <String , dynamic >;
3236 return StorageException .fromJson (data, '${error .statusCode }' );
@@ -70,7 +74,7 @@ class Fetch {
7074 return _handleResponse (streamedResponse, options);
7175 }
7276
73- Future <dynamic > _handleMultipartRequest (
77+ Future <dynamic > _handleFileRequest (
7478 String method,
7579 String url,
7680 File file,
@@ -79,7 +83,6 @@ class Fetch {
7983 int retryAttempts,
8084 StorageRetryController ? retryController,
8185 ) async {
82- final headers = options? .headers ?? {};
8386 final contentType = fileOptions.contentType != null
8487 ? MediaType .parse (fileOptions.contentType! )
8588 : _parseMediaType (file.path);
@@ -89,28 +92,15 @@ class Fetch {
8992 filename: file.path,
9093 contentType: contentType,
9194 );
92- final request = http.MultipartRequest (method, Uri .parse (url))
93- ..headers.addAll (headers)
94- ..files.add (multipartFile)
95- ..fields['cacheControl' ] = fileOptions.cacheControl
96- ..headers['x-upsert' ] = fileOptions.upsert.toString ();
97-
98- final http.StreamedResponse streamedResponse;
99- final r = RetryOptions (maxAttempts: (retryAttempts + 1 ));
100- streamedResponse = await r.retry< http.StreamedResponse > (
101- () async {
102- if (httpClient != null ) {
103- return httpClient! .send (request);
104- } else {
105- return request.send ();
106- }
107- },
108- retryIf: (error) =>
109- retryController? .cancelled != true &&
110- (error is ClientException || error is TimeoutException ),
95+ return _handleMultipartRequest (
96+ method,
97+ url,
98+ multipartFile,
99+ fileOptions,
100+ options,
101+ retryAttempts,
102+ retryController,
111103 );
112-
113- return _handleResponse (streamedResponse, options);
114104 }
115105
116106 Future <dynamic > _handleBinaryFileRequest (
@@ -122,7 +112,6 @@ class Fetch {
122112 int retryAttempts,
123113 StorageRetryController ? retryController,
124114 ) async {
125- final headers = options? .headers ?? {};
126115 final contentType = fileOptions.contentType != null
127116 ? MediaType .parse (fileOptions.contentType! )
128117 : _parseMediaType (url);
@@ -133,11 +122,38 @@ class Fetch {
133122 filename: '' ,
134123 contentType: contentType,
135124 );
125+ return _handleMultipartRequest (
126+ method,
127+ url,
128+ multipartFile,
129+ fileOptions,
130+ options,
131+ retryAttempts,
132+ retryController,
133+ );
134+ }
135+
136+ Future <dynamic > _handleMultipartRequest (
137+ String method,
138+ String url,
139+ MultipartFile multipartFile,
140+ FileOptions fileOptions,
141+ FetchOptions ? options,
142+ int retryAttempts,
143+ StorageRetryController ? retryController,
144+ ) async {
145+ final headers = options? .headers ?? {};
136146 final request = http.MultipartRequest (method, Uri .parse (url))
137147 ..headers.addAll (headers)
138148 ..files.add (multipartFile)
139149 ..fields['cacheControl' ] = fileOptions.cacheControl
140150 ..headers['x-upsert' ] = fileOptions.upsert.toString ();
151+ if (fileOptions.metadata != null ) {
152+ request.fields['metadata' ] = json.encode (fileOptions.metadata);
153+ }
154+ if (fileOptions.headers != null ) {
155+ request.headers.addAll (fileOptions.headers! );
156+ }
141157
142158 final http.StreamedResponse streamedResponse;
143159 final r = RetryOptions (maxAttempts: (retryAttempts + 1 ));
@@ -170,10 +186,19 @@ class Fetch {
170186 return jsonBody;
171187 }
172188 } else {
173- throw _handleError (response, StackTrace .current);
189+ throw _handleError (response, StackTrace .current, options );
174190 }
175191 }
176192
193+ Future <dynamic > head (String url, {FetchOptions ? options}) async {
194+ return _handleRequest (
195+ 'HEAD' ,
196+ url,
197+ null ,
198+ FetchOptions (headers: options? .headers, noResolveJson: true ),
199+ );
200+ }
201+
177202 Future <dynamic > get (String url, {FetchOptions ? options}) async {
178203 return _handleRequest ('GET' , url, null , options);
179204 }
@@ -210,7 +235,7 @@ class Fetch {
210235 required int retryAttempts,
211236 required StorageRetryController ? retryController,
212237 }) async {
213- return _handleMultipartRequest ('POST' , url, file, fileOptions, options,
238+ return _handleFileRequest ('POST' , url, file, fileOptions, options,
214239 retryAttempts, retryController);
215240 }
216241
@@ -222,7 +247,7 @@ class Fetch {
222247 required int retryAttempts,
223248 required StorageRetryController ? retryController,
224249 }) async {
225- return _handleMultipartRequest (
250+ return _handleFileRequest (
226251 'PUT' ,
227252 url,
228253 file,
0 commit comments