Skip to content

Commit

Permalink
Support https protocol (testcafe #1985) (#1590)
Browse files Browse the repository at this point in the history
* run testcafe with https protocol (#1985)

* fix some places, add `--ssl` option to playground, add tests

* make separate tasks

* rename tasks

* fix tests
  • Loading branch information
intermike authored and miherlosev committed May 17, 2018
1 parent d1852b7 commit e254ca1
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 25 deletions.
13 changes: 12 additions & 1 deletion Gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const util = require('gulp-util');
const ll = require('gulp-ll');
const path = require('path');

const selfSignedCertificate = require('openssl-self-signed-certificate');

ll
.tasks('lint')
.onlyInDebug([
Expand Down Expand Up @@ -192,12 +194,21 @@ gulp.task('test-client-travis', ['build'], () => {
.pipe(qunitHarness(CLIENT_TESTS_SETTINGS, SAUCELABS_SETTINGS));
});

gulp.task('playground', ['set-dev-mode', 'build'], () => {
gulp.task('http-playground', ['set-dev-mode', 'build'], () => {
require('./test/playground/server.js').start();

return hang();
});

gulp.task('https-playground', ['set-dev-mode', 'build'], () => {
require('./test/playground/server.js').start({
key: selfSignedCertificate.key,
cert: selfSignedCertificate.cert
});

return hang();
});

gulp.task('travis', [process.env.GULP_TASK || '']);

gulp.task('set-dev-mode', function () {
Expand Down
19 changes: 12 additions & 7 deletions src/client/utils/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,18 @@ export function getProxyUrl (url, opts) {
return url;

/*eslint-disable no-restricted-properties*/
const proxyHostname = opts && opts.proxyHostname || location.hostname;
const proxyPort = opts && opts.proxyPort || location.port.toString();
const proxyHostname = opts && opts.proxyHostname || location.hostname;
const proxyPort = opts && opts.proxyPort || location.port.toString();
const proxyServerProtocol = opts && opts.proxyProtocol || location.protocol;
/*eslint-enable no-restricted-properties*/

const proxyProtocol = parsedResourceType.isWebSocket ? 'ws:' : void 0;
const sessionId = opts && opts.sessionId || settings.get().sessionId;
let charset = opts && opts.charset;
let reqOrigin = opts && opts.reqOrigin;
const proxyProtocol = parsedResourceType.isWebSocket
? proxyServerProtocol.replace('http', 'ws')
: proxyServerProtocol;

const sessionId = opts && opts.sessionId || settings.get().sessionId;
let charset = opts && opts.charset;
let reqOrigin = opts && opts.reqOrigin;

const crossDomainPort = getCrossDomainProxyPort(proxyPort);

Expand Down Expand Up @@ -69,7 +73,8 @@ export function getProxyUrl (url, opts) {
// NOTE: It seems that the relative URL had the leading slash or dots, so that the proxy info path part was
// removed by the resolver and we have an origin URL with the incorrect host and protocol.
/*eslint-disable no-restricted-properties*/
if (parsedUrl.protocol === 'http:' && parsedUrl.hostname === proxyHostname && parsedUrl.port === proxyPort) {
if (parsedUrl.protocol === proxyServerProtocol && parsedUrl.hostname === proxyHostname &&
parsedUrl.port === proxyPort) {
const parsedDestLocation = destLocation.getParsed();

parsedUrl.protocol = parsedDestLocation.protocol;
Expand Down
26 changes: 19 additions & 7 deletions src/proxy/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Router from './router';
import http from 'http';
import https from 'https';
import * as urlUtils from '../utils/url';
import { readSync as read } from 'read-file-relative';
import { respond204, respond500, respondWithJSON, fetchBody, preventCaching } from '../utils/http';
Expand All @@ -22,26 +23,36 @@ function parseAsJson (msg) {
}
}

function createServerInfo (hostname, port, crossDomainPort) {
function createServerInfo (hostname, port, crossDomainPort, protocol) {
return {
hostname: hostname,
port: port,
crossDomainPort: crossDomainPort,
domain: `http://${hostname}:${port}`
protocol: protocol,
domain: `${protocol}//${hostname}:${port}`
};
}

// Proxy
export default class Proxy extends Router {
constructor (hostname, port1, port2) {
constructor (hostname, port1, port2, sslOptions) {
super();

this.openSessions = {};

this.server1Info = createServerInfo(hostname, port1, port2);
this.server2Info = createServerInfo(hostname, port2, port1);
this.server1 = http.createServer((req, res) => this._onRequest(req, res, this.server1Info));
this.server2 = http.createServer((req, res) => this._onRequest(req, res, this.server2Info));
const protocol = sslOptions ? 'https:' : 'http:';

this.server1Info = createServerInfo(hostname, port1, port2, protocol);
this.server2Info = createServerInfo(hostname, port2, port1, protocol);

if (sslOptions) {
this.server1 = https.createServer(sslOptions, (req, res) => this._onRequest(req, res, this.server1Info));
this.server2 = https.createServer(sslOptions, (req, res) => this._onRequest(req, res, this.server2Info));
}
else {
this.server1 = http.createServer((req, res) => this._onRequest(req, res, this.server1Info));
this.server2 = http.createServer((req, res) => this._onRequest(req, res, this.server2Info));
}

this.server1.on('upgrade', (req, socket, head) => this._onUpgradeRequest(req, socket, head, this.server1Info));
this.server2.on('upgrade', (req, socket, head) => this._onUpgradeRequest(req, socket, head, this.server2Info));
Expand Down Expand Up @@ -171,6 +182,7 @@ export default class Proxy extends Router {
return urlUtils.getProxyUrl(url, {
proxyHostname: this.server1Info.hostname,
proxyPort: this.server1Info.port,
proxyProtocol: this.server1Info.protocol,
sessionId: session.id
});
}
Expand Down
2 changes: 2 additions & 0 deletions src/request-pipeline/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,13 @@ export default class RequestPipelineContext {

toProxyUrl (url, isCrossDomain, resourceType, charset) {
const proxyHostname = this.serverInfo.hostname;
const proxyProtocol = this.serverInfo.protocol;
const proxyPort = isCrossDomain ? this.serverInfo.crossDomainPort : this.serverInfo.port;
const sessionId = this.session.id;

return urlUtils.getProxyUrl(url, {
proxyHostname,
proxyProtocol,
proxyPort,
sessionId,
resourceType,
Expand Down
48 changes: 41 additions & 7 deletions test/client/fixtures/utils/url-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ var PROXY_PORT = 1337;
var PROXY_HOSTNAME = '127.0.0.1';
var PROXY_HOST = PROXY_HOSTNAME + ':' + PROXY_PORT;

function getProxyUrl (url, resourceType) {
function getProxyUrl (url, resourceType, protocol) {
return urlUtils.getProxyUrl(url, {
proxyHostname: PROXY_HOSTNAME,
proxyPort: PROXY_PORT,
sessionId: 'sessionId',
resourceType: resourceType
resourceType: resourceType,
proxyProtocol: protocol || 'http:'
});
}

Expand Down Expand Up @@ -170,7 +171,6 @@ test('already proxied', function () {
var newUrl = getProxyUrl(proxyUrl, 'i');

strictEqual(urlUtils.parseProxyUrl(newUrl).resourceType, 'i');

});

test('destination with query, path, hash and host', function () {
Expand All @@ -195,13 +195,11 @@ test('destination with https protocol', function () {
});

test('relative path', function () {
var destUrl = '/Image1.jpg';
var proxyUrl = urlUtils.getProxyUrl(destUrl);
var proxyUrl = urlUtils.getProxyUrl('/Image1.jpg');

strictEqual(proxyUrl, 'http://' + location.host + '/sessionId/https://example.com/Image1.jpg');

var relativeUrl = 'share?id=1kjQMWh7IcHdTBbTv6otRvCGYr-p02q206M7aR7dmog0';
var parsedUrl = urlUtils.parseUrl(relativeUrl);
var parsedUrl = urlUtils.parseUrl('share?id=1kjQMWh7IcHdTBbTv6otRvCGYr-p02q206M7aR7dmog0');

ok(!parsedUrl.hostname);
ok(!parsedUrl.host);
Expand Down Expand Up @@ -293,6 +291,42 @@ test('convert a charset to lower case (GH-752)', function () {
strictEqual(sharedUrlUtils.getProxyUrl(url, opts), 'http://localhost:5555/sessionId!utf-8/' + url);
});

module('https proxy protocol');

test('destination with host only', function () {
var destUrl = 'http://test.example.com/';
var proxyUrl = getProxyUrl(destUrl, '', 'https:');

strictEqual(proxyUrl, 'https://' + PROXY_HOST + '/sessionId/' + destUrl);
});

test('relative path', function () {
var proxyUrl = getProxyUrl('/Image1.jpg', '', 'https:');

strictEqual(proxyUrl, 'https://' + PROXY_HOST + '/sessionId/https://example.com/Image1.jpg');
});

test('special pages', function () {
sharedUrlUtils.SPECIAL_PAGES.forEach(function (url) {
var proxyUrl = getProxyUrl(url, '', 'https:');

strictEqual(proxyUrl, 'https://' + PROXY_HOST + '/sessionId/' + url);
});
});

test('parse proxy url', function () {
var proxyUrl = 'https://' + PROXY_HOST + '/sessionId/http://test.example.com:53/PA/TH/?#testHash';
var parsingResult = urlUtils.parseProxyUrl(proxyUrl);

strictEqual(parsingResult.destUrl, 'http://test.example.com:53/PA/TH/?#testHash');
strictEqual(parsingResult.destResourceInfo.protocol, 'http:');
strictEqual(parsingResult.destResourceInfo.host, 'test.example.com:53');
strictEqual(parsingResult.destResourceInfo.hostname, 'test.example.com');
strictEqual(parsingResult.destResourceInfo.port, '53');
strictEqual(parsingResult.destResourceInfo.partAfterHost, '/PA/TH/?#testHash');
strictEqual(parsingResult.sessionId, 'sessionId');
});

module('parse proxy url');

test('http', function () {
Expand Down
4 changes: 2 additions & 2 deletions test/playground/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ function createSession () {
return session;
}

exports.start = () => {
exports.start = sslOptions => {
const app = express();
const proxy = new Proxy('localhost', PROXY_PORT_1, PROXY_PORT_2);
const appServer = http.createServer(app);
const proxy = new Proxy('localhost', PROXY_PORT_1, PROXY_PORT_2, sslOptions);

app.use(express.bodyParser());

Expand Down
Loading

0 comments on commit e254ca1

Please sign in to comment.