monkey-proxy
Version:
fork of tootallnate's proxy, adding hooks for modifying requests
247 lines (221 loc) • 6.63 kB
JavaScript
/**
* Module dependencies.
*/
var fs = require('fs');
var net = require('net');
var path = require('path');
var http = require('http');
var https = require('https');
var assert = require('assert');
var setup = require('../');
var stream = require('stream');
describe('proxy', function () {
var proxy;
var proxyPort;
var transformProxy;
var transformProxyPort;
var responseStream = new stream.PassThrough();
var requestStream = new stream.PassThrough();
var server;
var serverPort;
before(function (done) {
// plain old proxy.
function createProxy(cb) {
proxy = setup(http.createServer());
proxy.listen(function () {
proxyPort = proxy.address().port;
return cb();
});
}
// proxy that transforms HTTP stream.
function createTransformProxy(cb) {
transformProxy = setup(http.createServer(), {
transformResponse: function() {
return responseStream;
},
transformRequest: function() {
return requestStream;
}
});
transformProxy.listen(function () {
transformProxyPort = transformProxy.address().port;
return cb();
});
}
createProxy(function() {
createTransformProxy(function() {
return done();
});
});
});
before(function (done) {
// setup target server
server = http.createServer();
server.listen(function () {
serverPort = server.address().port;
done();
});
});
after(function (done) {
proxy.once('close', function () { done(); });
proxy.close();
});
after(function (done) {
transformProxy.once('close', function () { done(); });
transformProxy.close();
});
after(function (done) {
server.once('close', function () { done(); });
server.close();
});
it('should proxy HTTP GET requests', function (done) {
var gotData = false;
var gotRequest = false;
var host = '127.0.0.1:' + serverPort;
server.once('request', function (req, res) {
gotRequest = true;
// ensure headers are being proxied
assert(req.headers['user-agent'] == 'curl/7.30.0');
assert(req.headers.host == host);
assert(req.headers.accept == '*/*');
res.end();
});
var socket = net.connect({ port: proxyPort });
socket.once('close', function () {
assert(gotData);
assert(gotRequest);
done();
});
socket.once('connect', function () {
socket.write(
'GET http://' + host + '/ HTTP/1.1\r\n' +
'User-Agent: curl/7.30.0\r\n' +
'Host: ' + host + '\r\n' +
'Accept: */*\r\n' +
'Proxy-Connection: Keep-Alive\r\n' +
'\r\n');
});
socket.setEncoding('utf8');
socket.once('data', function (data) {
assert(0 == data.indexOf('HTTP/1.1 200 OK\r\n'));
gotData = true;
socket.destroy();
});
});
it('should allow the request and response streams to be transformed', function (done) {
var host = '127.0.0.1:' + serverPort;
server.once('request', function (req, res) {
res.end();
});
var socket = net.connect({ port: transformProxyPort });
socket.once('close', function () {
assert(requestStream._writableState.ended);
assert(responseStream._writableState.ended);
done();
});
socket.once('connect', function () {
socket.write(
'GET http://' + host + '/ HTTP/1.1\r\n' +
'User-Agent: curl/7.30.0\r\n' +
'Host: ' + host + '\r\n' +
'Accept: */*\r\n' +
'Proxy-Connection: Keep-Alive\r\n' +
'\r\n');
});
socket.setEncoding('utf8');
socket.once('data', function (data) {
socket.destroy();
});
});
it('should establish connection for CONNECT requests', function (done) {
var gotData = false;
var socket = net.connect({ port: proxyPort });
socket.once('close', function () {
assert(gotData);
done();
});
socket.once('connect', function () {
var host = '127.0.0.1:' + serverPort;
socket.write(
'CONNECT ' + host + ' HTTP/1.1\r\n' +
'Host: ' + host + '\r\n' +
'User-Agent: curl/7.30.0\r\n' +
'Proxy-Connection: Keep-Alive\r\n' +
'\r\n');
});
socket.setEncoding('utf8');
socket.once('data', function (data) {
assert(0 == data.indexOf('HTTP/1.1 200 Connection established\r\n'));
gotData = true;
socket.destroy();
});
});
describe('authentication', function () {
function clearAuth () {
delete proxy.authenticate;
}
before(clearAuth);
after(clearAuth);
it('should invoke the `server.authenticate()` function when set', function (done) {
var auth = 'Basic Zm9vOmJhcg==';
var called = false;
proxy.authenticate = function (req, fn) {
assert(auth == req.headers['proxy-authorization']);
socket.destroy();
called = true;
};
var socket = net.connect({ port: proxyPort });
socket.once('close', function () {
assert(called);
done();
});
socket.once('connect', function () {
socket.write(
'GET / HTTP/1.1\r\n' +
'Proxy-Authorization: ' + auth + '\r\n' +
'\r\n');
});
});
it('should provide the HTTP client with a 407 response status code', function (done) {
proxy.authenticate = function (req, fn) {
// reject everything
fn(null, false);
};
var gotData = false;
var socket = net.connect({ port: proxyPort });
socket.once('close', function () {
assert(gotData);
done();
});
socket.once('connect', function () {
socket.write('GET / HTTP/1.1\r\n\r\n');
});
socket.setEncoding('utf8');
socket.once('data', function (data) {
assert(0 == data.indexOf('HTTP/1.1 407'));
gotData = true;
socket.destroy();
});
});
it('should close the socket after a CONNECT request\'s 407 response status code', function (done) {
proxy.authenticate = function (req, fn) {
// reject everything
fn(null, false);
};
var gotData = false;
var socket = net.connect({ port: proxyPort });
socket.once('close', function () {
assert(gotData);
done();
});
socket.once('connect', function () {
socket.write('CONNECT 127.0.0.1:80 HTTP/1.1\r\n\r\n');
});
socket.setEncoding('utf8');
socket.once('data', function (data) {
assert(0 == data.indexOf('HTTP/1.1 407'));
gotData = true;
});
});
});
});