How to upload files in Web Workers when FormData is not defined How to upload files in Web Workers when FormData is not defined php php

How to upload files in Web Workers when FormData is not defined


I have written the following polyfill to emulate the FormData method in Web Workers. Since Web workers do not support DOM, the new FormData(<HTMLFormElement>); constructor call is not supported either.
File and Blob objects, typed arrays and strings are supported by the polyfill though.

It was originally posted as a part of the answer to Upload a File in a Google Chrome Extension. To see an example of how it can be used, have a look at the other answer.

/* * FormData for XMLHttpRequest 2  -  Polyfill for Web Worker  (c) 2012 Rob W * License: Creative Commons BY - http://creativecommons.org/licenses/by/3.0/ * - append(name, value[, filename]) * - toString: Returns an ArrayBuffer object *  * Specification: http://www.w3.org/TR/XMLHttpRequest/#formdata *                http://www.w3.org/TR/XMLHttpRequest/#the-send-method * The .append() implementation also accepts Uint8Array and ArrayBuffer objects * Web Workers do not natively support FormData: *                http://dev.w3.org/html5/workers/#apis-available-to-workers **/(function() {    // Export variable to the global scope    (this == undefined ? self : this)['FormData'] = FormData;    var ___send$rw = XMLHttpRequest.prototype.send;    XMLHttpRequest.prototype['send'] = function(data) {        if (data instanceof FormData) {            if (!data.__endedMultipart) data.__append('--' + data.boundary + '--\r\n');            data.__endedMultipart = true;            this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + data.boundary);            data = new Uint8Array(data.data).buffer;        }        // Invoke original XHR.send        return ___send$rw.call(this, data);    };    function FormData() {        // Force a Constructor        if (!(this instanceof FormData)) return new FormData();        // Generate a random boundary - This must be unique with respect to the form's contents.        this.boundary = '------RWWorkerFormDataBoundary' + Math.random().toString(36);        var internal_data = this.data = [];        /**        * Internal method.        * @param inp String | ArrayBuffer | Uint8Array  Input        */        this.__append = function(inp) {            var i=0, len;            if (typeof inp === 'string') {                for (len=inp.length; i<len; i++)                    internal_data.push(inp.charCodeAt(i) & 0xff);            } else if (inp && inp.byteLength) {/*If ArrayBuffer or typed array */                if (!('byteOffset' in inp))   /* If ArrayBuffer, wrap in view */                    inp = new Uint8Array(inp);                for (len=inp.byteLength; i<len; i++)                    internal_data.push(inp[i] & 0xff);            }        };    }    /**    * @param name     String                                  Key name    * @param value    String|Blob|File|Uint8Array|ArrayBuffer Value    * @param filename String                                  Optional File name (when value is not a string).    **/    FormData.prototype['append'] = function(name, value, filename) {        if (this.__endedMultipart) {            // Truncate the closing boundary            this.data.length -= this.boundary.length + 6;            this.__endedMultipart = false;        }        var valueType = Object.prototype.toString.call(value),            part = '--' + this.boundary + '\r\n' +                 'Content-Disposition: form-data; name="' + name + '"';        if (/^\[object (?:Blob|File)(?:Constructor)?\]$/.test(valueType)) {            return this.append(name,                            new Uint8Array(new FileReaderSync().readAsArrayBuffer(value)),                            filename || value.name);        } else if (/^\[object (?:Uint8Array|ArrayBuffer)(?:Constructor)?\]$/.test(valueType)) {            part += '; filename="'+ (filename || 'blob').replace(/"/g,'%22') +'"\r\n';            part += 'Content-Type: application/octet-stream\r\n\r\n';            this.__append(part);            this.__append(value);            part = '\r\n';        } else {            part += '\r\n\r\n' + value + '\r\n';        }        this.__append(part);    };})();