かわじ、です。
> 10日ほど前に1.9に追加したのですが、:ServerAliasがnilの時に一
> 致させるのはよくなかったようなので、次のような修正を考えてみ
> ました。
これはもともとの私のパッチが間違っていたものでした。
ご迷惑をおかけしました。
> で、ついでによく考えてみると(エイリアスとは関係ないのですが)、
>
> * :BindAddressの指定ありで:Portはnil
> * :BindAddressはnilで:Portの指定あり
>
> というホストが同時に存在する場合に、どちらに一致するか曖昧な
> なんですね。現状ではvirtual_hostで先に追加したほうに一致する
> のですが、どちらかを優先するべきなんでしょうか。
喩えに出していいのか分かりませんが、 Apache の場合ですと、
先にIPアドレスの一致を調べてから、ポートの一致を調べるようですので、
以下のような感じになるかと思います。
# 優先順位の付け方が、もっと良い方法があると思いますが、
# とりあえず思いついた方法にしておきます。
もしもこのようにするのでしたら、warn は必要ないと思います。
でも、まあ、 virtual_host の順位でも良いような気もしますが。
Index: lib/webrick/httpserver.rb
===================================================================
RCS file: /src/ruby/lib/webrick/httpserver.rb,v
retrieving revision 1.7
diff -u -r1.7 httpserver.rb
--- lib/webrick/httpserver.rb 7 Mar 2004 16:06:42 -0000 1.7
+++ lib/webrick/httpserver.rb 20 Mar 2004 20:25:15 -0000
@@ -135,12 +135,32 @@
end
def lookup_server(req)
- @virtual_hosts.find{|s|
+ servers = @virtual_hosts.select{|s|
(s[:Port].nil? || req.port == s[:Port]) &&
(s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) &&
((s[:ServerName].nil? || req.host == s[:ServerName]) ||
- (s[:ServerAlias].nil? || s[:ServerAlias].find{|h| h === req.host}))
+ (!s[:ServerAlias].nil? && s[:ServerAlias].find{|h| h === req.host}))
}
+ if (len = servers.length) > 1
+ args = [len, req.host, req.addr[3], req.port]
+ msg = "ambiguous virtual hosts (matches %d hosts for %s@%s:%d)" % args
+ @logger.warn(msg)
+ servers.sort_by{|s|
+ num = 0
+ if !s[:BindAddress].nil? and s[:BindAddress] == req.addr[3]
+ num += 4
+ end
+ if !s[:Port].nil? and s[:Port] == req.port
+ num += 2
+ end
+ if !s[:ServerName].nil? and s[:ServerName] == req.host
+ num += 1
+ end
+ num
+ }.last
+ else
+ return servers.first
+ end
end
def access_log(config, req, res)
> # 簡単にテストを書いてみたので付けておきます。
デバック用に、Failure になったときにどのサーバーの一致を試したときのものか、
分かるようにしてみました(ちょっと適当にやった感じですが)。
あと、shuffle を復活させて、念のため 10回 shuffle するようにしました。
(1回だけの shuffle ですと、たまたま通ってしまうこともあるようでしたので)
両方とも、不要な改造かもしれません。
require "test/unit"
require "webrick"
module WEBrick
class TestHTTPServer < Test::Unit::TestCase
TEST_TIMES = 10
def obj_id(obj)
if obj.nil?
nil
else
[
obj.object_id,
obj.config[:BindAddress].inspect,
obj.config[:Port].inspect,
obj.config[:ServerName].inspect,
obj.config[:ServerAlias].inspect,
].join(',')
end
end
def assert_eql?(v1, v2)
assert_equal(obj_id(v1), obj_id(v2))
end
NullWriter = Object.new
def NullWriter.write(msg) return msg.size end
def NullWriter.<<(msg) return self end
def httpd(addr, port, host, ali)
hash = {:DoNotListen => true}
hash[:BindAddress] = addr
hash[:Port] = port
hash[:ServerName] = host
hash[:ServerAlias] = ali
WEBrick::HTTPServer.new(hash)
end
def shuffle(ary)
ary.replace(ary.sort_by{ rand })
end
class Req
attr_reader :port, :host
def initialize(addr, port, host)
@addr, @port, @host = addr, port, host
end
def addr
[0,0,0,@addr]
end
end
def test_lookup_server
addr1 = "192.168.100.1"
addr2 = "192.168.100.2"
addrz = "192.168.100.254"
local = "127.0.0.1"
port1 = 80
port2 = 8080
port3 = 10080
portz = 32767
name1 = "www.example.com"
name2 = "www2.example.com"
name3 = "www3.example.com"
namea = "www.example.co.jp"
nameb = "www.example.jp"
namec = "www2.example.co.jp"
named = "www2.example.jp"
namez = "foobar.example.com"
alias1 = [namea, nameb]
alias2 = [namec, named]
stderr = $stderr
$stderr = NullWriter
host1 = httpd(nil, port1, name1, nil)
hosts = [
host2 = httpd(addr1, port1, name1, nil),
host3 = httpd(addr1, port1, name2, alias1),
host4 = httpd(addr1, port2, name1, nil),
host5 = httpd(addr1, port2, name2, alias1),
host6 = httpd(addr1, port2, name3, alias2),
host7 = httpd(addr2, nil, name1, nil),
host8 = httpd(addr2, nil, name2, alias1),
host9 = httpd(addr2, nil, name3, alias2),
host10 = httpd(local, nil, nil, nil),
host11 = httpd(nil, port3, nil, nil),
]
$stderr = stderr
TEST_TIMES.times{
# p hosts.collect{|h| h.object_id }
shuffle(hosts)
# p hosts.collect{|h| h.object_id }
$stderr = NullWriter
hosts.each{|h| host1.virtual_host(h) }
$stderr = stderr
# connect to addr1
assert_eql?(host2, host1.lookup_server(Req.new(addr1, port1, name1)))
assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, name2)))
assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, namea)))
assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addr1, port1, namez)))
assert_eql?(host4, host1.lookup_server(Req.new(addr1, port2, name1)))
assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, name2)))
assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, namea)))
assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addr1, port2, namez)))
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, name1)))
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, name2)))
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, namea)))
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, nameb)))
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, namez)))
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, name1)))
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, name2)))
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, namea)))
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, namez)))
# connect to addr2
assert_eql?(host7, host1.lookup_server(Req.new(addr2, port1, name1)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, name2)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, namea)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addr2, port1, namez)))
assert_eql?(host7, host1.lookup_server(Req.new(addr2, port2, name1)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, name2)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, namea)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addr2, port2, namez)))
assert_eql?(host7, host1.lookup_server(Req.new(addr2, port3, name1))) #!
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, name2))) #!
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, namea))) #!
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, nameb))) #!
assert_eql?(host11, host1.lookup_server(Req.new(addr2, port3, namez)))
assert_eql?(host7, host1.lookup_server(Req.new(addr2, portz, name1)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, name2)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, namea)))
assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addr2, portz, namez)))
# connect to addrz
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, name1)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, name2)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, namea)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, namez)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, name1)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, name2)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, namea)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, namez)))
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, name1)))
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, name2)))
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, namea)))
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, nameb)))
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, namez)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, name1)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, name2)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, namea)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, nameb)))
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, namez)))
# connect to localhost
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, name1)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, name2)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, namea)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, nameb)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, namez)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, name1)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, name2)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, namea)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, nameb)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, namez)))
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, name1))) #!
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, name2))) #!
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, namea))) #!
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, nameb))) #!
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, namez))) #!
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, name1)))
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, name2)))
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, namea)))
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, nameb)))
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, namez)))
}
end
end
end