HTTPSStreamFactory.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. //
  2. // HTTPSStreamFactory.cpp
  3. //
  4. // Library: NetSSL_OpenSSL
  5. // Package: HTTPSClient
  6. // Module: HTTPSStreamFactory
  7. //
  8. // Copyright (c) 2006-2012, Applied Informatics Software Engineering GmbH.
  9. // and Contributors.
  10. //
  11. // SPDX-License-Identifier: BSL-1.0
  12. //
  13. #include "Poco/Net/HTTPSStreamFactory.h"
  14. #include "Poco/Net/HTTPSClientSession.h"
  15. #include "Poco/Net/HTTPIOStream.h"
  16. #include "Poco/Net/HTTPRequest.h"
  17. #include "Poco/Net/HTTPResponse.h"
  18. #include "Poco/Net/HTTPCredentials.h"
  19. #include "Poco/Net/NetException.h"
  20. #include "Poco/URI.h"
  21. #include "Poco/URIStreamOpener.h"
  22. #include "Poco/UnbufferedStreamBuf.h"
  23. #include "Poco/NullStream.h"
  24. #include "Poco/StreamCopier.h"
  25. #include "Poco/Format.h"
  26. #include "Poco/Version.h"
  27. using Poco::URIStreamFactory;
  28. using Poco::URI;
  29. using Poco::URIStreamOpener;
  30. using Poco::UnbufferedStreamBuf;
  31. namespace Poco {
  32. namespace Net {
  33. HTTPSStreamFactory::HTTPSStreamFactory():
  34. _proxyPort(HTTPSession::HTTP_PORT)
  35. {
  36. }
  37. HTTPSStreamFactory::HTTPSStreamFactory(const std::string& proxyHost, Poco::UInt16 proxyPort):
  38. _proxyHost(proxyHost),
  39. _proxyPort(proxyPort)
  40. {
  41. }
  42. HTTPSStreamFactory::HTTPSStreamFactory(const std::string& proxyHost, Poco::UInt16 proxyPort, const std::string& proxyUsername, const std::string& proxyPassword):
  43. _proxyHost(proxyHost),
  44. _proxyPort(proxyPort),
  45. _proxyUsername(proxyUsername),
  46. _proxyPassword(proxyPassword)
  47. {
  48. }
  49. HTTPSStreamFactory::~HTTPSStreamFactory()
  50. {
  51. }
  52. std::istream* HTTPSStreamFactory::open(const URI& uri)
  53. {
  54. poco_assert (uri.getScheme() == "https" || uri.getScheme() == "http");
  55. URI resolvedURI(uri);
  56. URI proxyUri;
  57. HTTPClientSession* pSession = 0;
  58. HTTPResponse res;
  59. try
  60. {
  61. bool retry = false;
  62. bool authorize = false;
  63. int redirects = 0;
  64. std::string username;
  65. std::string password;
  66. do
  67. {
  68. if (!pSession)
  69. {
  70. if (resolvedURI.getScheme() != "http")
  71. pSession = new HTTPSClientSession(resolvedURI.getHost(), resolvedURI.getPort());
  72. else
  73. pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort());
  74. if (proxyUri.empty())
  75. {
  76. if (!_proxyHost.empty())
  77. {
  78. pSession->setProxy(_proxyHost, _proxyPort);
  79. pSession->setProxyCredentials(_proxyUsername, _proxyPassword);
  80. }
  81. }
  82. else
  83. {
  84. pSession->setProxy(proxyUri.getHost(), proxyUri.getPort());
  85. if (!_proxyUsername.empty())
  86. {
  87. pSession->setProxyCredentials(_proxyUsername, _proxyPassword);
  88. }
  89. }
  90. }
  91. std::string path = resolvedURI.getPathAndQuery();
  92. if (path.empty()) path = "/";
  93. HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
  94. if (authorize)
  95. {
  96. HTTPCredentials::extractCredentials(uri, username, password);
  97. HTTPCredentials cred(username, password);
  98. cred.authenticate(req, res);
  99. }
  100. req.set("User-Agent", Poco::format("poco/%d.%d.%d",
  101. (POCO_VERSION >> 24) & 0xFF,
  102. (POCO_VERSION >> 16) & 0xFF,
  103. (POCO_VERSION >> 8) & 0xFF));
  104. req.set("Accept", "*/*");
  105. pSession->sendRequest(req);
  106. std::istream& rs = pSession->receiveResponse(res);
  107. bool moved = (res.getStatus() == HTTPResponse::HTTP_MOVED_PERMANENTLY ||
  108. res.getStatus() == HTTPResponse::HTTP_FOUND ||
  109. res.getStatus() == HTTPResponse::HTTP_SEE_OTHER ||
  110. res.getStatus() == HTTPResponse::HTTP_TEMPORARY_REDIRECT);
  111. if (moved)
  112. {
  113. resolvedURI.resolve(res.get("Location"));
  114. if (!username.empty())
  115. {
  116. resolvedURI.setUserInfo(username + ":" + password);
  117. authorize = false;
  118. }
  119. delete pSession;
  120. pSession = 0;
  121. ++redirects;
  122. retry = true;
  123. }
  124. else if (res.getStatus() == HTTPResponse::HTTP_OK)
  125. {
  126. return new HTTPResponseStream(rs, pSession);
  127. }
  128. else if (res.getStatus() == HTTPResponse::HTTP_USEPROXY && !retry)
  129. {
  130. // The requested resource MUST be accessed through the proxy
  131. // given by the Location field. The Location field gives the
  132. // URI of the proxy. The recipient is expected to repeat this
  133. // single request via the proxy. 305 responses MUST only be generated by origin servers.
  134. // only use for one single request!
  135. proxyUri.resolve(res.get("Location"));
  136. delete pSession;
  137. pSession = 0;
  138. retry = true; // only allow useproxy once
  139. }
  140. else if (res.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED && !authorize)
  141. {
  142. authorize = true;
  143. retry = true;
  144. Poco::NullOutputStream null;
  145. Poco::StreamCopier::copyStream(rs, null);
  146. }
  147. else throw HTTPException(res.getReason(), uri.toString());
  148. }
  149. while (retry && redirects < MAX_REDIRECTS);
  150. throw HTTPException("Too many redirects", uri.toString());
  151. }
  152. catch (...)
  153. {
  154. delete pSession;
  155. throw;
  156. }
  157. }
  158. void HTTPSStreamFactory::registerFactory()
  159. {
  160. URIStreamOpener::defaultOpener().registerStreamFactory("https", new HTTPSStreamFactory);
  161. }
  162. void HTTPSStreamFactory::unregisterFactory()
  163. {
  164. URIStreamOpener::defaultOpener().unregisterStreamFactory("https");
  165. }
  166. } } // namespace Poco::Net