FormData.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow
  9. */
  10. 'use strict';
  11. type FormDataValue = any;
  12. type FormDataNameValuePair = [string, FormDataValue];
  13. type Headers = {[name: string]: string, ...};
  14. type FormDataPart =
  15. | {
  16. string: string,
  17. headers: Headers,
  18. ...
  19. }
  20. | {
  21. uri: string,
  22. headers: Headers,
  23. name?: string,
  24. type?: string,
  25. ...
  26. };
  27. /**
  28. * Polyfill for XMLHttpRequest2 FormData API, allowing multipart POST requests
  29. * with mixed data (string, native files) to be submitted via XMLHttpRequest.
  30. *
  31. * Example:
  32. *
  33. * var photo = {
  34. * uri: uriFromCameraRoll,
  35. * type: 'image/jpeg',
  36. * name: 'photo.jpg',
  37. * };
  38. *
  39. * var body = new FormData();
  40. * body.append('authToken', 'secret');
  41. * body.append('photo', photo);
  42. * body.append('title', 'A beautiful photo!');
  43. *
  44. * xhr.open('POST', serverURL);
  45. * xhr.send(body);
  46. */
  47. class FormData {
  48. _parts: Array<FormDataNameValuePair>;
  49. constructor() {
  50. this._parts = [];
  51. }
  52. append(key: string, value: FormDataValue) {
  53. // The XMLHttpRequest spec doesn't specify if duplicate keys are allowed.
  54. // MDN says that any new values should be appended to existing values.
  55. // In any case, major browsers allow duplicate keys, so that's what we'll do
  56. // too. They'll simply get appended as additional form data parts in the
  57. // request body, leaving the server to deal with them.
  58. this._parts.push([key, value]);
  59. }
  60. getParts(): Array<FormDataPart> {
  61. return this._parts.map(([name, value]) => {
  62. const contentDisposition = 'form-data; name="' + name + '"';
  63. const headers: Headers = {'content-disposition': contentDisposition};
  64. // The body part is a "blob", which in React Native just means
  65. // an object with a `uri` attribute. Optionally, it can also
  66. // have a `name` and `type` attribute to specify filename and
  67. // content type (cf. web Blob interface.)
  68. if (typeof value === 'object' && value) {
  69. if (typeof value.name === 'string') {
  70. headers['content-disposition'] += '; filename="' + value.name + '"';
  71. }
  72. if (typeof value.type === 'string') {
  73. headers['content-type'] = value.type;
  74. }
  75. return {...value, headers, fieldName: name};
  76. }
  77. // Convert non-object values to strings as per FormData.append() spec
  78. return {string: String(value), headers, fieldName: name};
  79. });
  80. }
  81. }
  82. module.exports = FormData;