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