From a5f1c430a3ef510150d87409ebdf6ff12a732fe0 Mon Sep 17 00:00:00 2001 From: toby Date: Wed, 7 Jun 2017 22:42:37 -0400 Subject: [PATCH 1/3] Add "HTTP request" operation --- src/core/config/OperationConfig.js | 33 +++++++++++++++++ src/core/operations/HTTP.js | 57 ++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index 5fd5a9ee..ddb67d28 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -3388,6 +3388,39 @@ const OperationConfig = { } ] }, + "HTTP request": { + description: [ + "Makes a HTTP request and returns the response body.", + "

", + "This operation supports different HTTP verbs like GET, POST, PUT, etc.", + "

", + "You can add headers line by line in the format Key: Value", + "

", + "This operation will throw an error for any status code that is not 200, unless the 'Ignore status code' option is checked.", + ].join("\n"), + run: HTTP.runHTTPRequest, + inputType: "string", + outputType: "string", + args: [ + { + name: "Method", + type: "option", + value: HTTP.METHODS, + }, { + name: "URL", + type: "string", + value: "", + }, { + name: "Headers", + type: "text", + value: "", + }, { + name: "Ignore status code", + type: "boolean", + value: false, + }, + ] + }, }; export default OperationConfig; diff --git a/src/core/operations/HTTP.js b/src/core/operations/HTTP.js index 28c41ad5..e80c0fb3 100755 --- a/src/core/operations/HTTP.js +++ b/src/core/operations/HTTP.js @@ -11,6 +11,14 @@ import {UAS_parser as UAParser} from "../lib/uas_parser.js"; * @namespace */ const HTTP = { + /** + * @constant + * @default + */ + METHODS: [ + "GET", "POST", "HEAD", + "PUT", "PATCH", "DELETE", + ], /** * Strip HTTP headers operation. @@ -51,6 +59,55 @@ const HTTP = { "Device Type: " + ua.deviceType + "\n"; }, + + /** + * HTTP request operation. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runHTTPRequest(input, args) { + const method = args[0], + url = args[1], + headersText = args[2], + ignoreStatusCode = args[3]; + + if (url.length === 0) return ""; + + let headers = new Headers(); + headersText.split(/\r?\n/).forEach(line => { + line = line.trim(); + + if (line.length === 0) return; + + let split = line.split(":"); + if (split.length !== 2) throw `Could not parse header in line: ${line}`; + + headers.set(split[0].trim(), split[1].trim()); + }); + + let config = { + method, + headers, + mode: "cors", + cache: "no-cache", + }; + + if (method !== "GET" && method !== "HEAD") { + config.body = input; + } + + return fetch(url, config) + .then(r => { + if (ignoreStatusCode || r.status === 200) { + return r.text(); + } else { + throw `HTTP response code was ${r.status}.`; + } + }); + }, + }; export default HTTP; From cbab995c6dd0381f559a624619ab1ce2284e4e55 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 8 Jun 2017 15:03:55 +0000 Subject: [PATCH 2/3] Added error handling and CORS support --- src/core/config/Categories.js | 3 ++ src/core/config/OperationConfig.js | 34 +++++++++++++++---- src/core/operations/HTTP.js | 54 +++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js index 9e6f6157..ea095649 100755 --- a/src/core/config/Categories.js +++ b/src/core/config/Categories.js @@ -126,6 +126,7 @@ const Categories = [ { name: "Networking", ops: [ + "HTTP request", "Strip HTTP headers", "Parse User Agent", "Parse IP range", @@ -288,6 +289,8 @@ const Categories = [ "Scan for Embedded Files", "Generate UUID", "Render Image", + "Remove EXIF", + "Extract EXIF", "Numberwang", ] }, diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index ddb67d28..a22bc9e2 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -3370,7 +3370,7 @@ const OperationConfig = { "

", "EXIF data from photos usually contains information about the image file itself as well as the device used to create it.", ].join("\n"), - run: Image.runEXIF, + run: Image.runExtractEXIF, inputType: "byteArray", outputType: "string", args: [], @@ -3388,9 +3388,20 @@ const OperationConfig = { } ] }, + "Remove EXIF": { + description: [ + "Removes EXIF data from a JPEG image.", + "

", + "EXIF data embedded in photos usually contains information about the image file itself as well as the device used to create it.", + ].join("\n"), + run: Image.runRemoveEXIF, + inputType: "byteArray", + outputType: "byteArray", + args: [] + }, "HTTP request": { description: [ - "Makes a HTTP request and returns the response body.", + "Makes an HTTP request and returns the response.", "

", "This operation supports different HTTP verbs like GET, POST, PUT, etc.", "

", @@ -3401,24 +3412,33 @@ const OperationConfig = { run: HTTP.runHTTPRequest, inputType: "string", outputType: "string", + manualBake: true, args: [ { name: "Method", type: "option", value: HTTP.METHODS, - }, { + }, + { name: "URL", type: "string", value: "", - }, { + }, + { name: "Headers", type: "text", value: "", - }, { - name: "Ignore status code", + }, + { + name: "Mode", + type: "option", + value: HTTP.MODE, + }, + { + name: "Show response metadata", type: "boolean", value: false, - }, + } ] }, }; diff --git a/src/core/operations/HTTP.js b/src/core/operations/HTTP.js index e80c0fb3..fd90f455 100755 --- a/src/core/operations/HTTP.js +++ b/src/core/operations/HTTP.js @@ -11,6 +11,7 @@ import {UAS_parser as UAParser} from "../lib/uas_parser.js"; * @namespace */ const HTTP = { + /** * @constant * @default @@ -18,8 +19,10 @@ const HTTP = { METHODS: [ "GET", "POST", "HEAD", "PUT", "PATCH", "DELETE", + "CONNECT", "TRACE", "OPTIONS" ], + /** * Strip HTTP headers operation. * @@ -60,9 +63,31 @@ const HTTP = { }, + /** + * @constant + * @default + */ + MODE: [ + "Cross-Origin Resource Sharing", + "No CORS (limited to HEAD, GET or POST)", + ], + + /** + * Lookup table for HTTP modes + * + * @private + * @constant + */ + _modeLookup: { + "Cross-Origin Resource Sharing": "cors", + "No CORS (limited to HEAD, GET or POST)": "no-cors", + }, + /** * HTTP request operation. * + * @author tlwr [toby@toby.codes] + * @author n1474335 [n1474335@gmail.com] * @param {string} input * @param {Object[]} args * @returns {string} @@ -71,7 +96,8 @@ const HTTP = { const method = args[0], url = args[1], headersText = args[2], - ignoreStatusCode = args[3]; + mode = args[3], + showResponseMetadata = args[4]; if (url.length === 0) return ""; @@ -88,9 +114,9 @@ const HTTP = { }); let config = { - method, - headers, - mode: "cors", + method: method, + headers: headers, + mode: HTTP._modeLookup[mode], cache: "no-cache", }; @@ -100,11 +126,23 @@ const HTTP = { return fetch(url, config) .then(r => { - if (ignoreStatusCode || r.status === 200) { - return r.text(); - } else { - throw `HTTP response code was ${r.status}.`; + if (showResponseMetadata) { + let headers = ""; + for (let pair of r.headers.entries()) { + headers += " " + pair[0] + ": " + pair[1] + "\n"; + } + return r.text().then(b => { + return "####\n Status: " + r.status + " " + r.statusText + + "\n Exposed headers:\n" + headers + "####\n\n" + b; + }); } + return r.text(); + }) + .catch(e => { + return e.toString() + + "\n\nThis error could be caused by one of the following:\n" + + " - An invalid URL\n" + + " - Making a cross-origin request to a server which does not support CORS\n"; }); }, From 127364e8a4b2735c7a4c1081db96b1e44426a4e4 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 9 Jun 2017 14:53:15 +0000 Subject: [PATCH 3/3] Added error handling for non-CORS requests. --- src/core/config/OperationConfig.js | 2 +- src/core/operations/HTTP.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index a22bc9e2..0d6778fc 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -3407,7 +3407,7 @@ const OperationConfig = { "

", "You can add headers line by line in the format Key: Value", "

", - "This operation will throw an error for any status code that is not 200, unless the 'Ignore status code' option is checked.", + "The status code of the response, along with a limited selection of exposed headers, can be viewed by checking the 'Show response metadata' option. Only a limited set of response headers are exposed by the browser for security reasons.", ].join("\n"), run: HTTP.runHTTPRequest, inputType: "string", diff --git a/src/core/operations/HTTP.js b/src/core/operations/HTTP.js index fd90f455..c02c3628 100755 --- a/src/core/operations/HTTP.js +++ b/src/core/operations/HTTP.js @@ -126,6 +126,10 @@ const HTTP = { return fetch(url, config) .then(r => { + if (r.status === 0 && r.type === "opaque") { + return "Error: Null response. Try setting the connection mode to CORS."; + } + if (showResponseMetadata) { let headers = ""; for (let pair of r.headers.entries()) {