Skip to content

Commit 8d9df64

Browse files
fix: reframe request body forwarded upstream in serverless plugins
The openfunction, aws-lambda and azure-functions plugins share generic-upstream.lua, which forwarded every inbound client header verbatim, including Transfer-Encoding, while supplying the request body already de-chunked by nginx. resty.http then kept Transfer-Encoding: chunked and wrote the unframed body raw, so the upstream request advertised chunked framing over a body that had none, letting the upstream misread the message length. Drop transfer-encoding and content-length before forwarding so the http client reframes the body with a correct Content-Length. Adds an end-to-end test that a chunked client body reaches the upstream reframed.
1 parent b79329d commit 8d9df64

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

apisix/plugins/serverless/generic-upstream.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ return function(plugin_name, version, priority, request_processor, authz_schema,
6262
local uri_args = core.request.get_uri_args(ctx)
6363
local headers = core.request.headers(ctx) or {}
6464

65+
-- body is already de-chunked by nginx; drop the client's framing headers
66+
-- so the http client reframes it with a correct Content-Length
67+
headers["transfer-encoding"] = nil
68+
headers["content-length"] = nil
69+
6570
local req_body, err = core.request.get_body()
6671

6772
if err then

t/plugin/aws-lambda.t

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,3 +510,75 @@ end
510510
passed
511511
query: a=%2A&a-=x&flag=&multi=m1&multi=m2&with%20space=a%2Fb%20c
512512
signature: ok
513+
514+
515+
516+
=== TEST 12: create route for chunked-body framing check
517+
--- config
518+
location /t {
519+
content_by_lua_block {
520+
local t = require("lib.test_admin").test
521+
local code, body = t('/apisix/admin/routes/1',
522+
ngx.HTTP_PUT,
523+
[[{
524+
"plugins": {
525+
"aws-lambda": {
526+
"function_uri": "http://localhost:8765/generic"
527+
}
528+
},
529+
"uri": "/aws"
530+
}]]
531+
)
532+
if code >= 300 then
533+
ngx.status = code
534+
ngx.say("fail")
535+
return
536+
end
537+
ngx.say(body)
538+
}
539+
}
540+
--- response_body
541+
passed
542+
543+
544+
545+
=== TEST 13: chunked client body is reframed with a correct Content-Length
546+
--- inside_lua_block
547+
ngx.req.read_body()
548+
local te = ngx.req.get_headers()["transfer-encoding"]
549+
ngx.say("te=", tostring(te))
550+
ngx.say("body=", ngx.req.get_body_data() or "")
551+
--- config
552+
location /t {
553+
content_by_lua_block {
554+
local sock = ngx.socket.tcp()
555+
sock:settimeout(2000)
556+
local ok, err = sock:connect("127.0.0.1", 1984)
557+
if not ok then
558+
ngx.say("connect failed: ", err)
559+
return
560+
end
561+
local payload = "hello world"
562+
local req = "POST /aws HTTP/1.1\r\n"
563+
.. "Host: 127.0.0.1\r\n"
564+
.. "Transfer-Encoding: chunked\r\n"
565+
.. "Content-Type: text/plain\r\n"
566+
.. "Connection: close\r\n\r\n"
567+
.. string.format("%x\r\n%s\r\n0\r\n\r\n", #payload, payload)
568+
local bytes, err = sock:send(req)
569+
if not bytes then
570+
ngx.say("send failed: ", err)
571+
return
572+
end
573+
local data, err, partial = sock:receive("*a")
574+
data = data or partial or ""
575+
sock:close()
576+
if data:find("te=nil", 1, true) and data:find("body=hello world", 1, true) then
577+
ngx.say("PASS")
578+
else
579+
ngx.say("FAIL: ", data)
580+
end
581+
}
582+
}
583+
--- response_body
584+
PASS

0 commit comments

Comments
 (0)