@@ -16,8 +16,7 @@ local utils = require("rest-nvim.utils")
1616local logger = require (" rest-nvim.logger" )
1717local config = require (" rest-nvim.config" )
1818local curl_utils = require (" rest-nvim.client.curl.utils" )
19-
20- -- TODO: add support for submitting forms in the `client.request` function
19+ local curl_cli = require (" rest-nvim.client.curl.cli" )
2120
2221--- Get request statistics
2322--- @param req table cURL request class
@@ -46,7 +45,6 @@ local function get_stats(req, statistics_tbl)
4645 local stats = {}
4746
4847 for name , _ in pairs (statistics_tbl ) do
49- -- stats[name] = style.title .. " " .. get_stat(req, name)
5048 stats [name ] = get_stat (req , name )
5149 end
5250
5553
5654--- Execute an HTTP request using cURL
5755--- return return nil if execution failed
58- --- @param request rest.Request Request data to be passed to cURL
59- --- @return table ? info The request information (url , method , headers , body , etc )
60- function client .request_ (request )
61- logger .info (" sending request to: " .. request .url )
62- -- write to `Context.response` without altering the reference
63- local info = request .context .aesponse
56+ --- @param req rest.Request Request data to be passed to cURL
57+ --- @return rest.Response ? info The request information (url , method , headers , body , etc )
58+ function client .request (req )
59+ logger .info (" sending request to: " .. req .url )
6460 if not found_curl then
6561 --- @diagnostic disable-next-line need-check-nil
6662 logger .error (" lua-curl could not be found, therefore the cURL client will not work." )
6763 return
6864 end
69- local host = request .headers [" host" ]
65+ local host = req .headers [" host" ]
7066 if host then
71- request .url = host .. request .url
67+ req .url = host .. req .url
7268 end
7369
7470 -- We have to concat request headers to a single string, e.g. ["Content-Type"]: "application/json" -> "Content-Type: application/json"
7571 local headers = {}
76- for name , value in pairs (request .headers ) do
77- table.insert (headers , name .. " : " .. value )
72+ for name , values in pairs (req .headers ) do
73+ for _ , value in ipairs (values ) do
74+ table.insert (headers , name .. " : " .. value )
75+ end
7876 end
7977
8078 -- Whether to skip SSL host and peer verification
8179 local skip_ssl_verification = config .skip_ssl_verification
82- local req = curl .easy_init ()
83- req :setopt ({
84- url = request .url ,
80+ local req_ = curl .easy_init ()
81+ req_ :setopt ({
82+ url = req .url ,
8583 -- verbose = true,
8684 httpheader = headers ,
8785 ssl_verifyhost = skip_ssl_verification ,
@@ -92,89 +90,100 @@ function client.request_(request)
9290 local should_encode_url = config .encode_url
9391 if should_encode_url then
9492 -- Create a new URL as we cannot extract the URL from the req object
95- local _url = curl .url ()
96- _url :set_url (request .url )
93+ local url_ = curl .url ()
94+ url_ :set_url (req .url )
9795 -- Re-add the request query with the encoded parameters
98- local query = _url :get_query ()
96+ local query = url_ :get_query ()
9997 if type (query ) == " string" then
100- _url :set_query (" " )
98+ url_ :set_query (" " )
10199 for param in vim .gsplit (query , " &" ) do
102- _url :set_query (param , curl .U_URLENCODE + curl .U_APPENDQUERY )
100+ url_ :set_query (param , curl .U_URLENCODE + curl .U_APPENDQUERY )
103101 end
104102 end
105103 -- Re-add the request URL to the req object
106- req :setopt_url (_url :get_url ())
104+ req_ :setopt_url (url_ :get_url ())
107105 end
108106
109107 -- Set request HTTP version, defaults to HTTP/1.1
110- if request .http_version then
111- local http_version = request .http_version :gsub (" %." , " _" )
112- req :setopt_http_version (curl [" HTTP_VERSION_" .. http_version ])
108+ if req .http_version then
109+ local http_version = req .http_version :gsub (" %." , " _" )
110+ req_ :setopt_http_version (curl [" HTTP_VERSION_" .. http_version ])
113111 else
114- req :setopt_http_version (curl .HTTP_VERSION_1_1 )
112+ req_ :setopt_http_version (curl .HTTP_VERSION_1_1 )
115113 end
116114
117115 -- If the request method is not GET then we have to build the method in our own
118116 -- See: https://github.com/Lua-cURL/Lua-cURLv3/issues/156
119- local method = request .method
117+ local method = req .method
120118 if vim .tbl_contains ({ " POST" , " PUT" , " PATCH" , " TRACE" , " OPTIONS" , " DELETE" }, method ) then
121- req :setopt_post (true )
122- req :setopt_customrequest (method )
119+ req_ :setopt_post (true )
120+ req_ :setopt_customrequest (method )
123121 end
124122
125123 -- local body = vim.deepcopy(request.body)
126- if request .body then
127- if request .body .__TYPE == " json" then
128- req :setopt_postfields (request .body .data )
129- elseif request .body .__TYPE == " xml" then
130- req :setopt_postfields (request .body .data )
131- elseif request .body .__TYPE == " external" then
124+ if req .body then
125+ if req .body .__TYPE == " json" then
126+ req_ :setopt_postfields (req .body .data )
127+ elseif req .body .__TYPE == " xml" then
128+ req_ :setopt_postfields (req .body .data )
129+ elseif req .body .__TYPE == " external" then
132130 local mimetypes = require (" mimetypes" )
133- local body_mimetype = mimetypes .guess (request .body .data .path )
131+ local body_mimetype = mimetypes .guess (req .body .data .path )
134132 local post_data = {
135- [request .body .data .name and request .body .data .name or " body" ] = {
136- file = request .body .data .path ,
133+ [req .body .data .name and req .body .data .name or " body" ] = {
134+ file = req .body .data .path ,
137135 type = body_mimetype ,
138136 },
139137 }
140- req :post (post_data )
141- elseif request .body .__TYPE == " form" then
138+ req_ :post (post_data )
139+ elseif req .body .__TYPE == " form" then
142140 local form = curl .form ()
143- for k , v in pairs (request .body .data ) do
141+ for k , v in pairs (req .body .data ) do
144142 form :add_content (k , v )
145143 end
146- req :setopt_httppost (form )
144+ req_ :setopt_httppost (form )
147145 else
148- logger .error ((" '%s' type body is not supported yet" ):format (request .body .__TYPE ))
146+ logger .error ((" '%s' type body is not supported yet" ):format (req .body .__TYPE ))
149147 return
150148 end
151149 end
152150
153151 -- Request execution
154152 local res_result = {}
155- local res_headers = {}
156- req :setopt_writefunction (table.insert , res_result )
157- req :setopt_headerfunction (table.insert , res_headers )
158-
159- local ok , err = req :perform ()
160- if ok then
161- -- Get request statistics if they are enabled
162- local stats_config = config .result .behavior .statistics
163- if stats_config .enable then
164- info .statistics = get_stats (req , stats_config .stats )
165- end
153+ --- @type table<string , string[]>
154+ local res_raw_headers = {}
155+ req_ :setopt_writefunction (table.insert , res_result )
156+ req_ :setopt_headerfunction (table.insert , res_raw_headers )
166157
167- info .url = req :getinfo_effective_url ()
168- info .code = req :getinfo_response_code ()
169- info .method = req :getinfo_effective_method ()
170- info .headers = table.concat (res_headers ):gsub (" \r " , " " )
171- info .body = table.concat (res_result )
172- else
158+ local ok , err = req_ :perform ()
159+ if not ok then
173160 logger .error (" Something went wrong when making the request with cURL:\n " .. curl_utils .curl_error (err :no ()))
174161 return
175162 end
176- req :close ()
177- return info
163+ --- @diagnostic disable-next-line : invisible
164+ local status = curl_cli .parser .parse_verbose_status (table.remove (res_raw_headers , 1 ))
165+ local res_headers = {}
166+ for _ , header in ipairs (res_raw_headers ) do
167+ --- @diagnostic disable-next-line : invisible
168+ local key , value = curl_cli .parser .parse_header_pair (header )
169+ if key then
170+ if not res_headers [key ] then
171+ res_headers [key ] = {}
172+ end
173+ table.insert (res_headers [key ], value )
174+ end
175+ end
176+ --- @type rest.Response
177+ local res = {
178+ status = status ,
179+ headers = res_headers ,
180+ body = table.concat (res_result ),
181+ statistics = get_stats (req_ , {})
182+ }
183+ logger .debug (vim .inspect (res .headers ))
184+ res .status .text = vim .trim (res .status .text )
185+ req_ :close ()
186+ return res
178187end
179188
180189return client
0 commit comments