Skip to content

Commit 27d3353

Browse files
committed
conditional post requests + test
1 parent 51e87f2 commit 27d3353

File tree

3 files changed

+182
-40
lines changed

3 files changed

+182
-40
lines changed

lib/helper.js

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@
55
* Released under the MIT License
66
*/
77

8-
var xml2js = require('xml2js'),
9-
url = require('url'),
10-
os = require('os'),
11-
csv = require('csv'),
12-
entities = require('entities');
8+
var xml2js = require('xml2js'),
9+
url = require('url'),
10+
os = require('os'),
11+
csv = require('csv'),
12+
entities = require('entities');
1313

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

1616
var reNumber = /^[\.\+\-]?[\d\.]+$/,
17-
reInvalidDec = /(?:\.\d*){2,}/,
18-
reDec = /\./,
19-
reLineBreak = /[\n\r]+/g,
20-
reLastBreak = /\n$/,
21-
reProtocol = /^https?:\/\//i,
22-
reIp = /\d+\.\d+\.\d+\.\d+/, // 127.0.0.1
17+
reInvalidDec = /(?:\.\d*){2,}/,
18+
reDec = /\./,
19+
reLineBreak = /[\n\r]+/g,
20+
reLastBreak = /\n$/,
21+
reProtocol = /^https?:\/\//i,
22+
reIp = /\d+\.\d+\.\d+\.\d+/, // 127.0.0.1
2323

24-
TAB = '\t',
25-
NEWLINE = '\n';
24+
TAB = '\t',
25+
NEWLINE = '\n';
2626

