106
106
107
107
108
108
local _M = {
109
- _VERSION = ' 0.14 ' ,
109
+ _VERSION = ' 0.16.1 ' ,
110
110
}
111
111
_M ._USER_AGENT = " lua-resty-http/" .. _M ._VERSION .. " (Lua) ngx_lua/" .. ngx .config .ngx_lua_version
112
112
@@ -362,7 +362,21 @@ local function _receive_status(sock)
362
362
return nil , nil , nil , err
363
363
end
364
364
365
- return tonumber (str_sub (line , 10 , 12 )), tonumber (str_sub (line , 6 , 8 )), str_sub (line , 14 )
365
+ local version = tonumber (str_sub (line , 6 , 8 ))
366
+ if not version then
367
+ return nil , nil , nil ,
368
+ " couldn't parse HTTP version from response status line: " .. line
369
+ end
370
+
371
+ local status = tonumber (str_sub (line , 10 , 12 ))
372
+ if not status then
373
+ return nil , nil , nil ,
374
+ " couldn't parse status code from response status line: " .. line
375
+ end
376
+
377
+ local reason = str_sub (line , 14 )
378
+
379
+ return status , version , reason
366
380
end
367
381
368
382
@@ -398,6 +412,23 @@ local function _receive_headers(sock)
398
412
end
399
413
400
414
415
+ local function transfer_encoding_is_chunked (headers )
416
+ local te = headers [" Transfer-Encoding" ]
417
+ if not te then
418
+ return false
419
+ end
420
+
421
+ -- Handle duplicate headers
422
+ -- This shouldn't happen but can in the real world
423
+ if type (te ) ~= " string" then
424
+ te = tbl_concat (te , " ," )
425
+ end
426
+
427
+ return str_find (str_lower (te ), " chunked" , 1 , true ) ~= nil
428
+ end
429
+ _M .transfer_encoding_is_chunked = transfer_encoding_is_chunked
430
+
431
+
401
432
local function _chunked_body_reader (sock , default_chunk_size )
402
433
return co_wrap (function (max_chunk_size )
403
434
local remaining = 0
575
606
576
607
577
608
local function _send_body (sock , body )
578
- if type (body ) == ' function' then
609
+ if type (body ) == " function" then
579
610
repeat
580
611
local chunk , err , partial = body ()
581
612
@@ -627,12 +658,13 @@ function _M.send_request(self, params)
627
658
local body = params .body
628
659
local headers = http_headers .new ()
629
660
630
- local params_headers = params .headers or {}
631
- -- We assign one by one so that the metatable can handle case insensitivity
661
+ -- We assign one-by-one so that the metatable can handle case insensitivity
632
662
-- for us. You can blame the spec for this inefficiency.
663
+ local params_headers = params .headers or {}
633
664
for k , v in pairs (params_headers ) do
634
665
headers [k ] = v
635
666
end
667
+
636
668
if not headers [" Proxy-Authorization" ] then
637
669
-- TODO: next major, change this to always override the provided
638
670
-- header. Can't do that yet because it would be breaking.
@@ -641,15 +673,40 @@ function _M.send_request(self, params)
641
673
headers [" Proxy-Authorization" ] = self .http_proxy_auth
642
674
end
643
675
644
- -- Ensure minimal headers are set
676
+ -- Ensure we have appropriate message length or encoding.
677
+ do
678
+ local is_chunked = transfer_encoding_is_chunked (headers )
679
+
680
+ if is_chunked then
681
+ -- If we have both Transfer-Encoding and Content-Length we MUST
682
+ -- drop the Content-Length, to help prevent request smuggling.
683
+ -- https://tools.ietf.org/html/rfc7230#section-3.3.3
684
+ headers [" Content-Length" ] = nil
645
685
646
- if not headers [" Content-Length" ] then
647
- if type (body ) == ' string' then
648
- headers [" Content-Length" ] = # body
649
- elseif body == nil and EXPECTING_BODY [str_upper (params .method )] then
650
- headers [" Content-Length" ] = 0
686
+ elseif not headers [" Content-Length" ] then
687
+ -- A length was not given, try to calculate one.
688
+
689
+ local body_type = type (body )
690
+
691
+ if body_type == " function" then
692
+ return nil , " Request body is a function but a length or chunked encoding is not specified"
693
+
694
+ elseif body_type == " table" then
695
+ local length = 0
696
+ for _ , v in ipairs (body ) do
697
+ length = length + # tostring (v )
698
+ end
699
+ headers [" Content-Length" ] = length
700
+
701
+ elseif body == nil and EXPECTING_BODY [str_upper (params .method )] then
702
+ headers [" Content-Length" ] = 0
703
+
704
+ elseif body ~= nil then
705
+ headers [" Content-Length" ] = # tostring (body )
706
+ end
651
707
end
652
708
end
709
+
653
710
if not headers [" Host" ] then
654
711
if (str_sub (self .host , 1 , 5 ) == " unix:" ) then
655
712
return nil , " Unable to generate a useful Host header for a unix domain socket. Please provide one."
@@ -751,22 +808,8 @@ function _M.read_response(self, params)
751
808
if _should_receive_body (params .method , status ) then
752
809
has_body = true
753
810
754
- local te = res_headers [" Transfer-Encoding" ]
755
-
756
- -- Handle duplicate headers
757
- -- This shouldn't happen but can in the real world
758
- if type (te ) == " table" then
759
- te = tbl_concat (te , " " )
760
- end
761
-
762
- local ok , encoding = pcall (str_lower , te )
763
- if not ok then
764
- encoding = " "
765
- end
766
-
767
- if version == 1.1 and str_find (encoding , " chunked" , 1 , true ) ~= nil then
811
+ if version == 1.1 and transfer_encoding_is_chunked (res_headers ) then
768
812
body_reader , err = _chunked_body_reader (sock )
769
-
770
813
else
771
814
local ok , length = pcall (tonumber , res_headers [" Content-Length" ])
772
815
if not ok then
@@ -775,9 +818,7 @@ function _M.read_response(self, params)
775
818
end
776
819
777
820
body_reader , err = _body_reader (sock , length )
778
-
779
821
end
780
-
781
822
end
782
823
783
824
if res_headers [" Trailer" ] then
@@ -872,6 +913,7 @@ function _M.request_uri(self, uri, params)
872
913
params .scheme , params .host , params .port , path , query = unpack (parsed_uri )
873
914
params .path = params .path or path
874
915
params .query = params .query or query
916
+ params .ssl_server_name = params .ssl_server_name or params .host
875
917
end
876
918
877
919
do
@@ -941,10 +983,9 @@ function _M.get_client_body_reader(_, chunksize, sock)
941
983
942
984
local headers = ngx_req_get_headers ()
943
985
local length = headers .content_length
944
- local encoding = headers .transfer_encoding
945
986
if length then
946
987
return _body_reader (sock , tonumber (length ), chunksize )
947
- elseif encoding and str_lower ( encoding ) == ' chunked ' then
988
+ elseif transfer_encoding_is_chunked ( headers ) then
948
989
-- Not yet supported by ngx_lua but should just work...
949
990
return _chunked_body_reader (sock , chunksize )
950
991
else
0 commit comments