Skip to content

Commit d5228fe

Browse files
fix(curl/cli): parse redirected response as list
Don't merge multiple responses from redirected requests into one. Parse them individually and return last response instead. `parser.parse_verbose()` method should return all request&response history in future
1 parent 4449bca commit d5228fe

File tree

2 files changed

+145
-9
lines changed

2 files changed

+145
-9
lines changed

lua/rest-nvim/client/curl/cli.lua

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,19 @@ end
118118
---@param lines string[]
119119
---@return rest.Response
120120
function parser.parse_verbose(lines)
121-
local response = {
122-
headers = {},
123-
statistics = {},
124-
}
121+
---@type rest.Response[]
122+
local list = {}
123+
---@type rest.Response
124+
local response
125125
vim.iter(lines):map(parser.parse_verbose_line):each(function(ln)
126126
if ln.prefix == VERBOSE_PREFIX_RES_HEADER then
127-
if not response.status then
128-
-- response status
129-
response.status = parser.parse_verbose_status(ln.str)
127+
if vim.startswith(ln.str, "HTTP/") then
128+
response = {
129+
status = parser.parse_verbose_status(ln.str),
130+
headers = {},
131+
statistics = {},
132+
}
133+
table.insert(list, response)
130134
else
131135
-- response header
132136
local key, value = parser.parse_header_pair(ln.str)
@@ -137,14 +141,15 @@ function parser.parse_verbose(lines)
137141
table.insert(response.headers[key], value)
138142
end
139143
end
140-
elseif ln.prefix == VERBOSE_PREFIX_STAT then
144+
elseif response and ln.prefix == VERBOSE_PREFIX_STAT then
141145
local key, value = parser.parse_stat_pair(ln.str)
142146
if key then
143147
response.statistics[key] = value
144148
end
145149
end
146150
end)
147-
return response
151+
-- TODO: return all response history
152+
return list[#list]
148153
end
149154

150155
--- Builder ---

spec/client/curl/cli_spec.lua

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,137 @@ describe("curl cli response parser", function()
161161
},
162162
}, response)
163163
end)
164+
it("Redirected response", function()
165+
local stdin = {
166+
"* Trying 34.78.67.165:80...",
167+
"* Connected to ijhttp-examples.jetbrains.com (34.78.67.165) port 80 (#0)",
168+
-- request
169+
"> POST /post HTTP/1.1",
170+
"> Host: ijhttp-examples.jetbrains.com",
171+
"> User-Agent: curl/7.81.0",
172+
"> Accept: */*",
173+
">",
174+
"* Mark bundle as not supporting multiuse",
175+
-- resopnse (301)
176+
"< HTTP/1.1 301 Moved Permanently",
177+
"< Date: Sun, 09 Feb 2025 15:25:31 GMT",
178+
"< Content-Type: text/html",
179+
"< Content-Length: 162",
180+
"< Connection: keep-alive",
181+
"< Location: http://examples.http-client.intellij.net/post",
182+
"<",
183+
"* Ignoring the response-body",
184+
"* Connection #0 to host ijhttp-examples.jetbrains.com left intact",
185+
"* Issue another request to this URL: 'http://examples.http-client.intellij.net/post'",
186+
"* Trying 34.78.67.165:80...",
187+
"* Connected to examples.http-client.intellij.net (34.78.67.165) port 80 (#1)",
188+
-- request
189+
"> POST /post HTTP/1.1",
190+
"> Host: examples.http-client.intellij.net",
191+
"> User-Agent: curl/7.81.0",
192+
"> Accept: */*",
193+
">",
194+
"* Mark bundle as not supporting multiuse",
195+
-- response (308)
196+
"< HTTP/1.1 308 Permanent Redirect",
197+
"< Date: Sun, 09 Feb 2025 15:25:32 GMT",
198+
"< Content-Type: text/html",
199+
"< Content-Length: 164",
200+
"< Connection: keep-alive",
201+
"< Location: https://examples.http-client.intellij.net/post",
202+
"<",
203+
"* Ignoring the response-body",
204+
"* Connection #1 to host examples.http-client.intellij.net left intact",
205+
"* Clear auth, redirects to port from 80 to 443",
206+
"* Issue another request to this URL: 'https://examples.http-client.intellij.net/post'",
207+
"* Trying 34.78.67.165:443...",
208+
"* Connected to examples.http-client.intellij.net (34.78.67.165) port 443 (#2)",
209+
"* ALPN, offering h2",
210+
"* ALPN, offering http/1.1",
211+
"* CAfile: /etc/ssl/certs/ca-certificates.crt",
212+
"* CApath: /etc/ssl/certs",
213+
"* TLSv1.0 (OUT), TLS header, Certificate Status (22):",
214+
"* TLSv1.3 (OUT), TLS handshake, Client hello (1):",
215+
"* TLSv1.2 (IN), TLS header, Certificate Status (22):",
216+
"* TLSv1.3 (IN), TLS handshake, Server hello (2):",
217+
"* TLSv1.2 (IN), TLS header, Finished (20):",
218+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
219+
"* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):",
220+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
221+
"* TLSv1.3 (IN), TLS handshake, Certificate (11):",
222+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
223+
"* TLSv1.3 (IN), TLS handshake, CERT verify (15):",
224+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
225+
"* TLSv1.3 (IN), TLS handshake, Finished (20):",
226+
"* TLSv1.2 (OUT), TLS header, Finished (20):",
227+
"* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):",
228+
"* TLSv1.2 (OUT), TLS header, Supplemental data (23):",
229+
"* TLSv1.3 (OUT), TLS handshake, Finished (20):",
230+
"* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384",
231+
"* ALPN, server accepted to use h2",
232+
"* Server certificate:",
233+
"* subject: CN=examples.http-client.intellij.net",
234+
"* start date: Feb 9 08:45:35 2025 GMT",
235+
"* expire date: May 10 08:45:34 2025 GMT",
236+
[[* subjectAltName: host "examples.http-client.intellij.net" matched cert's "examples.http-client.intellij.net"]],
237+
"* issuer: C=US; O=Let's Encrypt; CN=R11",
238+
"* SSL certificate verify ok.",
239+
"* Using HTTP2, server supports multiplexing",
240+
"* Connection state changed (HTTP/2 confirmed)",
241+
"* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0",
242+
"* TLSv1.2 (OUT), TLS header, Supplemental data (23):",
243+
"* TLSv1.2 (OUT), TLS header, Supplemental data (23):",
244+
"* TLSv1.2 (OUT), TLS header, Supplemental data (23):",
245+
"* Using Stream ID: 1 (easy handle 0xaf9f59cebcc0)",
246+
"* TLSv1.2 (OUT), TLS header, Supplemental data (23):",
247+
-- request
248+
"> POST /post HTTP/2",
249+
"> Host: examples.http-client.intellij.net",
250+
"> user-agent: curl/7.81.0",
251+
"> accept: */*",
252+
">",
253+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
254+
"* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):",
255+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
256+
"* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):",
257+
"* old SSL session ID is stale, removing",
258+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
259+
"* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!",
260+
"* TLSv1.2 (OUT), TLS header, Supplemental data (23):",
261+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
262+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
263+
-- response (200)
264+
"< HTTP/2 200",
265+
"< date: Sun, 09 Feb 2025 15:25:32 GMT",
266+
"< content-type: application/json",
267+
"< content-length: 419",
268+
"< vary: Accept-Encoding",
269+
"< access-control-allow-origin: https://examples.http-client.intellij.net",
270+
"< access-control-allow-credentials: true",
271+
"< strict-transport-security: max-age=31536000; includeSubDomains",
272+
"<",
273+
"* TLSv1.2 (IN), TLS header, Supplemental data (23):",
274+
"* Connection #2 to host examples.http-client.intellij.net left intact",
275+
}
276+
local response = parser.parse_verbose(stdin)
277+
assert.same({
278+
status = {
279+
version = "HTTP/2",
280+
code = 200,
281+
text = "",
282+
},
283+
statistics = {},
284+
headers = {
285+
date = { "Sun, 09 Feb 2025 15:25:32 GMT" },
286+
["content-type"] = { "application/json" },
287+
["content-length"] = { "419" },
288+
["vary"] = { "Accept-Encoding" },
289+
["access-control-allow-origin"] = { "https://examples.http-client.intellij.net" },
290+
["access-control-allow-credentials"] = { "true" },
291+
["strict-transport-security"] = { "max-age=31536000; includeSubDomains" },
292+
},
293+
}, response)
294+
end)
164295
end)
165296

166297
-- -- don't run real request on test by default

0 commit comments

Comments
 (0)