ruby-changes:3475
From: ko1@a...
Date: 9 Jan 2008 20:37:27 +0900
Subject: [ruby-changes:3475] gotoyuzo - Ruby:r14968 (trunk): * lib/webrick/httprequest.rb: supprt X-Forwarded-* header fields.
gotoyuzo 2008-01-09 20:37:03 +0900 (Wed, 09 Jan 2008) New Revision: 14968 Modified files: trunk/ChangeLog trunk/lib/webrick/httprequest.rb trunk/test/webrick/test_httprequest.rb Log: * lib/webrick/httprequest.rb: supprt X-Forwarded-* header fields. WEBrick::HTTPRequest#{host,port,request_uri} is derived having regards to X-Forwarded-Proto and X-Forwarded-Host. * lib/webrick/httprequest.rb (WEBrick::HTTPRequest#server_name?): new method. (WEBrick::HTTPRequest#remote_ip?): new method. (WEBrick::HTTPRequest#ssl?): new method. * string.c (rb_enc_cr_str_buf_cat): fix self appending. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/webrick/httprequest.rb?r1=14968&r2=14967&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14968&r2=14967&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/webrick/test_httprequest.rb?r1=14968&r2=14967&diff_format=u Index: ChangeLog =================================================================== --- ChangeLog (revision 14967) +++ ChangeLog (revision 14968) @@ -1,3 +1,14 @@ +Wed Jan 9 20:35:42 2008 GOTOU Yuuzou <gotoyuzo@n...> + + * lib/webrick/httprequest.rb: supprt X-Forwarded-* header fields. + WEBrick::HTTPRequest#{host,port,request_uri} is derived having + regards to X-Forwarded-Proto and X-Forwarded-Host. + + * lib/webrick/httprequest.rb + (WEBrick::HTTPRequest#server_name?): new method. + (WEBrick::HTTPRequest#remote_ip?): new method. + (WEBrick::HTTPRequest#ssl?): new method. + Wed Jan 9 18:24:39 2008 WATANABE Hirofumi <eban@r...> * golf_prelude.rb (Array#to_s): alias to join. Index: lib/webrick/httprequest.rb =================================================================== --- lib/webrick/httprequest.rb (revision 14967) +++ lib/webrick/httprequest.rb (revision 14968) @@ -69,6 +69,9 @@ @remaining_size = nil @socket = nil + + @forwarded_proto = @forwarded_host = @forwarded_port = + @forwarded_server = @forwarded_for = nil end def parse(socket=nil) @@ -95,6 +98,7 @@ return if @unparsed_uri == "*" begin + setup_forwarded_info @request_uri = parse_uri(@unparsed_uri) @path = HTTPUtils::unescape(@request_uri.path) @path = HTTPUtils::normalize_path(@path) @@ -153,6 +157,26 @@ } end + def host + return @forwarded_host || @host + end + + def port + return @forwarded_port || @port + end + + def server_name + return @forwarded_server || @config[:ServerName] + end + + def remote_ip + return self["client-ip"] || @forwarded_for || @peeraddr[3] + end + + def ssl? + return @request_uri.scheme == "https" + end + def keep_alive? @keep_alive end @@ -255,7 +279,9 @@ end uri = URI::parse(str) return uri if uri.absolute? - if self["host"] + if @forwarded_host + host, port = @forwarded_host, @forwarded_port + elsif self["host"] pattern = /\A(#{URI::REGEXP::PATTERN::HOST})(?::(\d+))?\z/n host, port = *self['host'].scan(pattern)[0] elsif @addr.size > 0 @@ -263,7 +289,7 @@ else host, port = @config[:ServerName], @config[:Port] end - uri.scheme = scheme + uri.scheme = @forwarded_proto || scheme uri.host = host uri.port = port ? port.to_i : nil return URI::parse(uri.to_s) @@ -356,5 +382,25 @@ raise HTTPStatus::BadRequest, ex.message end end + + PrivateNetworkRegexp = / + ^unknown$| + ^((::ffff:)?127.0.0.1|::1)$| + ^(::ffff:)?(10|172\.(1[6-9]|2[0-9]|3[01])|192\.168)\. + /ixo + + def setup_forwarded_info + @forwarded_server = self["x-forwarded-server"] + @forwarded_proto = self["x-forwarded-proto"] + if host_port = self["x-forwarded-host"] + @forwarded_host, tmp = host_port.split(":", 2) + @forwarded_port = (tmp || (@forwarded_proto == "https" ? 443 : 80)).to_i + end + if addrs = self["x-forwarded-for"] + addrs = addrs.split(",").collect(&:strip) + addrs.reject!{|ip| PrivateNetworkRegexp =~ ip } + @forwarded_for = addrs.first + end + end end end Index: test/webrick/test_httprequest.rb =================================================================== --- test/webrick/test_httprequest.rb (revision 14967) +++ test/webrick/test_httprequest.rb (revision 14968) @@ -79,6 +79,7 @@ Accept-Language: ja Content-Type: text/plain Content-Length: 7 + X-Empty-Header: foobar _end_of_message_ @@ -97,6 +98,8 @@ assert_equal(7, req.content_length) assert_equal("text/plain", req.content_type) assert_equal("foobar\n", req.body) + assert_equal("", req["x-empty-header"]) + assert_equal(nil, req["x-no-header"]) assert(req.query.empty?) end @@ -238,6 +241,70 @@ assert_equal(File.read(__FILE__), req.body) end + def test_forwarded + msg = <<-_end_of_message_ + GET /foo HTTP/1.1 + Host: localhost:10080 + User-Agent: w3m/0.5.2 + X-Forwarded-For: 123.123.123.123 + X-Forwarded-Host: forward.example.com + X-Forwarded-Server: server.example.com + Connection: Keep-Alive + + _end_of_message_ + msg.gsub!(/^ {6}/, "") + req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) + req.parse(StringIO.new(msg)) + assert_equal("server.example.com", req.server_name) + assert_equal("http://forward.example.com/foo", req.request_uri.to_s) + assert_equal("forward.example.com", req.host) + assert_equal(80, req.port) + assert_equal("123.123.123.123", req.remote_ip) + assert(!req.ssl?) + + msg = <<-_end_of_message_ + GET /foo HTTP/1.1 + Host: localhost:10080 + User-Agent: w3m/0.5.2 + X-Forwarded-For: 192.168.1.10, 172.16.1.1, 123.123.123.123 + X-Forwarded-Host: forward.example.com:8080 + X-Forwarded-Server: server.example.com + Connection: Keep-Alive + + _end_of_message_ + msg.gsub!(/^ {6}/, "") + req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) + req.parse(StringIO.new(msg)) + assert_equal("server.example.com", req.server_name) + assert_equal("http://forward.example.com:8080/foo", req.request_uri.to_s) + assert_equal("forward.example.com", req.host) + assert_equal(8080, req.port) + assert_equal("123.123.123.123", req.remote_ip) + assert(!req.ssl?) + + msg = <<-_end_of_message_ + GET /foo HTTP/1.1 + Host: localhost:10080 + Client-IP: 234.234.234.234 + X-Forwarded-Proto: https + X-Forwarded-For: 192.168.1.10, 10.0.0.1, 123.123.123.123 + X-Forwarded-Host: forward.example.com + X-Forwarded-Server: server.example.com + X-Requested-With: XMLHttpRequest + Connection: Keep-Alive + + _end_of_message_ + msg.gsub!(/^ {6}/, "") + req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) + req.parse(StringIO.new(msg)) + assert_equal("server.example.com", req.server_name) + assert_equal("https://forward.example.com/foo", req.request_uri.to_s) + assert_equal("forward.example.com", req.host) + assert_equal(443, req.port) + assert_equal("234.234.234.234", req.remote_ip) + assert(req.ssl?) + end + def test_bad_messages param = "foo=1;foo=2;foo=3;bar=x" msg = <<-_end_of_message_ -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml