Monero
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"
43 #include "string_tools_lexical.h"
44 #include "reg_exp_definer.h"
45 #include "abstract_http_client.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 
61 namespace epee
62 {
63 namespace 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:
111  {
118  };
119 
120 
121 
127  };
128 
129 
130  net_client_type m_net_client;
138  //std::string* m_ptarget_buffer;
139  boost::shared_ptr<i_sub_handler> m_pcontent_encoding_handler;
145 
146  public:
149  , m_net_client()
150  , m_host_buff()
151  , m_port()
152  , m_auth()
153  , m_header_cache()
154  , m_response_info()
155  , m_len_in_summary(0)
156  , m_len_in_remain(0)
157  , m_pcontent_encoding_handler(nullptr)
158  , m_state()
159  , m_chunked_state()
160  , m_chunked_cache()
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();
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 
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 
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  //---------------------------------------------------------------------------
322  uint64_t get_bytes_received() const override
323  {
324  return m_net_client.get_bytes_received();
325  }
326  //---------------------------------------------------------------------------
328  {
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  {
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);
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);
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);
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  {
771  std::string fake_str; //gcc error workaround
772 
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 
778  m_len_in_summary = 0;
779  bool content_len_valid = false;
782 
783 
784 
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;
792  {
795  {
796  LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding);
798  return false;
799  }
802  return true;
803  }
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  }
813  if(!m_len_in_summary)
814  {
816  return true;
817  }
818  else
819  {
822  return true;
823  }
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
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 }
const char * res
Definition: hmac_keccak.cpp:42
std::string m_content_type
Definition: http_base.h:88
std::string m_content_length
Definition: http_base.h:87
#define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags)
Definition: reg_exp_definer.h:48
Definition: net_ssl.h:76
std::list< std::pair< std::string, std::string > > fields_list
Definition: http_base.h:66
static void add_field(std::string &out, const boost::string_ref name, const boost::string_ref value)
Definition: http_base.h:72
bool isdigit(char c)
Definition: parserse_base_utils.h:91
http_simple_client_template()
Definition: http_client.h:147
reciev_machine_state m_state
Definition: http_client.h:140
Definition: http_client_base.h:53
http_header_info m_header_info
Definition: http_base.h:169
::std::string string
Definition: gtest-port.h:1097
Implements RFC 2617 digest auth. Digests from RFC 7616 can be added.
Definition: http_auth.h:94
#define F(w, k)
Definition: sha512-blocks.c:61
virtual bool on_header(const http_response_info &headers)
Definition: http_client.h:218
bool is_multipart_body(const http_header_info &head_info, OUT std::string &boundary)
Definition: http_client.h:851
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
net_client_type m_net_client
Definition: http_client.h:130
host
Definition: console.py:27
const std::string & get_port() const
Definition: http_client.h:166
bool isspace(char c)
Definition: parserse_base_utils.h:86
const char * key
Definition: hmac_keccak.cpp:40
const char * s
Definition: minissdp.c:596
int m_http_ver_hi
Definition: http_base.h:170
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
std::string m_transfer_encoding
Definition: http_base.h:89
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
std::string m_origin
Definition: http_base.h:94
tools::wallet2::message_signature_result_t result
Definition: signature.cpp:62
std::string & trim(std::string &str)
Definition: string_tools.h:75
Definition: abstract_http_client.h:59
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 analize_cached_header_and_invoke_state()
Definition: http_client.h:767
std::string m_cookie
Definition: http_base.h:92
http_client_auth m_auth
Definition: http_client.h:133
std::string m_connection
Definition: http_base.h:85
#define OUT
Definition: string_tools.h:40
boost::shared_ptr< i_sub_handler > m_pcontent_encoding_handler
Definition: http_client.h:139
bool get_chunk_head(std::string &buff, size_t &chunk_size, bool &is_matched)
Definition: http_client.h:497
uint64_t get_bytes_sent() const override
Definition: http_client.h:317
size_t m_len_in_summary
Definition: http_client.h:136
std::string m_host_buff
Definition: http_client.h:131
bool test(const std::string &s, std::chrono::milliseconds timeout)
Definition: http_client.h:309
http_simple_client_template< blocked_mode_client > http_simple_client
Definition: http_client.h:877
bool handle_header(std::string &recv_buff, bool &need_more_data)
Definition: http_client.h:398
std::string m_host
Definition: http_base.h:91
void clear()
Definition: http_base.h:173
Definition: http_client_base.h:60
Definition: syncobj.h:81
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
status handle_401(const http_response_info &response)
Definition: http_auth.h:143
bool is_connected(bool *ssl=NULL) override
Definition: http_client.h:204
http_response_info m_response_info
Definition: http_client.h:135
bool m_auto_connect
Definition: http_client.h:143
Definition: http_base.h:83
chunked_state m_chunked_state
Definition: http_client.h:141
unsigned __int64 uint64_t
Definition: stdint.h:136
bool compare_no_case(const std::string &str1, const std::string &str2)
Definition: string_tools.cpp:136
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:153
const std::string & get_host() const
Definition: http_client.h:165
critical_section m_lock
Definition: http_client.h:144
int m_response_code
Definition: http_base.h:164
uint64_t get_bytes_received() const override
Definition: http_client.h:322
reciev_machine_state
Definition: http_client.h:110
bool analize_first_response_line()
Definition: http_client.h:712
int m_http_ver_lo
Definition: http_base.h:171
std::string m_content_encoding
Definition: http_base.h:90
virtual bool handle_target_data(std::string &piece_of_transfer) override
Definition: http_client.h:210
boost::endian::big_uint16_t port
Definition: socks.cpp:61
bool parse_header(http_header_info &body_info, const std::string &m_cache_to_process)
Definition: http_client.h:646
const char *const str
Definition: portlistingparse.c:23
bool is_connection_close_field(const std::string &str)
Definition: http_client.h:841
TODO: (mj-xmr) This will be reduced in an another PR.
Definition: byte_slice.h:39
bool handle_body_body_chunked(std::string &recv_buff, bool &need_more_data)
Definition: http_client.h:553
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
fields_list m_etc_fields
Definition: http_base.h:95
bool disconnect() override
Definition: http_client.h:198
const T & move(const T &t)
Definition: gtest-port.h:1317
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
epee::critical_section gregexp_lock
void set_auto_connect(bool auto_connect) override
Definition: http_client.h:180
bool set_reply_content_encoder()
Definition: http_client.h:749
std::string m_header_cache
Definition: http_client.h:134
std::string m_chunked_cache
Definition: http_client.h:142
std::string m_user_agent
Definition: http_base.h:93
size_t m_len_in_remain
Definition: http_client.h:137
bool handle_body_content_len(std::string &recv_buff, bool &need_more_data)
Definition: http_client.h:435
bool handle_body_connection_close(std::string &recv_buff, bool &need_more_data)
Definition: http_client.h:461
bool is_hex_symbol(char ch)
Definition: http_client.h:476
Definition: uri.py:1
Definition: abstract_http_client.h:61
std::string m_body
Definition: http_base.h:167
std::string to_string(t_connection_type type)
Definition: connection_basic.cpp:70
boost::optional< std::pair< std::string, std::string > > get_auth_field(const boost::string_ref method, const boost::string_ref uri)
Definition: http_auth.h:157
void set_connector(F connector)
Definition: http_client.h:186
bool connect(std::chrono::milliseconds timeout) override
Definition: http_client.h:192
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Definition: string_tools_lexical.h:45
static constexpr const char hex[]
Definition: wipeable_string.cpp:36
std::string m_referer
Definition: http_base.h:86
#define true
Definition: stdbool.h:36
void wipe()
Definition: http_base.h:179
std::string m_port
Definition: http_client.h:132
bool handle_reciev(std::chrono::milliseconds timeout)
Definition: http_client.h:334