Skip to content
Merged
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ webpagetest --help
- **-s, --server** _\<server\>_: the WPT server URL [https://www.webpagetest.org]
- **-d, --dryrun**: just return the RESTful API URL
- **-o, --out** _\<file\>_: place the output into \<file\>. Defaults to stdout
- **--http_method** _\<method\>_: the HTTP method to use (GET, POST) [GET]

_The default WPT server can also be specified via environment variable `WEBPAGETEST_SERVER`_

Expand Down Expand Up @@ -522,6 +523,7 @@ wpt.runTest(script, (err, data) => {

- **dryRun**: _Boolean_, if `true`, method does not make an actual request to the API Server but rather returns an object with `url` which contains the actual URL to make the GET request to WebPageTest API Server
- **server**: _String_, if specified, overrides the WebPageTest server informed in the constructor only for that method call
- **http_method**: _String_, if specified, overrides the HTTP method in the constructor only for that method call (GET, POST) [GET]

#### Test (works with `runTest` and `runTestAndWait`)

Expand Down
2 changes: 2 additions & 0 deletions bin/webpagetest
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ function cleanupProgram() {
delete program.server;
delete program.dryrun;
delete program.out;
delete program.http_method;
}

function execCommand() {
Expand All @@ -277,6 +278,7 @@ function execCommand() {
// options
if (options) {
options.dryRun = program.dryrun;
options.http_method = program.http_method;
args.push(options);
}

Expand Down
18 changes: 16 additions & 2 deletions lib/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ var xml2js = require('xml2js'),
url = require('url'),
os = require('os'),
csv = require('csv'),
entities = require('entities');
entities = require('entities')
qs = require('querystring');

var parser = new xml2js.Parser({explicitArray: false, mergeAttrs: true});

Expand Down Expand Up @@ -155,9 +156,22 @@ function scriptToString(data) {
}

// Build the RESTful API url call only
function dryRun(config, path) {
function dryRun(config, path, form) {
path = url.parse(path, true);

if (config.method == "POST") {
Comment thread
max-ostapenko marked this conversation as resolved.
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)
};
}

return {
url: url.format({
protocol: config.protocol,
Expand Down
4 changes: 4 additions & 0 deletions lib/mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ var options = {
bool: true,
info: "just return the RESTful API URL",
},
http_method: {
name: "http_method",
info: "HTTP method to use for submitting the test (GET or POST) [GET]",
}
},
test: {
location: {
Expand Down
51 changes: 40 additions & 11 deletions lib/webpagetest.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ 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 =
/^(?:Cable|DSL|3GSlow|3G|3GFast|4G|LTE|Edge|2G|Dial|FIOS|Native|custom)$/,
reHTMLOutput = /<h\d[^<]*>([^<]+)<\/h\d>/; // for H3 on cancelTest.php
reHTMLOutput = /<h\d[^<]*>([^<]+)<\/h\d>/, // for H3 on cancelTest.php
reHTTPmethods = /^(?:GET|POST)$/;

var paths = {
testStatus: "testStatus.php",
Expand Down Expand Up @@ -57,8 +59,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) {
Expand All @@ -79,6 +81,7 @@ function get(config, pathname, proxy, agent, callback, encoding) {
headers: {
Host: config.hostname,
},
method: config.method
};
} else {
protocol = config.protocol === "https:" ? https : http;
Expand All @@ -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";
Expand All @@ -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;
Expand Down Expand Up @@ -159,6 +167,13 @@ 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));
}

return request.end();

}

// execute callback properly normalizing optional args
Expand Down Expand Up @@ -186,22 +201,35 @@ function api(pathname, callback, query, options) {
config = this.config;
}

pathname = url.format({
pathname: url.resolve(config.pathname, pathname),
query: query,
});
pathname = url.resolve(config.pathname, pathname);

if (reHTTPmethods.test(options.http_method)) {
config.method = options.http_method;
} else {
config.method = WebPageTest.defaultHTTPMethod;
}


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
get.call(
this,
config,
pathname,
query,
options.proxy,
options.agent,
function apiCallback(err, data, info) {
Expand Down Expand Up @@ -935,6 +963,7 @@ WebPageTest.filenames = filenames;
WebPageTest.defaultServer = "https://www.webpagetest.org";
WebPageTest.defaultListenPort = 7791;
WebPageTest.defaultWaitResultsPort = 8000;
WebPageTest.defaultHTTPMethod = "GET";

// Version
Object.defineProperty(WebPageTest, "version", {
Expand Down
11 changes: 11 additions & 0 deletions test/command-line-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,15 @@ describe('WebPageTest Command Line', function() {
});
});

it('gets a test with long custom metrics script then returns API url and payload with custom metrics data', function (done) {
Comment thread
lbartoli79 marked this conversation as resolved.
let script = '"[example]\n\\\\' + 'X'.repeat(10000) + '\nreturn 1;"'
exec(mock('test http://foobar.com --http_method POST --custom ' + script), function (err, data) {
if (err) return done(err);
data = JSON.parse(data);
assert.equal(data.url, wptServer + 'runtest.php');
assert.equal(data.form.length, 10089);
done();
});
});

});
14 changes: 14 additions & 0 deletions test/edge-cases-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ describe('Edge Cases of', function() {
});
});

it('gets a test with long custom metrics script then returns API url and payload with custom metrics data', function (done) {
wpt.runTest('http://foobar.com', {
dryRun: true,
mobile: 1,
http_method: 'POST',
custom: '[example]\n\\\\' + 'X'.repeat(10000) + '\nreturn 1;'
}, function (err, data) {
if (err) return done(err);
assert.equal(data.url, wptServer + 'runtest.php');
assert.equal(data.form.length, 10089);
done();
});
});

});

describe('WebPageTest localhost helper', function() {
Expand Down