chunk encoding / simple redirect support / -I option
This commit is contained in:
		@@ -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, "");
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user