about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--lib/unicorn/configurator.rb14
-rw-r--r--lib/unicorn/socket_helper.rb14
-rw-r--r--test/unit/test_configurator.rb8
3 files changed, 29 insertions, 7 deletions
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index 9aa84f1..8913928 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -473,10 +473,10 @@ class Unicorn::Configurator
       File.expand_path(address)
     when %r{\A(?:\*:)?(\d+)\z}
       "0.0.0.0:#$1"
-    when %r{\A(.*):(\d+)\z}
-      # canonicalize the name
-      packed = Socket.pack_sockaddr_in($2.to_i, $1)
-      Socket.unpack_sockaddr_in(packed).reverse!.join(':')
+    when %r{\A\[([a-fA-F0-9:]+)\]\z}, %r/\A((?:\d+\.){3}\d+)\z/
+      canonicalize_tcp($1, 80)
+    when %r{\A\[([a-fA-F0-9:]+)\]:(\d+)\z}, %r{\A(.*):(\d+)\z}
+      canonicalize_tcp($1, $2.to_i)
     else
       address
     end
@@ -489,6 +489,12 @@ private
     set[var] = n
   end
 
+  def canonicalize_tcp(addr, port)
+    packed = Socket.pack_sockaddr_in(port, addr)
+    port, addr = Socket.unpack_sockaddr_in(packed)
+    /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
+  end
+
   def set_path(var, path) #:nodoc:
     case path
     when NilClass, String
diff --git a/lib/unicorn/socket_helper.rb b/lib/unicorn/socket_helper.rb
index 0cab3cb..e5b0735 100644
--- a/lib/unicorn/socket_helper.rb
+++ b/lib/unicorn/socket_helper.rb
@@ -136,7 +136,9 @@ module Unicorn
         ensure
           File.umask(old_umask)
         end
-      elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/
+      elsif /\A(\d+\.\d+\.\d+\.\d+):(\d+)\z/ =~ address ||
+            /\A\[([a-fA-F0-9:]+)\]:(\d+)\z/ =~ address
+        p [ $1, $2 ]
         Kgio::TCPServer.new($1, $2.to_i)
       else
         raise ArgumentError, "Don't know how to bind: #{address}"
@@ -145,6 +147,12 @@ module Unicorn
       sock
     end
 
+    # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
+    def tcp_name(sock)
+      port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
+      /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
+    end
+
     # Returns the configuration name of a socket as a string.  sock may
     # be a string value, in which case it is returned as-is
     # Warning: TCP sockets may not always return the name given to it.
@@ -154,10 +162,10 @@ module Unicorn
       when UNIXServer
         Socket.unpack_sockaddr_un(sock.getsockname)
       when TCPServer
-        Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':')
+        tcp_name(sock)
       when Socket
         begin
-          Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':')
+          tcp_name(sock)
         rescue ArgumentError
           Socket.unpack_sockaddr_un(sock.getsockname)
         end
diff --git a/test/unit/test_configurator.rb b/test/unit/test_configurator.rb
index ac1efa8..c19c427 100644
--- a/test/unit/test_configurator.rb
+++ b/test/unit/test_configurator.rb
@@ -33,6 +33,14 @@ class TestConfigurator < Test::Unit::TestCase
     assert_equal "0.0.0.0:2007", meth.call('2007')
     assert_equal "0.0.0.0:2007", meth.call(2007)
 
+    %w([::1]:2007 [::]:2007).each do |addr|
+      assert_equal addr, meth.call(addr.dup)
+    end
+
+    # for Rainbows! users only
+    assert_equal "[::]:80", meth.call("[::]")
+    assert_equal "127.6.6.6:80", meth.call("127.6.6.6")
+
     # the next two aren't portable, consider them unsupported for now
     # assert_match %r{\A\d+\.\d+\.\d+\.\d+:2007\z}, meth.call('1:2007')
     # assert_match %r{\A\d+\.\d+\.\d+\.\d+:2007\z}, meth.call('2:2007')