From 5cd58dcbba32cfc5bb6c15aacbac004dd796cda9 Mon Sep 17 00:00:00 2001 From: Jason Leyba Date: Fri, 23 May 2014 12:54:07 -0700 Subject: [PATCH] Fail with a more descriptive error if the server returns a malformed redirect --- javascript/node/selenium-webdriver/CHANGES.md | 1 + .../node/selenium-webdriver/http/index.js | 10 ++- .../selenium-webdriver/test/http/http_test.js | 88 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 javascript/node/selenium-webdriver/test/http/http_test.js diff --git a/javascript/node/selenium-webdriver/CHANGES.md b/javascript/node/selenium-webdriver/CHANGES.md index 3f9349266bf16..d665faf75c3a3 100644 --- a/javascript/node/selenium-webdriver/CHANGES.md +++ b/javascript/node/selenium-webdriver/CHANGES.md @@ -2,6 +2,7 @@ * Removed deprecated functions `Promise#addCallback()`, `Promise#addCallbacks()`, `Promise#addErrback()`, and `Promise#addBoth()`. +* Fail with a more descriptive error if the server returns a malformed redirect * FIXED: 7300: Connect to ChromeDriver using the loopback address since ChromeDriver 2.10.267517 binds to localhost by default. * FIXED: 7339: Preserve wrapped test function's string representation for diff --git a/javascript/node/selenium-webdriver/http/index.js b/javascript/node/selenium-webdriver/http/index.js index 3ae491b9a9ada..2571cd3fbf54d 100644 --- a/javascript/node/selenium-webdriver/http/index.js +++ b/javascript/node/selenium-webdriver/http/index.js @@ -86,7 +86,15 @@ HttpClient.prototype.send = function(httpRequest, callback) { var sendRequest = function(options, callback, opt_data) { var request = http.request(options, function(response) { if (response.statusCode == 302 || response.statusCode == 303) { - var location = url.parse(response.headers['location']); + 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; diff --git a/javascript/node/selenium-webdriver/test/http/http_test.js b/javascript/node/selenium-webdriver/test/http/http_test.js new file mode 100644 index 0000000000000..eafc6adb73841 --- /dev/null +++ b/javascript/node/selenium-webdriver/test/http/http_test.js @@ -0,0 +1,88 @@ +// Copyright 2014 Selenium committers +// Copyright 2014 Software Freedom Conservancy +// +// 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. + +var assert = require('assert'); + +var HttpClient = require('../../http').HttpClient; +var HttpRequest = require('../../_base').require('webdriver.http.Request'); +var Server = require('../../lib/test/httpserver').Server; +var promise = require('../..').promise; +var test = require('../../lib/test'); + +describe('HttpClient', function() { + var server = new Server(function(req, res) { + if (req.method == 'GET' && req.url == '/echo') { + res.writeHead(200, req.headers); + res.end(); + + } else if (req.method == 'GET' && req.url == '/redirect') { + res.writeHead(303, {'Location': server.url('/hello')}); + res.end(); + + } else if (req.method == 'GET' && req.url == '/hello') { + res.writeHead(200, {'content-type': 'text/plain'}); + res.end('hello, world!'); + + } else if (req.method == 'GET' && req.url == '/badredirect') { + res.writeHead(303, {}); + res.end(); + + } else { + res.writeHead(404, {}); + res.end(); + } + }); + + test.before(server.start.bind(server)); + test.after(server.stop.bind(server)); + + test.it('can send a basic HTTP request', function() { + var request = new HttpRequest('GET', '/echo'); + request.headers['Foo'] = 'Bar'; + + var client = new HttpClient(server.url()); + return promise.checkedNodeCall(client.send.bind(client, request)) + .then(function(response) { + assert.equal(200, response.status); + assert.equal( + 'application/json; charset=utf-8', response.headers['accept']); + assert.equal('Bar', response.headers['foo']); + assert.equal('0', response.headers['content-length']); + assert.equal('keep-alive', response.headers['connection']); + assert.equal(server.host(), response.headers['host']); + }); + }); + + test.it('automatically follows redirects', function() { + var request = new HttpRequest('GET', '/redirect'); + var client = new HttpClient(server.url()); + return promise.checkedNodeCall(client.send.bind(client, request)) + .then(function(response) { + assert.equal(200, response.status); + assert.equal('text/plain', response.headers['content-type']); + assert.equal('hello, world!', response.body); + }); + }); + + test.it('handles malformed redirect responses', function() { + var request = new HttpRequest('GET', '/badredirect'); + var client = new HttpClient(server.url()); + return promise.checkedNodeCall(client.send.bind(client, request)). + thenCatch(function(err) { + assert.ok(/Failed to parse "Location"/.test(err.message), + 'Not the expected error: ' + err.message); + }); + }); +});