This is an automated email from the ASF dual-hosted git repository.

tokers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new cd3a80c  feat: parse_addr supports IPv6 without brackets (#4784)
cd3a80c is described below

commit cd3a80c29567e3a5711283908544690e46eeab2f
Author: 罗泽轩 <[email protected]>
AuthorDate: Wed Aug 11 19:18:02 2021 +0800

    feat: parse_addr supports IPv6 without brackets (#4784)
    
    Signed-off-by: spacewander <[email protected]>
---
 apisix/core/utils.lua | 54 ++++++++++++++++++++++++++++++++++++++++-----------
 t/core/utils.t        |  3 +++
 2 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/apisix/core/utils.lua b/apisix/core/utils.lua
index 7fb1493..5f22852 100644
--- a/apisix/core/utils.lua
+++ b/apisix/core/utils.lua
@@ -136,13 +136,31 @@ local function rfind_char(s, ch, idx)
 end
 
 
+local function _parse_ipv4_or_host(addr)
+    local pos = rfind_char(addr, ":", #addr - 1)
+    if not pos then
+        return addr, nil
+    end
+
+    local host = sub_str(addr, 1, pos - 1)
+    local port = sub_str(addr, pos + 1)
+    return host, tonumber(port)
+end
+
+
+local function _parse_ipv6_without_port(addr)
+    return addr
+end
+
+
 -- parse_addr parses 'addr' into the host and the port parts. If the 'addr'
--- doesn't have a port, nil is used to return. For malformed 'addr', the entire
--- 'addr' is returned as the host part. For IPv6 literal host, like [::1],
--- the square brackets will be kept.
+-- doesn't have a port, nil is used to return.
+-- For IPv6 literal host with brackets, like [::1], the square brackets will 
be kept.
+-- For malformed 'addr', the returned value can be anything. This method 
doesn't validate
+-- if the input is valid.
 function _M.parse_addr(addr)
     if str_byte(addr, 1) == str_byte("[") then
-        -- IPv6 format
+        -- IPv6 format, with brackets, maybe with port
         local right_bracket = str_byte("]")
         local len = #addr
         if str_byte(addr, len) == right_bracket then
@@ -162,15 +180,29 @@ function _M.parse_addr(addr)
         end
 
     else
-        -- IPv4 format
-        local pos = rfind_char(addr, ":", #addr - 1)
-        if not pos then
-            return addr, nil
+        -- When we reach here, the input can be:
+        -- 1. IPv4
+        -- 2. IPv4, with port
+        -- 3. IPv6, like "2001:db8::68" or "::ffff:192.0.2.1"
+        -- 4. Malformed input
+        -- 5. Host, like "test.com" or "localhost"
+        -- 6. Host with port
+        local colon = str_byte(":")
+        local colon_counter = 0
+        local dot = str_byte(".")
+        for i = 1, #addr do
+            local ch = str_byte(addr, i, i)
+            if ch == dot then
+                return _parse_ipv4_or_host(addr)
+            elseif ch == colon then
+                colon_counter = colon_counter + 1
+                if colon_counter == 2 then
+                    return _parse_ipv6_without_port(addr)
+                end
+            end
         end
 
-        local host = sub_str(addr, 1, pos - 1)
-        local port = sub_str(addr, pos + 1)
-        return host, tonumber(port)
+        return _parse_ipv4_or_host(addr)
     end
 end
 
diff --git a/t/core/utils.t b/t/core/utils.t
index 481a704..9b40610 100644
--- a/t/core/utils.t
+++ b/t/core/utils.t
@@ -52,10 +52,13 @@ qr/random seed \d+(\.\d+)?(e\+\d+)?\ntwice: false/
                 {addr = "127.0.0.1:90", host = "127.0.0.1", port = 90},
                 {addr = "www.test.com", host = "www.test.com"},
                 {addr = "www.test.com:90", host = "www.test.com", port = 90},
+                {addr = "localhost", host = "localhost"},
+                {addr = "localhost:90", host = "localhost", port = 90},
                 {addr = "[127.0.0.1:90", host = "[127.0.0.1:90"},
                 {addr = "[::1]", host = "[::1]"},
                 {addr = "[::1]:1234", host = "[::1]", port = 1234},
                 {addr = "[::1234:1234]:12345", host = "[::1234:1234]", port = 
12345},
+                {addr = "::1", host = "::1"},
             }
             for _, case in ipairs(cases) do
                 local host, port = parse_addr(case.addr)

Reply via email to