@ledsun blog

無味の味は佳境に入らざればすなわち知れず

自作WebSocktライブラリーのテストがGitHub Actionsでだけ失敗する

失敗しているGitHub Actionsです。 https://github.com/ledsun/wands/actions/runs/12547524257/job/34985157639#step:4:48

次のようなエラーが起きています。

/opt/hostedtoolcache/Ruby/3.4.1/x64/lib/ruby/3.4.0/uri/generic.rb:601:in 'URI::Generic#check_host': bad component(expected host component): ::1 (URI::InvalidComponentError)
    from /opt/hostedtoolcache/Ruby/3.4.1/x64/lib/ruby/3.4.0/uri/generic.rb:640:in 'URI::Generic#host='
    from /home/runner/work/wands/wands/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.1/lib/webrick/httprequest.rb:520:in 'WEBrick::HTTPRequest#parse_uri'
    from /home/runner/work/wands/wands/vendor/bundle/ruby/3.4.0/gems/webrick-1.9.1/lib/webrick/httprequest.rb:218:in 'WEBrick::HTTPRequest#parse'
    from /home/runner/work/wands/wands/lib/wands/web_socket_server.rb:72:in 'Wands::WebSocketServer#read_headers_from'
    from /home/runner/work/wands/wands/lib/wands/web_socket_server.rb:52:in 'Wands::WebSocketServer#accept'
    from /home/runner/work/wands/wands/test/test_wands.rb:15:in 'block (2 levels) in TestWands#test_open_connection'
    from /home/runner/work/wands/wands/vendor/bundle/ruby/3.4.0/gems/async-2.21.1/lib/async/task.rb:197:in 'block in Async::Task#run'
    from /home/runner/work/wands/wands/vendor/bundle/ruby/3.4.0/gems/async-2.21.1/lib/async/task.rb:435:in 'block in Async::Task#schedule'

こんな感じのコードが実行されているようです。

irb(main):007> uri = URI.parse('/')
=> #<URI::Generic />
irb(main):008> uri.host = '::1'

WEBRickソースコードでは https://github.com/ruby/webrick/blob/v1.9.1/lib/webrick/httprequest.rb#L512-L520 です。

      elsif self["host"]
        host, port = parse_host_request_line(self["host"])
      elsif @addr.size > 0
        host, port = @addr[2], @addr[1]
      else
        host, port = @config[:ServerName], @config[:Port]
      end
      uri.scheme = @forwarded_proto || scheme
      uri.host = host

HOSTヘッダーがなかったのでIPアドレスを取得しているようです。 こんな感じの動作だと思います。

irb(main):019> socket = TCPServer.new(11111)
=> #<TCPServer:fd 5, AF_INET, 0.0.0.0, 11111>
irb(main):020> socket.addr[2]
=> "0.0.0.0"

ローカル環境でテストを実行すると、IPv6アドレスの::1がとれて居るみたいです。 IPv6アドレスの時はuri.host = '[::1]'のようにアドレスを[]で囲ってあげる必要があります。

HTTPリクエストでHOSTヘッダーを設定すれば、このテストは通るようになりそうです。

しかし、他のIPv6環境でWEBrickを動かしても起きそうな気がします。 こんなイメージです。

irb(main):023> socket = TCPServer.new('::1', 11111)
=> #<TCPServer:fd 8, AF_INET6, ::1, 11111>
irb(main):025> uri.host = socket.addr[2]
/home/ledsun/.rbenv/versions/3.4.1/lib/ruby/3.4.0/uri/generic.rb:601:in 'URI::Generic#check_host': bad component(expected host component): ::1 (URI::InvalidComponentError)