2019-03-01 06:54:03 +01:00
|
|
|
/*
|
|
|
|
* http_client.cpp
|
|
|
|
* Author: Benjamin Sergeant
|
|
|
|
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <ixwebsocket/IXHttpClient.h>
|
2019-09-30 03:29:51 +02:00
|
|
|
#include <ixwebsocket/IXSocketTLSOptions.h>
|
2019-10-01 02:52:39 +02:00
|
|
|
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
|
2019-12-25 06:55:34 +01:00
|
|
|
#include <spdlog/spdlog.h>
|
2019-09-23 19:25:23 +02:00
|
|
|
#include <sstream>
|
2019-03-01 06:54:03 +01:00
|
|
|
|
|
|
|
namespace ix
|
|
|
|
{
|
|
|
|
std::string extractFilename(const std::string& path)
|
|
|
|
{
|
|
|
|
std::string::size_type idx;
|
|
|
|
|
|
|
|
idx = path.rfind('/');
|
|
|
|
if (idx != std::string::npos)
|
|
|
|
{
|
2019-09-23 19:25:23 +02:00
|
|
|
std::string filename = path.substr(idx + 1);
|
2019-03-01 06:54:03 +01:00
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WebSocketHttpHeaders parseHeaders(const std::string& data)
|
|
|
|
{
|
|
|
|
WebSocketHttpHeaders headers;
|
|
|
|
|
|
|
|
// Split by \n
|
|
|
|
std::string token;
|
|
|
|
std::stringstream tokenStream(data);
|
|
|
|
|
|
|
|
while (std::getline(tokenStream, token))
|
|
|
|
{
|
|
|
|
std::size_t pos = token.rfind(':');
|
|
|
|
|
|
|
|
// Bail out if last '.' is found
|
|
|
|
if (pos == std::string::npos) continue;
|
|
|
|
|
|
|
|
auto key = token.substr(0, pos);
|
2019-09-23 19:25:23 +02:00
|
|
|
auto val = token.substr(pos + 1);
|
2019-03-01 06:54:03 +01:00
|
|
|
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("{}: {}", key, val);
|
2019-03-01 06:54:03 +01:00
|
|
|
headers[key] = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
return headers;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Useful endpoint to test HTTP post
|
|
|
|
// https://postman-echo.com/post
|
|
|
|
//
|
|
|
|
HttpParameters parsePostParameters(const std::string& data)
|
|
|
|
{
|
|
|
|
HttpParameters httpParameters;
|
|
|
|
|
|
|
|
// Split by \n
|
|
|
|
std::string token;
|
|
|
|
std::stringstream tokenStream(data);
|
|
|
|
|
|
|
|
while (std::getline(tokenStream, token))
|
|
|
|
{
|
|
|
|
std::size_t pos = token.rfind('=');
|
|
|
|
|
|
|
|
// Bail out if last '.' is found
|
|
|
|
if (pos == std::string::npos) continue;
|
|
|
|
|
|
|
|
auto key = token.substr(0, pos);
|
2019-09-23 19:25:23 +02:00
|
|
|
auto val = token.substr(pos + 1);
|
2019-03-01 06:54:03 +01:00
|
|
|
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("{}: {}", key, val);
|
2019-03-01 06:54:03 +01:00
|
|
|
httpParameters[key] = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
return httpParameters;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ws_http_client_main(const std::string& url,
|
|
|
|
const std::string& headersData,
|
|
|
|
const std::string& data,
|
|
|
|
bool headersOnly,
|
|
|
|
int connectTimeout,
|
|
|
|
int transferTimeout,
|
|
|
|
bool followRedirects,
|
|
|
|
int maxRedirects,
|
|
|
|
bool verbose,
|
|
|
|
bool save,
|
|
|
|
const std::string& output,
|
2019-09-30 03:29:51 +02:00
|
|
|
bool compress,
|
|
|
|
const ix::SocketTLSOptions& tlsOptions)
|
2019-03-01 06:54:03 +01:00
|
|
|
{
|
2019-06-06 02:04:24 +02:00
|
|
|
HttpClient httpClient;
|
2019-09-30 06:13:11 +02:00
|
|
|
httpClient.setTLSOptions(tlsOptions);
|
|
|
|
|
2019-06-06 02:04:24 +02:00
|
|
|
auto args = httpClient.createRequest();
|
|
|
|
args->extraHeaders = parseHeaders(headersData);
|
|
|
|
args->connectTimeout = connectTimeout;
|
|
|
|
args->transferTimeout = transferTimeout;
|
|
|
|
args->followRedirects = followRedirects;
|
|
|
|
args->maxRedirects = maxRedirects;
|
|
|
|
args->verbose = verbose;
|
|
|
|
args->compress = compress;
|
2019-12-25 06:55:34 +01:00
|
|
|
args->logger = [](const std::string& msg) { spdlog::info(msg); };
|
2020-05-30 01:49:29 +02:00
|
|
|
args->onProgressCallback = [verbose](int current, int total) -> bool {
|
|
|
|
if (verbose)
|
|
|
|
{
|
|
|
|
spdlog::info("Downloaded {} bytes out of {}", current, total);
|
|
|
|
}
|
2019-03-03 06:11:16 +01:00
|
|
|
return true;
|
|
|
|
};
|
2019-03-01 06:54:03 +01:00
|
|
|
|
|
|
|
HttpParameters httpParameters = parsePostParameters(data);
|
|
|
|
|
2019-06-06 02:04:24 +02:00
|
|
|
HttpResponsePtr response;
|
2019-03-01 06:54:03 +01:00
|
|
|
if (headersOnly)
|
|
|
|
{
|
2019-06-04 07:12:52 +02:00
|
|
|
response = httpClient.head(url, args);
|
2019-03-01 06:54:03 +01:00
|
|
|
}
|
|
|
|
else if (data.empty())
|
|
|
|
{
|
2019-06-04 07:12:52 +02:00
|
|
|
response = httpClient.get(url, args);
|
2019-03-01 06:54:03 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-04 07:12:52 +02:00
|
|
|
response = httpClient.post(url, httpParameters, args);
|
2019-03-01 06:54:03 +01:00
|
|
|
}
|
|
|
|
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("");
|
2019-03-03 06:11:16 +01:00
|
|
|
|
2019-06-06 02:04:24 +02:00
|
|
|
for (auto it : response->headers)
|
2019-03-01 06:54:03 +01:00
|
|
|
{
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("{}: {}", it.first, it.second);
|
2019-03-01 06:54:03 +01:00
|
|
|
}
|
|
|
|
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("Upload size: {}", response->uploadSize);
|
|
|
|
spdlog::info("Download size: {}", response->downloadSize);
|
2019-03-01 06:54:03 +01:00
|
|
|
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("Status: {}", response->statusCode);
|
2019-06-06 02:04:24 +02:00
|
|
|
if (response->errorCode != HttpErrorCode::Ok)
|
2019-03-01 06:54:03 +01:00
|
|
|
{
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("error message: ", response->errorMsg);
|
2019-03-01 06:54:03 +01:00
|
|
|
}
|
|
|
|
|
2019-06-06 02:04:24 +02:00
|
|
|
if (!headersOnly && response->errorCode == HttpErrorCode::Ok)
|
2019-03-01 06:54:03 +01:00
|
|
|
{
|
|
|
|
if (save || !output.empty())
|
|
|
|
{
|
|
|
|
// FIMXE we should decode the url first
|
|
|
|
std::string filename = extractFilename(url);
|
|
|
|
if (!output.empty())
|
|
|
|
{
|
|
|
|
filename = output;
|
|
|
|
}
|
|
|
|
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("Writing to disk: {}", filename);
|
2019-03-01 06:54:03 +01:00
|
|
|
std::ofstream out(filename);
|
2019-09-23 19:25:23 +02:00
|
|
|
out.write((char*) &response->payload.front(), response->payload.size());
|
2019-03-01 06:54:03 +01:00
|
|
|
out.close();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-06 02:04:24 +02:00
|
|
|
if (response->headers["Content-Type"] != "application/octet-stream")
|
2019-03-01 06:54:03 +01:00
|
|
|
{
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("payload: {}", response->payload);
|
2019-03-01 06:54:03 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-25 06:55:34 +01:00
|
|
|
spdlog::info("Binary output can mess up your terminal.");
|
|
|
|
spdlog::info("Use the -O flag to save the file to disk.");
|
|
|
|
spdlog::info("You can also use the --output option to specify a filename.");
|
2019-03-01 06:54:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-09-23 19:25:23 +02:00
|
|
|
} // namespace ix
|