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 fede22e  feat(Wasm): get response body (#6514)
fede22e is described below

commit fede22edb50b70a54f59f6ca244bc48c46ca93de
Author: 罗泽轩 <[email protected]>
AuthorDate: Mon Mar 7 10:13:05 2022 +0800

    feat(Wasm): get response body (#6514)
---
 apisix/cli/ngx_tpl.lua          |  1 +
 apisix/wasm.lua                 | 35 +++++++++++++++
 docs/en/latest/wasm.md          |  1 +
 t/APISIX.pm                     |  1 +
 t/wasm/response-rewrite.t       | 98 +++++++++++++++++++++++++++++++++++++++++
 t/wasm/response-rewrite/main.go | 25 +++++++++++
 6 files changed, 161 insertions(+)

diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index 186884f..aaac144 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -621,6 +621,7 @@ http {
 
             {% if wasm then %}
             set $wasm_process_req_body       '';
+            set $wasm_process_resp_body      '';
             {% end %}
 
             # http server location configuration snippet starts
diff --git a/apisix/wasm.lua b/apisix/wasm.lua
index d406089..56a44b8 100644
--- a/apisix/wasm.lua
+++ b/apisix/wasm.lua
@@ -112,6 +112,37 @@ local function header_filter_wrapper(self, conf, ctx)
         core.log.error(name, ": failed to run wasm plugin: ", err)
         return 503
     end
+
+    -- $wasm_process_resp_body is predefined in ngx_tpl.lua
+    local handle_body = ngx_var.wasm_process_resp_body
+    if handle_body ~= '' then
+        -- reset the flag so we can use it for the next Wasm plugin
+        -- use ngx.var to bypass the cache
+        ngx_var.wasm_process_resp_body = ""
+        ctx["wasm_" .. name .. "_process_resp_body"] = true
+    end
+end
+
+
+local function body_filter_wrapper(self, conf, ctx)
+    local name = self.name
+
+    local enabled = ctx["wasm_" .. name .. "_process_resp_body"]
+    if not enabled then
+        return
+    end
+
+    local plugin_ctx, err = fetch_plugin_ctx(conf, ctx, self.plugin)
+    if not plugin_ctx then
+        core.log.error(name, ": failed to fetch wasm plugin ctx: ", err)
+        return
+    end
+
+    local ok, err = wasm.on_http_response_body(plugin_ctx)
+    if not ok then
+        core.log.error(name, ": failed to run wasm plugin: ", err)
+        return
+    end
 end
 
 
@@ -151,6 +182,10 @@ function _M.require(attrs)
         return header_filter_wrapper(mod, conf, ctx)
     end
 
+    mod.body_filter = function (conf, ctx)
+        return body_filter_wrapper(mod, conf, ctx)
+    end
+
     -- the returned values need to be the same as the Lua's 'require'
     return true, mod
 end
diff --git a/docs/en/latest/wasm.md b/docs/en/latest/wasm.md
index 52089dd..f0579c5 100644
--- a/docs/en/latest/wasm.md
+++ b/docs/en/latest/wasm.md
@@ -103,6 +103,7 @@ For example, when the first request hits the route which 
has Wasm plugin configu
 * `proxy_on_http_request_headers`: run in the access/rewrite phase, depends on 
the configuration of `http_request_phase`.
 * `proxy_on_http_request_body`: run in the same phase of 
`proxy_on_http_request_headers`. To run this callback, we need to set property 
`wasm_process_req_body` to non-empty value in `proxy_on_http_request_headers`. 
See `t/wasm/request-body/main.go` as an example.
 * `proxy_on_http_response_headers`: run in the header_filter phase.
+* `proxy_on_http_response_body`: run in the body_filter phase. To run this 
callback, we need to set property `wasm_process_resp_body` to non-empty value 
in `proxy_on_http_response_headers`. See `t/wasm/response-rewrite/main.go` as 
an example.
 
 ## Example
 
diff --git a/t/APISIX.pm b/t/APISIX.pm
index bcd8daf..671ffe3 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -222,6 +222,7 @@ my $a6_ngx_vars = "";
 if ($version =~ m/\/apisix-nginx-module/) {
     $a6_ngx_vars = <<_EOC_;
     set \$wasm_process_req_body       '';
+    set \$wasm_process_resp_body      '';
 _EOC_
 }
 
diff --git a/t/wasm/response-rewrite.t b/t/wasm/response-rewrite.t
index 250a07c..15b9bd1 100644
--- a/t/wasm/response-rewrite.t
+++ b/t/wasm/response-rewrite.t
@@ -42,6 +42,9 @@ wasm:
         - name: wasm-response-rewrite
           priority: 7997
           file: t/wasm/response-rewrite/main.go.wasm
+        - name: wasm-response-rewrite2
+          priority: 7996
+          file: t/wasm/response-rewrite/main.go.wasm
 _EOC_
     $block->set_value("extra_yaml_config", $extra_yaml_config);
 });
@@ -92,3 +95,98 @@ passed
 GET /hello
 --- response_headers
 x-wasm: apisix
+
+
+
+=== TEST 3: log response body
+--- 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": "/hello",
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        }
+                    },
+                    "plugins": {
+                        "wasm-response-rewrite": {
+                            "conf": "{\"body\":\"a\"}"
+                        }
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 4: hit
+--- request
+GET /hello
+--- grep_error_log eval
+qr/get body .+/
+--- grep_error_log_out
+get body [hello world
+
+
+
+=== TEST 5: ensure the process body flag is plugin independent
+--- 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": "/hello",
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        }
+                    },
+                    "plugins": {
+                        "wasm-response-rewrite": {
+                            "conf": "{\"body\":\"a\"}"
+                        },
+                        "wasm-response-rewrite2": {
+                            "conf": 
"{\"headers\":[{\"name\":\"x-wasm\",\"value\":\"apisix\"}]}"
+                        }
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 6: hit
+--- request
+GET /hello
+--- grep_error_log eval
+qr/get body .+/
+--- grep_error_log_out
+get body [hello world
diff --git a/t/wasm/response-rewrite/main.go b/t/wasm/response-rewrite/main.go
index 41fa7b1..fb7b184 100644
--- a/t/wasm/response-rewrite/main.go
+++ b/t/wasm/response-rewrite/main.go
@@ -44,6 +44,7 @@ type header struct {
 type pluginContext struct {
        types.DefaultPluginContext
        Headers []header
+       Body    []byte
 }
 
 func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int) 
types.OnPluginStartStatus {
@@ -68,6 +69,9 @@ func (ctx *pluginContext) 
OnPluginStart(pluginConfigurationSize int) types.OnPlu
                }
        }
 
+       body := v.GetStringBytes("body")
+       ctx.Body = body
+
        return types.OnPluginStartStatusOK
 }
 
@@ -85,5 +89,26 @@ func (ctx *httpContext) OnHttpResponseHeaders(numHeaders 
int, endOfStream bool)
        for _, hdr := range plugin.Headers {
                proxywasm.ReplaceHttpResponseHeader(hdr.Name, hdr.Value)
        }
+
+       if len(plugin.Body) > 0 {
+               proxywasm.SetProperty([]string{"wasm_process_resp_body"}, 
[]byte("true"))
+       }
+
+       return types.ActionContinue
+}
+
+func (ctx *httpContext) OnHttpResponseBody(bodySize int, endOfStream bool) 
types.Action {
+       plugin := ctx.parent
+
+       if len(plugin.Body) > 0 && !endOfStream {
+               // TODO support changing body
+               body, err := proxywasm.GetHttpResponseBody(0, bodySize)
+               if err != nil {
+                       proxywasm.LogErrorf("failed to get body: %v", err)
+                       return types.ActionContinue
+               }
+               proxywasm.LogWarnf("get body [%s]", string(body))
+       }
+
        return types.ActionContinue
 }

Reply via email to