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

shreemaanabhishek 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 3ba27f680 chore: header related fixes (#12961)
3ba27f680 is described below

commit 3ba27f680f358384b2bc5b913b990485a7a04315
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Thu Feb 5 15:11:47 2026 +0545

    chore: header related fixes (#12961)
---
 apisix/plugins/ai-drivers/openai-base.lua |  30 ++++++-
 t/plugin/ai-proxy-multi3.t                |  18 ----
 t/plugin/ai-proxy.t                       | 135 ++++++++++++++++++++++++++++--
 t/plugin/ai-rate-limiting.t               |  16 ----
 4 files changed, 158 insertions(+), 41 deletions(-)

diff --git a/apisix/plugins/ai-drivers/openai-base.lua 
b/apisix/plugins/ai-drivers/openai-base.lua
index 8688f9eb0..4f279bbc3 100644
--- a/apisix/plugins/ai-drivers/openai-base.lua
+++ b/apisix/plugins/ai-drivers/openai-base.lua
@@ -40,6 +40,7 @@ local math  = math
 local os    = os
 local ipairs = ipairs
 local setmetatable = setmetatable
+local str_lower = string.lower
 
 local HTTP_INTERNAL_SERVER_ERROR = ngx.HTTP_INTERNAL_SERVER_ERROR
 local HTTP_GATEWAY_TIMEOUT = ngx.HTTP_GATEWAY_TIMEOUT
@@ -193,6 +194,7 @@ local function read_response(conf, ctx, res, 
response_filter)
         end
         ctx.var.llm_prompt_tokens = ctx.ai_token_usage.prompt_tokens or 0
         ctx.var.llm_completion_tokens = ctx.ai_token_usage.completion_tokens 
or 0
+
         if type(res_body.choices) == "table" and #res_body.choices > 0 then
             local contents = {}
             for _, choice in ipairs(res_body.choices) do
@@ -209,6 +211,31 @@ local function read_response(conf, ctx, res, 
response_filter)
     plugin.lua_response_filter(ctx, headers, raw_res_body)
 end
 
+-- We want to forward all client headers to the LLM upstream by copying 
headers from the client
+-- but copying content-length is destructive, similarly some headers like 
`host`
+-- should not be forwarded either
+local function construct_forward_headers(ext_opts_headers, ctx)
+    local blacklist = {
+        "host",
+        "content-length"
+    }
+
+    -- make header keys lower case to overwrite downstream headers correctly,
+    -- because downstream headers are lower case
+    local opts_headers_lower = {}
+    for k, v in pairs(ext_opts_headers or {}) do
+        opts_headers_lower[str_lower(k)] = v
+    end
+    local headers = core.table.merge(core.request.headers(ctx), 
opts_headers_lower)
+    headers["Content-Type"] = "application/json"
+
+    for _, h in ipairs(blacklist) do
+        headers[h] = nil
+    end
+
+    return headers
+end
+
 
 local gcp_access_token_cache = lrucache.new(1024 * 4)
 
@@ -297,8 +324,7 @@ function _M.request(self, ctx, conf, request_table, 
extra_opts)
 
     local path = (parsed_url and parsed_url.path or self.path)
 
-    local headers = auth.header or {}
-    headers["Content-Type"] = "application/json"
+    local headers = construct_forward_headers(auth.header or {}, ctx)
     if token then
         headers["Authorization"] = "Bearer " .. token
     end
diff --git a/t/plugin/ai-proxy-multi3.t b/t/plugin/ai-proxy-multi3.t
index dfb95d8a2..bec93fc4a 100644
--- a/t/plugin/ai-proxy-multi3.t
+++ b/t/plugin/ai-proxy-multi3.t
@@ -70,18 +70,6 @@ add_block_preprocessor(sub {
                     local body, err = ngx.req.get_body_data()
                     body, err = json.decode(body)
 
-                    local test_type = ngx.req.get_headers()["test-type"]
-                    if test_type == "options" then
-                        if body.foo == "bar" then
-                            ngx.status = 200
-                            ngx.say("options works")
-                        else
-                            ngx.status = 500
-                            ngx.say("model options feature doesn't work")
-                        end
-                        return
-                    end
-
                     local header_auth = ngx.req.get_headers()["authorization"]
                     local query_auth = ngx.req.get_uri_args()["apikey"]
 
@@ -255,7 +243,6 @@ passed
                     }]],
                     nil,
                     {
-                        ["test-type"] = "options",
                         ["Content-Type"] = "application/json",
                     }
                 )
@@ -419,7 +406,6 @@ passed
                     }]],
                     nil,
                     {
-                        ["test-type"] = "options",
                         ["Content-Type"] = "application/json",
                     }
                 )
@@ -581,7 +567,6 @@ passed
                     }]],
                     nil,
                     {
-                        ["test-type"] = "options",
                         ["Content-Type"] = "application/json",
                     }
                 )
@@ -769,7 +754,6 @@ passed
                     }]],
                     nil,
                     {
-                        ["test-type"] = "options",
                         ["Content-Type"] = "application/json",
                     }
                 )
@@ -1022,7 +1006,6 @@ POST /ai
                 }]],
                 nil,
                 {
-                    ["test-type"] = "options",
                     ["Content-Type"] = "application/json",
                 }
             )
@@ -1040,7 +1023,6 @@ POST /ai
                 }]],
                 nil,
                 {
-                    ["test-type"] = "options",
                     ["Content-Type"] = "application/json",
                 }
             )
diff --git a/t/plugin/ai-proxy.t b/t/plugin/ai-proxy.t
index cc86332af..bad63aeaf 100644
--- a/t/plugin/ai-proxy.t
+++ b/t/plugin/ai-proxy.t
@@ -62,7 +62,7 @@ add_block_preprocessor(sub {
                     if test_type == "options" then
                         if body.foo == "bar" then
                             ngx.status = 200
-                            ngx.say("options works")
+                            ngx.print("options works")
                         else
                             ngx.status = 500
                             ngx.say("model options feature doesn't work")
@@ -70,6 +70,11 @@ add_block_preprocessor(sub {
                         return
                     end
 
+                    if test_type == "header_forwarding" then
+                        ngx.say(json.encode(ngx.req.get_headers()))
+                        return
+                    end
+
                     local header_auth = ngx.req.get_headers()["authorization"]
                     local query_auth = ngx.req.get_uri_args()["apikey"]
 
@@ -168,7 +173,7 @@ add_block_preprocessor(sub {
 
             location /random {
                 content_by_lua_block {
-                    ngx.say("path override works")
+                    ngx.print("path override works")
                 }
             }
         }
@@ -448,8 +453,8 @@ unsupported content-type: 
application/x-www-form-urlencoded, only application/js
         }
     }
 --- error_code: 200
---- response_body_chomp
-options_works
+--- response_body
+options works
 
 
 
@@ -510,7 +515,7 @@ options_works
 
         }
     }
---- response_body_chomp
+--- response_body
 path override works
 
 
@@ -698,3 +703,123 @@ qr/.*text-embedding-ada-002*/
 GET /t
 --- response_body
 ok
+
+
+
+=== TEST 18: set route with right auth header
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "uri": "/anything",
+                    "plugins": {
+                        "ai-proxy": {
+                            "provider": "openai",
+                            "auth": {
+                                "header": {
+                                    "Authorization": "Bearer token"
+                                }
+                            },
+                            "options": {
+                                "model": "gpt-35-turbo-instruct",
+                                "max_tokens": 512,
+                                "temperature": 1.0
+                            },
+                            "override": {
+                                "endpoint": "http://localhost:6724";
+                            },
+                            "ssl_verify": false
+                        }
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 19: send request
+--- request
+POST /anything
+{ "messages": [ { "role": "system", "content": "You are a mathematician" }, { 
"role": "user", "content": "What is 1+1?"} ] }
+--- more_headers
+test-type: header_forwarding
+--- error_code: 200
+--- response_body eval
+qr/"test-type":"header_forwarding"/
+
+
+
+=== TEST 20: set route with right auth header
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "uri": "/anything",
+                    "plugins": {
+                        "ai-proxy": {
+                            "provider": "openai",
+                            "auth": {
+                                "header": {
+                                    "Authorization": "Bearer token"
+                                }
+                            },
+                            "options": {
+                                "model": "gpt-35-turbo-instruct",
+                                "max_tokens": 512,
+                                "temperature": 1.0
+                            },
+                            "override": {
+                                "endpoint": "http://localhost:6724";
+                            },
+                            "ssl_verify": false
+                        },
+                        "request-id": {
+                        }
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 21: send request
+--- request
+POST /anything
+{ "messages": [ { "role": "system", "content": "You are a mathematician" }, { 
"role": "user", "content": "What is 1+1?"} ] }
+--- more_headers
+test-type: header_forwarding
+--- error_code: 200
+--- response_body eval
+qr/"x-request-id":"[\d\w-]+"/
+
+
+
+=== TEST 22: send request with Authorization header
+--- request
+POST /anything
+{ "messages": [ { "role": "system", "content": "You are a mathematician" }, { 
"role": "user", "content": "What is 1+1?"} ] }
+--- more_headers
+Authorization: Bearer wrong token
+--- error_code: 200
diff --git a/t/plugin/ai-rate-limiting.t b/t/plugin/ai-rate-limiting.t
index c6112b9ab..48c71d04f 100644
--- a/t/plugin/ai-rate-limiting.t
+++ b/t/plugin/ai-rate-limiting.t
@@ -78,18 +78,6 @@ add_block_preprocessor(sub {
                     local body, err = ngx.req.get_body_data()
                     body, err = json.decode(body)
 
-                    local test_type = ngx.req.get_headers()["test-type"]
-                    if test_type == "options" then
-                        if body.foo == "bar" then
-                            ngx.status = 200
-                            ngx.say("options works")
-                        else
-                            ngx.status = 500
-                            ngx.say("model options feature doesn't work")
-                        end
-                        return
-                    end
-
                     local header_auth = ngx.req.get_headers()["authorization"]
                     local query_auth = ngx.req.get_uri_args()["apikey"]
 
@@ -656,7 +644,6 @@ passed
                 }]],
                 nil,
                 {
-                    ["test-type"] = "options",
                     ["Content-Type"] = "application/json",
                 }
             )
@@ -675,7 +662,6 @@ passed
                 }]],
                 nil,
                 {
-                    ["test-type"] = "options",
                     ["Content-Type"] = "application/json",
                 }
             )
@@ -694,7 +680,6 @@ passed
                 }]],
                 nil,
                 {
-                    ["test-type"] = "options",
                     ["Content-Type"] = "application/json",
                 }
             )
@@ -793,7 +778,6 @@ passed
                     }]],
                     nil,
                     {
-                        ["test-type"] = "options",
                         ["Content-Type"] = "application/json",
                     }
                 )

Reply via email to