class Pacproxy::Pacproxy
Pacproxy::Pacproxy
represent http/https proxy server
Constants
- HOP_BY_HOP
This method is mainly from WEBrick::HTTPProxyServer. proxy-authenticate can be transferred from a upstream proxy server to a client see: github.com/ruby/ruby/blob/trunk/lib/webrick/httpproxy.rb
- SHOULD_NOT_TRANSFER
Public Class Methods
new(config = {}, default = WEBrick::Config::HTTP)
click to toggle source
Calls superclass method
# File lib/pacproxy/pacproxy.rb, line 10 def initialize(config = {}, default = WEBrick::Config::HTTP) super({ Port: config['port'], Logger: general_logger }, default) @auth = config['auth'] return unless config['pac_file'] && config['pac_file']['location'] @pac = PacFile.new(config['pac_file']['location'], config['pac_file']['update_interval']) end
Public Instance Methods
create_proxy_uri(proxy, header)
click to toggle source
# File lib/pacproxy/pacproxy.rb, line 33 def create_proxy_uri(proxy, header) return nil unless proxy return URI.parse("http://#{proxy}") unless @auth || header.key?('proxy-authorization') if @auth basic_auth = "#{@auth['user']}:#{@auth['password']}" elsif header.key?('proxy-authorization') auth = header['proxy-authorization'][0] pattern = /basic (\S+)/i basic_auth = pattern.match(auth)[1].unpack('m').first header.delete('proxy-authorization') end URI.parse("http://#{basic_auth}@#{proxy}") end
do_CONNECT(req, res)
click to toggle source
This method is mainly from WEBrick::HTTPProxyServer. To allow upstream proxy authentication, it operate 407 response from an upstream proxy. see: github.com/ruby/ruby/blob/trunk/lib/webrick/httpproxy.rb rubocop:disable all
# File lib/pacproxy/pacproxy.rb, line 55 def do_CONNECT(req, res) # Proxy Authentication proxy_auth(req, res) ua = Thread.current[:WEBrickSocket] # User-Agent raise WEBrick::HTTPStatus::InternalServerError, "[BUG] cannot get socket" unless ua host, port = req.unparsed_uri.split(":", 2) # Proxy authentication for upstream proxy server if proxy = proxy_uri(req, res) proxy_request_line = "CONNECT #{host}:#{port} HTTP/1.0" if proxy.userinfo credentials = "Basic " + [proxy.userinfo].pack("m").delete("\n") end host, port = proxy.host, proxy.port end begin @logger.debug("CONNECT: upstream proxy is `#{host}:#{port}'.") os = TCPSocket.new(host, port) # origin server if proxy @logger.debug("CONNECT: sending a Request-Line") os << proxy_request_line << WEBrick::CRLF @logger.debug("CONNECT: > #{proxy_request_line}") if credentials @logger.debug("CONNECT: sending a credentials") os << "Proxy-Authorization: " << credentials << WEBrick::CRLF end os << WEBrick::CRLF proxy_status_line = os.gets(WEBrick::LF) @logger.debug("CONNECT: read a Status-Line form the upstream server") @logger.debug("CONNECT: < #{proxy_status_line}") if /^HTTP\/\d+\.\d+\s+(?<st>200|407)\s*/ =~ proxy_status_line res.status = st.to_i while line = os.gets(WEBrick::LF) res.header['Proxy-Authenticate'] = line.split(':')[1] if /Proxy-Authenticate/i =~ line break if /\A(#{WEBrick::CRLF}|#{WEBrick::LF})\z/om =~ line end else raise WEBrick::HTTPStatus::BadGateway end end @logger.debug("CONNECT #{host}:#{port}: succeeded") rescue => ex @logger.debug("CONNECT #{host}:#{port}: failed `#{ex.message}'") res.set_error(ex) raise WEBrick::HTTPStatus::EOFError ensure if handler = @config[:ProxyContentHandler] handler.call(req, res) end res.send_response(ua) accesslog(req, res) # Should clear request-line not to send the response twice. # see: HTTPServer#run req.parse(WEBrick::NullReader) rescue nil end begin while fds = IO::select([ua, os]) if fds[0].member?(ua) buf = ua.sysread(1024); @logger.debug("CONNECT: #{buf.bytesize} byte from User-Agent") os.syswrite(buf) elsif fds[0].member?(os) buf = os.sysread(1024); @logger.debug("CONNECT: #{buf.bytesize} byte from #{host}:#{port}") ua.syswrite(buf) end end rescue os.close @logger.debug("CONNECT #{host}:#{port}: closed") end raise WEBrick::HTTPStatus::EOFError end
proxy_auth(req, res)
click to toggle source
rubocop:enable all
# File lib/pacproxy/pacproxy.rb, line 138 def proxy_auth(req, res) @config[:ProxyAuthProc].call(req, res) if @config[:ProxyAuthProc] end
proxy_uri(req, res)
click to toggle source
Calls superclass method
# File lib/pacproxy/pacproxy.rb, line 24 def proxy_uri(req, res) super(req, res) return unless @pac proxy_line = @pac.find(request_uri(req)) proxy = lookup_proxy_uri(proxy_line) create_proxy_uri(proxy, req.header) end
shutdown()
click to toggle source
Calls superclass method
# File lib/pacproxy/pacproxy.rb, line 19 def shutdown @pac.shutdown if @pac super end
Private Instance Methods
choose_header(src, dst)
click to toggle source
# File lib/pacproxy/pacproxy.rb, line 169 def choose_header(src, dst) connections = split_field(src['connection']) src.each do |key, value| key = key.downcase next if HOP_BY_HOP.member?(key) || # RFC2616: 13.5.1 connections.member?(key) || # RFC2616: 14.10 SHOULD_NOT_TRANSFER.member?(key) # pragmatics dst[key] = value end end
do_PUT(req, res)
click to toggle source
allow PUT method on proxy server method names for webrick is indicated by rubocop rubocop:disable all
# File lib/pacproxy/pacproxy.rb, line 189 def do_PUT(req, res) perform_proxy_request(req, res) do |http, path, header| http.put(path, req.body || '', header) end end
lookup_proxy_uri(proxy_line)
click to toggle source
# File lib/pacproxy/pacproxy.rb, line 152 def lookup_proxy_uri(proxy_line) case proxy_line when /^DIRECT/ nil when /PROXY/ primary_proxy = proxy_line.split(';')[0] /PROXY (.*)/.match(primary_proxy)[1] end end
perform_proxy_request(req, res)
click to toggle source
Calls superclass method
# File lib/pacproxy/pacproxy.rb, line 181 def perform_proxy_request(req, res) super accesslog(req, res) end
request_uri(request)
click to toggle source
# File lib/pacproxy/pacproxy.rb, line 144 def request_uri(request) if 'CONNECT' == request.request_method "https://#{request.unparsed_uri}/" else request.unparsed_uri end end