4848--- @private
4949local parser = {}
5050
51+ --- @class rest.Result
52+ --- @field requests rest.Response_[]
53+ --- @field statistics table<string,string> Response statistics
54+
55+ --- @class rest.Response_
56+ --- @field request rest.RequestCore
57+ --- @field response rest.Response
58+
59+ --- @class rest.RequestCore
60+ --- @field method string
61+ --- @field url string
62+ --- @field http_version string
63+ --- @field headers table<string,string[]>
64+
5165--- @package
5266--- @param str string
53- --- @return rest.Response.status
54- function parser .parse_verbose_status (str )
55- local version , code , text = str :match (" ^(%S+) (%d+) ?(.*)" )
67+ --- @return rest.RequestCore ?
68+ function parser .parse_req_info (str )
69+ local method , url , version = str :match (" ^([A-Z]+) (.+) (HTTP/[%d%.]+)" )
70+ if not method then
71+ return
72+ end
73+ return {
74+ method = method ,
75+ url = url ,
76+ http_version = version ,
77+ headers = {},
78+ }
79+ end
80+
81+ function parser .parse_req_header (str , requests )
82+ local info = parser .parse_req_info (str )
83+ if info then
84+ table.insert (requests , {
85+ request = info ,
86+ response = {},
87+ })
88+ return
89+ end
90+ local req = requests [# requests ].request
91+ local key , value = parser .parse_header_pair (str )
92+ if key then
93+ if not req .headers [key ] then
94+ req .headers [key ] = {}
95+ end
96+ table.insert (req .headers [key ], value )
97+ else
98+ log .error (" Error while parsing verbose curl output header:" , str )
99+ end
100+ end
101+
102+ --- @package
103+ --- @param str string
104+ --- @return rest.Response.status ?
105+ function parser .parse_res_status (str )
106+ local version , code , text = str :match (" ^(HTTP/[%d%.]+) (%d+) ?(.*)" )
107+ if not version then
108+ return
109+ end
56110 return {
57111 version = version ,
58112 code = tonumber (code ),
@@ -73,22 +127,49 @@ function parser.parse_header_pair(str)
73127end
74128
75129--- @package
130+ --- @param str string
131+ function parser .parse_res_header (str , requests )
132+ local status = parser .parse_res_status (str )
133+ if status then
134+ -- reset response object
135+ requests [# requests ].response = {
136+ status = status ,
137+ headers = {},
138+ }
139+ return
140+ end
141+ local res = requests [# requests ].response
142+ local key , value = parser .parse_header_pair (str )
143+ if key then
144+ if not res .headers [key ] then
145+ res .headers [key ] = {}
146+ end
147+ table.insert (res .headers [key ], value )
148+ else
149+ log .error (" Error while parsing verbose curl output header:" , str )
150+ end
151+ end
152+
153+ --- @package
154+ --- @param idx number
76155--- @param line string
77- --- @return { prefix : string,str : string ?}| nil
78- function parser .parse_verbose_line ( line )
156+ --- @return { idx : number, prefix: string,str : string ?}| nil
157+ function parser .lex_verbose_line ( idx , line )
79158 local prefix , str = line :match (" (.) ?(.*)" )
159+ log .debug (" line" , idx , line )
80160 if not prefix then
81- log .error (" Error while parsing verbose curl output: \n " .. line )
161+ log .error (( " Error while parsing verbose curl output at line %d: " ): format ( idx ), line )
82162 return
83163 end
84164 return {
165+ idx = idx ,
85166 prefix = prefix ,
86167 str = str ,
87168 }
88169end
89170
90171local _VERBOSE_PREFIX_META = " *"
91- local _VERBOSE_PREFIX_REQ_HEADER = " >"
172+ local VERBOSE_PREFIX_REQ_HEADER = " >"
92173local _VERBOSE_PREFIX_REQ_BODY = " }"
93174local VERBOSE_PREFIX_RES_HEADER = " <"
94175-- NOTE: we don't parse response body with trace output. response body will
@@ -114,35 +195,32 @@ function parser.parse_stat_pair(str)
114195end
115196
116197--- @param lines string[]
117- --- @return rest.Response
198+ --- @return rest.Result
118199function parser .parse_verbose (lines )
119- local response = {
120- headers = {},
200+ --- @type rest.Result
201+ local result = {
202+ --- @type rest.Response_[]
203+ requests = {},
204+ --- @type table<string,string> Response statistics
121205 statistics = {},
122206 }
123- vim .iter (lines ):map (parser .parse_verbose_line ):each (function (ln )
124- if ln .prefix == VERBOSE_PREFIX_RES_HEADER then
125- if not response .status then
126- -- response status
127- response .status = parser .parse_verbose_status (ln .str )
128- else
129- -- response header
130- local key , value = parser .parse_header_pair (ln .str )
131- if key then
132- if not response .headers [key ] then
133- response .headers [key ] = {}
134- end
135- table.insert (response .headers [key ], value )
136- end
137- end
207+ -- ignore last newline
208+ if lines [# lines ] == " " then
209+ lines [# lines ] = nil
210+ end
211+ vim .iter (lines ):enumerate ():map (parser .lex_verbose_line ):each (function (ln )
212+ if ln .prefix == VERBOSE_PREFIX_REQ_HEADER then
213+ parser .parse_req_header (ln .str , result .requests )
214+ elseif ln .prefix == VERBOSE_PREFIX_RES_HEADER then
215+ parser .parse_res_header (ln .str , result .requests )
138216 elseif ln .prefix == VERBOSE_PREFIX_STAT then
139217 local key , value = parser .parse_stat_pair (ln .str )
140218 if key then
141- response .statistics [key ] = value
219+ result .statistics [key ] = value
142220 end
143221 end
144222 end )
145- return response
223+ return result
146224end
147225
148226--- Builder ---
332410
333411--- Send request via `curl` cli
334412--- @param request rest.Request Request data to be passed to cURL
335- --- @return nio.control.Future future Future containing rest.Response
413+ --- @return nio.control.Future future Future containing rest.Result
336414function curl .request (request )
337415 local progress_handle = progress .handle .create ({
338416 title = " Executing" ,
@@ -354,9 +432,9 @@ function curl.request(request)
354432 progress_handle :report ({
355433 message = " Parsing response..." ,
356434 })
357- local response = parser .parse_verbose (vim .split (sc .stderr , " \n " ))
358- response .body = sc .stdout
359- future .set (response )
435+ local result = parser .parse_verbose (vim .split (sc .stderr , " \n " ))
436+ result . requests [ # result . requests ]. response .body = sc .stdout
437+ future .set (result )
360438 progress_handle :report ({
361439 message = " Success" ,
362440 })
0 commit comments