forked from 3scale/APIcast
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This policy allow user to disable request buffering. With this change, the upstream location is changed based on the value provided in the context.
- Loading branch information
Showing
6 changed files
with
274 additions
and
3 deletions.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
gateway/src/apicast/policy/request_unbuffered/apicast-policy.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"$schema": "http://apicast.io/policy-v1/schema#manifest#", | ||
"name": "Request Unbuffered", | ||
"summary": "Disable request buffering", | ||
"description": [ | ||
"Disable request buffering. This is useful when proxying big payloads with HTTP/1.1 chunked encoding" | ||
], | ||
"version": "builtin", | ||
"configuration": { | ||
"type": "object", | ||
"properties": {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
return require('request_unbuffered') |
22 changes: 22 additions & 0 deletions
22
gateway/src/apicast/policy/request_unbuffered/request_unbuffered.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
-- Request Unbuffered policy | ||
-- This policy will disable request buffering | ||
|
||
local policy = require('apicast.policy') | ||
local _M = policy.new('request_unbuffered') | ||
|
||
local new = _M.new | ||
|
||
--- Initialize a buffering | ||
-- @tparam[opt] table config Policy configuration. | ||
function _M.new(config) | ||
local self = new(config) | ||
return self | ||
end | ||
|
||
function _M:export() | ||
return { | ||
request_unbuffered = true, | ||
} | ||
end | ||
|
||
return _M |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
use lib 't'; | ||
use Test::APIcast::Blackbox 'no_plan'; | ||
|
||
sub large_body { | ||
my $res = ""; | ||
for (my $i=0; $i <= 1024; $i++) { | ||
$res = $res . "1111111 1111111 1111111 1111111\n"; | ||
} | ||
return $res; | ||
} | ||
|
||
$ENV{'LARGE_BODY'} = large_body(); | ||
|
||
require("policies.pl"); | ||
|
||
run_tests(); | ||
|
||
__DATA__ | ||
|
||
=== TEST 1: request_unbuffered policy with big file | ||
--- configuration | ||
{ | ||
"services": [ | ||
{ | ||
"backend_version": 1, | ||
"proxy": { | ||
"api_backend": "http://test-upstream.lvh.me:$TEST_NGINX_SERVER_PORT/", | ||
"proxy_rules": [ | ||
{ "pattern": "/", "http_method": "POST", "metric_system_name": "hits", "delta": 2 } | ||
], | ||
"policy_chain": [ | ||
{ | ||
"name": "request_unbuffered", | ||
"version": "builtin", | ||
"configuration": {} | ||
}, | ||
{ | ||
"name": "apicast", | ||
"version": "builtin", | ||
"configuration": {} | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
--- backend | ||
location /transactions/authrep.xml { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- upstream | ||
server_name test-upstream.lvh.me; | ||
location / { | ||
echo_read_request_body; | ||
echo_request_body; | ||
} | ||
--- request eval | ||
"POST /?user_key= \n" . $ENV{LARGE_BODY} | ||
--- response_body eval chomp | ||
$ENV{LARGE_BODY} | ||
--- error_code: 200 | ||
--- grep_error_log | ||
a client request body is buffered to a temporary file | ||
--- grep_error_log_out | ||
--- no_error_log | ||
[error] | ||
|
||
|
||
|
||
=== TEST 2: with small chunked request | ||
--- configuration | ||
{ | ||
"services": [ | ||
{ | ||
"backend_version": 1, | ||
"proxy": { | ||
"api_backend": "http://test-upstream.lvh.me:$TEST_NGINX_SERVER_PORT/", | ||
"proxy_rules": [ | ||
{ "pattern": "/", "http_method": "POST", "metric_system_name": "hits", "delta": 2 } | ||
], | ||
"policy_chain": [ | ||
{ | ||
"name": "request_unbuffered", | ||
"version": "builtin", | ||
"configuration": {} | ||
}, | ||
{ | ||
"name": "apicast", | ||
"version": "builtin", | ||
"configuration": {} | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
--- backend | ||
location /transactions/authrep.xml { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- upstream | ||
server_name test-upstream.lvh.me; | ||
location / { | ||
access_by_lua_block { | ||
assert = require('luassert') | ||
ngx.say("yay, api backend") | ||
|
||
-- Nginx will read the entire body in one chunk, the upstream request will not be chunked | ||
-- and Content-Length header will be added. | ||
local content_length = ngx.req.get_headers()["Content-Length"] | ||
local encoding = ngx.req.get_headers()["Transfer-Encoding"] | ||
assert.equal('12', content_length) | ||
assert.falsy(encoding, "chunked") | ||
} | ||
} | ||
--- more_headers | ||
Transfer-Encoding: chunked | ||
--- request eval | ||
"POST /test?user_key=value | ||
7\r | ||
hello, \r | ||
5\r | ||
world\r | ||
0\r | ||
\r | ||
" | ||
--- error_code: 200 | ||
--- no_error_log | ||
[error] | ||
|
||
|
||
|
||
=== TEST 3: With big chunked request | ||
--- configuration | ||
{ | ||
"services": [ | ||
{ | ||
"backend_version": 1, | ||
"proxy": { | ||
"api_backend": "http://test-upstream.lvh.me:$TEST_NGINX_SERVER_PORT/", | ||
"proxy_rules": [ | ||
{ "pattern": "/", "http_method": "POST", "metric_system_name": "hits", "delta": 2 } | ||
], | ||
"policy_chain": [ | ||
{ | ||
"name": "request_unbuffered", | ||
"version": "builtin", | ||
"configuration": {} | ||
}, | ||
{ | ||
"name": "apicast", | ||
"version": "builtin", | ||
"configuration": {} | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
--- backend | ||
location /transactions/authrep.xml { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- upstream | ||
server_name test-upstream.lvh.me; | ||
location / { | ||
access_by_lua_block { | ||
assert = require('luassert') | ||
local content_length = ngx.req.get_headers()["Content-Length"] | ||
local encoding = ngx.req.get_headers()["Transfer-Encoding"] | ||
assert.equal('chunked', encoding) | ||
assert.falsy(content_length) | ||
} | ||
echo_read_request_body; | ||
echo_request_body; | ||
} | ||
--- more_headers | ||
Transfer-Encoding: chunked | ||
--- request eval | ||
$::data = ''; | ||
for (my $i = 0; $i < 16384; $i++) { | ||
my $c = chr int rand 128; | ||
$::data .= $c; | ||
} | ||
my $s = "POST https://localhost/test?user_key=value | ||
". | ||
sprintf("%x\r\n", length $::data). | ||
$::data | ||
."\r | ||
0\r | ||
\r | ||
"; | ||
open my $out, '>/tmp/out.txt' or die $!; | ||
print $out $s; | ||
close $out; | ||
$s | ||
--- response_body eval | ||
$::data | ||
--- error_code: 200 | ||
--- grep_error_log | ||
a client request body is buffered to a temporary file | ||
--- grep_error_log_out | ||
--- no_error_log | ||
[error] |