diff --git a/lib/helper.js b/lib/helper.js index f9a67ce..5cb8e6f 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -5,24 +5,25 @@ * Released under the MIT License */ -var xml2js = require('xml2js'), - url = require('url'), - os = require('os'), - csv = require('csv'), - entities = require('entities'); +var xml2js = require('xml2js'), + url = require('url'), + os = require('os'), + csv = require('csv'), + entities = require('entities'), + qs = require('querystring'); -var parser = new xml2js.Parser({explicitArray: false, mergeAttrs: true}); +var parser = new xml2js.Parser({ explicitArray: false, mergeAttrs: true }); var reNumber = /^[\.\+\-]?[\d\.]+$/, - reInvalidDec = /(?:\.\d*){2,}/, - reDec = /\./, - reLineBreak = /[\n\r]+/g, - reLastBreak = /\n$/, - reProtocol = /^https?:\/\//i, - reIp = /\d+\.\d+\.\d+\.\d+/, // 127.0.0.1 + reInvalidDec = /(?:\.\d*){2,}/, + reDec = /\./, + reLineBreak = /[\n\r]+/g, + reLastBreak = /\n$/, + reProtocol = /^https?:\/\//i, + reIp = /\d+\.\d+\.\d+\.\d+/, // 127.0.0.1 - TAB = '\t', - NEWLINE = '\n'; + TAB = '\t', + NEWLINE = '\n'; function parseNumber(s) { if (typeof s !== 'string' || !reNumber.test(s) || reInvalidDec.test(s)) { @@ -34,7 +35,7 @@ function parseNumber(s) { function normalizeObj(root) { if (typeof root === 'object') { - Object.keys(root).forEach(function(key) { + Object.keys(root).forEach(function (key) { var value = root[key]; if (typeof value === 'string') { if (value.length === 0 || value === '\n') { @@ -62,8 +63,8 @@ function xmlToObj(xml, callback) { function svToObj(delimiter, headers, sv) { var data, - start = 0, - obj = {}; + start = 0, + obj = {}; delimiter = delimiter || ','; @@ -101,11 +102,11 @@ function svToObj(delimiter, headers, sv) { } function csvParser(data, callback) { - csv.parse(data.toString(), { columns: true }, function(err, data) { + csv.parse(data.toString(), { columns: true }, function (err, data) { if (err) { callback.bind(this, err); } - csv.transform(data, function(row) { + csv.transform(data, function (row) { var key, value; for (key in row) { value = row[key].replace(/|<\/b>/g, ''); @@ -155,19 +156,32 @@ function scriptToString(data) { } // Build the RESTful API url call only -function dryRun(config, path) { +function dryRun(config, path, form) { path = url.parse(path, true); - return { - url: url.format({ - protocol: config.protocol, - hostname: config.hostname, - port: (config.port !== 80 && config.port !== 443 ? - config.port : undefined), - pathname: path.pathname, - query: path.query - }) - }; + if (config.method == "POST") { + return { + url: url.format({ + protocol: config.protocol, + hostname: config.hostname, + port: (config.port !== 80 && config.port !== 443 ? + config.port : undefined), + pathname: path.pathname, + }), + form: qs.stringify(form) + }; + } else { + return { + url: url.format({ + protocol: config.protocol, + hostname: config.hostname, + port: (config.port !== 80 && config.port !== 443 ? + config.port : undefined), + pathname: path.pathname, + query: path.query + }) + }; + } } // Normalize server config @@ -221,8 +235,8 @@ function setQuery(map, options, query) { map.options.forEach(function eachOpts(opt) { Object.keys(opt).forEach(function eachOpt(key) { var param = opt[key], - name = param.name, - value = options[name] || options[key]; + name = param.name, + value = options[name] || options[key]; if (value !== undefined && param.api) { if (param.array) { diff --git a/lib/webpagetest.js b/lib/webpagetest.js index 2f61306..fb4477e 100644 --- a/lib/webpagetest.js +++ b/lib/webpagetest.js @@ -13,7 +13,8 @@ var http = require("http"), specs = require("./specs"), helper = require("./helper"), server = require("./server"), - mapping = require("./mapping"); + mapping = require("./mapping"), + qs = require('querystring'); var reSpace = /\s/, reConnectivity = @@ -57,8 +58,8 @@ var filenames = { cached: "_Cached", }; -// GET helper function -function get(config, pathname, proxy, agent, callback, encoding) { +// GET/POST helper function +function get(config, pathname, data, proxy, agent, callback, encoding) { var protocol, options; if (proxy) { @@ -79,6 +80,8 @@ function get(config, pathname, proxy, agent, callback, encoding) { headers: { Host: config.hostname, }, + method: config.method + }; } else { protocol = config.protocol === "https:" ? https : http; @@ -87,10 +90,15 @@ function get(config, pathname, proxy, agent, callback, encoding) { host: config.hostname, auth: config.auth, port: config.port, + method: config.method, headers: {}, }; } + if (options.method == "POST") { + options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + if (encoding !== "binary") { options.headers["X-WPT-API-KEY"] = this.config.key; options.headers["accept-encoding"] = "gzip,deflate"; @@ -101,8 +109,8 @@ function get(config, pathname, proxy, agent, callback, encoding) { options.agent = agent; } - return protocol - .get(options, function getResponse(res) { + var request = protocol + .request(options, function getResponse(res) { var data, length, statusCode = res.statusCode; @@ -158,7 +166,14 @@ function get(config, pathname, proxy, agent, callback, encoding) { }) .on("error", function onError(err) { callback(err); - }); + }) + + if (options.method == "POST") { + return request.end(qs.stringify(data)); + } else { + return request.end(); + } + } // execute callback properly normalizing optional args @@ -186,15 +201,25 @@ function api(pathname, callback, query, options) { config = this.config; } - pathname = url.format({ - pathname: url.resolve(config.pathname, pathname), + pathname = url.resolve(config.pathname, pathname); + + config.method = url.format({ + pathname: pathname, query: query, - }); + }).toString().length > 6 * 1024 ? "POST" : "GET"; + + if (config.method == "GET") { + pathname = url.format({ + pathname: pathname, + query: query, + }); + query = undefined; + } if (options.dryRun) { // dry run: return the API url (string) only if (typeof callback === "function") { - callback.apply(callback, [undefined, helper.dryRun(config, pathname)]); + callback.apply(callback, [undefined, helper.dryRun(config, pathname, query)]); } } else { // make the real API call @@ -202,6 +227,7 @@ function api(pathname, callback, query, options) { this, config, pathname, + query, options.proxy, options.agent, function apiCallback(err, data, info) { diff --git a/test/edge-cases-test.js b/test/edge-cases-test.js index 77ab4eb..cfb4c21 100644 --- a/test/edge-cases-test.js +++ b/test/edge-cases-test.js @@ -85,6 +85,19 @@ describe('Edge Cases of', function() { }); }); + it('gets a test with custom metrics then returns API url and payload with custom metrics data present', function (done) { + wpt.runTest('http://foobar.com', { + dryRun: true, + mobile: 1, + custom: '[example]\n\\\\' + 'X'.repeat(6 * 1024) + '\nreturn 1;' + }, function (err, data) { + if (err) return done(err); + assert.equal(data.url, wptServer + 'runtest.php'); + assert.equal(data.form.length, 6233); + done(); + }); + }); + }); describe('WebPageTest localhost helper', function() {