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

shreemaan-abhishek 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 e1053faa7 fix(opa): apply send_headers_upstream for headers absent 
from OPA response (#13433)
e1053faa7 is described below

commit e1053faa7c501bd9ba835f7fa6ab30be02d200f7
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Tue Jun 2 14:22:10 2026 +0800

    fix(opa): apply send_headers_upstream for headers absent from OPA response 
(#13433)
---
 apisix/plugins/opa.lua | 14 ++++++---
 t/plugin/opa3.t        | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/apisix/plugins/opa.lua b/apisix/plugins/opa.lua
index 0475529f0..790ef5f1a 100644
--- a/apisix/plugins/opa.lua
+++ b/apisix/plugins/opa.lua
@@ -137,13 +137,17 @@ function _M.access(conf, ctx)
         end
 
         return status_code, reason
-    else if result.headers and conf.send_headers_upstream then
+    else if conf.send_headers_upstream then
+        local headers = result.headers or {}
+        -- set headers from the OPA response, clearing any client-supplied
+        -- values for configured headers not present in the OPA response
         for _, name in ipairs(conf.send_headers_upstream) do
-            local value = result.headers[name]
-            if value then
-                core.request.set_header(ctx, name, value)
-            end
+            local value = headers[name]
+            -- if value is nil, the client header's value will be removed if 
it exists
+            core.request.set_header(ctx, name, value)
         end
+        -- discard cached request headers so downstream readers observe the 
update
+        ctx.headers = nil
         end
     end
 end
diff --git a/t/plugin/opa3.t b/t/plugin/opa3.t
new file mode 100644
index 000000000..17f348626
--- /dev/null
+++ b/t/plugin/opa3.t
@@ -0,0 +1,84 @@
+#
+# 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(1);
+no_long_string();
+no_root_location();
+
+add_block_preprocessor(sub {
+    my ($block) = @_;
+
+    if (!defined $block->request) {
+        $block->set_value("request", "GET /t");
+    }
+});
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: setup route with send_headers_upstream
+--- 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,
+                 [[{
+                        "plugins": {
+                            "opa": {
+                                "host": "http://127.0.0.1:8181";,
+                                "policy": "example",
+                                "send_headers_upstream": ["X-Foo"]
+                            },
+                            "serverless-post-function": {
+                                "phase": "access",
+                                "functions": [
+                                    "return function(conf, ctx) local core = 
require(\"apisix.core\"); core.response.exit(200, core.request.headers(ctx)); 
end"
+                                ]
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/echo"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 2: client-supplied send_headers_upstream entry is cleared when OPA 
response omits it
+--- request
+GET /echo
+--- more_headers
+X-Foo: client-value
+--- error_code: 200
+--- response_body_unlike eval
+qr/x-foo/

Reply via email to