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());
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);
294 &aux_all_headers[0], &buf[0], content_offset);
297 aux_all_headers,
"\r\n", lstLines);
299 for (
auto i = lstLines.begin(); i != lstLines.end();
302 const size_t p = i->find(
":");
303 if (p == string::npos)
continue;
305 const string key = i->substr(0, p);
306 const string val = i->substr(p + 2);
307 rx_headers[key] =
val;
314 if (out_http_responsecode) *out_http_responsecode = http_code;
315 if (out_headers) *out_headers = rx_headers;
318 buf.erase(buf.begin(), buf.begin() + content_offset);
321 if (rx_headers.
has(
"Transfer-Encoding") &&
322 rx_headers[
"Transfer-Encoding"] ==
"chunked")
327 while (index < buf.size())
329 if (buf[index] ==
'\r' && buf[index + 1] ==
'\n')
331 buf.erase(buf.begin() + index, buf.begin() + index + 2);
335 const char* pCRLF = ::strstr((
const char*)&buf[index],
"\r\n");
338 const size_t len_substr = ((
char*)pCRLF) - (
char*)(&buf[index]);
340 string sLen((
const char*)&buf[index], len_substr);
341 sLen = string(
"0x") + sLen;
343 unsigned int lenChunk;
344 int fields = ::sscanf(sLen.c_str(),
"%x", &lenChunk);
349 buf.begin() + index, buf.begin() + index + len_substr + 2);
362 out_content.swap(buf);
364 if (http_code == 200)
370 out_errormsg =
format(
"HTTP error %i", http_code);
374 catch (
const std::exception& e)
376 out_errormsg = e.what();
387 const string&
url, std::vector<uint8_t>& out_content,
string& out_errormsg,
388 int port,
const string& auth_user,
const string& auth_pass,
389 int* out_http_responsecode,
394 "GET",
"",
url, out_content, out_errormsg, port, auth_user, auth_pass,
395 out_http_responsecode, extra_headers, out_headers, timeout_ms);
405 const std::string& server_name, std::string& out_ip,
406 const unsigned int timeout_ms)
409 if (server_name.find_first_not_of(
"0123456789. ") == std::string::npos)
412 out_ip = server_name;
420 std::future<std::string> dns_result_fut =
421 std::async(std::launch::async, [&]() {
426 WORD wVersionRequested = MAKEWORD(2, 0);
428 if (WSAStartup(wVersionRequested, &wsaData))
431 <<
"thread_DNS_solver_async: Error calling WSAStartup";
432 return std::string();
438 std::string dns_result;
440 hostent* he = gethostbyname(server_name.c_str());
452 dns_result = string(inet_ntoa(ADDR));
462 dns_result_fut.wait_for(std::chrono::milliseconds(timeout_ms));
464 if (status == std::future_status::ready)
467 out_ip = dns_result_fut.get();
468 return !out_ip.empty();
483 const int errnum = WSAGetLastError();
486 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
487 FORMAT_MESSAGE_IGNORE_INSERTS,
488 nullptr, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&s,
490 const std::string str =
mrpt::format(
"%s [errno=%d]", s, errnum);
494 return std::string(strerror(errno));
499 const std::string& address,
const int max_attempts,
500 std::string* output_str )
505 string cmd_str =
"ping";
508 #if defined(MRPT_OS_LINUX) || defined(__APPLE__)
520 #if defined(MRPT_OS_LINUX) || defined(__APPLE__)