|
|
@@ -11,100 +11,95 @@
|
|
|
* @license MIT
|
|
|
*/
|
|
|
|
|
|
-var Url = require("url")
|
|
|
- , spawn = require("child_process").spawn
|
|
|
- , fs = require('fs');
|
|
|
+const { URL } = require('url')
|
|
|
+var spawn = require('child_process').spawn
|
|
|
+var fs = require('fs')
|
|
|
|
|
|
-exports.XMLHttpRequest = function() {
|
|
|
+exports.XMLHttpRequest = function () {
|
|
|
/**
|
|
|
* Private variables
|
|
|
*/
|
|
|
- var self = this;
|
|
|
- var http = require('http');
|
|
|
- var https = require('https');
|
|
|
+ var self = this
|
|
|
+ var http = require('http')
|
|
|
+ var https = require('https')
|
|
|
|
|
|
// Holds http.js objects
|
|
|
- var client;
|
|
|
- var request;
|
|
|
- var response;
|
|
|
+ var request
|
|
|
+ var response
|
|
|
|
|
|
// Request settings
|
|
|
- var settings = {};
|
|
|
+ var settings = {}
|
|
|
|
|
|
// Set some default headers
|
|
|
var defaultHeaders = {
|
|
|
- "User-Agent": "node-XMLHttpRequest",
|
|
|
- "Accept": "*/*",
|
|
|
- };
|
|
|
+ 'User-Agent': 'node-XMLHttpRequest',
|
|
|
+ Accept: '*/*'
|
|
|
+ }
|
|
|
|
|
|
- var headers = defaultHeaders;
|
|
|
+ var headers = defaultHeaders
|
|
|
|
|
|
// These headers are not user setable.
|
|
|
// The following are allowed but banned in the spec:
|
|
|
// * user-agent
|
|
|
var forbiddenRequestHeaders = [
|
|
|
- "accept-charset",
|
|
|
- "accept-encoding",
|
|
|
- "access-control-request-headers",
|
|
|
- "access-control-request-method",
|
|
|
- "connection",
|
|
|
- "content-length",
|
|
|
- "content-transfer-encoding",
|
|
|
- //"cookie",
|
|
|
- "cookie2",
|
|
|
- "date",
|
|
|
- "expect",
|
|
|
- "host",
|
|
|
- "keep-alive",
|
|
|
- "origin",
|
|
|
- "referer",
|
|
|
- "te",
|
|
|
- "trailer",
|
|
|
- "transfer-encoding",
|
|
|
- "upgrade",
|
|
|
- "via"
|
|
|
- ];
|
|
|
+ 'accept-charset',
|
|
|
+ 'accept-encoding',
|
|
|
+ 'access-control-request-headers',
|
|
|
+ 'access-control-request-method',
|
|
|
+ 'connection',
|
|
|
+ 'content-length',
|
|
|
+ 'content-transfer-encoding',
|
|
|
+ // "cookie",
|
|
|
+ 'cookie2',
|
|
|
+ 'date',
|
|
|
+ 'expect',
|
|
|
+ 'host',
|
|
|
+ 'keep-alive',
|
|
|
+ 'origin',
|
|
|
+ 'referer',
|
|
|
+ 'te',
|
|
|
+ 'trailer',
|
|
|
+ 'transfer-encoding',
|
|
|
+ 'upgrade',
|
|
|
+ 'via'
|
|
|
+ ]
|
|
|
|
|
|
// These request methods are not allowed
|
|
|
- var forbiddenRequestMethods = [
|
|
|
- "TRACE",
|
|
|
- "TRACK",
|
|
|
- "CONNECT"
|
|
|
- ];
|
|
|
+ var forbiddenRequestMethods = ['TRACE', 'TRACK', 'CONNECT']
|
|
|
|
|
|
// Send flag
|
|
|
- var sendFlag = false;
|
|
|
+ var sendFlag = false
|
|
|
// Error flag, used when errors occur or abort is called
|
|
|
- var errorFlag = false;
|
|
|
+ var errorFlag = false
|
|
|
|
|
|
// Event listeners
|
|
|
- var listeners = {};
|
|
|
+ var listeners = {}
|
|
|
|
|
|
/**
|
|
|
* Constants
|
|
|
*/
|
|
|
|
|
|
- this.UNSENT = 0;
|
|
|
- this.OPENED = 1;
|
|
|
- this.HEADERS_RECEIVED = 2;
|
|
|
- this.LOADING = 3;
|
|
|
- this.DONE = 4;
|
|
|
+ this.UNSENT = 0
|
|
|
+ this.OPENED = 1
|
|
|
+ this.HEADERS_RECEIVED = 2
|
|
|
+ this.LOADING = 3
|
|
|
+ this.DONE = 4
|
|
|
|
|
|
/**
|
|
|
* Public vars
|
|
|
*/
|
|
|
|
|
|
// Current state
|
|
|
- this.readyState = this.UNSENT;
|
|
|
+ this.readyState = this.UNSENT
|
|
|
|
|
|
// default ready state change handler in case one is not set or is set late
|
|
|
- this.onreadystatechange = null;
|
|
|
+ this.onreadystatechange = null
|
|
|
|
|
|
// Result & response
|
|
|
- this.responseText = "";
|
|
|
- this.responseXML = "";
|
|
|
- this.status = null;
|
|
|
- this.statusText = null;
|
|
|
+ this.responseText = ''
|
|
|
+ this.responseXML = ''
|
|
|
+ this.status = null
|
|
|
+ this.statusText = null
|
|
|
|
|
|
/**
|
|
|
* Private methods
|
|
|
@@ -116,9 +111,11 @@ exports.XMLHttpRequest = function() {
|
|
|
* @param string header Header to validate
|
|
|
* @return boolean False if not allowed, otherwise true
|
|
|
*/
|
|
|
- var isAllowedHttpHeader = function(header) {
|
|
|
- return (header && forbiddenRequestHeaders.indexOf(header.toLowerCase()) === -1);
|
|
|
- };
|
|
|
+ var isAllowedHttpHeader = function (header) {
|
|
|
+ return (
|
|
|
+ header && forbiddenRequestHeaders.indexOf(header.toLowerCase()) === -1
|
|
|
+ )
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Check if the specified method is allowed.
|
|
|
@@ -126,9 +123,9 @@ exports.XMLHttpRequest = function() {
|
|
|
* @param string method Request method to validate
|
|
|
* @return boolean False if not allowed, otherwise true
|
|
|
*/
|
|
|
- var isAllowedHttpMethod = function(method) {
|
|
|
- return (method && forbiddenRequestMethods.indexOf(method) === -1);
|
|
|
- };
|
|
|
+ var isAllowedHttpMethod = function (method) {
|
|
|
+ return method && forbiddenRequestMethods.indexOf(method) === -1
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Public methods
|
|
|
@@ -143,26 +140,25 @@ exports.XMLHttpRequest = function() {
|
|
|
* @param string user Username for basic authentication (optional)
|
|
|
* @param string password Password for basic authentication (optional)
|
|
|
*/
|
|
|
- this.open = function(method, url, async, user, password) {
|
|
|
- this.abort();
|
|
|
- errorFlag = false;
|
|
|
+ this.open = function (method, url, async, user, password) {
|
|
|
+ this.abort()
|
|
|
+ errorFlag = false
|
|
|
|
|
|
// Check for valid request method
|
|
|
if (!isAllowedHttpMethod(method)) {
|
|
|
- throw "SecurityError: Request method not allowed";
|
|
|
- return;
|
|
|
+ throw new Error('SecurityError: Request method not allowed')
|
|
|
}
|
|
|
|
|
|
settings = {
|
|
|
- "method": method,
|
|
|
- "url": url.toString(),
|
|
|
- "async": (typeof async !== "boolean" ? true : async),
|
|
|
- "user": user || null,
|
|
|
- "password": password || null
|
|
|
- };
|
|
|
+ method: method,
|
|
|
+ url: url.toString(),
|
|
|
+ async: typeof async !== 'boolean' ? true : async,
|
|
|
+ user: user || null,
|
|
|
+ password: password || null
|
|
|
+ }
|
|
|
|
|
|
- setState(this.OPENED);
|
|
|
- };
|
|
|
+ setState(this.OPENED)
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Sets a header for the request.
|
|
|
@@ -170,19 +166,21 @@ exports.XMLHttpRequest = function() {
|
|
|
* @param string header Header name
|
|
|
* @param string value Header value
|
|
|
*/
|
|
|
- this.setRequestHeader = function(header, value) {
|
|
|
- if (this.readyState != this.OPENED) {
|
|
|
- throw "INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN";
|
|
|
+ this.setRequestHeader = function (header, value) {
|
|
|
+ if (this.readyState !== this.OPENED) {
|
|
|
+ throw new Error(
|
|
|
+ 'INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN'
|
|
|
+ )
|
|
|
}
|
|
|
if (!isAllowedHttpHeader(header)) {
|
|
|
- console.warn('Refused to set unsafe header "' + header + '"');
|
|
|
- return;
|
|
|
+ console.warn('Refused to set unsafe header "' + header + '"')
|
|
|
+ return
|
|
|
}
|
|
|
if (sendFlag) {
|
|
|
- throw "INVALID_STATE_ERR: send flag is true";
|
|
|
+ throw new Error('INVALID_STATE_ERR: send flag is true')
|
|
|
}
|
|
|
- headers[header] = value;
|
|
|
- };
|
|
|
+ headers[header] = value
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Gets a header from the server response.
|
|
|
@@ -190,37 +188,38 @@ exports.XMLHttpRequest = function() {
|
|
|
* @param string header Name of header to get.
|
|
|
* @return string Text of the header or null if it doesn't exist.
|
|
|
*/
|
|
|
- this.getResponseHeader = function(header) {
|
|
|
- if (typeof header === "string"
|
|
|
- && this.readyState > this.OPENED
|
|
|
- && response.headers[header.toLowerCase()]
|
|
|
- && !errorFlag
|
|
|
+ this.getResponseHeader = function (header) {
|
|
|
+ if (
|
|
|
+ typeof header === 'string' &&
|
|
|
+ this.readyState > this.OPENED &&
|
|
|
+ response.headers[header.toLowerCase()] &&
|
|
|
+ !errorFlag
|
|
|
) {
|
|
|
- return response.headers[header.toLowerCase()];
|
|
|
+ return response.headers[header.toLowerCase()]
|
|
|
}
|
|
|
|
|
|
- return null;
|
|
|
- };
|
|
|
+ return null
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Gets all the response headers.
|
|
|
*
|
|
|
* @return string A string with all response headers separated by CR+LF
|
|
|
*/
|
|
|
- this.getAllResponseHeaders = function() {
|
|
|
+ this.getAllResponseHeaders = function () {
|
|
|
if (this.readyState < this.HEADERS_RECEIVED || errorFlag) {
|
|
|
- return "";
|
|
|
+ return ''
|
|
|
}
|
|
|
- var result = "";
|
|
|
+ var result = ''
|
|
|
|
|
|
for (var i in response.headers) {
|
|
|
// Cookie headers are excluded
|
|
|
- if (i !== "set-cookie" && i !== "set-cookie2") {
|
|
|
- result += i + ": " + response.headers[i] + "\r\n";
|
|
|
+ if (i !== 'set-cookie' && i !== 'set-cookie2') {
|
|
|
+ result += i + ': ' + response.headers[i] + '\r\n'
|
|
|
}
|
|
|
}
|
|
|
- return result.substr(0, result.length - 2);
|
|
|
- };
|
|
|
+ return result.substr(0, result.length - 2)
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Gets a request header
|
|
|
@@ -228,13 +227,13 @@ exports.XMLHttpRequest = function() {
|
|
|
* @param string name Name of header to get
|
|
|
* @return string Returns the request header or empty string if not set
|
|
|
*/
|
|
|
- this.getRequestHeader = function(name) {
|
|
|
+ this.getRequestHeader = function (name) {
|
|
|
// @TODO Make this case insensitive
|
|
|
- if (typeof name === "string" && headers[name]) {
|
|
|
- return headers[name];
|
|
|
+ if (typeof name === 'string' && headers[name]) {
|
|
|
+ return headers[name]
|
|
|
}
|
|
|
|
|
|
- return "";
|
|
|
+ return ''
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -242,103 +241,108 @@ exports.XMLHttpRequest = function() {
|
|
|
*
|
|
|
* @param string data Optional data to send as request body.
|
|
|
*/
|
|
|
- this.send = function(data) {
|
|
|
- if (this.readyState != this.OPENED) {
|
|
|
- throw "INVALID_STATE_ERR: connection must be opened before send() is called";
|
|
|
+ this.send = function (data) {
|
|
|
+ if (this.readyState !== this.OPENED) {
|
|
|
+ throw new Error(
|
|
|
+ 'INVALID_STATE_ERR: connection must be opened before send() is called'
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
if (sendFlag) {
|
|
|
- throw "INVALID_STATE_ERR: send has already been called";
|
|
|
+ throw new Error('INVALID_STATE_ERR: send has already been called')
|
|
|
}
|
|
|
|
|
|
- var ssl = false, local = false;
|
|
|
- var url = Url.parse(settings.url);
|
|
|
+ var host
|
|
|
+ var ssl = false
|
|
|
+ var local = false
|
|
|
+ var url = new URL(settings.url)
|
|
|
|
|
|
// Determine the server
|
|
|
switch (url.protocol) {
|
|
|
case 'https:':
|
|
|
- ssl = true;
|
|
|
- // SSL & non-SSL both need host, no break here.
|
|
|
+ ssl = true
|
|
|
+ host = url.hostname
|
|
|
+ break
|
|
|
case 'http:':
|
|
|
- var host = url.hostname;
|
|
|
- break;
|
|
|
+ host = url.hostname
|
|
|
+ break
|
|
|
|
|
|
case 'file:':
|
|
|
- local = true;
|
|
|
- break;
|
|
|
+ local = true
|
|
|
+ break
|
|
|
|
|
|
case undefined:
|
|
|
case '':
|
|
|
- var host = "localhost";
|
|
|
- break;
|
|
|
+ host = 'localhost'
|
|
|
+ break
|
|
|
|
|
|
default:
|
|
|
- throw "Protocol not supported.";
|
|
|
+ throw new Error('Protocol not supported.')
|
|
|
}
|
|
|
|
|
|
// Load files off the local filesystem (file://)
|
|
|
if (local) {
|
|
|
- if (settings.method !== "GET") {
|
|
|
- throw "XMLHttpRequest: Only GET method is supported";
|
|
|
+ if (settings.method !== 'GET') {
|
|
|
+ throw new Error('XMLHttpRequest: Only GET method is supported')
|
|
|
}
|
|
|
|
|
|
if (settings.async) {
|
|
|
- fs.readFile(url.pathname, 'utf8', function(error, data) {
|
|
|
+ fs.readFile(url.pathname, 'utf8', (error, data) => {
|
|
|
if (error) {
|
|
|
- self.handleError(error);
|
|
|
+ self.handleError(error)
|
|
|
} else {
|
|
|
- self.status = 200;
|
|
|
- self.responseText = data;
|
|
|
- setState(self.DONE);
|
|
|
+ self.status = 200
|
|
|
+ self.responseText = data
|
|
|
+ setState(self.DONE)
|
|
|
}
|
|
|
- });
|
|
|
+ })
|
|
|
} else {
|
|
|
try {
|
|
|
- this.responseText = fs.readFileSync(url.pathname, 'utf8');
|
|
|
- this.status = 200;
|
|
|
- setState(self.DONE);
|
|
|
- } catch(e) {
|
|
|
- this.handleError(e);
|
|
|
+ this.responseText = fs.readFileSync(url.pathname, 'utf8')
|
|
|
+ this.status = 200
|
|
|
+ setState(self.DONE)
|
|
|
+ } catch (e) {
|
|
|
+ this.handleError(e)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return;
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
// Default to port 80. If accessing localhost on another port be sure
|
|
|
// to use http://localhost:port/path
|
|
|
- var port = url.port || (ssl ? 443 : 80);
|
|
|
+ var port = url.port || (ssl ? 443 : 80)
|
|
|
// Add query string if one is used
|
|
|
- var uri = url.pathname + (url.search ? url.search : '');
|
|
|
+ var uri = url.pathname + (url.search ? url.search : '')
|
|
|
|
|
|
// Set the Host header or the server may reject the request
|
|
|
- headers["Host"] = host;
|
|
|
+ headers.Host = host
|
|
|
if (!((ssl && port === 443) || port === 80)) {
|
|
|
- headers["Host"] += ':' + url.port;
|
|
|
+ headers.Host += ':' + url.port
|
|
|
}
|
|
|
|
|
|
// Set Basic Auth if necessary
|
|
|
if (settings.user) {
|
|
|
- if (typeof settings.password == "undefined") {
|
|
|
- settings.password = "";
|
|
|
+ if (typeof settings.password === 'undefined') {
|
|
|
+ settings.password = ''
|
|
|
}
|
|
|
- var authBuf = new Buffer(settings.user + ":" + settings.password);
|
|
|
- headers["Authorization"] = "Basic " + authBuf.toString("base64");
|
|
|
+ var authBuf = Buffer.from(settings.user + ':' + settings.password)
|
|
|
+ headers.Authorization = 'Basic ' + authBuf.toString('base64')
|
|
|
}
|
|
|
|
|
|
// Set content length header
|
|
|
- if (settings.method === "GET" || settings.method === "HEAD") {
|
|
|
- data = null;
|
|
|
+ if (settings.method === 'GET' || settings.method === 'HEAD') {
|
|
|
+ data = null
|
|
|
} else if (data) {
|
|
|
- headers["Content-Length"] = Buffer.byteLength(data);
|
|
|
+ headers['Content-Length'] = Buffer.byteLength(data)
|
|
|
|
|
|
- if (!headers["Content-Type"]) {
|
|
|
- headers["Content-Type"] = "text/plain;charset=UTF-8";
|
|
|
+ if (!headers['Content-Type']) {
|
|
|
+ headers['Content-Type'] = 'text/plain;charset=UTF-8'
|
|
|
}
|
|
|
- } else if (settings.method === "POST") {
|
|
|
+ } else if (settings.method === 'POST') {
|
|
|
// For a post with no data set Content-Length: 0.
|
|
|
// This is required by buggy servers that don't meet the specs.
|
|
|
- headers["Content-Length"] = 0;
|
|
|
+ headers['Content-Length'] = 0
|
|
|
}
|
|
|
|
|
|
var options = {
|
|
|
@@ -347,202 +351,229 @@ exports.XMLHttpRequest = function() {
|
|
|
path: uri,
|
|
|
method: settings.method,
|
|
|
headers: headers
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
// Reset error flag
|
|
|
- errorFlag = false;
|
|
|
+ errorFlag = false
|
|
|
|
|
|
// Handle async requests
|
|
|
if (settings.async) {
|
|
|
// Use the proper protocol
|
|
|
- var doRequest = ssl ? https.request : http.request;
|
|
|
+ var doRequest = ssl ? https.request : http.request
|
|
|
|
|
|
// Request is being sent, set send flag
|
|
|
- sendFlag = true;
|
|
|
+ sendFlag = true
|
|
|
|
|
|
// As per spec, this is called here for historical reasons.
|
|
|
- self.dispatchEvent("readystatechange");
|
|
|
+ self.dispatchEvent('readystatechange')
|
|
|
|
|
|
// Create the request
|
|
|
- request = doRequest(options, function(resp) {
|
|
|
- response = resp;
|
|
|
- response.setEncoding("utf8");
|
|
|
+ request = doRequest(options, (resp) => {
|
|
|
+ response = resp
|
|
|
+ response.setEncoding('utf8')
|
|
|
|
|
|
- setState(self.HEADERS_RECEIVED);
|
|
|
- self.status = response.statusCode;
|
|
|
+ setState(self.HEADERS_RECEIVED)
|
|
|
+ self.status = response.statusCode
|
|
|
|
|
|
- response.on('data', function(chunk) {
|
|
|
+ response.on('data', (chunk) => {
|
|
|
// Make sure there's some data
|
|
|
if (chunk) {
|
|
|
- self.responseText += chunk;
|
|
|
+ self.responseText += chunk
|
|
|
}
|
|
|
// Don't emit state changes if the connection has been aborted.
|
|
|
if (sendFlag) {
|
|
|
- setState(self.LOADING);
|
|
|
+ setState(self.LOADING)
|
|
|
}
|
|
|
- });
|
|
|
+ })
|
|
|
|
|
|
- response.on('end', function() {
|
|
|
+ response.on('end', () => {
|
|
|
if (sendFlag) {
|
|
|
// Discard the 'end' event if the connection has been aborted
|
|
|
- setState(self.DONE);
|
|
|
- sendFlag = false;
|
|
|
+ setState(self.DONE)
|
|
|
+ sendFlag = false
|
|
|
}
|
|
|
- });
|
|
|
+ })
|
|
|
|
|
|
- response.on('error', function(error) {
|
|
|
- self.handleError(error);
|
|
|
- });
|
|
|
- }).on('error', function(error) {
|
|
|
- self.handleError(error);
|
|
|
- });
|
|
|
+ response.on('error', (error) => {
|
|
|
+ self.handleError(error)
|
|
|
+ })
|
|
|
+ }).on('error', (error) => {
|
|
|
+ self.handleError(error)
|
|
|
+ })
|
|
|
|
|
|
// Node 0.4 and later won't accept empty data. Make sure it's needed.
|
|
|
if (data) {
|
|
|
- request.write(data);
|
|
|
+ request.write(data)
|
|
|
}
|
|
|
|
|
|
- request.end();
|
|
|
+ request.end()
|
|
|
|
|
|
- self.dispatchEvent("loadstart");
|
|
|
- } else { // Synchronous
|
|
|
+ self.dispatchEvent('loadstart')
|
|
|
+ } else {
|
|
|
+ // Synchronous
|
|
|
// Create a temporary file for communication with the other Node process
|
|
|
- var syncFile = ".node-xmlhttprequest-sync-" + process.pid;
|
|
|
- fs.writeFileSync(syncFile, "", "utf8");
|
|
|
+ var syncFile = '.node-xmlhttprequest-sync-' + process.pid
|
|
|
+ fs.writeFileSync(syncFile, '', 'utf8')
|
|
|
// The async request the other Node process executes
|
|
|
- var execString = "var http = require('http'), https = require('https'), fs = require('fs');"
|
|
|
- + "var doRequest = http" + (ssl ? "s" : "") + ".request;"
|
|
|
- + "var options = " + JSON.stringify(options) + ";"
|
|
|
- + "var responseText = '';"
|
|
|
- + "var req = doRequest(options, function(response) {"
|
|
|
- + "response.setEncoding('utf8');"
|
|
|
- + "response.on('data', function(chunk) {"
|
|
|
- + "responseText += chunk;"
|
|
|
- + "});"
|
|
|
- + "response.on('end', function() {"
|
|
|
- + "fs.writeFileSync('" + syncFile + "', 'NODE-XMLHTTPREQUEST-STATUS:' + response.statusCode + ',' + responseText, 'utf8');"
|
|
|
- + "});"
|
|
|
- + "response.on('error', function(error) {"
|
|
|
- + "fs.writeFileSync('" + syncFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');"
|
|
|
- + "});"
|
|
|
- + "}).on('error', function(error) {"
|
|
|
- + "fs.writeFileSync('" + syncFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');"
|
|
|
- + "});"
|
|
|
- + (data ? "req.write('" + data.replace(/'/g, "\\'") + "');":"")
|
|
|
- + "req.end();";
|
|
|
+ var execString =
|
|
|
+ "var http = require('http'), https = require('https'), fs = require('fs');" +
|
|
|
+ 'var doRequest = http' +
|
|
|
+ (ssl ? 's' : '') +
|
|
|
+ '.request;' +
|
|
|
+ 'var options = ' +
|
|
|
+ JSON.stringify(options) +
|
|
|
+ ';' +
|
|
|
+ "var responseText = '';" +
|
|
|
+ 'var req = doRequest(options, function(response) {' +
|
|
|
+ "response.setEncoding('utf8');" +
|
|
|
+ "response.on('data', function(chunk) {" +
|
|
|
+ 'responseText += chunk;' +
|
|
|
+ '});' +
|
|
|
+ "response.on('end', function() {" +
|
|
|
+ "fs.writeFileSync('" +
|
|
|
+ syncFile +
|
|
|
+ "', 'NODE-XMLHTTPREQUEST-STATUS:' + response.statusCode + ',' + responseText, 'utf8');" +
|
|
|
+ '});' +
|
|
|
+ "response.on('error', function(error) {" +
|
|
|
+ "fs.writeFileSync('" +
|
|
|
+ syncFile +
|
|
|
+ "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');" +
|
|
|
+ '});' +
|
|
|
+ "}).on('error', function(error) {" +
|
|
|
+ "fs.writeFileSync('" +
|
|
|
+ syncFile +
|
|
|
+ "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');" +
|
|
|
+ '});' +
|
|
|
+ (data ? "req.write('" + data.replace(/'/g, "\\'") + "');" : '') +
|
|
|
+ 'req.end();'
|
|
|
// Start the other Node Process, executing this string
|
|
|
- syncProc = spawn(process.argv[0], ["-e", execString]);
|
|
|
- while((self.responseText = fs.readFileSync(syncFile, 'utf8')) == "") {
|
|
|
+ const syncProc = spawn(process.argv[0], ['-e', execString])
|
|
|
+ while ((self.responseText = fs.readFileSync(syncFile, 'utf8')) === '') {
|
|
|
// Wait while the file is empty
|
|
|
}
|
|
|
// Kill the child process once the file has data
|
|
|
- syncProc.stdin.end();
|
|
|
+ syncProc.stdin.end()
|
|
|
// Remove the temporary file
|
|
|
- fs.unlinkSync(syncFile);
|
|
|
+ fs.unlinkSync(syncFile)
|
|
|
if (self.responseText.match(/^NODE-XMLHTTPREQUEST-ERROR:/)) {
|
|
|
// If the file returned an error, handle it
|
|
|
- var errorObj = self.responseText.replace(/^NODE-XMLHTTPREQUEST-ERROR:/, "");
|
|
|
- self.handleError(errorObj);
|
|
|
+ var errorObj = self.responseText.replace(
|
|
|
+ /^NODE-XMLHTTPREQUEST-ERROR:/,
|
|
|
+ ''
|
|
|
+ )
|
|
|
+ self.handleError(errorObj)
|
|
|
} else {
|
|
|
// If the file returned okay, parse its data and move to the DONE state
|
|
|
- self.status = self.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:([0-9]*),.*/, "$1");
|
|
|
- self.responseText = self.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:[0-9]*,(.*)/, "$1");
|
|
|
- setState(self.DONE);
|
|
|
+ self.status = self.responseText.replace(
|
|
|
+ /^NODE-XMLHTTPREQUEST-STATUS:([0-9]*),.*/,
|
|
|
+ '$1'
|
|
|
+ )
|
|
|
+ self.responseText = self.responseText.replace(
|
|
|
+ /^NODE-XMLHTTPREQUEST-STATUS:[0-9]*,(.*)/,
|
|
|
+ '$1'
|
|
|
+ )
|
|
|
+ setState(self.DONE)
|
|
|
}
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Called when an error is encountered to deal with it.
|
|
|
*/
|
|
|
- this.handleError = function(error) {
|
|
|
- this.status = 503;
|
|
|
- this.statusText = error;
|
|
|
- this.responseText = error.stack;
|
|
|
- errorFlag = true;
|
|
|
- setState(this.DONE);
|
|
|
- };
|
|
|
+ this.handleError = function (error) {
|
|
|
+ this.status = 503
|
|
|
+ this.statusText = error
|
|
|
+ this.responseText = error.stack
|
|
|
+ errorFlag = true
|
|
|
+ setState(this.DONE)
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Aborts a request.
|
|
|
*/
|
|
|
- this.abort = function() {
|
|
|
+ this.abort = function () {
|
|
|
if (request) {
|
|
|
- request.abort();
|
|
|
- request = null;
|
|
|
+ request.abort()
|
|
|
+ request = null
|
|
|
}
|
|
|
|
|
|
- headers = defaultHeaders;
|
|
|
- this.responseText = "";
|
|
|
- this.responseXML = "";
|
|
|
+ headers = defaultHeaders
|
|
|
+ this.responseText = ''
|
|
|
+ this.responseXML = ''
|
|
|
|
|
|
- errorFlag = true;
|
|
|
+ errorFlag = true
|
|
|
|
|
|
- if (this.readyState !== this.UNSENT
|
|
|
- && (this.readyState !== this.OPENED || sendFlag)
|
|
|
- && this.readyState !== this.DONE) {
|
|
|
- sendFlag = false;
|
|
|
- setState(this.DONE);
|
|
|
+ if (
|
|
|
+ this.readyState !== this.UNSENT &&
|
|
|
+ (this.readyState !== this.OPENED || sendFlag) &&
|
|
|
+ this.readyState !== this.DONE
|
|
|
+ ) {
|
|
|
+ sendFlag = false
|
|
|
+ setState(this.DONE)
|
|
|
}
|
|
|
- this.readyState = this.UNSENT;
|
|
|
- };
|
|
|
+ this.readyState = this.UNSENT
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Adds an event listener. Preferred method of binding to events.
|
|
|
*/
|
|
|
- this.addEventListener = function(event, callback) {
|
|
|
+ this.addEventListener = function (event, callback) {
|
|
|
if (!(event in listeners)) {
|
|
|
- listeners[event] = [];
|
|
|
+ listeners[event] = []
|
|
|
}
|
|
|
// Currently allows duplicate callbacks. Should it?
|
|
|
- listeners[event].push(callback);
|
|
|
- };
|
|
|
+ listeners[event].push(callback)
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Remove an event callback that has already been bound.
|
|
|
* Only works on the matching funciton, cannot be a copy.
|
|
|
*/
|
|
|
- this.removeEventListener = function(event, callback) {
|
|
|
+ this.removeEventListener = function (event, callback) {
|
|
|
if (event in listeners) {
|
|
|
// Filter will return a new array with the callback removed
|
|
|
- listeners[event] = listeners[event].filter(function(ev) {
|
|
|
- return ev !== callback;
|
|
|
- });
|
|
|
+ listeners[event] = listeners[event].filter((ev) => {
|
|
|
+ return ev !== callback
|
|
|
+ })
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Dispatch any events, including both "on" methods and events attached using addEventListener.
|
|
|
*/
|
|
|
- this.dispatchEvent = function(event) {
|
|
|
- if (typeof self["on" + event] === "function") {
|
|
|
- self["on" + event]();
|
|
|
+ this.dispatchEvent = function (event) {
|
|
|
+ if (typeof self['on' + event] === 'function') {
|
|
|
+ self['on' + event]()
|
|
|
}
|
|
|
if (event in listeners) {
|
|
|
for (var i = 0, len = listeners[event].length; i < len; i++) {
|
|
|
- listeners[event][i].call(self);
|
|
|
+ listeners[event][i].call(self)
|
|
|
}
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Changes readyState and calls onreadystatechange.
|
|
|
*
|
|
|
* @param int state New state
|
|
|
*/
|
|
|
- var setState = function(state) {
|
|
|
+ var setState = function (state) {
|
|
|
if (self.readyState !== state) {
|
|
|
- self.readyState = state;
|
|
|
-
|
|
|
- if (settings.async || self.readyState < self.OPENED || self.readyState === self.DONE) {
|
|
|
- self.dispatchEvent("readystatechange");
|
|
|
+ self.readyState = state
|
|
|
+
|
|
|
+ if (
|
|
|
+ settings.async ||
|
|
|
+ self.readyState < self.OPENED ||
|
|
|
+ self.readyState === self.DONE
|
|
|
+ ) {
|
|
|
+ self.dispatchEvent('readystatechange')
|
|
|
}
|
|
|
|
|
|
if (self.readyState === self.DONE && !errorFlag) {
|
|
|
- self.dispatchEvent("load");
|
|
|
+ self.dispatchEvent('load')
|
|
|
// @TODO figure out InspectorInstrumentation::didLoadXHR(cookie)
|
|
|
- self.dispatchEvent("loadend");
|
|
|
+ self.dispatchEvent('loadend')
|
|
|
}
|
|
|
}
|
|
|
- };
|
|
|
-};
|
|
|
+ }
|
|
|
+}
|