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