From c06d71344f8db3c013446dd0cc4894b71002a203 Mon Sep 17 00:00:00 2001 From: Igor Dralyuk Date: Wed, 14 Mar 2012 22:18:44 -0700 Subject: [PATCH 1/7] Added follow redirects feature. --- modules/engine/test/mock/redirect-response.json | 4 ++++ modules/engine/test/mock/redirect.ql | 6 ++++++ modules/engine/test/redirect-test.js | 0 3 files changed, 10 insertions(+) create mode 100644 modules/engine/test/mock/redirect-response.json create mode 100644 modules/engine/test/mock/redirect.ql create mode 100644 modules/engine/test/redirect-test.js diff --git a/modules/engine/test/mock/redirect-response.json b/modules/engine/test/mock/redirect-response.json new file mode 100644 index 00000000..f716cb70 --- /dev/null +++ b/modules/engine/test/mock/redirect-response.json @@ -0,0 +1,4 @@ +{ + "id": "42", + "title":"Redirect Response" +} diff --git a/modules/engine/test/mock/redirect.ql b/modules/engine/test/mock/redirect.ql new file mode 100644 index 00000000..df02b04d --- /dev/null +++ b/modules/engine/test/mock/redirect.ql @@ -0,0 +1,6 @@ +create table redirect + on select get from "http://127.0.0.1:8300/redirect-response.json" + +response = select * from redirect; + +return response; diff --git a/modules/engine/test/redirect-test.js b/modules/engine/test/redirect-test.js new file mode 100644 index 00000000..e69de29b From e8268a961d069c2c09de11175d2086f2b22c4413 Mon Sep 17 00:00:00 2001 From: Igor Dralyuk Date: Wed, 14 Mar 2012 22:20:36 -0700 Subject: [PATCH 2/7] Added follow redirects feature. --- modules/engine/lib/engine/http/request.js | 34 ++++- modules/engine/test/redirect-test.js | 159 ++++++++++++++++++++++ 2 files changed, 190 insertions(+), 3 deletions(-) diff --git a/modules/engine/lib/engine/http/request.js b/modules/engine/lib/engine/http/request.js index 3a291115..20e7bc4b 100644 --- a/modules/engine/lib/engine/http/request.js +++ b/modules/engine/lib/engine/http/request.js @@ -81,8 +81,36 @@ function putInCache(key, cache, result, res, timeout) { } } -function sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry) { +var followRedirects = true, maxRedirects = 10; + +function sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry, redirects) { var clientRequest = client.request(options, function (res) { + if (followRedirects && res.statusCode >= 300 && res.statusCode < 400) { + res.socket.destroy(); + if (res.headers.location) { + if (redirects++ >= maxRedirects) { + args.logEmitter.emitError(args.httpReqTx.event, 'Error with uri - ' + args.uri + ' - ' + + 'Exceeded max redirects (' + maxRedirects + '). In a loop? ' + (Date.now() - start) + 'msec'); + return args.httpReqTx.cb(err); + } + + var location = new URI(res.headers.location, false); + options.host = location.heirpart().authority().host(); + options.port = location.heirpart().authority().port(); + options.path = location.heirpart().path(); + + args.logEmitter.emitEvent(args.httpReqTx.event, 'being redirected for the ' + redirects + ' time, ' + + 'going to ' + options.host + ':' + options.port + options.path + ' - ' + args.uri + ' - ' + (Date.now() - start) + 'msec'); + sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry, redirects); + return; + } else { + args.logEmitter.emitError(args.httpReqTx.event, 'Error with uri - ' + args.uri + ' - ' + + 'Received status code ' + res.statusCode + ', but Location header was not provided' + + ' ' + (Date.now() - start) + 'msec'); + return args.httpReqTx.cb(err); + } + } + var bufs = []; // array for bufs for each chunk var responseLength = 0; var contentEncoding = res.headers['content-encoding']; @@ -228,7 +256,7 @@ function sendMessage(args, client, options, retry) { cache.get(key,function(err,result){ if(err || !result.data){ sendHttpRequest(client, options, args, start, timings, reqStart, - key, cache, timeout, uniqueId, status, retry); + key, cache, timeout, uniqueId, status, retry, 0); } else { response.exec(timings, reqStart, args, uniqueId, res, result.start, result.result, options, status); @@ -236,7 +264,7 @@ function sendMessage(args, client, options, retry) { }); } else { - sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry); + sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry, 0); } } diff --git a/modules/engine/test/redirect-test.js b/modules/engine/test/redirect-test.js index e69de29b..f7eae3c0 100644 --- a/modules/engine/test/redirect-test.js +++ b/modules/engine/test/redirect-test.js @@ -0,0 +1,159 @@ +/** + /* + * Copyright 2011 eBay Software Foundation + * + * 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. + */ +"use strict" + +var Engine = require('../lib/engine'), + http = require('http'), + fs = require('fs'), + util = require('util'), + logger = require('winston'); + +logger.remove(logger.transports.Console); +logger.add(logger.transports.Console, {level:'error'}); + +var localhost = "127.0.0.1", protocol = "http"; + +// http/request.js will follow up to 10 redirects + +var servers_positive = [ + { 'host' : localhost, 'port' : '8300' }, + { 'host' : localhost, 'port' : '8301' }, + { 'host' : localhost, 'port' : '8302' }, + { 'host' : localhost, 'port' : '8303' }, + { 'host' : localhost, 'port' : '8304' }, + { 'host' : localhost, 'port' : '8305' }, + { 'host' : localhost, 'port' : '8306' }, + { 'host' : localhost, 'port' : '8307' }, + { 'host' : localhost, 'port' : '8308' }, + { 'host' : localhost, 'port' : '8309' }, + { 'host' : localhost, 'port' : '8310' } +]; + +var servers_negative = [ + { 'host' : localhost, 'port' : '8300' }, + { 'host' : localhost, 'port' : '8301' }, + { 'host' : localhost, 'port' : '8302' }, + { 'host' : localhost, 'port' : '8303' }, + { 'host' : localhost, 'port' : '8304' }, + { 'host' : localhost, 'port' : '8305' }, + { 'host' : localhost, 'port' : '8306' }, + { 'host' : localhost, 'port' : '8307' }, + { 'host' : localhost, 'port' : '8308' }, + { 'host' : localhost, 'port' : '8309' }, + { 'host' : localhost, 'port' : '8310' }, + { 'host' : localhost, 'port' : '8311' }, + { 'host' : localhost, 'port' : '8312' } +]; + +function setupServers(servers) { + + //create redirect servers that return response codes in the 300 range (from 300 to 309), and provide Location header + for (var i = 0; i < servers.length - 1; i++) { + servers[i].instance = http.createServer((function(j) { + return function (req, res) { + var location = protocol + '://' + servers[j + 1].host + ':' + servers[j + 1].port + req.url; + res.writeHead(300 + j, { 'Location': location }); + res.end(); + } + })(i)).listen(servers[i].port, servers[i].host); + } + + // create the final server, the one that's going to return data + servers[i].instance = http.createServer(function (req, res) { + var file = __dirname + '/mock' + req.url; + var stat = fs.statSync(file); + res.writeHead(200, { + 'Content-Type':file.indexOf('.xml') >= 0 ? 'application/xml' : 'application/json', + 'Content-Length':stat.size + }); + var readStream = fs.createReadStream(file); + util.pump(readStream, res, function (e) { + if (e) { + console.log(e.stack || e); + } + res.end(); + }); + }).listen(servers[i].port, servers[i].host); +} + +module.exports = { + 'positive':function (test) { + var servers = servers_positive; + + setupServers(servers); + + var engine = new Engine({ + config:__dirname + '/config/dev.json' + }); + + var script = fs.readFileSync(__dirname + '/mock/redirect.ql', 'UTF-8'); + + engine.exec({ + script:script, + cb:function (err, result) { + try { + if (err) { + console.log(err.stack || err); + test.ok(false); + } + else { + test.ok(result && result.body.id === "42"); + } + test.done(); + } + finally { + for (var i = 0; i < servers.length; i++) { + servers[i].instance.close(); + } + } + } + }); + }, + 'negative':function (test) { + var servers = servers_negative; + + setupServers(servers); + + var engine = new Engine({ + config:__dirname + '/config/dev.json' + }); + + var script = fs.readFileSync(__dirname + '/mock/redirect.ql', 'UTF-8'); + + engine.exec({ + script:script, + cb:function (err, result) { + try { + if (err) { + console.log(err.stack || err); + test.ok(false); + } + else { + test.ok(result && !result.body); + } + test.done(); + } + finally { + for (var i = 0; i < servers.length; i++) { + servers[i].instance.close(); + } + } + } + }); + + } +} From 895287a5413069dc758b5ffc4215b9b027ba431c Mon Sep 17 00:00:00 2001 From: Igor Dralyuk Date: Wed, 14 Mar 2012 22:28:01 -0700 Subject: [PATCH 3/7] Version bump. --- modules/engine/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/engine/package.json b/modules/engine/package.json index 51f80121..d7b9878b 100644 --- a/modules/engine/package.json +++ b/modules/engine/package.json @@ -1,7 +1,7 @@ { "author": "ql.io", "name": "ql.io-engine", - "version": "0.4.16", + "version": "0.4.17", "repository": { "type": "git", "url": "https://github.com/ql-io/ql.io" From e4b0b55eaeb8483bf68430430a755facfec80b6f Mon Sep 17 00:00:00 2001 From: Igor Dralyuk Date: Wed, 14 Mar 2012 23:02:35 -0700 Subject: [PATCH 4/7] Return appropriate error back to the client when maxRedirects are exceeded. --- modules/engine/lib/engine/http/request.js | 6 ++++++ modules/engine/test/redirect-test.js | 10 ++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/modules/engine/lib/engine/http/request.js b/modules/engine/lib/engine/http/request.js index 20e7bc4b..2cb426f8 100644 --- a/modules/engine/lib/engine/http/request.js +++ b/modules/engine/lib/engine/http/request.js @@ -91,6 +91,9 @@ function sendHttpRequest(client, options, args, start, timings, reqStart, key, c if (redirects++ >= maxRedirects) { args.logEmitter.emitError(args.httpReqTx.event, 'Error with uri - ' + args.uri + ' - ' + 'Exceeded max redirects (' + maxRedirects + '). In a loop? ' + (Date.now() - start) + 'msec'); + var err = new Error('Exceeded max redirects'); + err.uri = args.uri; + err.status = 502; return args.httpReqTx.cb(err); } @@ -107,6 +110,9 @@ function sendHttpRequest(client, options, args, start, timings, reqStart, key, c args.logEmitter.emitError(args.httpReqTx.event, 'Error with uri - ' + args.uri + ' - ' + 'Received status code ' + res.statusCode + ', but Location header was not provided' + ' ' + (Date.now() - start) + 'msec'); + var err = new Error('Missing Location header in redirect'); + err.uri = args.uri; + err.status = 502; return args.httpReqTx.cb(err); } } diff --git a/modules/engine/test/redirect-test.js b/modules/engine/test/redirect-test.js index f7eae3c0..410aece3 100644 --- a/modules/engine/test/redirect-test.js +++ b/modules/engine/test/redirect-test.js @@ -138,12 +138,10 @@ module.exports = { script:script, cb:function (err, result) { try { - if (err) { - console.log(err.stack || err); - test.ok(false); - } - else { - test.ok(result && !result.body); + if (!err) { + test.ok(false, "Error expected."); + } else { + test.ok(err.message === "Exceeded max redirects"); } test.done(); } From 22b4accb27c5195313c87bfe30dc916270c0651f Mon Sep 17 00:00:00 2001 From: Igor Dralyuk Date: Thu, 15 Mar 2012 12:56:28 -0700 Subject: [PATCH 5/7] Tighten up the logic for redirects. --- modules/engine/lib/engine/http/request.js | 56 +++++---- modules/engine/test/redirect-test.js | 139 ++++++++++++++++++---- 2 files changed, 149 insertions(+), 46 deletions(-) diff --git a/modules/engine/lib/engine/http/request.js b/modules/engine/lib/engine/http/request.js index 2cb426f8..7426338d 100644 --- a/modules/engine/lib/engine/http/request.js +++ b/modules/engine/lib/engine/http/request.js @@ -85,35 +85,45 @@ var followRedirects = true, maxRedirects = 10; function sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry, redirects) { var clientRequest = client.request(options, function (res) { - if (followRedirects && res.statusCode >= 300 && res.statusCode < 400) { + if (followRedirects && (res.statusCode >= 301 && res.statusCode <= 307) && + (options.method.toUpperCase() === 'GET' || options.method.toUpperCase() === 'HEAD')) { res.socket.destroy(); - if (res.headers.location) { - if (redirects++ >= maxRedirects) { + if (res.statusCode === 305) { // Log but don't follow + args.logEmitter.emitWarning(args.httpReqTx.event, 'Warning with uri - ' + args.uri + ' - ' + + 'Received status code 305 ' + (Date.now() - start) + 'msec'); + var err = new Error('Received status code 305 from downstream server'); + err.uri = args.uri; + err.status = 502; + return args.httpReqTx.cb(err); + } else if (res.statusCode !== 304 && res.statusCode !== 306) { // Only follow 301, 302, 303, 307 + if (res.headers.location) { + if (redirects++ >= maxRedirects) { + args.logEmitter.emitError(args.httpReqTx.event, 'Error with uri - ' + args.uri + ' - ' + + 'Exceeded max redirects (' + maxRedirects + '). In a loop? ' + (Date.now() - start) + 'msec'); + var err = new Error('Exceeded max redirects'); + err.uri = args.uri; + err.status = 502; + return args.httpReqTx.cb(err); + } + + var location = new URI(res.headers.location, false); + options.host = location.heirpart().authority().host(); + options.port = location.heirpart().authority().port(); + options.path = location.heirpart().path(); + + args.logEmitter.emitEvent(args.httpReqTx.event, 'being redirected for the ' + redirects + ' time, ' + + 'going to ' + options.host + ':' + options.port + options.path + ' - ' + args.uri + ' - ' + (Date.now() - start) + 'msec'); + sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry, redirects); + return; + } else { args.logEmitter.emitError(args.httpReqTx.event, 'Error with uri - ' + args.uri + ' - ' + - 'Exceeded max redirects (' + maxRedirects + '). In a loop? ' + (Date.now() - start) + 'msec'); - var err = new Error('Exceeded max redirects'); + 'Received status code ' + res.statusCode + ', but Location header was not provided' + + ' ' + (Date.now() - start) + 'msec'); + var err = new Error('Missing Location header in redirect'); err.uri = args.uri; err.status = 502; return args.httpReqTx.cb(err); } - - var location = new URI(res.headers.location, false); - options.host = location.heirpart().authority().host(); - options.port = location.heirpart().authority().port(); - options.path = location.heirpart().path(); - - args.logEmitter.emitEvent(args.httpReqTx.event, 'being redirected for the ' + redirects + ' time, ' + - 'going to ' + options.host + ':' + options.port + options.path + ' - ' + args.uri + ' - ' + (Date.now() - start) + 'msec'); - sendHttpRequest(client, options, args, start, timings, reqStart, key, cache, timeout, uniqueId, status, retry, redirects); - return; - } else { - args.logEmitter.emitError(args.httpReqTx.event, 'Error with uri - ' + args.uri + ' - ' + - 'Received status code ' + res.statusCode + ', but Location header was not provided' + - ' ' + (Date.now() - start) + 'msec'); - var err = new Error('Missing Location header in redirect'); - err.uri = args.uri; - err.status = 502; - return args.httpReqTx.cb(err); } } diff --git a/modules/engine/test/redirect-test.js b/modules/engine/test/redirect-test.js index 410aece3..ffb37db6 100644 --- a/modules/engine/test/redirect-test.js +++ b/modules/engine/test/redirect-test.js @@ -30,35 +30,46 @@ var localhost = "127.0.0.1", protocol = "http"; // http/request.js will follow up to 10 redirects var servers_positive = [ - { 'host' : localhost, 'port' : '8300' }, - { 'host' : localhost, 'port' : '8301' }, - { 'host' : localhost, 'port' : '8302' }, - { 'host' : localhost, 'port' : '8303' }, - { 'host' : localhost, 'port' : '8304' }, - { 'host' : localhost, 'port' : '8305' }, - { 'host' : localhost, 'port' : '8306' }, - { 'host' : localhost, 'port' : '8307' }, - { 'host' : localhost, 'port' : '8308' }, - { 'host' : localhost, 'port' : '8309' }, + { 'host' : localhost, 'port' : '8300', 'status' : 301 }, + { 'host' : localhost, 'port' : '8301', 'status' : 302 }, + { 'host' : localhost, 'port' : '8302', 'status' : 303 }, + { 'host' : localhost, 'port' : '8303', 'status' : 307 }, + { 'host' : localhost, 'port' : '8304', 'status' : 301 }, + { 'host' : localhost, 'port' : '8305', 'status' : 302 }, + { 'host' : localhost, 'port' : '8306', 'status' : 303 }, + { 'host' : localhost, 'port' : '8307', 'status' : 307 }, + { 'host' : localhost, 'port' : '8308', 'status' : 301 }, + { 'host' : localhost, 'port' : '8309', 'status' : 302 }, { 'host' : localhost, 'port' : '8310' } ]; var servers_negative = [ - { 'host' : localhost, 'port' : '8300' }, - { 'host' : localhost, 'port' : '8301' }, - { 'host' : localhost, 'port' : '8302' }, - { 'host' : localhost, 'port' : '8303' }, - { 'host' : localhost, 'port' : '8304' }, - { 'host' : localhost, 'port' : '8305' }, - { 'host' : localhost, 'port' : '8306' }, - { 'host' : localhost, 'port' : '8307' }, - { 'host' : localhost, 'port' : '8308' }, - { 'host' : localhost, 'port' : '8309' }, - { 'host' : localhost, 'port' : '8310' }, - { 'host' : localhost, 'port' : '8311' }, + { 'host' : localhost, 'port' : '8300', 'status' : 301 }, + { 'host' : localhost, 'port' : '8301', 'status' : 302 }, + { 'host' : localhost, 'port' : '8302', 'status' : 303 }, + { 'host' : localhost, 'port' : '8303', 'status' : 307 }, + { 'host' : localhost, 'port' : '8304', 'status' : 301 }, + { 'host' : localhost, 'port' : '8305', 'status' : 302 }, + { 'host' : localhost, 'port' : '8306', 'status' : 303 }, + { 'host' : localhost, 'port' : '8307', 'status' : 307 }, + { 'host' : localhost, 'port' : '8308', 'status' : 301 }, + { 'host' : localhost, 'port' : '8309', 'status' : 302 }, + { 'host' : localhost, 'port' : '8310', 'status' : 303 }, + { 'host' : localhost, 'port' : '8311', 'status' : 307 }, { 'host' : localhost, 'port' : '8312' } ]; +var servers_no_location = [ + { 'host' : localhost, 'port' : '8300', 'status' : 301 }, + { 'host' : localhost, 'port' : '8301' } +]; + +var servers_305 = [ + { 'host' : localhost, 'port' : '8300', 'status' : 305 }, + { 'host' : localhost, 'port' : '8301' } +]; + + function setupServers(servers) { //create redirect servers that return response codes in the 300 range (from 300 to 309), and provide Location header @@ -66,7 +77,7 @@ function setupServers(servers) { servers[i].instance = http.createServer((function(j) { return function (req, res) { var location = protocol + '://' + servers[j + 1].host + ':' + servers[j + 1].port + req.url; - res.writeHead(300 + j, { 'Location': location }); + res.writeHead(servers[j].status, { 'Location': location }); res.end(); } })(i)).listen(servers[i].port, servers[i].host); @@ -153,5 +164,87 @@ module.exports = { } }); + }, + 'no-location-header':function (test) { + var servers = servers_no_location; + + // Special case: need to create bad server + servers[0].instance = http.createServer(function (req, res) { + var location = protocol + '://' + servers[1].host + ':' + servers[1].port + req.url; + res.writeHead(servers[0].status, { 'WrongLocationHeader': location }); + res.end(); + }).listen(servers[0].port, servers[0].host); + + // create the final server, the one that's going to return data + servers[1].instance = http.createServer(function (req, res) { + var file = __dirname + '/mock' + req.url; + var stat = fs.statSync(file); + res.writeHead(200, { + 'Content-Type':file.indexOf('.xml') >= 0 ? 'application/xml' : 'application/json', + 'Content-Length':stat.size + }); + var readStream = fs.createReadStream(file); + util.pump(readStream, res, function (e) { + if (e) { + console.log(e.stack || e); + } + res.end(); + }); + }).listen(servers[1].port, servers[1].host); + + var engine = new Engine({ + config:__dirname + '/config/dev.json' + }); + + var script = fs.readFileSync(__dirname + '/mock/redirect.ql', 'UTF-8'); + + engine.exec({ + script:script, + cb:function (err, result) { + try { + if (!err) { + test.ok(false, "Error expected."); + } else { + test.ok(err.message === "Missing Location header in redirect"); + } + test.done(); + } + finally { + for (var i = 0; i < servers.length; i++) { + servers[i].instance.close(); + } + } + } + }); + }, + 'status-305':function (test) { + var servers = servers_305; + + setupServers(servers); + + var engine = new Engine({ + config:__dirname + '/config/dev.json' + }); + + var script = fs.readFileSync(__dirname + '/mock/redirect.ql', 'UTF-8'); + + engine.exec({ + script:script, + cb:function (err, result) { + try { + if (!err) { + test.ok(false, "Error expected."); + } else { + test.ok(err.message === "Received status code 305 from downstream server"); + } + test.done(); + } + finally { + for (var i = 0; i < servers.length; i++) { + servers[i].instance.close(); + } + } + } + }); } } From b99f0ae4a69defdf272cdf19334d4dda1161bf03 Mon Sep 17 00:00:00 2001 From: Igor Dralyuk Date: Mon, 19 Mar 2012 17:24:44 -0700 Subject: [PATCH 6/7] Added ability to resolve relative urls in Location header on redirects. --- modules/engine/lib/engine/http/request.js | 12 ++- modules/engine/package.json | 2 +- modules/engine/test/mock/redirect-rel.ql | 6 ++ modules/engine/test/redirect-test.js | 112 +++++++++++++++++++++- 4 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 modules/engine/test/mock/redirect-rel.ql diff --git a/modules/engine/lib/engine/http/request.js b/modules/engine/lib/engine/http/request.js index 7426338d..ad5c3f4f 100644 --- a/modules/engine/lib/engine/http/request.js +++ b/modules/engine/lib/engine/http/request.js @@ -106,9 +106,15 @@ function sendHttpRequest(client, options, args, start, timings, reqStart, key, c return args.httpReqTx.cb(err); } - var location = new URI(res.headers.location, false); - options.host = location.heirpart().authority().host(); - options.port = location.heirpart().authority().port(); + var location = new URI(res.headers.location); + + if (location.isAbsolute()) { + options.host = location.heirpart().authority().host(); + options.port = location.heirpart().authority().port(); + } else { + location = new URI(args.uri); + location = location.resolveReference(res.headers.location); + } options.path = location.heirpart().path(); args.logEmitter.emitEvent(args.httpReqTx.event, 'being redirected for the ' + redirects + ' time, ' + diff --git a/modules/engine/package.json b/modules/engine/package.json index ee7a401b..c383e91a 100644 --- a/modules/engine/package.json +++ b/modules/engine/package.json @@ -1,7 +1,7 @@ { "author": "ql.io", "name": "ql.io-engine", - "version": "0.4.19", + "version": "0.4.20", "repository": { "type": "git", "url": "https://github.com/ql-io/ql.io" diff --git a/modules/engine/test/mock/redirect-rel.ql b/modules/engine/test/mock/redirect-rel.ql new file mode 100644 index 00000000..41b52445 --- /dev/null +++ b/modules/engine/test/mock/redirect-rel.ql @@ -0,0 +1,6 @@ +create table redirect + on select get from "http://127.0.0.1:8300/redirect-response.json" + using headers 'redirect-test' = 'true' +response = select * from redirect; + +return response; diff --git a/modules/engine/test/redirect-test.js b/modules/engine/test/redirect-test.js index ffb37db6..a64f48af 100644 --- a/modules/engine/test/redirect-test.js +++ b/modules/engine/test/redirect-test.js @@ -59,8 +59,12 @@ var servers_negative = [ { 'host' : localhost, 'port' : '8312' } ]; +var servers_rel_location = [ + { 'host' : localhost, 'port' : '8300', 'status' : 301 } +]; + var servers_no_location = [ - { 'host' : localhost, 'port' : '8300', 'status' : 301 }, + { 'host' : localhost, 'port' : '8300', 'status' : 302 }, { 'host' : localhost, 'port' : '8301' } ]; @@ -120,8 +124,7 @@ module.exports = { if (err) { console.log(err.stack || err); test.ok(false); - } - else { + } else { test.ok(result && result.body.id === "42"); } test.done(); @@ -165,6 +168,109 @@ module.exports = { }); }, + 'rel-location-header':function (test) { + var servers = servers_rel_location; + + // Special case: need to create custom server that will redirect if given a special header, but return data otherwise + servers[0].instance = http.createServer(function (req, res) { + if (req.headers.redirect-test) { + res.writeHead(servers[0].status, { 'Location': req.url }); + res.end(); + return; + } + + var file = __dirname + '/mock' + req.url; + var stat = fs.statSync(file); + res.writeHead(200, { + 'Content-Type':file.indexOf('.xml') >= 0 ? 'application/xml' : 'application/json', + 'Content-Length':stat.size + }); + var readStream = fs.createReadStream(file); + util.pump(readStream, res, function (e) { + if (e) { + console.log(e.stack || e); + } + res.end(); + }); + }).listen(servers[0].port, servers[0].host); + + var engine = new Engine({ + config:__dirname + '/config/dev.json' + }); + + var script = fs.readFileSync(__dirname + '/mock/redirect-rel.ql', 'UTF-8'); + + engine.exec({ + script:script, + cb:function (err, result) { + try { + if (err) { + console.log(err.stack || err); + test.ok(false); + } else { + test.ok(result && result.body.id === "42"); + } + test.done(); + } + finally { + for (var i = 0; i < servers.length; i++) { + servers[i].instance.close(); + } + } + } + }); + }, + 'bad-location-header':function (test) { + var servers = servers_no_location; + + // Special case: need to create bad server + servers[0].instance = http.createServer(function (req, res) { + res.writeHead(servers[0].status, { 'Location': 'BadLocationURI' }); + res.end(); + }).listen(servers[0].port, servers[0].host); + + // create the final server, the one that's going to return data + servers[1].instance = http.createServer(function (req, res) { + var file = __dirname + '/mock' + req.url; + var stat = fs.statSync(file); + res.writeHead(200, { + 'Content-Type':file.indexOf('.xml') >= 0 ? 'application/xml' : 'application/json', + 'Content-Length':stat.size + }); + var readStream = fs.createReadStream(file); + util.pump(readStream, res, function (e) { + if (e) { + console.log(e.stack || e); + } + res.end(); + }); + }).listen(servers[1].port, servers[1].host); + + var engine = new Engine({ + config:__dirname + '/config/dev.json' + }); + + var script = fs.readFileSync(__dirname + '/mock/redirect.ql', 'UTF-8'); + + engine.exec({ + script:script, + cb:function (err, result) { + try { + if (!err) { + test.ok(false, "Error expected."); + } else { + test.ok(err.status === 502); + } + test.done(); + } + finally { + for (var i = 0; i < servers.length; i++) { + servers[i].instance.close(); + } + } + } + }); + }, 'no-location-header':function (test) { var servers = servers_no_location; From 66b7cb3ce445dad04b6598b3e8244da291f43d26 Mon Sep 17 00:00:00 2001 From: Igor Dralyuk Date: Mon, 19 Mar 2012 17:46:48 -0700 Subject: [PATCH 7/7] Fixed relative location redirect test. --- modules/engine/test/mock/redirect-rel.ql | 3 +-- modules/engine/test/redirect-test.js | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/engine/test/mock/redirect-rel.ql b/modules/engine/test/mock/redirect-rel.ql index 41b52445..7c6fa229 100644 --- a/modules/engine/test/mock/redirect-rel.ql +++ b/modules/engine/test/mock/redirect-rel.ql @@ -1,6 +1,5 @@ create table redirect - on select get from "http://127.0.0.1:8300/redirect-response.json" - using headers 'redirect-test' = 'true' + on select get from "http://127.0.0.1:8300/rel/redirect-response.json" response = select * from redirect; return response; diff --git a/modules/engine/test/redirect-test.js b/modules/engine/test/redirect-test.js index a64f48af..f5bd5c80 100644 --- a/modules/engine/test/redirect-test.js +++ b/modules/engine/test/redirect-test.js @@ -171,10 +171,10 @@ module.exports = { 'rel-location-header':function (test) { var servers = servers_rel_location; - // Special case: need to create custom server that will redirect if given a special header, but return data otherwise + // Special case: need to create custom server that will redirect if given prefix '/rel' in the path, but return data otherwise servers[0].instance = http.createServer(function (req, res) { - if (req.headers.redirect-test) { - res.writeHead(servers[0].status, { 'Location': req.url }); + if (req.url.indexOf('/rel') === 0) { + res.writeHead(servers[0].status, { 'Location': req.url.substring('/rel'.length) }); res.end(); return; }