FormData.js 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * FormData for XMLHttpRequest 2 - Polyfill for Web Worker
  3. * (c) 2014 Rob Wu <rob@robwu.nl>
  4. * License: MIT
  5. * - append(name, value[, filename])
  6. * - XMLHttpRequest.prototype.send(object FormData)
  7. *
  8. * Specification: http://www.w3.org/TR/XMLHttpRequest/#formdata
  9. * http://www.w3.org/TR/XMLHttpRequest/#the-send-method
  10. * The .append() implementation also accepts Uint8Array and ArrayBuffer objects
  11. * Web Workers do not natively support FormData:
  12. * http://dev.w3.org/html5/workers/#apis-available-to-workers
  13. * Originally released in 2012 as a part of http://stackoverflow.com/a/10002486.
  14. * Updates since initial release:
  15. * - Forward-compatibility by testing whether FormData exists before defining it.
  16. * - Increased robustness of .append.
  17. * - Allow any typed array in .append.
  18. * - Remove use of String.prototype.toString to work around a Firefox bug.
  19. * - Use typed array in xhr.send instead of arraybuffer to get rid of deprecation
  20. * warnings.
  21. **/
  22. (function(exports) {
  23. if (exports.FormData) {
  24. // Don't replace FormData if it already exists
  25. return;
  26. }
  27. // Export variable to the global scope
  28. exports.FormData = FormData;
  29. var ___send$rw = XMLHttpRequest.prototype.send;
  30. XMLHttpRequest.prototype.send = function(data) {
  31. if (data instanceof FormData) {
  32. if (!data.__endedMultipart) data.__append('--' + data.boundary + '--\r\n');
  33. data.__endedMultipart = true;
  34. this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + data.boundary);
  35. data = new Uint8Array(data.data);
  36. }
  37. // Invoke original XHR.send
  38. return ___send$rw.call(this, data);
  39. };
  40. function FormData() {
  41. // Force a Constructor
  42. if (!(this instanceof FormData)) return new FormData();
  43. // Generate a random boundary - This must be unique with respect to the form's contents.
  44. this.boundary = '------RWWorkerFormDataBoundary' + Math.random().toString(36);
  45. var internal_data = this.data = [];
  46. /**
  47. * Internal method.
  48. * @param inp String | ArrayBuffer | Uint8Array Input
  49. */
  50. this.__append = function(inp) {
  51. var i = 0, len;
  52. if (typeof inp == 'string') {
  53. for (len = inp.length; i < len; ++i)
  54. internal_data.push(inp.charCodeAt(i) & 0xff);
  55. } else if (inp && inp.byteLength) {/*If ArrayBuffer or typed array */
  56. if (!('byteOffset' in inp)) /* If ArrayBuffer, wrap in view */
  57. inp = new Uint8Array(inp);
  58. for (len = inp.byteLength; i < len; ++i)
  59. internal_data.push(inp[i] & 0xff);
  60. }
  61. };
  62. }
  63. /**
  64. * @param name String Key name
  65. * @param value String|Blob|File|typed array|ArrayBuffer Value
  66. * @param filename String Optional File name (when value is not a string).
  67. **/
  68. FormData.prototype.append = function(name, value, filename) {
  69. if (this.__endedMultipart) {
  70. // Truncate the closing boundary
  71. this.data.length -= this.boundary.length + 6;
  72. this.__endedMultipart = false;
  73. }
  74. if (arguments.length < 2) {
  75. throw new SyntaxError('Not enough arguments');
  76. }
  77. var part = '--' + this.boundary + '\r\n' +
  78. 'Content-Disposition: form-data; name="' + name + '"';
  79. if (value instanceof File || value instanceof Blob) {
  80. return this.append(name,
  81. new Uint8Array(new FileReaderSync().readAsArrayBuffer(value)),
  82. filename || value.name);
  83. } else if (typeof value.byteLength == 'number') {
  84. // Duck-typed typed array or array buffer
  85. part += '; filename="'+ (filename || 'blob').replace(/"/g,'%22') +'"\r\n';
  86. part += 'Content-Type: application/octet-stream\r\n\r\n';
  87. this.__append(part);
  88. this.__append(value);
  89. part = '\r\n';
  90. } else {
  91. part += '\r\n\r\n' + value + '\r\n';
  92. }
  93. this.__append(part);
  94. };
  95. })(this || self);