[ruby/open-uri] Added SimpleHTTPProxyServer by TCPServer

https://github.com/ruby/open-uri/commit/ad47529306
This commit is contained in:
Hiroshi SHIBATA 2024-07-04 17:42:35 +09:00 коммит произвёл git
Родитель a574e290c5
Коммит debcf108fa
2 изменённых файлов: 95 добавлений и 55 удалений

Просмотреть файл

@ -2,21 +2,10 @@
require 'test/unit'
require 'open-uri'
require_relative 'utils'
require 'webrick'
require 'webrick/httpproxy'
begin
require 'zlib'
rescue LoadError
end
class TestOpenURIProxy < Test::Unit::TestCase
include TestOpenURIUtils
NullLog = Object.new
def NullLog.<<(arg)
#puts arg if / INFO / !~ arg
end
def with_env(h)
begin
old = {}
@ -41,18 +30,12 @@ class TestOpenURIProxy < Test::Unit::TestCase
def test_proxy
with_http {|srv, url|
proxy_log = StringIO.new(''.dup)
proxy_logger = WEBrick::Log.new(proxy_log, WEBrick::BasicLog::WARN)
proxy_auth_log = ''.dup
proxy = WEBrick::HTTPProxyServer.new({
:ServerType => Thread,
:Logger => proxy_logger,
:AccessLog => [[NullLog, ""]],
:ProxyAuthProc => lambda {|req, res|
proxy_host = '127.0.0.1'
proxy = SimpleHTTPProxyServer.new(proxy_host, 0, lambda {|req, res|
proxy_auth_log << req.request_line
},
:BindAddress => '127.0.0.1',
:Port => 0})
_, proxy_port, _, proxy_host = proxy.listeners[0].addr
}, proxy_log)
proxy_port = proxy.instance_variable_get(:@server).addr[1]
proxy_url = "http://#{proxy_host}:#{proxy_port}/"
begin
proxy_thread = proxy.start
@ -95,21 +78,15 @@ class TestOpenURIProxy < Test::Unit::TestCase
def test_proxy_http_basic_authentication_failure
with_http {|srv, url|
proxy_log = StringIO.new(''.dup)
proxy_logger = WEBrick::Log.new(proxy_log, WEBrick::BasicLog::WARN)
proxy_auth_log = ''.dup
proxy = WEBrick::HTTPProxyServer.new({
:ServerType => Thread,
:Logger => proxy_logger,
:AccessLog => [[NullLog, ""]],
:ProxyAuthProc => lambda {|req, res|
proxy_host = '127.0.0.1'
proxy = SimpleHTTPProxyServer.new(proxy_host, 0, lambda {|req, res|
proxy_auth_log << req.request_line
if req["Proxy-Authorization"] != "Basic #{['user:pass'].pack('m').chomp}"
raise WEBrick::HTTPStatus::ProxyAuthenticationRequired
raise ProxyAuthenticationRequired
end
},
:BindAddress => '127.0.0.1',
:Port => 0})
_, proxy_port, _, proxy_host = proxy.listeners[0].addr
}, proxy_log)
proxy_port = proxy.instance_variable_get(:@server).addr[1]
proxy_url = "http://#{proxy_host}:#{proxy_port}/"
begin
th = proxy.start
@ -121,28 +98,22 @@ class TestOpenURIProxy < Test::Unit::TestCase
proxy.shutdown
th.join
end
assert_match(/ERROR WEBrick::HTTPStatus::ProxyAuthenticationRequired/, proxy_log.string)
assert_match(/ERROR ProxyAuthenticationRequired/, proxy_log.string)
}
end
def test_proxy_http_basic_authentication_success
with_http {|srv, url|
proxy_log = StringIO.new(''.dup)
proxy_logger = WEBrick::Log.new(proxy_log, WEBrick::BasicLog::WARN)
proxy_auth_log = ''.dup
proxy = WEBrick::HTTPProxyServer.new({
:ServerType => Thread,
:Logger => proxy_logger,
:AccessLog => [[NullLog, ""]],
:ProxyAuthProc => lambda {|req, res|
proxy_host = '127.0.0.1'
proxy = SimpleHTTPProxyServer.new(proxy_host, 0, lambda {|req, res|
proxy_auth_log << req.request_line
if req["Proxy-Authorization"] != "Basic #{['user:pass'].pack('m').chomp}"
raise WEBrick::HTTPStatus::ProxyAuthenticationRequired
raise ProxyAuthenticationRequired
end
},
:BindAddress => '127.0.0.1',
:Port => 0})
_, proxy_port, _, proxy_host = proxy.listeners[0].addr
}, proxy_log)
proxy_port = proxy.instance_variable_get(:@server).addr[1]
proxy_url = "http://#{proxy_host}:#{proxy_port}/"
begin
th = proxy.start
@ -169,21 +140,15 @@ class TestOpenURIProxy < Test::Unit::TestCase
def test_authenticated_proxy_http_basic_authentication_success
with_http {|srv, url|
proxy_log = StringIO.new(''.dup)
proxy_logger = WEBrick::Log.new(proxy_log, WEBrick::BasicLog::WARN)
proxy_auth_log = ''.dup
proxy = WEBrick::HTTPProxyServer.new({
:ServerType => Thread,
:Logger => proxy_logger,
:AccessLog => [[NullLog, ""]],
:ProxyAuthProc => lambda {|req, res|
proxy_host = '127.0.0.1'
proxy = SimpleHTTPProxyServer.new(proxy_host, 0, lambda {|req, res|
proxy_auth_log << req.request_line
if req["Proxy-Authorization"] != "Basic #{['user:pass'].pack('m').chomp}"
raise WEBrick::HTTPStatus::ProxyAuthenticationRequired
raise ProxyAuthenticationRequired
end
},
:BindAddress => '127.0.0.1',
:Port => 0})
_, proxy_port, _, proxy_host = proxy.listeners[0].addr
}, proxy_log)
proxy_port = proxy.instance_variable_get(:@server).addr[1]
proxy_url = "http://user:pass@#{proxy_host}:#{proxy_port}/"
begin
th = proxy.start

Просмотреть файл

@ -148,8 +148,83 @@ class SimpleHTTPServer
end
end
class SimpleHTTPProxyServer
def initialize(host, port, auth_proc = nil, log)
@server = TCPServer.new(host, port)
@auth_proc = auth_proc
@log = log
end
def start
@thread = Thread.new do
loop do
client = @server.accept
request_line = client.gets
headers = {}
while (line = client.gets) && (line != "\r\n")
key, value = line.chomp.split(/:\s*/, 2)
headers[key] = value
end
next unless request_line
method, path, _ = request_line.split(' ')
handle_request(client, method, path, request_line, headers)
end
end
end
def shutdown
@thread.kill
@server.close
end
private
def handle_request(client, method, path, request_line, headers)
if @auth_proc
req = Request.new(method, path, request_line, headers)
res = Struct.new(:body, :status).new("", 200)
@auth_proc.call(req, res)
if res.status != 200
client.print "HTTP/1.1 #{res.status}\r\nContent-Type: text/plain\r\n\r\n#{res.body}"
return
end
end
uri = URI(path)
proxy_request(uri, client)
rescue TestOpenURIProxy::ProxyAuthenticationRequired
@log << "ERROR ProxyAuthenticationRequired"
client.print "HTTP/1.1 407 Proxy Authentication Required\r\nContent-Length: 0\r\n\r\n"
ensure
client.close
end
def proxy_request(uri, client)
Net::HTTP.start(uri.host, uri.port) do |http|
response = http.get(uri.path)
client.print "HTTP/1.1 #{response.code}\r\nContent-Type: #{response.content_type}\r\n\r\n#{response.body}"
end
end
class Request
attr_reader :method, :path, :request_line, :headers
def initialize(method, path, request_line, headers)
@method = method
@path = path
@request_line = request_line
@headers = headers
end
def [](key)
@headers[key]
end
end
end
module TestOpenURIUtils
class Unauthorized < StandardError; end
class ProxyAuthenticationRequired < StandardError; end
def with_http(log_tester=lambda {|log| assert_equal([], log) })
log = []