You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2020/09/10 08:49:26 UTC

[apisix] branch master updated: chore: add string utility for simplicity and correctness (#2181)

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

spacewander 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 37817e4  chore: add string utility for simplicity and correctness (#2181)
37817e4 is described below

commit 37817e419827889be3358bfc538aa6046becac58
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Thu Sep 10 16:49:20 2020 +0800

    chore: add string utility for simplicity and correctness (#2181)
    
    * chore: add string utility for simplicity and correctness
    
    * localize error
    
    * correct the misuse string.find
    
    Co-authored-by: YuanSheng Wang <me...@gmail.com>
---
 apisix/admin/ssl.lua                 |   3 +-
 apisix/core.lua                      |   1 +
 apisix/core/string.lua               |  68 ++++++++++++++++
 apisix/http/router/radixtree_sni.lua |   2 +-
 t/core/string.t                      | 145 +++++++++++++++++++++++++++++++++++
 5 files changed, 216 insertions(+), 3 deletions(-)

diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua
index f102f27..c86a172 100644
--- a/apisix/admin/ssl.lua
+++ b/apisix/admin/ssl.lua
@@ -18,7 +18,6 @@ local core              = require("apisix.core")
 local tostring          = tostring
 local aes               = require "resty.aes"
 local ngx_encode_base64 = ngx.encode_base64
-local str_find          = string.find
 local type              = type
 local assert            = assert
 
@@ -74,7 +73,7 @@ local function aes_encrypt(origin)
     local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and
             assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil
 
-    if aes_128_cbc_with_iv ~= nil and str_find(origin, "---") then
+    if aes_128_cbc_with_iv ~= nil and core.string.has_prefix(origin, "---") then
         local encrypted = aes_128_cbc_with_iv:encrypt(origin)
         if encrypted == nil then
             core.log.error("failed to encrypt key[", origin, "] ")
diff --git a/apisix/core.lua b/apisix/core.lua
index 2d3ca2e..da94af4 100644
--- a/apisix/core.lua
+++ b/apisix/core.lua
@@ -34,6 +34,7 @@ return {
     response = require("apisix.core.response"),
     lrucache = require("apisix.core.lrucache"),
     schema   = require("apisix.schema_def"),
+    string   = require("apisix.core.string"),
     ctx      = require("apisix.core.ctx"),
     timer    = require("apisix.core.timer"),
     id       = require("apisix.core.id"),
diff --git a/apisix/core/string.lua b/apisix/core/string.lua
new file mode 100644
index 0000000..952152a
--- /dev/null
+++ b/apisix/core/string.lua
@@ -0,0 +1,68 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local error = error
+local type = type
+local str_find = string.find
+local ffi         = require("ffi")
+local C           = ffi.C
+local ffi_cast    = ffi.cast
+
+
+ffi.cdef[[
+    int memcmp(const void *s1, const void *s2, size_t n);
+]]
+
+
+local _M = {
+    version = 0.1,
+}
+
+
+setmetatable(_M, {__index = string})
+
+
+-- find a needle from a haystack in the plain text way
+function _M.find(haystack, needle, from)
+    return str_find(haystack, needle, from or 1, true)
+end
+
+
+function _M.has_prefix(s, prefix)
+    if type(s) ~= "string" or type(prefix) ~= "string" then
+        error("unexpected type: s:" .. type(s) .. ", prefix:" .. type(prefix))
+    end
+    if #s < #prefix then
+        return false
+    end
+    local rc = C.memcmp(s, prefix, #prefix)
+    return rc == 0
+end
+
+
+function _M.has_suffix(s, suffix)
+    if type(s) ~= "string" or type(suffix) ~= "string" then
+        error("unexpected type: s:" .. type(s) .. ", suffix:" .. type(suffix))
+    end
+    if #s < #suffix then
+        return false
+    end
+    local rc = C.memcmp(ffi_cast("char *", s) + #s - #suffix, suffix, #suffix)
+    return rc == 0
+end
+
+
+return _M
diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua
index be24f52..4f54171 100644
--- a/apisix/http/router/radixtree_sni.lua
+++ b/apisix/http/router/radixtree_sni.lua
@@ -96,7 +96,7 @@ local function create_router(ssl_items)
 
             -- decrypt private key
             if aes_128_cbc_with_iv ~= nil and
-                not str_find(ssl.value.key, "---") then
+                not core.string.has_prefix(ssl.value.key, "---") then
                 local decrypted = aes_128_cbc_with_iv:decrypt(ngx_decode_base64(ssl.value.key))
                 if decrypted == nil then
                     core.log.error("decrypt ssl key failed. key[", ssl.value.key, "] ")
diff --git a/t/core/string.t b/t/core/string.t
new file mode 100644
index 0000000..0e196e1
--- /dev/null
+++ b/t/core/string.t
@@ -0,0 +1,145 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(2);
+no_long_string();
+no_root_location();
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: find
+--- config
+    location /t {
+        content_by_lua_block {
+            local encode = require "cjson".encode 
+            local str = require("apisix.core.string")
+            local cases = {
+                {"xx", "", true},
+                {"xx", "x", true},
+                {"", "x", false},
+                {"", "", true},
+                {"", 0, false},
+                {0, "x", false},
+                {"a[", "[", true},
+
+                {"[a", "[", false, 2},
+                {"[a", "[", false, 3},
+                {"[a", "[", true, 1},
+            }
+            for _, case in ipairs(cases) do
+                local ok, idx = pcall(str.find, case[1], case[2], case[4])
+                if not ok then
+                    if case[3] == true then
+                        ngx.log(ngx.ERR, "unexpected error: ", idx,
+                                " ", encode(case))
+                    end
+                else
+                    if case[3] ~= (idx ~= nil) then
+                        ngx.log(ngx.ERR, "unexpected res: ", idx,
+                                " ", encode(case))
+                    end
+                end
+            end
+        }
+    }
+--- request
+GET /t
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: prefix
+--- config
+    location /t {
+        content_by_lua_block {
+            local encode = require "cjson".encode 
+            local str = require("apisix.core.string")
+            local cases = {
+                {"xx", "", true},
+                {"xx", "x", true},
+                {"", "x", false},
+                {"", "", true},
+                {"", 0, false},
+                {0, "x", false},
+                {"a[", "[", false},
+                {"[a", "[", true},
+                {"[a", "[b", false},
+            }
+            for _, case in ipairs(cases) do
+                local ok, res = pcall(str.has_prefix, case[1], case[2])
+                if not ok then
+                    if case[3] == true then
+                        ngx.log(ngx.ERR, "unexpected error: ", res,
+                                " ", encode(case))
+                    end
+                else
+                    if case[3] ~= res then
+                        ngx.log(ngx.ERR, "unexpected res: ", res,
+                                " ", encode(case))
+                    end
+                end
+            end
+        }
+    }
+--- request
+GET /t
+--- no_error_log
+[error]
+
+
+
+=== TEST 3: suffix
+--- config
+    location /t {
+        content_by_lua_block {
+            local encode = require "cjson".encode 
+            local str = require("apisix.core.string")
+            local cases = {
+                {"xx", "", true},
+                {"xx", "x", true},
+                {"", "x", false},
+                {"", "", true},
+                {"", 0, false},
+                {0, "x", false},
+                {"a[", "[", true},
+                {"[a", "[", false},
+                {"[a", "[b", false},
+            }
+            for _, case in ipairs(cases) do
+                local ok, res = pcall(str.has_suffix, case[1], case[2])
+                if not ok then
+                    if case[3] == true then
+                        ngx.log(ngx.ERR, "unexpected error: ", res,
+                                " ", encode(case))
+                    end
+                else
+                    if case[3] ~= res then
+                        ngx.log(ngx.ERR, "unexpected res: ", res,
+                                " ", encode(case))
+                    end
+                end
+            end
+        }
+    }
+--- request
+GET /t
+--- no_error_log
+[error]