11
11
'use strict' ;
12
12
13
13
type FormDataValue = string | { name ?: string , type ?: string , uri : string } ;
14
- type FormDataNameValuePair = [ string , FormDataValue ] ;
14
+ type FormDataNameValueTuple = [ string , FormDataValue , Headers ] ;
15
15
16
16
type Headers = { [ name : string ] : string , ...} ;
17
17
type FormDataPart =
@@ -44,24 +44,25 @@ type FormDataPart =
44
44
* body.append('authToken', 'secret');
45
45
* body.append('photo', photo);
46
46
* body.append('title', 'A beautiful photo!');
47
+ * body.append('someInfo', JSON.stringify({date:new Date()}, { "content-type": "application/json" }));
47
48
*
48
49
* xhr.open('POST', serverURL);
49
50
* xhr.send(body);
50
51
*/
51
52
class FormData {
52
- _parts : Array < FormDataNameValuePair > ;
53
+ _parts : Array < FormDataNameValueTuple > ;
53
54
54
55
constructor() {
55
56
this . _parts = [ ] ;
56
57
}
57
58
58
- append(key: string, value: FormDataValue) {
59
+ append(key: string, value: FormDataValue, headers?: Headers ) {
59
60
// The XMLHttpRequest spec doesn't specify if duplicate keys are allowed.
60
61
// MDN says that any new values should be appended to existing values.
61
62
// In any case, major browsers allow duplicate keys, so that's what we'll do
62
63
// too. They'll simply get appended as additional form data parts in the
63
64
// request body, leaving the server to deal with them.
64
- this . _parts . push ( [ key , value ] ) ;
65
+ this . _parts . push ( [ key , value , headers ] ) ;
65
66
}
66
67
67
68
getAll(key: string): Array< FormDataValue > {
@@ -71,20 +72,26 @@ class FormData {
71
72
}
72
73
73
74
getParts(): Array< FormDataPart > {
74
- return this . _parts . map ( ( [ name , value ] ) => {
75
- const contentDisposition = 'form-data; name="' + name + '"' ;
76
-
77
- const headers : Headers = { 'content-disposition' : contentDisposition } ;
78
-
75
+ return this . _parts . map ( ( [ name , value , originalHeaders ] ) => {
76
+ if ( ! originalHeaders ) {
77
+ originalHeaders = { } ;
78
+ }
79
+ const isContentDispositionNeeded =
80
+ ! originalHeaders [ 'content-disposition' ] ;
81
+ const contentDisposition : Partial < Headers > = isContentDispositionNeeded
82
+ ? { 'content-disposition' : 'form-data; name="' + name + '"' }
83
+ : { } ;
84
+ const headers: Headers = {
85
+ ...originalHeaders ,
86
+ ...contentDisposition ,
87
+ } ;
79
88
// The body part is a "blob", which in React Native just means
80
89
// an object with a `uri` attribute. Optionally, it can also
81
90
// have a `name` and `type` attribute to specify filename and
82
91
// content type (cf. web Blob interface.)
83
92
if (typeof value === 'object' && ! Array . isArray ( value ) && value ) {
84
- if ( typeof value . name === 'string' ) {
85
- headers [ 'content-disposition' ] += `; filename="${
86
- value . name
87
- } "; filename*=utf-8''${ encodeURI ( value . name ) } `;
93
+ if ( typeof value . name === 'string' && isContentDispositionNeeded ) {
94
+ headers [ 'content-disposition' ] += '; filename="' + value . name + '"' ;
88
95
}
89
96
if (typeof value.type === 'string') {
90
97
headers [ 'content-type' ] = value . type ;
0 commit comments