Created
April 28, 2011 22:42
-
-
Save eventualbuddha/947505 to your computer and use it in GitHub Desktop.
An HTTP proxy server that can act as a system proxy or a local port forwarder with an optional delay
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env coffee | |
sys = require('sys') | |
http = require('http') | |
## Argument parsing | |
args = process.argv.slice(2) | |
port = 9090 | |
delay = 0 | |
proxyHost = null | |
proxyPort = 80 | |
usage = (error) -> | |
sys.error("error: #{error}\n") if error | |
sys.error "Usage: proxy [-p PORT] [-h HOST] -P PORT" | |
sys.error "" | |
sys.error "" | |
sys.error " -p, --port Run the file server on this port (defaults to #{port})" | |
sys.error " -d, --delay The delay (in seconds) to add to the response time for each request (defaults to #{delay})" | |
sys.error "" | |
sys.error " -h, --proxy-host The destination host to forward requests to (defaults to the request's Host header)" | |
sys.error " -P, --proxy-port The destination port to forward requests to (defaults to #{proxyPort})" | |
process.exit(if error then 1 else 0) | |
while args.length | |
arg = args.shift() | |
match = arg.match(/^(--\w+[\w-])(?:=(.*))?$/) | |
if match | |
# --port=1234, --port, etc | |
arg = match[1] | |
args.unshift(match[2]) if match[2] | |
switch arg | |
when '-p', '--port' | |
portArg = args.shift() | |
if portArg == undefined | |
usage "expected port number after #{arg}" | |
port = Number(portArg) | |
if port == 0 or isNaN(port) | |
usage "invalid port number #{port}" | |
when '-d', '--delay' | |
delayArg = args.shift() | |
if delayArg == undefined | |
usage "expected delay number after #{arg}" | |
delay = Number(delayArg) | |
if isNaN(delay) | |
usage "invalid delay number #{delay}" | |
when '-h', '--proxy-host' | |
proxyHostArg = args.shift() | |
if proxyHostArg == undefined | |
usage "expected host after #{arg}" | |
proxyHost = proxyHostArg | |
when '-P', '--proxy-port' | |
proxyPortArg = args.shift() | |
if proxyPortArg == undefined | |
usage "expected port after #{arg}" | |
proxyPort = Number(proxyPortArg) | |
if proxyPort == 0 or isNaN(proxyPort) | |
usage "invalid port number #{proxyPortArg}" | |
when '--help' | |
usage() | |
else | |
usage "unrecognized argument #{arg}" | |
## Support | |
class DelayedHTTPClientRequest | |
delayed: true | |
_delayedCalls: null | |
constructor: (@request) -> | |
@_delayedCalls = [] | |
addListener: (args...) -> | |
@request.addListener(args...) | |
write: (args...) -> | |
@send 'write', args... | |
end: (args...) -> | |
@send 'end', args... | |
send: (name, args...) -> | |
if @delayed | |
@_delayedCalls.push [name, args] | |
else | |
@request[name].call(@request, args...) | |
setDelayed: (delayed) -> | |
return if @delayed == delayed | |
if not (@delayed = delayed) | |
for [name, args] in @_delayedCalls | |
@request[name].call(@request, args...) | |
@_delayedCalls = [] | |
## Guts | |
server = (request, response) -> | |
console.log("#{request.method} #{request.url}") | |
proxy = http.createClient(proxyPort, proxyHost || request.headers['host']) | |
proxy_request = new DelayedHTTPClientRequest(proxy.request(request.method, request.url, request.headers)) | |
proxy_request.addListener 'response', (proxy_response) => | |
proxy_response.addListener 'data', (chunk) => | |
response.write(chunk, 'binary') | |
proxy_response.addListener 'end', => | |
response.end() | |
response.writeHead(proxy_response.statusCode, proxy_response.headers) | |
request.addListener 'data', (chunk) => | |
proxy_request.write(chunk, 'binary') | |
request.addListener 'end', => | |
proxy_request.end() | |
setTimeout((-> proxy_request.setDelayed(false)), delay*1000) | |
http.createServer(server).listen(port) | |
info = if proxyHost | |
"~ Forwarding HTTP traffic from 127.0.0.1:#{port} to #{proxyHost}:#{proxyPort}" | |
else | |
"~ Proxying HTTP traffic at 127.0.0.1:#{port}" | |
info += " with a #{delay}s delay" if delay > 0 | |
sys.puts info |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment