You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
4.4 KiB
160 lines
4.4 KiB
// Copyright 2011 Software Freedom Conservancy. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/**
|
|
* @fileoverview Defines a the {@code webdriver.http.Client} for use with
|
|
* NodeJS.
|
|
*/
|
|
|
|
var http = require('http'),
|
|
url = require('url');
|
|
|
|
var base = require('../_base'),
|
|
HttpResponse = base.require('webdriver.http.Response');
|
|
|
|
|
|
/**
|
|
* A {@link webdriver.http.Client} implementation using Node's built-in http
|
|
* module.
|
|
* @param {string} serverUrl URL for the WebDriver server to send commands to.
|
|
* @constructor
|
|
* @implements {webdriver.http.Client}
|
|
*/
|
|
var HttpClient = function(serverUrl) {
|
|
var parsedUrl = url.parse(serverUrl);
|
|
if (!parsedUrl.hostname) {
|
|
throw new Error('Invalid server URL: ' + serverUrl);
|
|
}
|
|
|
|
/**
|
|
* Base options for each request.
|
|
* @private {!Object}
|
|
*/
|
|
this.options_ = {
|
|
host: parsedUrl.hostname,
|
|
path: parsedUrl.pathname,
|
|
port: parsedUrl.port
|
|
};
|
|
};
|
|
|
|
|
|
/** @override */
|
|
HttpClient.prototype.send = function(httpRequest, callback) {
|
|
var data;
|
|
httpRequest.headers['Content-Length'] = 0;
|
|
if (httpRequest.method == 'POST' || httpRequest.method == 'PUT') {
|
|
data = JSON.stringify(httpRequest.data);
|
|
httpRequest.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
|
|
httpRequest.headers['Content-Type'] = 'application/json;charset=UTF-8';
|
|
}
|
|
|
|
var path = this.options_.path;
|
|
if (path[path.length - 1] === '/' && httpRequest.path[0] === '/') {
|
|
path += httpRequest.path.substring(1);
|
|
} else {
|
|
path += httpRequest.path;
|
|
}
|
|
|
|
sendRequest({
|
|
method: httpRequest.method,
|
|
host: this.options_.host,
|
|
port: this.options_.port,
|
|
path: path,
|
|
headers: httpRequest.headers
|
|
}, callback, data);
|
|
};
|
|
|
|
|
|
/**
|
|
* Sends a single HTTP request.
|
|
* @param {!Object} options The request options.
|
|
* @param {function(Error, !webdriver.http.Response=)} callback The function to
|
|
* invoke with the server's response.
|
|
* @param {string=} opt_data The data to send with the request.
|
|
*/
|
|
var sendRequest = function(options, callback, opt_data) {
|
|
var request = http.request(options, function(response) {
|
|
if (response.statusCode == 302 || response.statusCode == 303) {
|
|
try {
|
|
var location = url.parse(response.headers['location']);
|
|
} catch (ex) {
|
|
callback(Error(
|
|
'Failed to parse "Location" header for server redirect: ' +
|
|
ex.message + '\nResponse was: \n' +
|
|
new HttpResponse(response.statusCode, response.headers, '')));
|
|
return;
|
|
}
|
|
|
|
if (!location.hostname) {
|
|
location.hostname = options.host;
|
|
location.port = options.port;
|
|
}
|
|
|
|
request.abort();
|
|
sendRequest({
|
|
method: 'GET',
|
|
host: location.hostname,
|
|
path: location.pathname + (location.search || ''),
|
|
port: location.port,
|
|
headers: {
|
|
'Accept': 'application/json; charset=utf-8'
|
|
}
|
|
}, callback);
|
|
return;
|
|
}
|
|
|
|
var body = [];
|
|
response.on('data', body.push.bind(body));
|
|
response.on('end', function() {
|
|
var resp = new HttpResponse(response.statusCode,
|
|
response.headers, body.join('').replace(/\0/g, ''));
|
|
callback(null, resp);
|
|
});
|
|
});
|
|
|
|
request.on('error', function(e) {
|
|
if (e.code === 'ECONNRESET') {
|
|
setTimeout(function() {
|
|
sendRequest(options, callback, opt_data);
|
|
}, 15);
|
|
} else {
|
|
var message = e.message;
|
|
if (e.code) {
|
|
message = e.code + ' ' + message;
|
|
}
|
|
callback(new Error(message));
|
|
}
|
|
});
|
|
|
|
if (opt_data) {
|
|
request.write(opt_data);
|
|
}
|
|
|
|
request.end();
|
|
};
|
|
|
|
|
|
// PUBLIC API
|
|
|
|
/** @type {webdriver.http.Executor.} */
|
|
exports.Executor = base.require('webdriver.http.Executor');
|
|
|
|
/** @type {webdriver.http.Request.} */
|
|
exports.Request = base.require('webdriver.http.Request');
|
|
|
|
/** @type {webdriver.http.Response.} */
|
|
exports.Response = base.require('webdriver.http.Response');
|
|
|
|
exports.HttpClient = HttpClient;
|