| 1 | // |
| 2 | // HTTPRequest.cpp |
| 3 | // |
| 4 | // Library: Net |
| 5 | // Package: HTTP |
| 6 | // Module: HTTPRequest |
| 7 | // |
| 8 | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. |
| 9 | // and Contributors. |
| 10 | // |
| 11 | // SPDX-License-Identifier: BSL-1.0 |
| 12 | // |
| 13 | |
| 14 | |
| 15 | #include "Poco/Net/HTTPRequest.h" |
| 16 | #include "Poco/Net/NetException.h" |
| 17 | #include "Poco/Net/NameValueCollection.h" |
| 18 | #include "Poco/NumberFormatter.h" |
| 19 | #include "Poco/Ascii.h" |
| 20 | #include "Poco/String.h" |
| 21 | |
| 22 | |
| 23 | using Poco::NumberFormatter; |
| 24 | |
| 25 | |
| 26 | namespace Poco { |
| 27 | namespace Net { |
| 28 | |
| 29 | |
| 30 | const std::string HTTPRequest::HTTP_GET = "GET" ; |
| 31 | const std::string HTTPRequest::HTTP_HEAD = "HEAD" ; |
| 32 | const std::string HTTPRequest::HTTP_PUT = "PUT" ; |
| 33 | const std::string HTTPRequest::HTTP_POST = "POST" ; |
| 34 | const std::string HTTPRequest::HTTP_OPTIONS = "OPTIONS" ; |
| 35 | const std::string HTTPRequest::HTTP_DELETE = "DELETE" ; |
| 36 | const std::string HTTPRequest::HTTP_TRACE = "TRACE" ; |
| 37 | const std::string HTTPRequest::HTTP_CONNECT = "CONNECT" ; |
| 38 | const std::string HTTPRequest::HTTP_PATCH = "PATCH" ; |
| 39 | const std::string HTTPRequest::HOST = "Host" ; |
| 40 | const std::string HTTPRequest::COOKIE = "Cookie" ; |
| 41 | const std::string HTTPRequest::AUTHORIZATION = "Authorization" ; |
| 42 | const std::string HTTPRequest::PROXY_AUTHORIZATION = "Proxy-Authorization" ; |
| 43 | const std::string HTTPRequest::UPGRADE = "Upgrade" ; |
| 44 | const std::string HTTPRequest::EXPECT = "Expect" ; |
| 45 | |
| 46 | |
| 47 | HTTPRequest::HTTPRequest(): |
| 48 | _method(HTTP_GET), |
| 49 | _uri("/" ) |
| 50 | { |
| 51 | } |
| 52 | |
| 53 | |
| 54 | HTTPRequest::HTTPRequest(const std::string& version): |
| 55 | HTTPMessage(version), |
| 56 | _method(HTTP_GET), |
| 57 | _uri("/" ) |
| 58 | { |
| 59 | } |
| 60 | |
| 61 | |
| 62 | HTTPRequest::HTTPRequest(const std::string& method, const std::string& uri): |
| 63 | _method(method), |
| 64 | _uri(uri) |
| 65 | { |
| 66 | } |
| 67 | |
| 68 | |
| 69 | HTTPRequest::HTTPRequest(const std::string& method, const std::string& uri, const std::string& version): |
| 70 | HTTPMessage(version), |
| 71 | _method(method), |
| 72 | _uri(uri) |
| 73 | { |
| 74 | } |
| 75 | |
| 76 | |
| 77 | HTTPRequest::~HTTPRequest() |
| 78 | { |
| 79 | } |
| 80 | |
| 81 | |
| 82 | void HTTPRequest::setMethod(const std::string& method) |
| 83 | { |
| 84 | _method = method; |
| 85 | } |
| 86 | |
| 87 | |
| 88 | void HTTPRequest::setURI(const std::string& uri) |
| 89 | { |
| 90 | _uri = uri; |
| 91 | } |
| 92 | |
| 93 | |
| 94 | void HTTPRequest::setHost(const std::string& host) |
| 95 | { |
| 96 | set(HOST, host); |
| 97 | } |
| 98 | |
| 99 | |
| 100 | void HTTPRequest::setHost(const std::string& host, Poco::UInt16 port) |
| 101 | { |
| 102 | std::string value; |
| 103 | if (host.find(':') != std::string::npos) |
| 104 | { |
| 105 | // IPv6 address |
| 106 | value.append("[" ); |
| 107 | value.append(host); |
| 108 | value.append("]" ); |
| 109 | } |
| 110 | else |
| 111 | { |
| 112 | value.append(host); |
| 113 | } |
| 114 | |
| 115 | if (port != 80 && port != 443) |
| 116 | { |
| 117 | value.append(":" ); |
| 118 | NumberFormatter::append(value, port); |
| 119 | } |
| 120 | setHost(value); |
| 121 | } |
| 122 | |
| 123 | |
| 124 | const std::string& HTTPRequest::getHost() const |
| 125 | { |
| 126 | return get(HOST); |
| 127 | } |
| 128 | |
| 129 | |
| 130 | void HTTPRequest::setCookies(const NameValueCollection& cookies) |
| 131 | { |
| 132 | std::string cookie; |
| 133 | cookie.reserve(64); |
| 134 | for (NameValueCollection::ConstIterator it = cookies.begin(); it != cookies.end(); ++it) |
| 135 | { |
| 136 | if (it != cookies.begin()) |
| 137 | cookie.append("; " ); |
| 138 | cookie.append(it->first); |
| 139 | cookie.append("=" ); |
| 140 | cookie.append(it->second); |
| 141 | } |
| 142 | add(COOKIE, cookie); |
| 143 | } |
| 144 | |
| 145 | |
| 146 | void HTTPRequest::getCookies(NameValueCollection& cookies) const |
| 147 | { |
| 148 | NameValueCollection::ConstIterator it = find(COOKIE); |
| 149 | while (it != end() && Poco::icompare(it->first, COOKIE) == 0) |
| 150 | { |
| 151 | splitParameters(it->second.begin(), it->second.end(), cookies); |
| 152 | ++it; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | |
| 157 | bool HTTPRequest::hasCredentials() const |
| 158 | { |
| 159 | return has(AUTHORIZATION); |
| 160 | } |
| 161 | |
| 162 | |
| 163 | void HTTPRequest::getCredentials(std::string& scheme, std::string& authInfo) const |
| 164 | { |
| 165 | getCredentials(AUTHORIZATION, scheme, authInfo); |
| 166 | } |
| 167 | |
| 168 | |
| 169 | void HTTPRequest::setCredentials(const std::string& scheme, const std::string& authInfo) |
| 170 | { |
| 171 | setCredentials(AUTHORIZATION, scheme, authInfo); |
| 172 | } |
| 173 | |
| 174 | |
| 175 | bool HTTPRequest::hasProxyCredentials() const |
| 176 | { |
| 177 | return has(PROXY_AUTHORIZATION); |
| 178 | } |
| 179 | |
| 180 | |
| 181 | void HTTPRequest::getProxyCredentials(std::string& scheme, std::string& authInfo) const |
| 182 | { |
| 183 | getCredentials(PROXY_AUTHORIZATION, scheme, authInfo); |
| 184 | } |
| 185 | |
| 186 | |
| 187 | void HTTPRequest::setProxyCredentials(const std::string& scheme, const std::string& authInfo) |
| 188 | { |
| 189 | setCredentials(PROXY_AUTHORIZATION, scheme, authInfo); |
| 190 | } |
| 191 | |
| 192 | |
| 193 | void HTTPRequest::write(std::ostream& ostr) const |
| 194 | { |
| 195 | ostr << _method << " " << _uri << " " << getVersion() << "\r\n" ; |
| 196 | HTTPMessage::write(ostr); |
| 197 | ostr << "\r\n" ; |
| 198 | } |
| 199 | |
| 200 | |
| 201 | void HTTPRequest::read(std::istream& istr) |
| 202 | { |
| 203 | static const int eof = std::char_traits<char>::eof(); |
| 204 | |
| 205 | std::string method; |
| 206 | std::string uri; |
| 207 | std::string version; |
| 208 | method.reserve(16); |
| 209 | uri.reserve(64); |
| 210 | version.reserve(16); |
| 211 | int ch = istr.get(); |
| 212 | if (istr.bad()) throw NetException("Error reading HTTP request header" ); |
| 213 | if (ch == eof) throw NoMessageException(); |
| 214 | while (Poco::Ascii::isSpace(ch)) ch = istr.get(); |
| 215 | if (ch == eof) throw MessageException("No HTTP request header" ); |
| 216 | while (!Poco::Ascii::isSpace(ch) && ch != eof && method.length() < MAX_METHOD_LENGTH) { method += (char) ch; ch = istr.get(); } |
| 217 | if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP request method invalid or too long" ); |
| 218 | while (Poco::Ascii::isSpace(ch)) ch = istr.get(); |
| 219 | while (!Poco::Ascii::isSpace(ch) && ch != eof && uri.length() < MAX_URI_LENGTH) { uri += (char) ch; ch = istr.get(); } |
| 220 | if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP request URI invalid or too long" ); |
| 221 | while (Poco::Ascii::isSpace(ch)) ch = istr.get(); |
| 222 | while (!Poco::Ascii::isSpace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); } |
| 223 | if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP version string" ); |
| 224 | while (ch != '\n' && ch != eof) { ch = istr.get(); } |
| 225 | HTTPMessage::read(istr); |
| 226 | ch = istr.get(); |
| 227 | while (ch != '\n' && ch != eof) { ch = istr.get(); } |
| 228 | setMethod(method); |
| 229 | setURI(uri); |
| 230 | setVersion(version); |
| 231 | } |
| 232 | |
| 233 | |
| 234 | void HTTPRequest::getCredentials(const std::string& , std::string& scheme, std::string& authInfo) const |
| 235 | { |
| 236 | scheme.clear(); |
| 237 | authInfo.clear(); |
| 238 | if (has(header)) |
| 239 | { |
| 240 | const std::string& auth = get(header); |
| 241 | std::string::const_iterator it = auth.begin(); |
| 242 | std::string::const_iterator end = auth.end(); |
| 243 | while (it != end && Poco::Ascii::isSpace(*it)) ++it; |
| 244 | while (it != end && !Poco::Ascii::isSpace(*it)) scheme += *it++; |
| 245 | while (it != end && Poco::Ascii::isSpace(*it)) ++it; |
| 246 | while (it != end) authInfo += *it++; |
| 247 | } |
| 248 | else throw NotAuthenticatedException(); |
| 249 | } |
| 250 | |
| 251 | |
| 252 | void HTTPRequest::setCredentials(const std::string& , const std::string& scheme, const std::string& authInfo) |
| 253 | { |
| 254 | std::string auth(scheme); |
| 255 | auth.append(" " ); |
| 256 | auth.append(authInfo); |
| 257 | set(header, auth); |
| 258 | } |
| 259 | |
| 260 | |
| 261 | bool HTTPRequest::getExpectContinue() const |
| 262 | { |
| 263 | const std::string& expect = get(EXPECT, EMPTY); |
| 264 | return !expect.empty() && icompare(expect, "100-continue" ) == 0; |
| 265 | } |
| 266 | |
| 267 | |
| 268 | void HTTPRequest::setExpectContinue(bool expectContinue) |
| 269 | { |
| 270 | if (expectContinue) |
| 271 | set(EXPECT, "100-continue" ); |
| 272 | else |
| 273 | erase(EXPECT); |
| 274 | } |
| 275 | |
| 276 | |
| 277 | } } // namespace Poco::Net |
| 278 | |