2727
function parseNumber(s) {
2828
if (typeof s !== 'string' || !reNumber.test(s) || reInvalidDec.test(s)) {
@@ -34,7 +34,7 @@ function parseNumber(s) {
3434

3535
function normalizeObj(root) {
3636
if (typeof root === 'object') {
37-
Object.keys(root).forEach(function(key) {
37+
Object.keys(root).forEach(function (key) {
3838
var value = root[key];
3939
if (typeof value === 'string') {
4040
if (value.length === 0 || value === '\n') {
@@ -62,8 +62,8 @@ function xmlToObj(xml, callback) {
6262

6363
function svToObj(delimiter, headers, sv) {
6464
var data,
65-
start = 0,
66-
obj = {};
65+
start = 0,
66+
obj = {};
6767

6868
delimiter = delimiter || ',';
6969

@@ -101,11 +101,11 @@ function svToObj(delimiter, headers, sv) {
101101
}
102102

103103
function csvParser(data, callback) {
104-
csv.parse(data.toString(), { columns: true }, function(err, data) {
104+
csv.parse(data.toString(), { columns: true }, function (err, data) {
105105
if (err) {
106106
callback.bind(this, err);
107107
}
108-
csv.transform(data, function(row) {
108+
csv.transform(data, function (row) {
109109
var key, value;
110110
for (key in row) {
111111
value = row[key].replace(/<b>|<\/b>/g, '');
@@ -155,19 +155,33 @@ function scriptToString(data) {
155155
}
156156

157157
// Build the RESTful API url call only
158-
function dryRun(config, path) {
158+
function dryRun(config, path, params) {
159159
path = url.parse(path, true);
160160

161-
return {
162-
url: url.format({
163-
protocol: config.protocol,
164-
hostname: config.hostname,
165-
port: (config.port !== 80 && config.port !== 443 ?
166-
config.port : undefined),
167-
pathname: path.pathname,
168-
query: path.query
169-
})
170-
};
161+
if (params && params.custom) {
162+
return {
163+
url: url.format({
164+
protocol: config.protocol,
165+
hostname: config.hostname,
166+
port: (config.port !== 80 && config.port !== 443 ?
167+
config.port : undefined),
168+
pathname: path.pathname,
169+
}),
170+
form: params
171+
};
172+
173+
} else {
174+
return {
175+
url: url.format({
176+
protocol: config.protocol,
177+
hostname: config.hostname,
178+
port: (config.port !== 80 && config.port !== 443 ?
179+
config.port : undefined),
180+
pathname: path.pathname,
181+
query: params
182+
})
183+
};
184+
}
171185
}
172186

173187
// Normalize server config
@@ -221,8 +235,8 @@ function setQuery(map, options, query) {
221235
map.options.forEach(function eachOpts(opt) {
222236
Object.keys(opt).forEach(function eachOpt(key) {
223237
var param = opt[key],
224-
name = param.name,
225-
value = options[name] || options[key];
238+
name = param.name,
239+
value = options[name] || options[key];
226240

227241
if (value !== undefined && param.api) {
228242
if (param.array) {

lib/webpagetest.js

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ var http = require("http"),
1313
specs = require("./specs"),
1414
helper = require("./helper"),
1515
server = require("./server"),
16-
mapping = require("./mapping");
16+
mapping = require("./mapping"),
17+
qs = require('querystring');
1718

1819
var reSpace = /\s/,
1920
reConnectivity =
@@ -58,9 +59,14 @@ var filenames = {
5859
};
5960

6061
// GET helper function
61-
function get(config, pathname, proxy, agent, callback, encoding) {
62+
function get(config, pathname, query, proxy, agent, callback, encoding) {
6263
var protocol, options;
6364

65+
pathname = url.format({
66+
pathname: pathname,
67+
query: query,
68+
});
69+
6470
if (proxy) {
6571
var proxyUrl = url.parse(proxy);
6672
var pathForProxy = config.protocol + "//";
@@ -161,6 +167,118 @@ function get(config, pathname, proxy, agent, callback, encoding) {
161167
});
162168
}
163169

170+
// execute runTest using POST request
171+
function post(config, pathname, query, proxy, agent, callback, encoding) {
172+
var protocol, options;
173+
174+
if (proxy) {
175+
var proxyUrl = url.parse(proxy);
176+
var pathForProxy = config.protocol + "//";
177+
178+
if (config.auth) {
179+
pathForProxy += config.auth + "@";
180+
}
181+
182+
pathForProxy += config.hostname + ":" + config.port + pathname;
183+
protocol = proxyUrl.protocol === "https:" ? https : http;
184+
185+
options = {
186+
host: proxyUrl.hostname,
187+
port: proxyUrl.port,
188+
path: pathForProxy,
189+
method: "POST",
190+
headers: {
191+
Host: config.hostname,
192+
},
193+
194+
};
195+
} else {
196+
protocol = config.protocol === "https:" ? https : http;
197+
options = {
198+
path: pathname,
199+
host: config.hostname,
200+
auth: config.auth,
201+
port: config.port,
202+
method: "POST",
203+
headers: {
204+
'Content-Type': 'application/x-www-form-urlencoded',
205+
},
206+
};
207+
}
208+
209+
if (encoding !== "binary") {
210+
options.headers["X-WPT-API-KEY"] = this.config.key;
211+
options.headers["accept-encoding"] = "gzip,deflate";
212+
options.headers["User-Agent"] = "WebpagetestNodeWrapper/v0.6.0";
213+
}
214+
215+
if (agent) {
216+
options.agent = agent;
217+
}
218+
219+
postData = qs.stringify(query)
220+
221+
return protocol
222+
.request(options, function getResponse(res) {
223+
var data,
224+
length,
225+
statusCode = res.statusCode;
226+
227+
if (statusCode !== 200) {
228+
callback(
229+
new helper.WPTAPIError(statusCode, http.STATUS_CODES[statusCode])
230+
);
231+
} else {
232+
data = [];
233+
length = 0;
234+
235+
encoding = res.headers["content-encoding"] || encoding || "uft8";
236+
237+
res.on("data", function onData(chunk) {
238+
data.push(chunk);
239+
length += chunk.length;
240+
});
241+
242+
res.on("end", function onEnd() {
243+
var i,
244+
len,
245+
pos,
246+
buffer = new Buffer.alloc(length),
247+
type = (res.headers["content-type"] || "").split(";")[0];
248+
249+
for (i = 0, len = data.length, pos = 0; i < len; i += 1) {
250+
data[i].copy(buffer, pos);
251+
pos += data[i].length;
252+
}
253+
254+
if (encoding === "gzip" || encoding === "deflate") {
255+
// compressed response (gzip,deflate)
256+
zlib.unzip(buffer, function unzip(err, buffer) {
257+
if (err) {
258+
callback(err);
259+
} else {
260+
callback(undefined, buffer.toString(), {
261+
type: type,
262+
encoding: encoding,
263+
});
264+
}
265+
});
266+
} else {
267+
// uncompressed response
268+
callback(undefined, buffer, {
269+
type: type,
270+
encoding: encoding,
271+
});
272+
}
273+
});
274+
}
275+
})
276+
.on("error", function onError(err) {
277+
callback(err);
278+
})
279+
.end(postData);
280+
}
281+
164282
// execute callback properly normalizing optional args
165283
function callbackYield(callback, err, data, options) {
166284
if (typeof callback === "function") {
@@ -186,22 +304,20 @@ function api(pathname, callback, query, options) {
186304
config = this.config;
187305
}
188306

189-
pathname = url.format({
190-
pathname: url.resolve(config.pathname, pathname),
191-
query: query,
192-
});
307+
pathname = url.resolve(config.pathname, pathname);
193308

194309
if (options.dryRun) {
195310
// dry run: return the API url (string) only
196311
if (typeof callback === "function") {
197-
callback.apply(callback, [undefined, helper.dryRun(config, pathname)]);
312+
callback.apply(callback, [undefined, helper.dryRun(config, pathname, query)]);
198313
}
199314
} else {
200315
// make the real API call
201-
get.call(
316+
(options.custom !== undefined ? post : get).call(
202317
this,
203318
config,
204319
pathname,
320+
query,
205321
options.proxy,
206322
options.agent,
207323
function apiCallback(err, data, info) {

test/edge-cases-test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ describe('Edge Cases of', function() {
8585
});
8686
});
8787

88+
it('gets a test with custom metrics then returns API url and payload with custom metrics data present', function (done) {
89+
wpt.runTest('http://foobar.com', {
90+
dryRun: true,
91+
custom: '[example]\nreturn 1;'
92+
}, function (err, data) {
93+
if (err) return done(err);
94+
assert.equal(data.url, wptServer + 'runtest.php');
95+
assert.equal(data.form.custom, '[example]\nreturn 1;');
96+
done();
97+
});
98+
});
99+
88100
});
89101

90102
describe('WebPageTest localhost helper', function() {

0 commit comments

Comments
 (0)