chunk encoding / simple redirect support / -I option

This commit is contained in:
Benjamin Sergeant 2019-02-25 21:50:42 -08:00
parent b563541b14
commit 069eccf415
3 changed files with 107 additions and 32 deletions

View File

@ -117,7 +117,7 @@ namespace ix
ss << "\r\n";
}
std::string request(ss.str());
std::string req(ss.str());
int timeoutSecs = 10;
@ -138,14 +138,14 @@ namespace ix
{
std::cout << "Sending " << verb << " request "
<< "to " << host << ":" << port << std::endl
<< "request size: " << request.size() << " bytes"
<< "request size: " << req.size() << " bytes"
<< "=============" << std::endl
<< request
<< req
<< "=============" << std::endl
<< std::endl;
}
if (!_socket->writeBytes(request, isCancellationRequested))
if (!_socket->writeBytes(req, isCancellationRequested))
{
code = 0; // 0 ?
std::string errorMsg("Cannot send request");
@ -187,34 +187,102 @@ namespace ix
return std::make_tuple(code, headers, payload, errorMsg);
}
// Parse response:
// http://bryce-thomas.blogspot.com/2012/01/technical-parsing-http-to-extract.html
if (headers.find("content-length") == headers.end())
// Redirect ?
if (code == 301)
{
code = 0; // 0 ?
std::string errorMsg("No content length header");
return std::make_tuple(code, headers, payload, errorMsg);
}
ssize_t contentLength = -1;
ss.str("");
ss << headers["content-length"];
ss >> contentLength;
payload.reserve(contentLength);
// FIXME: very inefficient way to read bytes, but it works...
for (int i = 0; i < contentLength; ++i)
{
char c;
if (!_socket->readByte(&c, isCancellationRequested))
if (headers.find("location") == headers.end())
{
ss.str("");
ss << "Cannot read byte";
return std::make_tuple(-1, headers, payload, ss.str());
code = 0; // 0 ?
std::string errorMsg("Missing location header for redirect");
return std::make_tuple(code, headers, payload, errorMsg);
}
payload += c;
std::string location = headers["location"];
return request(location, verb, extraHeaders, httpParameters, verbose);
}
// Parse response:
// http://bryce-thomas.blogspot.com/2012/01/technical-parsing-http-to-extract.html
if (headers.find("content-length") != headers.end())
{
ssize_t contentLength = -1;
ss.str("");
ss << headers["content-length"];
ss >> contentLength;
payload.reserve(contentLength);
// FIXME: very inefficient way to read bytes, but it works...
for (int i = 0; i < contentLength; ++i)
{
char c;
if (!_socket->readByte(&c, isCancellationRequested))
{
ss.str("");
ss << "Cannot read byte";
return std::make_tuple(-1, headers, payload, ss.str());
}
payload += c;
}
}
else if (headers.find("transfer-encoding") != headers.end() &&
headers["transfer-encoding"] == "chunked")
{
std::stringstream ss;
while (true)
{
lineResult = _socket->readLine(isCancellationRequested);
line = lineResult.second;
if (!lineResult.first)
{
code = 0; // 0 ?
std::string errorMsg("Cannot read http body");
return std::make_tuple(code, headers, payload, errorMsg);
}
uint64_t chunkSize;
ss.str("");
ss << std::hex << line;
ss >> chunkSize;
payload.reserve(payload.size() + chunkSize);
// Read another line
for (uint64_t i = 0; i < chunkSize; ++i)
{
char c;
if (!_socket->readByte(&c, isCancellationRequested))
{
ss.str("");
ss << "Cannot read byte";
return std::make_tuple(-1, headers, payload, ss.str());
}
payload += c;
}
lineResult = _socket->readLine(isCancellationRequested);
if (!lineResult.first)
{
code = 0; // 0 ?
std::string errorMsg("Cannot read http body");
return std::make_tuple(code, headers, payload, errorMsg);
}
if (chunkSize == 0) break;
}
}
else
{
code = 0; // 0 ?
std::string errorMsg("Cannot read http body");
return std::make_tuple(code, headers, payload, errorMsg);
}
return std::make_tuple(code, headers, payload, "");

View File

@ -19,7 +19,8 @@ namespace ix
{
int ws_http_client_main(const std::string& url,
const std::string& headers,
const std::string& data);
const std::string& data,
bool headersOnly);
int ws_ping_pong_main(const std::string& url);
@ -51,6 +52,7 @@ int main(int argc, char** argv)
std::string user;
std::string data;
std::string headers;
bool headersOnly = false;
int port = 8080;
CLI::App* sendApp = app.add_subcommand("send", "Send a file");
@ -85,6 +87,7 @@ int main(int argc, char** argv)
httpClientApp->add_option("-d", data, "Form data")->join();
httpClientApp->add_option("-F", data, "Form data")->join();
httpClientApp->add_option("-H", headers, "Header")->join();
httpClientApp->add_flag("-I", headersOnly, "Header");
CLI11_PARSE(app, argc, argv);
@ -126,7 +129,7 @@ int main(int argc, char** argv)
else if (app.got_subcommand("http_client"))
{
std::cout << "data: " << data << std::endl;
return ix::ws_http_client_main(url, headers, data);
return ix::ws_http_client_main(url, headers, data, headersOnly);
}
return 1;

View File

@ -67,7 +67,8 @@ namespace ix
int ws_http_client_main(const std::string& url,
const std::string& headersData,
const std::string& data)
const std::string& data,
bool headersOnly)
{
HttpParameters httpParameters = parsePostParameters(data);
WebSocketHttpHeaders headers = parseHeaders(headersData);
@ -99,7 +100,10 @@ namespace ix
std::cout << "error message: " << errorMsg << std::endl;
}
std::cout << "payload: " << payload << std::endl;
if (!headersOnly)
{
std::cout << "payload: " << payload << std::endl;
}
return 0;
}