Cuberite
A lightweight, fast and extensible game server for Minecraft
UrlClient.cpp
Go to the documentation of this file.
1 
2 // UrlClient.cpp
3 
4 // Implements the cUrlClient class for high-level URL interaction
5 
6 #include "Globals.h"
7 
8 #include "HTTP/UrlClient.h"
9 #include "HTTP/UrlParser.h"
10 #include "HTTP/HTTPMessageParser.h"
11 #include "mbedTLS++/X509Cert.h"
12 #include "mbedTLS++/CryptoKey.h"
13 
14 
15 
16 
17 
18 // fwd:
19 class cSchemeHandler;
20 using cSchemeHandlerPtr = std::shared_ptr<cSchemeHandler>;
21 
22 
23 
24 
25 
26 namespace
27 {
29  class cBlockingHTTPCallbacks :
31  {
32  public:
33 
34  explicit cBlockingHTTPCallbacks(std::shared_ptr<cEvent> a_Event, AString & a_ResponseBody) :
35  m_Event(std::move(a_Event)), m_ResponseBody(a_ResponseBody),
36  m_IsError(false)
37  {
38  }
39 
40  void OnBodyFinished() override
41  {
42  m_Event->Set();
43  }
44 
45  void OnError(const AString & a_ErrorMsg) override
46  {
47  LOGERROR("%s %d: HTTP Error: %s", __FILE__, __LINE__, a_ErrorMsg.c_str());
48  m_IsError = true;
49  m_Event->Set();
50  }
51 
52  void OnBodyData(const void * a_Data, size_t a_Size) override
53  {
54  m_ResponseBody.append(static_cast<const char *>(a_Data), a_Size);
55  }
56 
57  std::shared_ptr<cEvent> m_Event;
58 
60  AString & m_ResponseBody;
61 
63  bool m_IsError;
64  };
65 }
66 
67 
68 
69 
70 
74 {
75  friend class cHttpSchemeHandler;
76 
77 public:
78  static std::pair<bool, AString> Request(
79  const AString & a_Method,
80  const AString & a_URL,
81  cUrlClient::cCallbacksPtr && a_Callbacks,
82  AStringMap && a_Headers,
83  const AString & a_Body,
84  const AStringMap & a_Options
85  )
86  {
87  // Create a new instance of cUrlClientRequest, wrapped in a SharedPtr, so that it has a controlled lifetime.
88  // Cannot use std::make_shared, because the constructor is not public
89  std::shared_ptr<cUrlClientRequest> ptr (new cUrlClientRequest(
90  a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
91  ));
92  return ptr->DoRequest(ptr);
93  }
94 
95 
97  void CallErrorCallback(const AString & a_ErrorMessage)
98  {
99  // Call the error callback:
100  m_Callbacks->OnError(a_ErrorMessage);
101 
102  // Terminate the request's TCP link:
103  if (auto link = m_Link.lock())
104  {
105  link->Close();
106  }
107  }
108 
109 
111 
112  void RedirectTo(const AString & a_RedirectUrl);
113 
114  bool ShouldAllowRedirects() const;
115 
117  {
118  auto itr = m_Options.find("OwnCert");
119  if (itr == m_Options.end())
120  {
121  return nullptr;
122  }
123  cX509CertPtr cert = std::make_shared<cX509Cert>();
124  if (!cert->Parse(itr->second.data(), itr->second.size()))
125  {
126  LOGD("OwnCert failed to parse");
127  return nullptr;
128  }
129  return cert;
130  }
131 
133  {
134  auto itr = m_Options.find("OwnPrivKey");
135  if (itr == m_Options.end())
136  {
137  return nullptr;
138  }
139  cCryptoKeyPtr key = std::make_shared<cCryptoKey>();
140  auto passItr = m_Options.find("OwnPrivKeyPassword");
141  auto pass = (passItr == m_Options.end()) ? AString() : passItr->second;
142  if (!key->ParsePrivate(itr->second.data(), itr->second.size(), pass))
143  {
144  return nullptr;
145  }
146  return key;
147  }
148 
152  {
153  auto itr = m_Options.find("TrustedRootCAs");
154  if (itr == m_Options.end())
155  {
156  return nullptr;
157  }
158  auto Cert = std::make_shared<cX509Cert>();
159  auto Res = Cert->Parse(itr->second.data(), itr->second.size());
160  if (Res != 0)
161  {
162  throw std::runtime_error(fmt::format("Failed to parse the TrustedRootCAs certificate: {}", Res));
163  }
164  return Cert;
165  }
166 
167 protected:
168 
171 
174 
178 
181 
184 
187 
190 
193  std::weak_ptr<cUrlClientRequest> m_Self;
194 
196  std::shared_ptr<cSchemeHandler> m_SchemeHandler;
197 
199  std::weak_ptr<cTCPLink> m_Link;
200 
205 
206 
208  const AString & a_Method,
209  const AString & a_Url,
210  cUrlClient::cCallbacksPtr && a_Callbacks,
211  AStringMap && a_Headers,
212  const AString & a_Body,
213  const AStringMap & a_Options
214  ):
215  m_Method(a_Method),
216  m_Url(a_Url),
217  m_Callbacks(std::move(a_Callbacks)),
218  m_Headers(std::move(a_Headers)),
219  m_Body(a_Body),
220  m_Options(a_Options)
221  {
223  }
224 
225 
226  std::pair<bool, AString> DoRequest(const std::shared_ptr<cUrlClientRequest> & a_Self);
227 
228 
229  // cNetwork::cConnectCallbacks override: TCP link connected:
230  virtual void OnConnected(cTCPLink & a_Link) override;
231 
232  // cNetwork::cConnectCallbacks override: An error has occurred:
233  virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override
234  {
235  m_Callbacks->OnError(fmt::format(FMT_STRING("Network error {} ({})"), a_ErrorCode, a_ErrorMsg));
236  }
237 
238 
239  // cTCPLink::cCallbacks override: TCP link created
240  virtual void OnLinkCreated(cTCPLinkPtr a_Link) override
241  {
242  m_Link = a_Link;
243  }
244 
245 
246  // cTCPLink::cCallbacks override: TLS handshake completed on the link:
247  virtual void OnTlsHandshakeCompleted(void) override;
248 
250  virtual void OnReceivedData(const char * a_Data, size_t a_Length) override;
251 
252 
256  virtual void OnRemoteClosed(void) override;
257 };
258 
259 
260 
261 
262 
268 class cSchemeHandler abstract
269 {
270 public:
271  cSchemeHandler(cUrlClientRequest & a_ParentRequest):
272  m_ParentRequest(a_ParentRequest)
273  {
274  }
275 
276  // Force a virtual destructor in all descendants
277  virtual ~cSchemeHandler() {}
278 
281  static cSchemeHandlerPtr Create(const AString & a_Scheme, cUrlClientRequest & a_ParentRequest);
282 
284  virtual void OnConnected(cTCPLink & a_Link) = 0;
285 
287  virtual void OnReceivedData(const char * a_Data, size_t a_Length) = 0;
288 
290  virtual void OnTlsHandshakeCompleted(void) = 0;
291 
295  virtual void OnRemoteClosed(void) = 0;
296 
297 protected:
298  cUrlClientRequest & m_ParentRequest;
299 };
300 
301 
302 
303 
304 
307  public cSchemeHandler,
309 {
310  using Super = cSchemeHandler;
311 
312 public:
313 
314  cHttpSchemeHandler(cUrlClientRequest & a_ParentRequest, bool a_IsTls):
315  Super(a_ParentRequest),
316  m_Parser(*this),
317  m_IsTls(a_IsTls),
318  m_IsRedirect(false)
319  {
320  }
321 
322 
323  virtual void OnConnected(cTCPLink & a_Link) override
324  {
325  m_Link = &a_Link;
326  if (m_IsTls)
327  {
328  m_Link->StartTLSClient(m_ParentRequest.GetOwnCert(), m_ParentRequest.GetOwnPrivKey(), m_ParentRequest.GetTrustedRootCAs());
329  }
330  else
331  {
332  SendRequest();
333  }
334  }
335 
336 
339  void SendRequest()
340  {
341  // Compose the request line:
342  auto requestLine = m_ParentRequest.m_UrlPath;
343  if (requestLine.empty())
344  {
345  requestLine = "/";
346  }
347  if (!m_ParentRequest.m_UrlQuery.empty())
348  {
349  requestLine.push_back('?');
350  requestLine.append(m_ParentRequest.m_UrlQuery);
351  }
352  m_Link->Send(fmt::format(FMT_STRING("{} {} HTTP/1.1\r\n"), m_ParentRequest.m_Method, requestLine));
353 
354  // Send the headers:
355  m_Link->Send(fmt::format(FMT_STRING("Host: {}\r\n"), m_ParentRequest.m_UrlHost));
356  m_Link->Send(fmt::format(FMT_STRING("Content-Length: {}\r\n"), m_ParentRequest.m_Body.size()));
357  for (const auto & hdr: m_ParentRequest.m_Headers)
358  {
359  m_Link->Send(fmt::format(FMT_STRING("{}: {}\r\n"), hdr.first, hdr.second));
360  } // for itr - m_Headers[]
361  m_Link->Send("\r\n", 2);
362 
363  // Send the body:
364  m_Link->Send(m_ParentRequest.m_Body);
365 
366  // Notify the callbacks that the request has been sent:
367  m_ParentRequest.GetCallbacks().OnRequestSent();
368  }
369 
370 
371  virtual void OnReceivedData(const char * a_Data, size_t a_Length) override
372  {
373  auto res = m_Parser.Parse(a_Data, a_Length);
374  if (res == AString::npos)
375  {
376  m_ParentRequest.CallErrorCallback("Failed to parse HTTP response");
377  return;
378  }
379  }
380 
381 
382  virtual void OnTlsHandshakeCompleted(void) override
383  {
384  SendRequest();
385  }
386 
387 
388  virtual void OnRemoteClosed(void) override
389  {
390  m_Link = nullptr;
391  }
392 
393 
394  // cHTTPResponseParser::cCallbacks overrides:
395  virtual void OnError(const AString & a_ErrorDescription) override
396  {
397  m_Link = nullptr;
398  m_ParentRequest.CallErrorCallback(a_ErrorDescription);
399  }
400 
401 
402  virtual void OnFirstLine(const AString & a_FirstLine) override
403  {
404  // Find the first space, parse the result code between it and the second space:
405  auto idxFirstSpace = a_FirstLine.find(' ');
406  if (idxFirstSpace == AString::npos)
407  {
408  m_ParentRequest.CallErrorCallback(fmt::format(FMT_STRING("Failed to parse HTTP status line \"{}\", no space delimiter."), a_FirstLine));
409  return;
410  }
411  auto idxSecondSpace = a_FirstLine.find(' ', idxFirstSpace + 1);
412  if (idxSecondSpace == AString::npos)
413  {
414  m_ParentRequest.CallErrorCallback(fmt::format(FMT_STRING("Failed to parse HTTP status line \"{}\", missing second space delimiter."), a_FirstLine));
415  return;
416  }
417  int resultCode;
418  auto resultCodeStr = a_FirstLine.substr(idxFirstSpace + 1, idxSecondSpace - idxFirstSpace - 1);
419  if (!StringToInteger(resultCodeStr, resultCode))
420  {
421  m_ParentRequest.CallErrorCallback(fmt::format(FMT_STRING("Failed to parse HTTP result code from response \"{}\""), resultCodeStr));
422  return;
423  }
424 
425  // Check for redirects, follow if allowed by the options:
426  switch (resultCode)
427  {
433  {
434  m_IsRedirect = true;
435  return;
436  }
437  }
438  m_ParentRequest.GetCallbacks().OnStatusLine(a_FirstLine.substr(0, idxFirstSpace), resultCode, a_FirstLine.substr(idxSecondSpace + 1));
439  }
440 
441 
442  virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override
443  {
444  if (m_IsRedirect)
445  {
446  if (a_Key == "Location")
447  {
448  m_RedirectLocation = a_Value;
449  }
450  }
451  else
452  {
453  m_ParentRequest.GetCallbacks().OnHeader(a_Key, a_Value);
454  }
455  }
456 
457 
459  virtual void OnHeadersFinished(void) override
460  {
461  if (!m_IsRedirect)
462  {
463  m_ParentRequest.GetCallbacks().OnHeadersFinished();
464  }
465  }
466 
467 
469  virtual void OnBodyData(const void * a_Data, size_t a_Size) override
470  {
471  if (!m_IsRedirect)
472  {
473  m_ParentRequest.GetCallbacks().OnBodyData(a_Data, a_Size);
474  }
475  }
476 
477 
479  virtual void OnBodyFinished(void) override
480  {
481  if (m_IsRedirect)
482  {
483  if (m_RedirectLocation.empty())
484  {
485  m_ParentRequest.CallErrorCallback("Invalid redirect, there's no location to redirect to");
486  }
487  else
488  {
489  m_ParentRequest.RedirectTo(m_RedirectLocation);
490  }
491  }
492  else
493  {
494  m_ParentRequest.GetCallbacks().OnBodyFinished();
495  // Finished recieving data, shutdown the link
496  m_Link->Shutdown();
497  }
498  }
499 
500 protected:
501 
504 
507 
509  bool m_IsTls;
510 
515 
519 };
520 
521 
522 
523 
524 
526 // cSchemeHandler:
527 
528 cSchemeHandlerPtr cSchemeHandler::Create(const AString & a_Scheme, cUrlClientRequest & a_ParentRequest)
529 {
530  auto lowerScheme = StrToLower(a_Scheme);
531  if (lowerScheme == "http")
532  {
533  return std::make_shared<cHttpSchemeHandler>(a_ParentRequest, false);
534  }
535  else if (lowerScheme == "https")
536  {
537  return std::make_shared<cHttpSchemeHandler>(a_ParentRequest, true);
538  }
539 
540  return nullptr;
541 }
542 
543 
544 
545 
546 
548 // cUrlClientRequest:
549 
550 void cUrlClientRequest::RedirectTo(const AString & a_RedirectUrl)
551 {
552  // Check that redirection is allowed:
553  m_Callbacks->OnRedirecting(a_RedirectUrl);
554  if (!ShouldAllowRedirects())
555  {
556  CallErrorCallback(fmt::format(FMT_STRING("Redirect to \"{}\" not allowed"), a_RedirectUrl));
557  return;
558  }
559 
560  // Keep ourself alive while the link drops ownership
561  auto Self = m_Self.lock();
562 
563  // Do the actual redirect:
564  if (auto Link = m_Link.lock())
565  {
566  Link->Close();
567  }
568 
569  m_Url = a_RedirectUrl;
571  auto res = DoRequest(Self);
572  if (!res.first)
573  {
574  m_Callbacks->OnError(fmt::format(FMT_STRING("Redirection failed: {}"), res.second));
575  }
576 }
577 
578 
579 
580 
581 
583 {
584  return (m_NumRemainingRedirects > 0);
585 }
586 
587 
588 
589 
590 
592 {
593  m_Callbacks->OnConnected(a_Link);
594  m_SchemeHandler->OnConnected(a_Link);
595 }
596 
597 
598 
599 
600 
602 {
603  // Notify the scheme handler and the callbacks:
604  m_SchemeHandler->OnTlsHandshakeCompleted();
605  m_Callbacks->OnTlsHandshakeCompleted();
606 }
607 
608 
609 
610 
611 
612 void cUrlClientRequest::OnReceivedData(const char * a_Data, size_t a_Length)
613 {
614  auto handler = m_SchemeHandler;
615  if (handler != nullptr)
616  {
617  handler->OnReceivedData(a_Data, a_Length);
618  }
619 }
620 
621 
622 
623 
624 
626 {
627  // Notify the callback:
628  auto handler = m_SchemeHandler;
629  if (handler != nullptr)
630  {
631  handler->OnRemoteClosed();
632  }
633 }
634 
635 
636 
637 
638 
639 std::pair<bool, AString> cUrlClientRequest::DoRequest(const std::shared_ptr<cUrlClientRequest> & a_Self)
640 {
641  // We need a shared pointer to self, care must be taken not to pass any other ptr:
642  ASSERT(a_Self.get() == this);
643 
644  m_Self = a_Self;
645 
646  // Parse the URL:
648  if (!res.first)
649  {
650  return res;
651  }
652 
653  // Get a handler that will work with the specified scheme:
654  m_SchemeHandler = cSchemeHandler::Create(m_UrlScheme, *this);
655  if (m_SchemeHandler == nullptr)
656  {
657  return std::make_pair(false, fmt::format(FMT_STRING("Unknown URL scheme: {}"), m_UrlScheme));
658  }
659 
660  // Connect and transfer ownership to the link
661  if (!cNetwork::Connect(m_UrlHost, m_UrlPort, a_Self, a_Self))
662  {
663  return std::make_pair(false, "Network connection failed");
664  }
665  return std::make_pair(true, AString());
666 }
667 
668 
669 
670 
671 
673 // cUrlClient:
674 
675 std::pair<bool, AString> cUrlClient::Request(
676  const AString & a_Method,
677  const AString & a_URL,
678  cCallbacksPtr && a_Callbacks,
679  AStringMap && a_Headers,
680  const AString & a_Body,
681  const AStringMap & a_Options
682 )
683 {
685  a_Method, a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
686  );
687 }
688 
689 
690 
691 
692 
693 std::pair<bool, AString> cUrlClient::Get(
694  const AString & a_URL,
695  cCallbacksPtr && a_Callbacks,
696  AStringMap && a_Headers,
697  const AString & a_Body,
698  const AStringMap & a_Options
699 )
700 {
702  "GET", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
703  );
704 }
705 
706 
707 
708 
709 
710 std::pair<bool, AString> cUrlClient::Post(
711  const AString & a_URL,
712  cCallbacksPtr && a_Callbacks,
713  AStringMap && a_Headers,
714  const AString & a_Body,
715  const AStringMap & a_Options
716 )
717 {
719  "POST", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
720  );
721 }
722 
723 
724 
725 
726 
727 std::pair<bool, AString> cUrlClient::Put(
728  const AString & a_URL,
729  cCallbacksPtr && a_Callbacks,
730  AStringMap && a_Headers,
731  const AString & a_Body,
732  const AStringMap & a_Options
733 )
734 {
736  "PUT", a_URL, std::move(a_Callbacks), std::move(a_Headers), a_Body, a_Options
737  );
738 }
739 
740 
741 
742 
743 
744 std::pair<bool, AString> cUrlClient::BlockingRequest(
745  const AString & a_Method,
746  const AString & a_URL,
747  AStringMap && a_Headers,
748  const AString & a_Body,
749  const AStringMap & a_Options
750 )
751 {
752  auto EvtFinished = std::make_shared<cEvent>();
753  AString Response;
754  auto Callbacks = std::make_shared<cBlockingHTTPCallbacks>(EvtFinished, Response);
755  auto [Success, ErrorMessage] = cUrlClient::Request(a_Method, a_URL, Callbacks, std::move(a_Headers), a_Body, a_Options);
756  if (Success)
757  {
758  if (!EvtFinished->Wait(10000))
759  {
760  return std::make_pair(false, "Timeout");
761  }
762  if (Callbacks->m_IsError)
763  {
764  return std::make_pair(false, AString());
765  }
766  }
767  else
768  {
769  LOGWARNING("%s: HTTP error: %s", __FUNCTION__, ErrorMessage.c_str());
770  return std::make_pair(false, AString());
771  }
772  return std::make_pair(true, Response);
773 }
774 
775 
776 
777 
778 
779 std::pair<bool, AString> cUrlClient::BlockingGet(
780  const AString & a_URL,
781  AStringMap a_Headers,
782  const AString & a_Body,
783  const AStringMap & a_Options
784 )
785 {
786  return BlockingRequest("GET", a_URL, std::move(a_Headers), a_Body, a_Options);
787 }
788 
789 
790 
791 
792 
793 std::pair<bool, AString> cUrlClient::BlockingPost(
794  const AString & a_URL,
795  AStringMap && a_Headers,
796  const AString & a_Body,
797  const AStringMap & a_Options
798 )
799 {
800  return BlockingRequest("POST", a_URL, std::move(a_Headers), a_Body, a_Options);
801 }
802 
803 
804 
805 
806 
807 std::pair<bool, AString> cUrlClient::BlockingPut(
808  const AString & a_URL,
809  AStringMap && a_Headers,
810  const AString & a_Body,
811  const AStringMap & a_Options
812 )
813 {
814  return BlockingRequest("PUT", a_URL, std::move(a_Headers), a_Body, a_Options);
815 }
816 
817 
818 
819 
820 
#define ASSERT(x)
Definition: Globals.h:276
unsigned short UInt16
Definition: Globals.h:158
std::shared_ptr< cSchemeHandler > cSchemeHandlerPtr
Definition: UrlClient.cpp:20
void LOGERROR(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:73
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
#define LOGD
Definition: LoggerSimple.h:83
std::shared_ptr< cCryptoKey > cCryptoKeyPtr
Definition: CryptoKey.h:72
std::shared_ptr< cX509Cert > cX509CertPtr
Definition: SslConfig.h:13
std::shared_ptr< cTCPLink > cTCPLinkPtr
Definition: Network.h:25
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
T GetStringMapInteger(const AStringMap &a_Map, const AString &a_Key, T a_Default)
Returns a number (of any integer type T) from a key-value string map.
Definition: StringUtils.h:216
std::string AString
Definition: StringUtils.h:11
bool StringToInteger(const AString &a_str, T &a_Num)
Parses any integer type.
Definition: StringUtils.h:143
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
Definition: StringUtils.h:16
Definition: FastNBT.h:132
size_t Parse(const char *a_Data, size_t a_Size)
Parses the incoming data and calls the appropriate callbacks.
virtual void OnLinkCreated(cTCPLinkPtr a_Link) override
Called when the cTCPLink for the connection is created.
Definition: UrlClient.cpp:240
bool ShouldAllowRedirects() const
Definition: UrlClient.cpp:582
virtual void OnConnected(cTCPLink &a_Link) override
Called when the Connect call succeeds.
Definition: UrlClient.cpp:591
cX509CertPtr GetOwnCert() const
Definition: UrlClient.cpp:116
cUrlClient::cCallbacksPtr m_Callbacks
Callbacks that report progress and results of the request.
Definition: UrlClient.cpp:180
virtual void OnReceivedData(const char *a_Data, size_t a_Length) override
Called when there's data incoming from the remote peer.
Definition: UrlClient.cpp:612
static std::pair< bool, AString > Request(const AString &a_Method, const AString &a_URL, cUrlClient::cCallbacksPtr &&a_Callbacks, AStringMap &&a_Headers, const AString &a_Body, const AStringMap &a_Options)
Definition: UrlClient.cpp:78
virtual void OnError(int a_ErrorCode, const AString &a_ErrorMsg) override
Called when an error is detected on the connection.
Definition: UrlClient.cpp:233
virtual void OnTlsHandshakeCompleted(void) override
Called when the TLS handshake has been completed and communication can continue regularly.
Definition: UrlClient.cpp:601
AString m_UrlScheme
Individual components of the URL that will be requested.
Definition: UrlClient.cpp:176
void CallErrorCallback(const AString &a_ErrorMessage)
Calls the error callback with the specified message, if it exists, and terminates the request.
Definition: UrlClient.cpp:97
AString m_Body
Body to be sent with the request, if any.
Definition: UrlClient.cpp:186
cX509CertPtr GetTrustedRootCAs() const
Returns the parsed TrustedRootCAs from the options, or an empty pointer if the option is not set.
Definition: UrlClient.cpp:151
std::weak_ptr< cTCPLink > m_Link
The link handling the request.
Definition: UrlClient.cpp:199
std::weak_ptr< cUrlClientRequest > m_Self
weak_ptr to self, so that this object can keep itself alive as needed by calling lock(),...
Definition: UrlClient.cpp:193
AStringMap m_Options
Extra options to be used for the request.
Definition: UrlClient.cpp:189
AString m_Method
Method to be used for the request.
Definition: UrlClient.cpp:170
cUrlClientRequest(const AString &a_Method, const AString &a_Url, cUrlClient::cCallbacksPtr &&a_Callbacks, AStringMap &&a_Headers, const AString &a_Body, const AStringMap &a_Options)
Definition: UrlClient.cpp:207
virtual void OnRemoteClosed(void) override
Called when the remote end closes the connection.
Definition: UrlClient.cpp:625
void RedirectTo(const AString &a_RedirectUrl)
Definition: UrlClient.cpp:550
AString m_UrlFragment
Definition: UrlClient.cpp:176
std::pair< bool, AString > DoRequest(const std::shared_ptr< cUrlClientRequest > &a_Self)
Definition: UrlClient.cpp:639
cCryptoKeyPtr GetOwnPrivKey() const
Definition: UrlClient.cpp:132
AString m_Url
URL that will be requested.
Definition: UrlClient.cpp:173
int m_NumRemainingRedirects
The number of redirect attempts that will still be followed.
Definition: UrlClient.cpp:204
std::shared_ptr< cSchemeHandler > m_SchemeHandler
The handler that "talks" the protocol specified in m_UrlScheme, handles all the sending and receiving...
Definition: UrlClient.cpp:196
AStringMap m_Headers
Extra headers to be sent with the request (besides the normal ones).
Definition: UrlClient.cpp:183
AString m_UrlPassword
Definition: UrlClient.cpp:176
AString m_UrlUsername
Definition: UrlClient.cpp:176
cUrlClient::cCallbacks & GetCallbacks()
Definition: UrlClient.cpp:110
cSchemeHandler descendant that handles HTTP (and HTTPS) requests.
Definition: UrlClient.cpp:309
virtual void OnFirstLine(const AString &a_FirstLine) override
Called when the first line of the request or response is fully parsed.
Definition: UrlClient.cpp:402
virtual void OnReceivedData(const char *a_Data, size_t a_Length) override
Definition: UrlClient.cpp:371
virtual void OnHeadersFinished(void) override
Called when all the headers have been parsed.
Definition: UrlClient.cpp:459
cSchemeHandler Super
Definition: UrlClient.cpp:310
cHTTPMessageParser m_Parser
Parser of the HTTP response message.
Definition: UrlClient.cpp:506
bool m_IsRedirect
Set to true if the first line contains a redirecting HTTP status code and the options specify to foll...
Definition: UrlClient.cpp:514
AString m_RedirectLocation
The Location where the request should be redirected.
Definition: UrlClient.cpp:518
virtual void OnBodyData(const void *a_Data, size_t a_Size) override
Called for each chunk of the incoming body data.
Definition: UrlClient.cpp:469
virtual void OnError(const AString &a_ErrorDescription) override
Called when an error has occured while parsing.
Definition: UrlClient.cpp:395
void SendRequest()
Sends the HTTP request over the link.
Definition: UrlClient.cpp:339
virtual void OnTlsHandshakeCompleted(void) override
Definition: UrlClient.cpp:382
bool m_IsTls
If true, the TLS should be started on the link before sending the request (used for https).
Definition: UrlClient.cpp:509
virtual void OnHeaderLine(const AString &a_Key, const AString &a_Value) override
Called when a single header line is parsed.
Definition: UrlClient.cpp:442
virtual void OnRemoteClosed(void) override
Definition: UrlClient.cpp:388
virtual void OnBodyFinished(void) override
Called when the entire body has been reported by OnBodyData().
Definition: UrlClient.cpp:479
cTCPLink * m_Link
The network link.
Definition: UrlClient.cpp:503
virtual void OnConnected(cTCPLink &a_Link) override
Definition: UrlClient.cpp:323
cHttpSchemeHandler(cUrlClientRequest &a_ParentRequest, bool a_IsTls)
Definition: UrlClient.cpp:314
static std::pair< bool, AString > BlockingPut(const AString &a_URL, AStringMap &&a_Headers, const AString &a_Body, const AStringMap &a_Options={})
Alias for BlockingRequest("PUT", ...)
Definition: UrlClient.cpp:807
static std::pair< bool, AString > BlockingRequest(const AString &a_Method, const AString &a_URL, AStringMap &&a_Headers={}, const AString &a_Body={}, const AStringMap &a_Options={})
Sends a generic request and block until a response is received or an error occurs.
Definition: UrlClient.cpp:744
std::shared_ptr< cCallbacks > cCallbacksPtr
Definition: UrlClient.h:90
static std::pair< bool, AString > Put(const AString &a_URL, cCallbacksPtr &&a_Callbacks, AStringMap &&a_Headers, const AString &a_Body, const AStringMap &a_Options={})
Alias for Request("PUT", ...)
Definition: UrlClient.cpp:727
static std::pair< bool, AString > Request(const AString &a_Method, const AString &a_URL, cCallbacksPtr &&a_Callbacks, AStringMap &&a_Headers, const AString &a_Body, const AStringMap &a_Options)
Makes a network request to the specified URL, using the specified method (if applicable).
Definition: UrlClient.cpp:675
@ HTTP_STATUS_MULTIPLE_CHOICES
Definition: UrlClient.h:97
@ HTTP_STATUS_FOUND
Definition: UrlClient.h:99
@ HTTP_STATUS_MOVED_PERMANENTLY
Definition: UrlClient.h:98
@ HTTP_STATUS_SEE_OTHER
Definition: UrlClient.h:100
@ HTTP_STATUS_TEMPORARY_REDIRECT
Definition: UrlClient.h:101
static std::pair< bool, AString > BlockingPost(const AString &a_URL, AStringMap &&a_Headers, const AString &a_Body, const AStringMap &a_Options={})
Alias for BlockingRequest("POST", ...)
Definition: UrlClient.cpp:793
static std::pair< bool, AString > BlockingGet(const AString &a_URL, AStringMap a_Headers={}, const AString &a_Body={}, const AStringMap &a_Options={})
Alias for BlockingRequest("GET", ...)
Definition: UrlClient.cpp:779
static std::pair< bool, AString > Post(const AString &a_URL, cCallbacksPtr &&a_Callbacks, AStringMap &&a_Headers, const AString &a_Body, const AStringMap &a_Options={})
Alias for Request("POST", ...)
Definition: UrlClient.cpp:710
static std::pair< bool, AString > Get(const AString &a_URL, cCallbacksPtr &&a_Callbacks, AStringMap &&a_Headers={}, const AString &a_Body={}, const AStringMap &a_Options={})
Alias for Request("GET", ...)
Definition: UrlClient.cpp:693
Callbacks that are used for progress and result reporting.
Definition: UrlClient.h:39
virtual void OnBodyData(const void *a_Data, size_t a_Size)
Called when the next fragment of the response body is received, unless the response is an allowed red...
Definition: UrlClient.h:73
virtual void OnError(const AString &a_ErrorMsg)
Called when an asynchronous error is encountered.
Definition: UrlClient.h:80
virtual void OnBodyFinished()
Called after the response body has been fully reported by OnBody() calls, unless the response is an a...
Definition: UrlClient.h:77
static std::pair< bool, AString > Parse(const AString &a_Url, AString &a_Scheme, AString &a_Username, AString &a_Password, AString &a_Host, UInt16 &a_Port, AString &a_Path, AString &a_Query, AString &a_Fragment)
Parses the given URL into individual components.
Definition: UrlParser.cpp:117
Interface that provides the methods available on a single TCP connection.
Definition: Network.h:42
virtual AString StartTLSClient(cX509CertPtr a_OwnCert, cCryptoKeyPtr a_OwnPrivKey, cX509CertPtr a_TrustedRootCAs)=0
Starts a TLS handshake as a client connection.
virtual bool Send(const void *a_Data, size_t a_Length)=0
Queues the specified data for sending to the remote peer.
virtual void Shutdown(void)=0
Closes the link gracefully.
static bool Connect(const AString &a_Host, UInt16 a_Port, cConnectCallbacksPtr a_ConnectCallbacks, cTCPLink::cCallbacksPtr a_LinkCallbacks)
Queues a TCP connection to be made to the specified host.
Callbacks used for connecting to other servers as a client.
Definition: Network.h:237