Fix parsing HTTP headers after redirects

This commit is contained in:
Tamás Bálint Misius
2025-06-04 13:57:30 +02:00
parent 9c35c537e5
commit d14d35982a

View File

@@ -63,6 +63,7 @@ namespace http
char curlErrorBuffer[CURL_ERROR_SIZE]; char curlErrorBuffer[CURL_ERROR_SIZE];
bool curlAddedToMulti = false; bool curlAddedToMulti = false;
bool gotStatusLine = false; bool gotStatusLine = false;
bool gotAllHeaders = false;
RequestHandleHttp() : RequestHandle(CtorTag{}) RequestHandleHttp() : RequestHandle(CtorTag{})
{ {
@@ -74,28 +75,47 @@ namespace http
auto bytes = size * count; auto bytes = size * count;
if (bytes >= 2 && ptr[bytes - 2] == '\r' && ptr[bytes - 1] == '\n') if (bytes >= 2 && ptr[bytes - 2] == '\r' && ptr[bytes - 1] == '\n')
{ {
if (bytes > 2 && handle->gotStatusLine) // Don't include header list terminator or the status line. if (handle->gotAllHeaders)
{ {
auto line = ByteString(ptr, ptr + bytes - 2); // Reset response headers if we see a new header arrive after seeing a header that we thought was the last.
if (auto split = line.SplitBy(':')) // This happens when a Request takes multiple HTTP requests to complete; think redirects.
// We are interested only in the response headers of the last response.
handle->responseHeaders.clear();
handle->gotStatusLine = false;
handle->gotAllHeaders = false;
}
if (bytes > 2) // Don't include header list terminator
{
if (handle->gotStatusLine) // ... or the status line.
{ {
auto value = split.After(); auto line = ByteString(ptr, ptr + bytes - 2);
while (value.size() && (value.front() == ' ' || value.front() == '\t')) if (auto split = line.SplitBy(':'))
{ {
value = value.Substr(1); auto value = split.After();
while (value.size() && (value.front() == ' ' || value.front() == '\t'))
{
value = value.Substr(1);
}
while (value.size() && (value.back() == ' ' || value.back() == '\t'))
{
value = value.Substr(0, value.size() - 1);
}
handle->responseHeaders.push_back({ split.Before().ToLower(), value });
} }
while (value.size() && (value.back() == ' ' || value.back() == '\t')) else
{ {
value = value.Substr(0, value.size() - 1); std::cerr << "skipping weird header: " << line << std::endl;
} }
handle->responseHeaders.push_back({ split.Before().ToLower(), value });
} }
else else
{ {
std::cerr << "skipping weird header: " << line << std::endl; handle->gotStatusLine = true;
} }
} }
handle->gotStatusLine = true; else
{
handle->gotAllHeaders = true;
}
return bytes; return bytes;
} }
return 0; return 0;