module Slinky::ProxyServer
Constants
- HOST_MATCHER
- HTTP_MATCHER
Public Class Methods
find_matcher(proxies, path)
click to toggle source
# File lib/slinky/proxy_server.rb, line 21 def self.find_matcher proxies, path proxies.find{|p| path.start_with?(p[0])} end
process_proxies(proxy_hash)
click to toggle source
# File lib/slinky/proxy_server.rb, line 6 def self.process_proxies proxy_hash proxy_hash.map{|from, h| begin to, opt = h.is_a?(Hash) ? [h.delete("to"), h] : [h, {}] a = [from, URI::parse(to), opt] rescue $stderr.puts "Invalid proxy setting: #{from} => #{to}".foreground(:red) end }.compact end
process_proxy_servers(proxies)
click to toggle source
# File lib/slinky/proxy_server.rb, line 17 def self.process_proxy_servers proxies proxies.map{|p| [p[1].host, p[1].port]} end
replace_host(http, host)
click to toggle source
# File lib/slinky/proxy_server.rb, line 42 def self.replace_host http, host http.gsub(HOST_MATCHER, "Host: #{host}") end
replace_path(http, old_path, new_path, addition)
click to toggle source
# File lib/slinky/proxy_server.rb, line 36 def self.replace_path http, old_path, new_path, addition # TODO: This may fail in certain, rare cases addition = addition[0..-2] if addition[-1] == "/" http.gsub(old_path, addition + new_path) end
rewrite_path(path, proxy)
click to toggle source
# File lib/slinky/proxy_server.rb, line 25 def self.rewrite_path path, proxy if proxy[0] == "/" # If we're proxying everything, we just want to pass the path # through unmodified. Otherwise we end up stripping the # initial slash, which is the wrong behavior. path else path.gsub(/^#{proxy[0]}/, "") end end
run(proxy_hash, port, slinky_port)
click to toggle source
# File lib/slinky/proxy_server.rb, line 46 def self.run proxy_hash, port, slinky_port proxies = process_proxies proxy_hash proxy_servers = process_proxy_servers proxies Proxy.start(:host => "0.0.0.0", :port => port){|conn| proxy = nil start_time = nil conn.server :slinky, :host => "127.0.0.1", :port => slinky_port server = nil conn.on_data do |data| begin matches = data.match(ProxyServer::HTTP_MATCHER) if matches path = matches[2] proxy = ProxyServer.find_matcher(proxies, path) start_time = Time.now server = if proxy new_path = ProxyServer.rewrite_path path, proxy data = ProxyServer.replace_path(data, path, new_path, proxy[1].path) new_host = proxy[1].select(:host, :port).join(":") data = ProxyServer.replace_host(data, new_host) conn.server [proxy[1].host, proxy[1].port], :host => proxy[1].host, :port => proxy[1].port [proxy[1].host, proxy[1].port] else :slinky end end [data, [server]] rescue conn.send_data "HTTP/1.1 500 Ooops...something went wrong\r\n" end end conn.on_response do |server, resp| opt = proxy && proxy[2] if opt && opt["lag"] # we want to get as close as possible to opt["lag"], so we # take into account the lag from the backend server so_far = Time.now - start_time time = opt["lag"]/1000.0-so_far EM.add_timer(time > 0 ? time : 0) do conn.send_data resp end else resp end end conn.on_finish do |name| unbind end } end