Index: [Article Count Order] [Thread]

Date: Fri, 19 Mar 2004 17:36:00 +0900 (JST)
From: GOTOU Yuuzou <gotoyuzo@notwork.org>
Subject: [webrickja:114] Re: ServerAlias
To: webrickja@notwork.org
Message-Id: <20040319.173600.521621012.gotoyuzo@sawara.does.notwork.org>
In-Reply-To: <20040128.180721.607957648.gotoyuzo@sawara.does.notwork.org>
References: <20040128153311FTWK%y@hoppeta.com>	<20040128.180721.607957648.gotoyuzo@sawara.does.notwork.org>
X-Mail-Count: 00114

In message <20040128.180721.607957648.gotoyuzo@sawara.does.notwork.org>,
 `GOTOU Yuuzou <gotoyuzo@notwork.org>' wrote:
> In message <20040128153311FTWK%y@hoppeta.com>,
>  `"Kawaji, Shinya" <kawaji@hoppeta.com>' wrote:
> > 以下の patch は簡便のために ServerAlias は String か Regexp ということに
> > していますので、Apache の場合とは違います(Array も使えない)。
> 
> かならずArrayということでいいんじゃないでしょうか。
> 
>  (server[:ServerAlias].nil? || server[:ServerAlias].find{|h| h === req.host })
> 
> とか。StringもEnumerableなので偶然動きますけど。

10日ほど前に1.9に追加したのですが、:ServerAliasがnilの時に一
致させるのはよくなかったようなので、次のような修正を考えてみ
ました。

diff -u -p -F^[^A-Za-z0-9_+-]*\(class\|module\|def\)[^A-Za-z0-9_+-] -2 -r1.7 httpserver.rb
--- lib/webrick/httpserver.rb	7 Mar 2004 16:06:42 -0000	1.7
+++ lib/webrick/httpserver.rb	19 Mar 2004 08:26:56 -0000
@@ -136,10 +136,16 @@     def virtual_host(server)
 
     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)
+      end
+      return servers[0]
     end

で、ついでによく考えてみると(エイリアスとは関係ないのですが)、

  * :BindAddressの指定ありで:Portはnil
  * :BindAddressはnilで:Portの指定あり

というホストが同時に存在する場合に、どちらに一致するか曖昧な
なんですね。現状ではvirtual_hostで先に追加したほうに一致する
のですが、どちらかを優先するべきなんでしょうか。

# 簡単にテストを書いてみたので付けておきます。

-- 
ごとうゆうぞう

require "test/unit"
require "webrick"

module WEBrick

class TestHTTPServer < Test::Unit::TestCase
  def assert_eql?(v1, v2)
    assert_equal(v1.object_id, v2.object_id)
  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.each_index{|i|
      j = rand(ary.length)
      ary[i], ary[j] = ary[j], ary[i]
    }
  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),
    ]
   #shuffle(hosts)
   #p hosts.collect{|h| h.object_id }
    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