1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
class ProxyServer
def initialize(options = {})
@options = options
end
def listen(port, tls = false)
@server = EM.start_server('localhost', port, Frontend) do |frontend|
if tls
frontend.start_tls(
:private_key_file => File.expand_path('../server.key', __FILE__),
:cert_chain_file => File.expand_path('../server.crt', __FILE__)
)
end
frontend.debug = @options[:debug]
end
end
def stop
EM.stop_server(@server) if @server
end
def self.format(data)
data.bytes.map { |b| "%02x" % b }.join(' ')
end
module Frontend
attr_writer :debug
def post_init
@request = WebSocket::HTTP::Request.new
@backend = nil
end
def receive_data(data)
if @backend
p [:I, ProxyServer.format(data)] if @debug
return @backend.send_data(data)
end
@request.parse(data)
return unless @request.complete?
unless @request.env['REQUEST_METHOD'] == 'CONNECT'
send_data("HTTP/1.1 403 Forbidden\r\n\r\n")
return close_connection_after_writing
end
p @request.env if @debug
hostname, port = @request.env['PATH_INFO'].split(':', 2)
EM.connect(hostname, port, Backend) do |backend|
backend.debug = @debug
backend.frontend = self
end
end
def unbind
@backend.close_connection_after_writing if @backend
end
def return_handshake(backend)
@backend = backend
send_data("HTTP/1.1 200 OK\r\n\r\n")
end
end
module Backend
attr_writer :debug, :frontend
def connection_completed
@frontend.return_handshake(self)
end
def receive_data(data)
p [:O, ProxyServer.format(data)] if @debug
@frontend.send_data(data)
end
def unbind
@frontend.close_connection_after_writing
end
end
end
|