Monero
Loading...
Searching...
No Matches
http_client.h
Go to the documentation of this file.
1// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above copyright
9// notice, this list of conditions and the following disclaimer in the
10// documentation and/or other materials provided with the distribution.
11// * Neither the name of the Andrey N. Sabelnikov nor the
12// names of its contributors may be used to endorse or promote products
13// derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
19// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25//
26
27
28
29#pragma once
30#include <ctype.h>
31#include <boost/shared_ptr.hpp>
32#include <boost/regex.hpp>
33#include <boost/optional/optional.hpp>
34#include <boost/utility/string_ref.hpp>
35//#include <mbstring.h>
36#include <algorithm>
37#include <cctype>
38#include <functional>
39
40#include "net_helper.h"
41#include "http_client_base.h"
42#include "string_tools.h"
44#include "reg_exp_definer.h"
46#include "http_base.h"
47#include "http_auth.h"
48#include "net_parse_helpers.h"
49#include "syncobj.h"
50
51//#include "shlwapi.h"
52
53//#pragma comment(lib, "shlwapi.lib")
54
55#undef MONERO_DEFAULT_LOG_CATEGORY
56#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
57
59
60
61namespace epee
62{
63namespace net_utils
64{
65
66 /*struct url
67 {
68 public:
69 void parse(const std::string& url_s)
70 {
71 const string prot_end("://");
72 string::const_iterator prot_i = search(url_s.begin(), url_s.end(),
73 prot_end.begin(), prot_end.end());
74 protocol_.reserve(distance(url_s.begin(), prot_i));
75 transform(url_s.begin(), prot_i,
76 back_inserter(protocol_),
77 ptr_fun<int,int>(tolower)); // protocol is icase
78 if( prot_i == url_s.end() )
79 return;
80 advance(prot_i, prot_end.length());
81 string::const_iterator path_i = find(prot_i, url_s.end(), '/');
82 host_.reserve(distance(prot_i, path_i));
83 transform(prot_i, path_i,
84 back_inserter(host_),
85 ptr_fun<int,int>(tolower)); // host is icase
86 string::const_iterator query_i = find(path_i, url_s.end(), '?');
87 path_.assign(path_i, query_i);
88 if( query_i != url_s.end() )
89 ++query_i;
90 query_.assign(query_i, url_s.end());
91 }
92
93 std::string protocol_;
94 std::string host_;
95 std::string path_;
96 std::string query_;
97 };*/
98
99
100
101
102 //---------------------------------------------------------------------------
103 namespace http
104 {
105
106 template<typename net_client_type>
108 {
109 private:
119
120
121
128
129
130 net_client_type m_net_client;
131 std::string m_host_buff;
132 std::string m_port;
134 std::string m_header_cache;
138 //std::string* m_ptarget_buffer;
139 boost::shared_ptr<i_sub_handler> m_pcontent_encoding_handler;
142 std::string m_chunked_cache;
145
146 public:
149 , m_net_client()
150 , m_host_buff()
151 , m_port()
152 , m_auth()
156 , m_len_in_remain(0)
158 , m_state()
162 , m_lock()
163 {}
164
165 const std::string &get_host() const { return m_host_buff; };
166 const std::string &get_port() const { return m_port; };
167
169
170 void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect) override
171 {
173 disconnect();
174 m_host_buff = std::move(host);
175 m_port = std::move(port);
176 m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
177 m_net_client.set_ssl(std::move(ssl_options));
178 }
179
180 void set_auto_connect(bool auto_connect) override
181 {
182 m_auto_connect = auto_connect;
183 }
184
185 template<typename F>
186 void set_connector(F connector)
187 {
189 m_net_client.set_connector(std::move(connector));
190 }
191
192 bool connect(std::chrono::milliseconds timeout) override
193 {
195 return m_net_client.connect(m_host_buff, m_port, timeout);
196 }
197 //---------------------------------------------------------------------------
198 bool disconnect() override
199 {
201 return m_net_client.disconnect();
202 }
203 //---------------------------------------------------------------------------
204 bool is_connected(bool *ssl = NULL) override
205 {
207 return m_net_client.is_connected(ssl);
208 }
209 //---------------------------------------------------------------------------
210 virtual bool handle_target_data(std::string& piece_of_transfer) override
211 {
213 m_response_info.m_body += piece_of_transfer;
214 piece_of_transfer.clear();
215 return true;
216 }
217 //---------------------------------------------------------------------------
218 virtual bool on_header(const http_response_info &headers)
219 {
220 return true;
221 }
222 //---------------------------------------------------------------------------
223 inline bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
224 {
226 return invoke(uri, "GET", body, timeout, ppresponse_info, additional_params);
227 }
228
229 //---------------------------------------------------------------------------
230 inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
231 {
233 if(!is_connected())
234 {
235 if (!m_auto_connect)
236 {
237 MWARNING("Auto connect attempt to " << m_host_buff << ":" << m_port << " disabled");
238 return false;
239 }
240 MDEBUG("Reconnecting...");
241 if(!connect(timeout))
242 {
243 MDEBUG("Failed to connect to " << m_host_buff << ":" << m_port);
244 return false;
245 }
246 }
247
248 std::string req_buff{};
249 req_buff.reserve(2048);
250 req_buff.append(method.data(), method.size()).append(" ").append(uri.data(), uri.size()).append(" HTTP/1.1\r\n");
251 add_field(req_buff, "Host", m_host_buff);
252 add_field(req_buff, "Content-Length", std::to_string(body.size()));
253
254 //handle "additional_params"
255 for(const auto& field : additional_params)
256 add_field(req_buff, field);
257
258 for (unsigned sends = 0; sends < 2; ++sends)
259 {
260 const std::size_t initial_size = req_buff.size();
261 const auto auth = m_auth.get_auth_field(method, uri);
262 if (auth)
263 add_field(req_buff, *auth);
264
265 req_buff += "\r\n";
266 //--
267
268 bool res = m_net_client.send(req_buff, timeout);
269 CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
270 if(body.size())
271 res = m_net_client.send(body, timeout);
272 CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
273
274 m_response_info.clear();
276 if (!handle_reciev(timeout))
277 return false;
278 if (m_response_info.m_response_code != 401)
279 {
280 if(ppresponse_info)
281 *ppresponse_info = std::addressof(m_response_info);
282 return true;
283 }
284
285 switch (m_auth.handle_401(m_response_info))
286 {
288 break;
290 sends = 2;
291 break;
292 default:
294 LOG_ERROR("Bad server response for authentication");
295 return false;
296 }
297 req_buff.resize(initial_size); // rollback for new auth generation
298 }
299 LOG_ERROR("Client has incorrect username/password for server requiring authentication");
300 return false;
301 }
302 //---------------------------------------------------------------------------
303 inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
304 {
306 return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params);
307 }
308 //---------------------------------------------------------------------------
309 bool test(const std::string &s, std::chrono::milliseconds timeout) // TEST FUNC ONLY
310 {
312 m_net_client.set_test_data(s);
314 return handle_reciev(timeout);
315 }
316 //---------------------------------------------------------------------------
317 uint64_t get_bytes_sent() const override
318 {
319 return m_net_client.get_bytes_sent();
320 }
321 //---------------------------------------------------------------------------
323 {
324 return m_net_client.get_bytes_received();
325 }
326 //---------------------------------------------------------------------------
328 {
329 m_response_info.wipe();
330 }
331 //---------------------------------------------------------------------------
332 private:
333 //---------------------------------------------------------------------------
334 inline bool handle_reciev(std::chrono::milliseconds timeout)
335 {
337 bool keep_handling = true;
338 bool need_more_data = true;
339 std::string recv_buffer;
340 while(keep_handling)
341 {
342 if(need_more_data)
343 {
344 if(!m_net_client.recv(recv_buffer, timeout))
345 {
346 MERROR("Unexpected recv fail");
348 }
349 if(!recv_buffer.size())
350 {
351 //connection is going to be closed
353 {
355 }
356 }
357 need_more_data = false;
358 }
359 switch(m_state)
360 {
362 keep_handling = handle_header(recv_buffer, need_more_data);
363 break;
365 keep_handling = handle_body_content_len(recv_buffer, need_more_data);
366 break;
368 keep_handling = handle_body_connection_close(recv_buffer, need_more_data);
369 break;
371 keep_handling = handle_body_body_chunked(recv_buffer, need_more_data);
372 break;
374 keep_handling = false;
375 break;
377 keep_handling = false;
378 break;
379 }
380
381 }
382 m_header_cache.clear();
384 {
385 if(m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection))
386 disconnect();
387
388 return true;
389 }
390 else
391 {
392 LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state);
393 return false;
394 }
395 }
396 //---------------------------------------------------------------------------
397 inline
398 bool handle_header(std::string& recv_buff, bool& need_more_data)
399 {
400
402 if(!recv_buff.size())
403 {
404 LOG_ERROR("Connection closed at handle_header");
406 return false;
407 }
408
409 m_header_cache += recv_buff;
410 recv_buff.clear();
411 std::string::size_type pos = m_header_cache.find("\r\n\r\n");
412 if(pos != std::string::npos)
413 {
414 recv_buff.assign(m_header_cache.begin()+pos+4, m_header_cache.end());
415 m_header_cache.erase(m_header_cache.begin()+pos+4, m_header_cache.end());
416
419 {
420 MDEBUG("Connection cancelled by on_header");
422 return false;
423 }
424 m_header_cache.clear();
425 if(!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done))
426 need_more_data = true;
427
428 return true;
429 }else
430 need_more_data = true;
431 return true;
432 }
433 //---------------------------------------------------------------------------
434 inline
435 bool handle_body_content_len(std::string& recv_buff, bool& need_more_data)
436 {
438 if(!recv_buff.size())
439 {
440 MERROR("Warning: Content-Len mode, but connection unexpectedly closed");
442 return true;
443 }
444 CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()");
445 m_len_in_remain -= recv_buff.size();
446 if (!m_pcontent_encoding_handler->update_in(recv_buff))
447 {
449 return false;
450 }
451
452 if(m_len_in_remain == 0)
454 else
455 need_more_data = true;
456
457 return true;
458 }
459 //---------------------------------------------------------------------------
460 inline
461 bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data)
462 {
464 if(!recv_buff.size())
465 {
467 return true;
468 }
469 need_more_data = true;
470 m_pcontent_encoding_handler->update_in(recv_buff);
471
472
473 return true;
474 }
475 //---------------------------------------------------------------------------
476 inline bool is_hex_symbol(char ch)
477 {
478
479 if( (ch >= '0' && ch <='9')||(ch >= 'A' && ch <='F')||(ch >= 'a' && ch <='f'))
480 return true;
481 else
482 return false;
483 }
484 //---------------------------------------------------------------------------
485 inline
486 bool get_len_from_chunk_head(const std::string &chunk_head, size_t& result_size)
487 {
488 std::stringstream str_stream;
489 str_stream << std::hex;
490 if(!(str_stream << chunk_head && str_stream >> result_size))
491 return false;
492
493 return true;
494 }
495 //---------------------------------------------------------------------------
496 inline
497 bool get_chunk_head(std::string& buff, size_t& chunk_size, bool& is_matched)
498 {
499 is_matched = false;
500 size_t offset = 0;
501 for(std::string::iterator it = buff.begin(); it!= buff.end(); it++, offset++)
502 {
503 if(!is_hex_symbol(*it))
504 {
505 if(*it == '\r' || *it == ' ' )
506 {
507 offset--;
508 continue;
509 }
510 else if(*it == '\n')
511 {
512 std::string chunk_head = buff.substr(0, offset);
513 if(!get_len_from_chunk_head(chunk_head, chunk_size))
514 return false;
515
516 if(0 == chunk_size)
517 {
518 //Here is a small confusion
519 //In brief - if the chunk is the last one we need to get terminating sequence
520 //along with the cipher, generally in the "ddd\r\n\r\n" form
521
522 for(it++;it != buff.end(); it++)
523 {
524 if('\r' == *it)
525 continue;
526 else if('\n' == *it)
527 break;
528 else
529 {
530 LOG_ERROR("http_stream_filter: Wrong last chunk terminator");
531 return false;
532 }
533 }
534
535 if(it == buff.end())
536 return true;
537 }
538
539 buff.erase(buff.begin(), ++it);
540
541 is_matched = true;
542 return true;
543 }
544 else
545 return false;
546 }
547 }
548
549 return true;
550 }
551 //---------------------------------------------------------------------------
552 inline
553 bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data)
554 {
556 if(!recv_buff.size())
557 {
558 MERROR("Warning: CHUNKED mode, but connection unexpectedly closed");
560 return true;
561 }
562 m_chunked_cache += recv_buff;
563 recv_buff.clear();
564 bool is_matched = false;
565
566 while(true)
567 {
568 if(!m_chunked_cache.size())
569 {
570 need_more_data = true;
571 break;
572 }
573
574 switch(m_chunked_state)
575 {
577 if(m_chunked_cache[0] == '\n' || m_chunked_cache[0] == '\r')
578 {
579 //optimize a bit
580 if(m_chunked_cache[0] == '\r' && m_chunked_cache.size()>1 && m_chunked_cache[1] == '\n')
581 m_chunked_cache.erase(0, 2);
582 else
583 m_chunked_cache.erase(0, 1);
584 break;
585 }
587 {
588 LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache);
590 return false;
591 }
592
593 if(!is_matched)
594 {
595 need_more_data = true;
596 return true;
597 }else
598 {
600 if(m_len_in_remain == 0)
601 {//last chunk, let stop the stream and fix the chunk queue.
603 return true;
604 }
606 break;
607 }
608 break;
610 {
611 std::string chunk_body;
612 if(m_len_in_remain >= m_chunked_cache.size())
613 {
615 chunk_body.swap(m_chunked_cache);
616 }else
617 {
618 chunk_body.assign(m_chunked_cache, 0, m_len_in_remain);
620 m_len_in_remain = 0;
621 }
622
623 if (!m_pcontent_encoding_handler->update_in(chunk_body))
624 {
626 return false;
627 }
628
629 if(!m_len_in_remain)
631 }
632 break;
635 return true;
637 default:
638 LOG_ERROR("http_stream_filter::handle_chunked(): Wrong state" << m_chunked_state);
639 return false;
640 }
641 }
642
643 return true;
644 }
645 //---------------------------------------------------------------------------
646 inline bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process)
647 {
648 MTRACE("http_stream_filter::parse_cached_header(*)");
649
650 const char *ptr = m_cache_to_process.c_str();
651 while (ptr[0] != '\r' || ptr[1] != '\n')
652 {
653 // optional \n
654 if (*ptr == '\n')
655 ++ptr;
656 // an identifier composed of letters or -
657 const char *key_pos = ptr;
658 while (isalnum(*ptr) || *ptr == '_' || *ptr == '-')
659 ++ptr;
660 const char *key_end = ptr;
661 // optional space (not in RFC, but in previous code)
662 if (*ptr == ' ')
663 ++ptr;
664 CHECK_AND_ASSERT_MES(*ptr == ':', true, "http_stream_filter::parse_cached_header() invalid header in: " << m_cache_to_process);
665 ++ptr;
666 // optional whitespace, but not newlines - line folding is obsolete, let's ignore it
667 while (isblank(*ptr))
668 ++ptr;
669 const char *value_pos = ptr;
670 while (*ptr != '\r' && *ptr != '\n')
671 ++ptr;
672 const char *value_end = ptr;
673 // optional trailing whitespace
674 while (value_end > value_pos && isblank(*(value_end-1)))
675 --value_end;
676 if (*ptr == '\r')
677 ++ptr;
678 CHECK_AND_ASSERT_MES(*ptr == '\n', true, "http_stream_filter::parse_cached_header() invalid header in: " << m_cache_to_process);
679 ++ptr;
680
681 const std::string key = std::string(key_pos, key_end - key_pos);
682 const std::string value = std::string(value_pos, value_end - value_pos);
683 if (!key.empty())
684 {
685 if (!string_tools::compare_no_case(key, "Connection"))
686 body_info.m_connection = value;
687 else if(!string_tools::compare_no_case(key, "Referrer"))
688 body_info.m_referer = value;
689 else if(!string_tools::compare_no_case(key, "Content-Length"))
690 body_info.m_content_length = value;
691 else if(!string_tools::compare_no_case(key, "Content-Type"))
692 body_info.m_content_type = value;
693 else if(!string_tools::compare_no_case(key, "Transfer-Encoding"))
694 body_info.m_transfer_encoding = value;
695 else if(!string_tools::compare_no_case(key, "Content-Encoding"))
696 body_info.m_content_encoding = value;
697 else if(!string_tools::compare_no_case(key, "Host"))
698 body_info.m_host = value;
699 else if(!string_tools::compare_no_case(key, "Cookie"))
700 body_info.m_cookie = value;
701 else if(!string_tools::compare_no_case(key, "User-Agent"))
702 body_info.m_user_agent = value;
703 else if(!string_tools::compare_no_case(key, "Origin"))
704 body_info.m_origin = value;
705 else
706 body_info.m_etc_fields.emplace_back(key, value);
707 }
708 }
709 return true;
710 }
711 //---------------------------------------------------------------------------
713 {
714 //First line response, look like this: "HTTP/1.1 200 OK"
715 const char *ptr = m_header_cache.c_str();
716 CHECK_AND_ASSERT_MES(!memcmp(ptr, "HTTP/", 5), false, "Invalid first response line: " + m_header_cache);
717 ptr += 5;
718 CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
719 unsigned long ul;
720 char *end;
721 ul = strtoul(ptr, &end, 10);
722 CHECK_AND_ASSERT_MES(ul <= INT_MAX && *end =='.', false, "Invalid first response line: " + m_header_cache);
723 m_response_info.m_http_ver_hi = ul;
724 ptr = end + 1;
725 CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
726 ul = strtoul(ptr, &end, 10);
727 CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(*end), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr);
728 m_response_info.m_http_ver_lo = ul;
729 ptr = end + 1;
730 while (isblank(*ptr))
731 ++ptr;
732 CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache);
733 ul = strtoul(ptr, &end, 10);
734 CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(*end), false, "Invalid first response line: " + m_header_cache);
735 m_response_info.m_response_code = ul;
736 ptr = end;
737 // ignore the optional text, till the end
738 while (*ptr != '\r' && *ptr != '\n')
739 ++ptr;
740 if (*ptr == '\r')
741 ++ptr;
742 CHECK_AND_ASSERT_MES(*ptr == '\n', false, "Invalid first response line: " << m_header_cache);
743 ++ptr;
744
745 m_header_cache.erase(0, ptr - m_header_cache.c_str());
746 return true;
747 }
748 inline
750 {
751 STATIC_REGEXP_EXPR_1(rexp_match_gzip, "^.*?((gzip)|(deflate))", boost::regex::icase | boost::regex::normal);
752 boost::smatch result; // 12 3
753 if(boost::regex_search( m_response_info.m_header_info.m_content_encoding, result, rexp_match_gzip, boost::match_default) && result[0].matched)
754 {
756 LOG_ERROR("GZIP encoding not supported");
757 return false;
758 }
759 else
760 {
762 }
763
764 return true;
765 }
766 inline
768 {
769 m_response_info.clear();
771 std::string fake_str; //gcc error workaround
772
773 bool res = parse_header(m_response_info.m_header_info, m_header_cache);
774 CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache);
775
777
779 bool content_len_valid = false;
780 if(m_response_info.m_header_info.m_content_length.size())
781 content_len_valid = string_tools::get_xtype_from_string(m_len_in_summary, m_response_info.m_header_info.m_content_length);
782
783
784
785 if(!m_len_in_summary && ((m_response_info.m_response_code>=100&&m_response_info.m_response_code<200)
786 || 204 == m_response_info.m_response_code
787 || 304 == m_response_info.m_response_code) )
788 {//There will be no response body, server will display the local page with error
790 return true;
791 }else if(m_response_info.m_header_info.m_transfer_encoding.size())
792 {
793 string_tools::trim(m_response_info.m_header_info.m_transfer_encoding);
794 if(string_tools::compare_no_case(m_response_info.m_header_info.m_transfer_encoding, "chunked"))
795 {
796 LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding);
798 return false;
799 }
802 return true;
803 }
804 else if(!m_response_info.m_header_info.m_content_length.empty())
805 {
806 //In the response header the length was specified
807 if(!content_len_valid)
808 {
809 LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_response_info.m_header_info.m_content_length);
811 return false;
812 }
814 {
816 return true;
817 }
818 else
819 {
822 return true;
823 }
824 }else if(!m_response_info.m_header_info.m_connection.empty() && is_connection_close_field(m_response_info.m_header_info.m_connection))
825 { //By indirect signs we suspect that data transfer will end with a connection break
827 }else if(is_multipart_body(m_response_info.m_header_info, fake_str))
828 {
830 LOG_ERROR("Unsupported MULTIPART BODY.");
831 return false;
832 }else
833 { //Apparently there are no signs of the form of transfer, will receive data until the connection is closed
835 MERROR("Undefined transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache);
836 return false;
837 }
838 return false;
839 }
840 inline
841 bool is_connection_close_field(const std::string& str)
842 {
843 STATIC_REGEXP_EXPR_1(rexp_match_close, "^\\s*close", boost::regex::icase | boost::regex::normal);
844 boost::smatch result;
845 if(boost::regex_search( str, result, rexp_match_close, boost::match_default) && result[0].matched)
846 return true;
847 else
848 return false;
849 }
850 inline
851 bool is_multipart_body(const http_header_info& head_info, OUT std::string& boundary)
852 {
853 //Check whether this is multi part - if yes, capture boundary immediately
854 STATIC_REGEXP_EXPR_1(rexp_match_multipart_type, "^\\s*multipart/([\\w\\-]+); boundary=((\"(.*?)\")|(\\\\\"(.*?)\\\\\")|([^\\s;]*))", boost::regex::icase | boost::regex::normal);
855 boost::smatch result;
856 if(boost::regex_search(head_info.m_content_type, result, rexp_match_multipart_type, boost::match_default) && result[0].matched)
857 {
858 if(result[4].matched)
859 boundary = result[4];
860 else if(result[6].matched)
861 boundary = result[6];
862 else if(result[7].matched)
863 boundary = result[7];
864 else
865 {
866 LOG_ERROR("Failed to match boundary in content-type=" << head_info.m_content_type);
867 return false;
868 }
869 return true;
870 }
871 else
872 return false;
873
874 return true;
875 }
876 };
878 }
879}
880}
#define s(x, c)
Definition aesb.c:47
Definition syncobj.h:82
Definition http_client_base.h:61
abstract_http_client()
Definition abstract_http_client.h:64
bool set_server(const std::string &address, boost::optional< login > user, ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect)
Definition abstract_http_client.cpp:134
Implements RFC 2617 digest auth. Digests from RFC 7616 can be added.
Definition http_auth.h:95
@ kSuccess
Definition http_auth.h:97
@ kParseFailure
Definition http_auth.h:97
@ kBadPassword
Definition http_auth.h:97
void set_connector(F connector)
Definition http_client.h:186
void set_auto_connect(bool auto_connect) override
Definition http_client.h:180
bool analize_cached_header_and_invoke_state()
Definition http_client.h:767
bool set_reply_content_encoder()
Definition http_client.h:749
blocked_mode_client m_net_client
Definition http_client.h:130
boost::shared_ptr< i_sub_handler > m_pcontent_encoding_handler
Definition http_client.h:139
http_simple_client_template()
Definition http_client.h:147
bool is_multipart_body(const http_header_info &head_info, OUT std::string &boundary)
Definition http_client.h:851
virtual bool handle_target_data(std::string &piece_of_transfer) override
Definition http_client.h:210
bool handle_body_connection_close(std::string &recv_buff, bool &need_more_data)
Definition http_client.h:461
bool is_connected(bool *ssl=NULL) override
Definition http_client.h:204
bool test(const std::string &s, std::chrono::milliseconds timeout)
Definition http_client.h:309
bool connect(std::chrono::milliseconds timeout) override
Definition http_client.h:192
bool parse_header(http_header_info &body_info, const std::string &m_cache_to_process)
Definition http_client.h:646
bool handle_body_content_len(std::string &recv_buff, bool &need_more_data)
Definition http_client.h:435
void wipe_response()
Definition http_client.h:327
bool get_len_from_chunk_head(const std::string &chunk_head, size_t &result_size)
Definition http_client.h:486
bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string &body=std::string(), const http_response_info **ppresponse_info=NULL, const fields_list &additional_params=fields_list()) override
Definition http_client.h:223
bool handle_body_body_chunked(std::string &recv_buff, bool &need_more_data)
Definition http_client.h:553
void set_server(std::string host, std::string port, boost::optional< login > user, ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect) override
Definition http_client.h:170
bool invoke_post(const boost::string_ref uri, const std::string &body, std::chrono::milliseconds timeout, const http_response_info **ppresponse_info=NULL, const fields_list &additional_params=fields_list()) override
Definition http_client.h:303
uint64_t get_bytes_received() const override
Definition http_client.h:322
bool invoke(const boost::string_ref uri, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info **ppresponse_info=NULL, const fields_list &additional_params=fields_list()) override
Definition http_client.h:230
bool handle_reciev(std::chrono::milliseconds timeout)
Definition http_client.h:334
http_response_info m_response_info
Definition http_client.h:135
bool is_hex_symbol(char ch)
Definition http_client.h:476
reciev_machine_state m_state
Definition http_client.h:140
bool disconnect() override
Definition http_client.h:198
bool get_chunk_head(std::string &buff, size_t &chunk_size, bool &is_matched)
Definition http_client.h:497
reciev_machine_state
Definition http_client.h:111
const std::string & get_host() const
Definition http_client.h:165
virtual bool on_header(const http_response_info &headers)
Definition http_client.h:218
bool is_connection_close_field(const std::string &str)
Definition http_client.h:841
const std::string & get_port() const
Definition http_client.h:166
bool handle_header(std::string &recv_buff, bool &need_more_data)
Definition http_client.h:398
uint64_t get_bytes_sent() const override
Definition http_client.h:317
bool analize_first_response_line()
Definition http_client.h:712
Definition net_ssl.h:77
#define true
const char * res
Definition hmac_keccak.cpp:42
const char * key
Definition hmac_keccak.cpp:40
epee::critical_section gregexp_lock
bool isdigit(char c)
Definition parserse_base_utils.h:91
bool isspace(char c)
Definition parserse_base_utils.h:86
http_simple_client_template< blocked_mode_client > http_simple_client
Definition http_client.h:877
static void add_field(std::string &out, const boost::string_ref name, const boost::string_ref value)
Definition http_base.h:73
std::list< std::pair< std::string, std::string > > fields_list
Definition http_base.h:67
@ e_ssl_support_autodetect
Definition net_ssl.h:52
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Definition string_tools_lexical.h:45
bool compare_no_case(const std::string &str1, const std::string &str2)
Definition string_tools.cpp:136
std::string & trim(std::string &str)
Definition string_tools.h:75
TODO: (mj-xmr) This will be reduced in an another PR.
Definition byte_slice.h:40
Definition uri.py:1
const GenericPointer< typename T::ValueType > T2 value
Definition pointer.h:1225
const char *const str
Definition portlistingparse.c:23
#define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags)
Definition reg_exp_definer.h:48
#define F(w, k)
Definition sha512-blocks.c:61
tools::wallet2::message_signature_result_t result
Definition signature.cpp:62
unsigned __int64 uint64_t
Definition stdint.h:136
#define OUT
Definition string_tools.h:40
fields_list m_etc_fields
Definition http_base.h:96
std::string m_content_length
Definition http_base.h:88
std::string m_content_encoding
Definition http_base.h:91
std::string m_origin
Definition http_base.h:95
std::string m_referer
Definition http_base.h:87
std::string m_cookie
Definition http_base.h:93
std::string m_connection
Definition http_base.h:86
std::string m_user_agent
Definition http_base.h:94
std::string m_content_type
Definition http_base.h:89
std::string m_transfer_encoding
Definition http_base.h:90
std::string m_host
Definition http_base.h:92
Definition http_client_base.h:54
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:153