@@ -5,6 +5,12 @@ local resty_resolver = require 'resty.resolver'
55local round_robin = require ' resty.balancer.round_robin'
66local http_proxy = require ' resty.http.proxy'
77local file_reader = require (" resty.file" ).file_reader
8+ local chunked_reader = require (' resty.http.chunked' ).chunked_reader
9+ local chunked_writer = require (' resty.http.chunked' ).chunked_writer
10+ local req_headers = ngx .req .get_headers
11+ local http_ver = ngx .req .http_version
12+ local ngx_send_headers = ngx .send_headers
13+ local ngx_flush = ngx .flush
814
915local _M = { }
1016
@@ -82,14 +88,58 @@ local function absolute_url(uri)
8288end
8389
8490local function forward_https_request (proxy_uri , uri , skip_https_connect )
85- -- This is needed to call ngx.req.get_body_data() below.
86- ngx .req .read_body ()
91+ local sock , ok , err
92+ local chunksize = 32 * 1024
93+ local body
94+ local headers = req_headers ()
95+
96+ local encoding = headers .transfer_encoding
97+ if type (encoding ) == " table" then
98+ encoding = encoding [1 ]
99+ end
87100
88- local request = {
89- uri = uri ,
90- method = ngx .req .get_method (),
91- headers = ngx .req .get_headers (0 , true ),
92- path = format (' %s%s%s' , ngx .var .uri , ngx .var .is_args , ngx .var .query_string or ' ' ),
101+ if encoding and encoding :lower () == " chunked" then
102+ if http_ver () ~= 1.1 then
103+ ngx .log (ngx .ERR , " bad http version" )
104+ ngx .exit (ngx .HTTP_BAD_REQUEST )
105+ end
106+ local expect = headers [" Expect" ]
107+
108+ if type (expect ) == " table" then
109+ expect = expect [1 ]
110+ end
111+
112+ if expect and expect :lower () == " 100-continue" then
113+ ngx .status = 100
114+ ok , err = ngx_send_headers ()
115+
116+ if not ok then
117+ ngx .log (ngx .ERR , " failed to send response header: " .. (err or " unknown" ))
118+ end
119+
120+ ok , err = ngx_flush (true )
121+ if not ok then
122+ ngx .log (ngx .ERR , " failed to flush response header: " .. (err or " unknown" ))
123+ end
124+ end
125+
126+ -- The default ngx reader does not support chunked request
127+ -- so we will need to get the raw request socket and manually
128+ -- decode the chunked request
129+ sock , err = ngx .req .socket (true )
130+
131+ if not sock then
132+ if err == " no body" then
133+ body = nil
134+ else
135+ return ngx .exit (ngx .HTTP_SERVICE_UNAVAILABLE )
136+ end
137+ else
138+ body = chunked_reader (sock , chunksize )
139+ end
140+ else
141+ -- This is needed to call ngx.req.get_body_data() below.
142+ ngx .req .read_body ()
93143
94144 -- We cannot use resty.http's .get_client_body_reader().
95145 -- In POST requests with HTTPS, the result of that call is nil, and it
@@ -100,24 +150,31 @@ local function forward_https_request(proxy_uri, uri, skip_https_connect)
100150 -- read and need to be cached in a local file. This request will return
101151 -- nil, so after this we need to read the temp file.
102152 -- https://github.com/openresty/lua-nginx-module#ngxreqget_body_data
103- body = ngx .req .get_body_data (),
104- proxy_uri = proxy_uri
105- }
106-
107- if not request .body then
108- local temp_file_path = ngx .req .get_body_file ()
109- ngx .log (ngx .INFO , " HTTPS Proxy: Request body is bigger than client_body_buffer_size, read the content from path='" , temp_file_path , " '" )
110-
111- if temp_file_path then
112- local body , err = file_reader (temp_file_path )
113- if err then
114- ngx .log (ngx .ERR , " HTTPS proxy: Failed to read temp body file, err: " , err )
115- ngx .exit (ngx .HTTP_INTERNAL_SERVER_ERROR )
116- end
117- request .body = body
153+ body = ngx .req .get_body_data ()
154+
155+ if not body then
156+ local temp_file_path = ngx .req .get_body_file ()
157+ ngx .log (ngx .INFO , " HTTPS Proxy: Request body is bigger than client_body_buffer_size, read the content from path='" , temp_file_path , " '" )
158+
159+ if temp_file_path then
160+ body , err = file_reader (temp_file_path )
161+ if err then
162+ ngx .log (ngx .ERR , " HTTPS proxy: Failed to read temp body file, err: " , err )
163+ ngx .exit (ngx .HTTP_INTERNAL_SERVER_ERROR )
164+ end
165+ end
118166 end
119167 end
120168
169+ local request = {
170+ uri = uri ,
171+ method = ngx .req .get_method (),
172+ headers = ngx .req .get_headers (0 , true ),
173+ path = format (' %s%s%s' , ngx .var .uri , ngx .var .is_args , ngx .var .query_string or ' ' ),
174+ body = body ,
175+ proxy_uri = proxy_uri
176+ }
177+
121178 local httpc , err = http_proxy .new (request , skip_https_connect )
122179
123180 if not httpc then
@@ -130,11 +187,20 @@ local function forward_https_request(proxy_uri, uri, skip_https_connect)
130187 res , err = httpc :request (request )
131188
132189 if res then
133- httpc :proxy_response (res )
190+ -- if we are using raw socket we will need to send the response back with sock:send
191+ if sock then
192+ chunked_writer (sock , res ,chunksize )
193+ else
194+ httpc :proxy_response (res )
195+ end
134196 httpc :set_keepalive ()
135197 else
136198 ngx .log (ngx .ERR , ' failed to proxy request to: ' , proxy_uri , ' err : ' , err )
137- return ngx .exit (ngx .HTTP_BAD_GATEWAY )
199+ if sock then
200+ sock :send (" HTTP/1.1 502 Bad Gateway\\ r\\ n" )
201+ else
202+ return ngx .exit (ngx .HTTP_BAD_GATEWAY )
203+ end
138204 end
139205end
140206
0 commit comments