25 #if defined(MRPT_OS_LINUX) || defined(__APPLE__) 26 #define INVALID_SOCKET (-1) 27 #include <arpa/inet.h> 30 #include <netinet/in.h> 31 #include <sys/ioctl.h> 32 #include <sys/socket.h> 33 #include <sys/types.h> 52 const string&
url,
string& out_content,
string& out_errormsg,
int port,
53 const string& auth_user,
const string& auth_pass,
54 int* out_http_responsecode,
58 std::vector<uint8_t>
data;
60 url,
data, out_errormsg, port, auth_user, auth_pass,
61 out_http_responsecode, extra_headers, out_headers, timeout_ms);
63 out_content.resize(
data.size());
70 const string& http_method,
const string& http_send_content,
71 const string&
url, std::vector<uint8_t>& out_content,
string& out_errormsg,
72 int port,
const string& auth_user,
const string& auth_pass,
73 int* out_http_responsecode,
79 if (out_http_responsecode) *out_http_responsecode = 0;
80 if (out_headers) out_headers->
clear();
85 if (0 != ::strncmp(
url.c_str(),
"http://", 7))
87 out_errormsg =
"URL must start with 'http://'";
91 string server_addr =
url.substr(7);
92 string get_object =
"/";
95 size_t pos = server_addr.find(
"/");
98 out_errormsg =
"Server name not found in URL";
101 if (pos != string::npos)
103 get_object = server_addr.substr(pos);
104 server_addr.resize(pos);
112 sock.
connect(server_addr, port, timeout_ms);
114 catch (
const std::exception& e)
116 out_errormsg = e.what();
124 if (extra_headers) headers_to_send = *extra_headers;
126 headers_to_send[
"Connection"] =
"close";
128 if (!headers_to_send.
has(
"User-Agent"))
129 headers_to_send[
"User-Agent"] =
"MRPT Library";
133 if (!auth_user.empty())
135 string auth_str = auth_user +
string(
":") + auth_pass;
136 std::vector<uint8_t>
v(auth_str.size());
137 ::memcpy(&
v[0], &auth_str[0], auth_str.size());
142 headers_to_send[
"Authorization"] =
string(
"Basic ") + encoded_str;
145 if (!http_send_content.empty() &&
146 headers_to_send.
find(
"Content-Length") == headers_to_send.
end())
148 headers_to_send[
"Content-Length"] =
149 mrpt::format(
"%u", (
unsigned int)http_send_content.size());
157 http_method.c_str(), get_object.c_str(), server_addr.c_str());
160 for (
auto i = headers_to_send.
begin(); i != headers_to_send.
end(); ++i)
172 req += http_send_content;
178 std::vector<uint8_t> buf;
179 buf.reserve(1 << 14);
181 size_t total_read = 0;
182 bool content_length_read =
false;
183 bool all_headers_read =
false;
184 size_t content_length = 0;
185 size_t content_offset = 0;
192 while (!content_length_read ||
193 total_read < (content_offset + content_length))
200 if (!content_length_read)
206 to_read_now = (content_length + content_offset) - total_read;
210 buf.resize(total_read + to_read_now + 1);
214 sock.
readAsync(&buf[total_read], to_read_now, timeout_ms, 100);
220 if (all_headers_read)
224 out_errormsg =
"Connection to server was lost";
229 if (watchdog.
Tac() > 1e-3 * timeout_ms)
231 out_errormsg =
"Timeout waiting answer from server";
234 std::this_thread::sleep_for(10ms);
240 buf[total_read] =
'\0';
243 if (!all_headers_read)
245 const char* ptr = ::strstr(
246 reinterpret_cast<const char*>(&buf[0]),
"\r\n\r\n");
249 all_headers_read =
true;
250 const size_t pos_dblret = ((
char*)ptr) - (
char*)(&buf[0]);
254 if (!::strncmp(
"HTTP/", (
const char*)&buf[0], 5))
256 http_code = ::atoi((
const char*)&buf[9]);
263 "SOURCETABLE ", (
const char*)&buf[0], 12))
265 http_code = ::atoi((
const char*)&buf[12]);
270 "Server didn't send an HTTP/1.1 answer.";
276 content_offset = pos_dblret + 4;
279 const char* ptr_len = ::strstr(
280 reinterpret_cast<const char*>(&buf[0]),
284 content_length = ::atol(ptr_len + 15);
285 content_length_read =
true;
290 string aux_all_headers;
291 deque<string> lstLines;
292 aux_all_headers.resize(content_offset);
293 ::memcpy(&aux_all_headers[0], &buf[0], content_offset);
296 aux_all_headers,
"\r\n", lstLines);
298 for (
auto i = lstLines.begin(); i != lstLines.end();
301 const size_t p = i->find(
":");
302 if (
p == string::npos)
continue;
304 const string key = i->substr(0,
p);
305 const string val = i->substr(
p + 2);
306 rx_headers[key] =
val;
313 if (out_http_responsecode) *out_http_responsecode = http_code;
314 if (out_headers) *out_headers = rx_headers;
317 buf.erase(buf.begin(), buf.begin() + content_offset);
320 if (rx_headers.
has(
"Transfer-Encoding") &&
321 rx_headers[
"Transfer-Encoding"] ==
"chunked")
326 while (
index < buf.size())
328 if (buf[
index] ==
'\r' && buf[
index + 1] ==
'\n')
330 buf.erase(buf.begin() +
index, buf.begin() +
index + 2);
334 const char* pCRLF = ::strstr((
const char*)&buf[
index],
"\r\n");
337 const size_t len_substr = ((
char*)pCRLF) - (
char*)(&buf[
index]);
339 string sLen((
const char*)&buf[
index], len_substr);
340 sLen =
string(
"0x") + sLen;
342 unsigned int lenChunk;
343 int fields = ::sscanf(sLen.c_str(),
"%x", &lenChunk);
348 buf.begin() +
index, buf.begin() +
index + len_substr + 2);
361 out_content.swap(buf);
363 if (http_code == 200)
369 out_errormsg =
format(
"HTTP error %i", http_code);
373 catch (
const std::exception& e)
375 out_errormsg = e.what();
386 const string&
url, std::vector<uint8_t>& out_content,
string& out_errormsg,
387 int port,
const string& auth_user,
const string& auth_pass,
388 int* out_http_responsecode,
393 "GET",
"",
url, out_content, out_errormsg, port, auth_user, auth_pass,
394 out_http_responsecode, extra_headers, out_headers, timeout_ms);
405 const unsigned int timeout_ms)
408 if (server_name.find_first_not_of(
"0123456789. ") == std::string::npos)
411 out_ip = server_name;
419 std::future<std::string> dns_result_fut =
420 std::async(std::launch::async, [&]() {
425 WORD wVersionRequested = MAKEWORD(2, 0);
427 if (WSAStartup(wVersionRequested, &wsaData))
430 <<
"thread_DNS_solver_async: Error calling WSAStartup";
439 hostent* he = gethostbyname(server_name.c_str());
451 dns_result =
string(inet_ntoa(ADDR));
461 dns_result_fut.wait_for(std::chrono::milliseconds(timeout_ms));
463 if (
status == std::future_status::ready)
466 out_ip = dns_result_fut.get();
467 return !out_ip.empty();
482 const int errnum = WSAGetLastError();
485 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
486 FORMAT_MESSAGE_IGNORE_INSERTS,
487 nullptr, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&
s,
504 string cmd_str =
"ping";
507 #if defined(MRPT_OS_LINUX) || defined(__APPLE__) 519 #if defined(MRPT_OS_LINUX) || defined(__APPLE__) double Tac() noexcept
Stops the stopwatch.
iterator begin() noexcept
void connect(const std::string &remotePartAddress, unsigned short remotePartTCPPort, unsigned int timeout_ms=0)
Establishes a connection with a remote part.
bool isConnected()
Returns true if this objects represents a successfully connected socket.
A high-performance stopwatch, with typical resolution of nanoseconds.
std::string getLastSocketErrorStr()
Returns a description of the last Sockets error.
ERRORCODE_HTTP http_get(const string &url, std::vector< uint8_t > &out_content, string &out_errormsg, int port=80, const string &auth_user=string(), const string &auth_pass=string(), int *out_http_responsecode=nullptr, mrpt::system::TParameters< string > *extra_headers=nullptr, mrpt::system::TParameters< string > *out_headers=nullptr, int timeout_ms=1000)
Perform an HTTP GET operation (version for retrieving the data as a std::vector<uint8_t>) ...
void tokenize(const std::string &inString, const std::string &inDelimiters, OUT_CONTAINER &outTokens, bool skipBlankTokens=true) noexcept
Tokenizes a string according to a set of delimiting characters.
bool Ping(const std::string &address, const int max_attempts, std::string *output_str=nullptr)
Ping an IP address.
ERRORCODE_HTTP
Possible returns from a HTTP request.
bool has(const std::string &s) const
bool DNS_resolve_async(const std::string &server_name, std::string &out_ip, const unsigned int timeout_ms=3000)
Resolve a server address by its name, returning its IP address as a string - This method has a timeou...
GLsizei const GLchar ** string
iterator find(const std::string &key)
int executeCommand(const std::string &command, std::string *output=nullptr, const std::string &mode="r")
Execute Generic Shell Command.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void encodeBase64(const std::vector< uint8_t > &inputData, std::string &outString)
Encode a sequence of bytes as a string in base-64.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
A TCP socket that can be connected to a TCP server, implementing MRPT's CStream interface for passing...
ERRORCODE_HTTP http_request(const string &http_method, const string &http_send_content, const string &url, std::vector< uint8_t > &out_content, string &out_errormsg, int port=80, const string &auth_user=string(), const string &auth_pass=string(), int *out_http_responsecode=nullptr, mrpt::system::TParameters< string > *extra_headers=nullptr, mrpt::system::TParameters< string > *out_headers=nullptr, int timeout_ms=1000)
Generic function for HTTP GET & POST methods.
A set of useful routines for networking.
std::string std::string to_string(T v)
Just like std::to_string(), but with an overloaded version for std::string arguments.
Serial and networking devices and utilities.
void Tic() noexcept
Starts the stopwatch.
size_t readAsync(void *Buffer, const size_t Count, const int timeoutStart_ms=-1, const int timeoutBetween_ms=-1)
A method for reading from the socket with an optional timeout.
For usage when passing a dynamic number of (numeric) arguments to a function, by name.
GLsizei GLsizei GLenum GLenum const GLvoid * data
void sendString(const std::string &str)
Writes a string to the socket.
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".