Extended maintenance of Ruby 1.9.3 ended on February 23, 2015. Read more
HTTPServer
An HTTP Proxy server which proxies GET, HEAD and POST requests.
Some header fields should not be transferred.
Proxy server configurations. The proxy server handles the following configuration items in addition to those supported by HTTPServer:
Called with a request and response to authorize a request
Appended to the via header
The proxy server's URI
Called with a request and resopnse and allows modification of the response
Sets the proxy timeouts to 30 seconds for open and 60 seconds for read operations
# File webrick/httpproxy.rb, line 54
def initialize(config={}, default=Config::HTTP)
super(config, default)
c = @config
@via = "#{c[:HTTPVersion]} #{c[:ServerName]}:#{c[:Port]}"
end
# File webrick/httpproxy.rb, line 102
def do_CONNECT(req, res)
# Proxy Authentication
proxy_auth(req, res)
ua = Thread.current[:WEBrickSocket] # User-Agent
raise 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 << CRLF
@logger.debug("CONNECT: > #{proxy_request_line}")
if credentials
@logger.debug("CONNECT: sending a credentials")
os << "Proxy-Authorization: " << credentials << CRLF
end
os << CRLF
proxy_status_line = os.gets(LF)
@logger.debug("CONNECT: read a Status-Line form the upstream server")
@logger.debug("CONNECT: < #{proxy_status_line}")
if %r{^HTTP/\d+\.\d+\s+200\s*} =~ proxy_status_line
while line = os.gets(LF)
break if /\A(#{CRLF}|#{LF})\z/om =~ line
end
else
raise HTTPStatus::BadGateway
end
end
@logger.debug("CONNECT #{host}:#{port}: succeeded")
res.status = HTTPStatus::RC_OK
rescue => ex
@logger.debug("CONNECT #{host}:#{port}: failed `#{ex.message}'")
res.set_error(ex)
raise HTTPStatus::EOFError
ensure
if handler = @config[:ProxyContentHandler]
handler.call(req, res)
end
res.send_response(ua)
access_log(@config, req, res)
# Should clear request-line not to send the sesponse twice.
# see: HTTPServer#run
req.parse(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 => ex
os.close
@logger.debug("CONNECT #{host}:#{port}: closed")
end
raise HTTPStatus::EOFError
end
# File webrick/httpproxy.rb, line 182
def do_GET(req, res)
perform_proxy_request(req, res) do |http, path, header|
http.get(path, header)
end
end
# File webrick/httpproxy.rb, line 188
def do_HEAD(req, res)
perform_proxy_request(req, res) do |http, path, header|
http.head(path, header)
end
end
# File webrick/httpproxy.rb, line 200
def do_OPTIONS(req, res)
res['allow'] = "GET,HEAD,POST,OPTIONS,CONNECT"
end
# File webrick/httpproxy.rb, line 194
def do_POST(req, res)
perform_proxy_request(req, res) do |http, path, header|
http.post(path, req.body || "", header)
end
end
# File webrick/httpproxy.rb, line 70
def proxy_auth(req, res)
if proc = @config[:ProxyAuthProc]
proc.call(req, res)
end
req.header.delete("proxy-authorization")
end
# File webrick/httpproxy.rb, line 82
def proxy_service(req, res)
# Proxy Authentication
proxy_auth(req, res)
begin
self.send("do_#{req.request_method}", req, res)
rescue NoMethodError
raise HTTPStatus::MethodNotAllowed,
"unsupported method `#{req.request_method}'."
rescue => err
logger.debug("#{err.class}: #{err.message}")
raise HTTPStatus::ServiceUnavailable, err.message
end
# Process contents
if handler = @config[:ProxyContentHandler]
handler.call(req, res)
end
end