diff --git a/ixwebsocket/IXHttpClient.cpp b/ixwebsocket/IXHttpClient.cpp index 04ee57a8..1646a4ba 100644 --- a/ixwebsocket/IXHttpClient.cpp +++ b/ixwebsocket/IXHttpClient.cpp @@ -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, ""); diff --git a/ws/ws.cpp b/ws/ws.cpp index f334fd76..91020163 100644 --- a/ws/ws.cpp +++ b/ws/ws.cpp @@ -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; diff --git a/ws/ws_http_client.cpp b/ws/ws_http_client.cpp index 88cf3d5c..a456e74d 100644 --- a/ws/ws_http_client.cpp +++ b/ws/ws_http_client.cpp @@ -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; }