Skip to content

Commit a279091

Browse files
committed
fix: Support IPv6 bind addresses in http_server helper
Fixes URI::InvalidURIError when binding to IPv6 addresses like '::' or '::1'. The http_server helper was generating invalid URIs such as 'http://:::24231' instead of the RFC 3986 compliant 'http://[::]:24231'. Changes: - Wrap IPv6 addresses in brackets when constructing URIs - Add unit tests for IPv6 localhost (::1) and wildcard (::) binding - Update CHANGELOG.md This bug affected all Fluentd versions including v1.19.1 and caused crashes when attempting to bind HTTP servers to IPv6 addresses in dual-stack environments. Resolves: Invalid URI generation for IPv6 bind addresses
1 parent a442416 commit a279091

3 files changed

Lines changed: 48 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# v1.19
22

3+
## Release v1.19.1 - TBD
4+
5+
### Bug fix
6+
7+
* http_server helper: Fix IPv6 bind address support in URI construction
8+
* Fixed `URI::InvalidURIError` when binding to IPv6 addresses (e.g., `::`)
9+
* IPv6 addresses are now properly bracketed in URIs per RFC 3986 (e.g., `http://[::]:24231`)
10+
* Affects all plugins using http_server helper with IPv6 bind addresses
11+
312
## Release v1.19.0 - 2025/07/30
413

514
### Enhancement

lib/fluent/plugin_helper/http_server/server.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def initialize(addr:, port:, logger:, default_app: nil, tls_context: nil)
3737

3838
# TODO: support http2
3939
scheme = tls_context ? 'https' : 'http'
40-
@uri = URI("#{scheme}://#{@addr}:#{@port}").to_s
40+
addr_display = @addr.include?(":") ? "[#{@addr}]" : @addr
41+
@uri = URI("#{scheme}://#{addr_display}:#{@port}").to_s
4142
@router = Router.new(default_app)
4243
@server_task = nil
4344
Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)

test/plugin_helper/test_http_server_helper.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ def teardown
2121
@port = nil
2222
end
2323

24+
def ipv6_enabled?
25+
begin
26+
sock = Socket.new(Socket::AF_INET6, Socket::SOCK_STREAM, 0)
27+
sock.close
28+
true
29+
rescue
30+
false
31+
end
32+
end
33+
2434
class Dummy < Fluent::Plugin::TestBase
2535
helpers :http_server
2636
end
@@ -364,6 +374,33 @@ def start_https_request(addr, port, verify: true, cert_path: nil, selfsigned: tr
364374
end
365375
end
366376

377+
test 'bind to IPv6 address' do
378+
omit('IPv6 not supported') unless ipv6_enabled?
379+
on_driver do |driver|
380+
driver.http_server_create_http_server(:http_server_helper_test, addr: '::1', port: @port, logger: NULL_LOGGER) do |s|
381+
s.get('/example/hello') { [200, { 'Content-Type' => 'text/plain' }, 'hello from ipv6'] }
382+
end
383+
384+
resp = get("http://[::1]:#{@port}/example/hello")
385+
assert_equal('200', resp.code)
386+
assert_equal('hello from ipv6', resp.body)
387+
end
388+
end
389+
390+
test 'bind to IPv6 wildcard address' do
391+
omit('IPv6 not supported') unless ipv6_enabled?
392+
on_driver do |driver|
393+
driver.http_server_create_http_server(:http_server_helper_test, addr: '::', port: @port, logger: NULL_LOGGER) do |s|
394+
s.get('/example/hello') { [200, { 'Content-Type' => 'text/plain' }, 'hello from ipv6 wildcard'] }
395+
end
396+
397+
# Can access via IPv4-mapped IPv6 or IPv6 loopback
398+
resp = get("http://[::1]:#{@port}/example/hello")
399+
assert_equal('200', resp.code)
400+
assert_equal('hello from ipv6 wildcard', resp.body)
401+
end
402+
end
403+
367404
test 'must be called #start and #stop' do
368405
on_driver do |driver|
369406
server = flexmock('Server') do |watcher|

0 commit comments

Comments
 (0)