25 #if defined(MRPT_OS_LINUX) || defined(__APPLE__)
26 #define INVALID_SOCKET (-1)
27 #include <sys/socket.h>
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
34 #include <arpa/inet.h>
35 #include <netinet/in.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 (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());
161 i != headers_to_send.end(); ++i)
173 req += http_send_content;
179 std::vector<uint8_t> buf;
180 buf.reserve(1 << 14);
182 size_t total_read = 0;
183 bool content_length_read =
false;
184 bool all_headers_read =
false;
185 size_t content_length = 0;
186 size_t content_offset = 0;
193 while (!content_length_read ||
194 total_read < (content_offset + content_length))
201 if (!content_length_read)
207 to_read_now = (content_length + content_offset) - total_read;
211 buf.resize(total_read + to_read_now + 1);
215 sock.
readAsync(&buf[total_read], to_read_now, timeout_ms, 100);
221 if (all_headers_read)
225 out_errormsg =
"Connection to server was lost";
230 if (watchdog.
Tac() > 1e-3 * timeout_ms)
232 out_errormsg =
"Timeout waiting answer from server";
235 std::this_thread::sleep_for(10ms);
241 buf[total_read] =
'\0';
244 if (!all_headers_read)
246 const char* ptr = ::strstr(
247 reinterpret_cast<const char*
>(&buf[0]),
"\r\n\r\n");
250 all_headers_read =
true;
251 const size_t pos_dblret = ((
char*)ptr) - (
char*)(&buf[0]);
255 if (!::strncmp(
"HTTP/", (
const char*)&buf[0], 5))
257 http_code = ::atoi((
const char*)&buf[9]);
264 "SOURCETABLE ", (
const char*)&buf[0], 12))
266 http_code = ::atoi((
const char*)&buf[12]);
271 "Server didn't send an HTTP/1.1 answer.";
277 content_offset = pos_dblret + 4;
280 const char* ptr_len = ::strstr(
281 reinterpret_cast<const char*
>(&buf[0]),
285 content_length = ::atol(ptr_len + 15);
286 content_length_read =
true;
291 string aux_all_headers;
292 deque<string> lstLines;
293 aux_all_headers.resize(content_offset);
294 ::memcpy(&aux_all_headers[0], &buf[0], content_offset);
297 aux_all_headers,
"\r\n", lstLines);
300 i != lstLines.end(); ++i)
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 (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);
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";
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,
505 string cmd_str =
"ping";
508 #if defined(MRPT_OS_LINUX) || defined(__APPLE__)
520 #if defined(MRPT_OS_LINUX) || defined(__APPLE__)