Created
January 31, 2019 19:47
-
-
Save jasonswearingen/7a62746a96c8d3ba539220dd9889748f to your computer and use it in GitHub Desktop.
toy proxy for NodeJs (http+https support)
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
//from: https://stackoverflow.com/a/49864522/1115220 re question: https://stackoverflow.com/questions/8165570/https-proxy-server-in-node-js | |
import http = require( 'http' ) | |
const port: number = Number.parseInt( process.env.PORT ) || 9191; | |
import net = require( 'net' ) | |
import url = require( 'url' ) | |
import xlib = require( "xlib" ); | |
import __ = xlib.lolo; | |
import log = xlib.diagnostics.log; | |
const requestHandler = ( req, res ) => { // discard all request to proxy server except HTTP/1.1 CONNECT method | |
res.writeHead( 405, { 'Content-Type': 'text/plain' } ) | |
res.end( 'Method not allowed' ) | |
} | |
const server = http.createServer( requestHandler ) | |
const listener = server.listen( port, ( err ) => { | |
if ( err ) { | |
return console.error( err ) | |
} | |
const info = listener.address() | |
if ( typeof ( info ) === "string" ) { | |
console.log( `Server is listening: info: ${ info }` ); | |
} else { | |
console.log( `Server is listening on address ${ info.address } port ${ info.port }` ) | |
} | |
} ) | |
server.on( 'connect', ( req: http.IncomingMessage, clientSocket: net.Socket, head: Buffer ) => { // listen only for HTTP/1.1 CONNECT method | |
console.log( clientSocket.remoteAddress, clientSocket.remotePort, req.method, req.url ) | |
if ( !req.headers[ 'proxy-authorization' ] ) { // here you can add check for any username/password, I just check that this header must exist! | |
log.trace( "no auth passed. closing connection. here you can add check for any username/password, I just check that this header must exist!" ); | |
clientSocket.write( [ | |
'HTTP/1.1 407 Proxy Authentication Required', | |
'Proxy-Authenticate: Basic realm="proxy"', | |
'Proxy-Connection: close', | |
].join( '\r\n' ) ) | |
clientSocket.end( '\r\n\r\n' ) // empty body | |
return; | |
} | |
else { | |
//log.trace( `auth passed: req.headers[ 'proxy-authorization' ]===${ req.headers[ 'proxy-authorization' ] }` ); | |
if ( req.url.includes( "example" ) ) { | |
log.info( "req passed:", req ); | |
} | |
} | |
const destUrl = url.parse( `//${ req.url }`, false, true ) // extract destination host and port from CONNECT request | |
if ( destUrl.hostname && destUrl.port ) { | |
const serverErrorHandler = ( err ) => { | |
console.error( err.message ) | |
if ( clientSocket ) { | |
clientSocket.end( `HTTP/1.1 500 ${ err.message }\r\n` ) | |
} | |
} | |
const serverEndHandler = () => { | |
if ( clientSocket ) { | |
clientSocket.end( `HTTP/1.1 500 External Server End\r\n` ) | |
} | |
} | |
const serverSocket = net.connect( Number.parseInt( destUrl.port ), destUrl.hostname ) // connect to destination host and port | |
const clientErrorHandler = ( err ) => { | |
console.error( err.message ) | |
if ( serverSocket ) { | |
serverSocket.end() | |
} | |
} | |
const clientEndHandler = () => { | |
if ( serverSocket ) { | |
serverSocket.end() | |
} | |
} | |
clientSocket.on( 'error', clientErrorHandler ) | |
clientSocket.on( 'end', clientEndHandler ) | |
serverSocket.on( 'error', serverErrorHandler ) | |
serverSocket.on( 'end', serverEndHandler ) | |
serverSocket.on( 'connect', () => { | |
clientSocket.write( [ | |
'HTTP/1.1 200 Connection Established', | |
'Proxy-agent: Node-VPN', | |
].join( '\r\n' ) ) | |
clientSocket.write( '\r\n\r\n' ) // empty body | |
// "blindly" (for performance) pipe client socket and destination socket between each other | |
serverSocket.pipe( clientSocket, { end: false } ) | |
clientSocket.pipe( serverSocket, { end: false } ) | |
} ) | |
} else { | |
clientSocket.end( 'HTTP/1.1 400 Bad Request\r\n' ) | |
clientSocket.destroy() | |
} | |
} ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
note: https proxy works, but http proxy seems not to. I think http proxy needs to pipe requests (not just handle connect events)