aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/poco/Net/src/HTTPResponse.cpp
blob: 70093ac07ee8564110f6ffb21c2443427fad59c9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
//
// HTTPResponse.cpp
//
// Library: Net
// Package: HTTP
// Module:  HTTPResponse
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeParser.h"
#include "Poco/Ascii.h"
#include "Poco/String.h"


using Poco::DateTime;
using Poco::NumberFormatter;
using Poco::NumberParser;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::DateTimeParser;


namespace Poco {
namespace Net {


const std::string HTTPResponse::HTTP_REASON_CONTINUE                        = "Continue";
const std::string HTTPResponse::HTTP_REASON_SWITCHING_PROTOCOLS             = "Switching Protocols";
const std::string HTTPResponse::HTTP_REASON_PROCESSING                      = "Processing";
const std::string HTTPResponse::HTTP_REASON_OK                              = "OK";
const std::string HTTPResponse::HTTP_REASON_CREATED                         = "Created";
const std::string HTTPResponse::HTTP_REASON_ACCEPTED                        = "Accepted";
const std::string HTTPResponse::HTTP_REASON_NONAUTHORITATIVE                = "Non-Authoritative Information";
const std::string HTTPResponse::HTTP_REASON_NO_CONTENT                      = "No Content";
const std::string HTTPResponse::HTTP_REASON_RESET_CONTENT                   = "Reset Content";
const std::string HTTPResponse::HTTP_REASON_PARTIAL_CONTENT                 = "Partial Content";
const std::string HTTPResponse::HTTP_REASON_MULTI_STATUS                    = "Multi Status";
const std::string HTTPResponse::HTTP_REASON_ALREADY_REPORTED                = "Already Reported";
const std::string HTTPResponse::HTTP_REASON_IM_USED                         = "IM Used";
const std::string HTTPResponse::HTTP_REASON_MULTIPLE_CHOICES                = "Multiple Choices";
const std::string HTTPResponse::HTTP_REASON_MOVED_PERMANENTLY               = "Moved Permanently";
const std::string HTTPResponse::HTTP_REASON_FOUND                           = "Found";
const std::string HTTPResponse::HTTP_REASON_SEE_OTHER                       = "See Other";
const std::string HTTPResponse::HTTP_REASON_NOT_MODIFIED                    = "Not Modified";
const std::string HTTPResponse::HTTP_REASON_USE_PROXY                       = "Use Proxy";
const std::string HTTPResponse::HTTP_REASON_TEMPORARY_REDIRECT              = "Temporary Redirect";
const std::string HTTPResponse::HTTP_REASON_PERMANENT_REDIRECT              = "Permanent Redirect";
const std::string HTTPResponse::HTTP_REASON_BAD_REQUEST                     = "Bad Request";
const std::string HTTPResponse::HTTP_REASON_UNAUTHORIZED                    = "Unauthorized";
const std::string HTTPResponse::HTTP_REASON_PAYMENT_REQUIRED                = "Payment Required";
const std::string HTTPResponse::HTTP_REASON_FORBIDDEN                       = "Forbidden";
const std::string HTTPResponse::HTTP_REASON_NOT_FOUND                       = "Not Found";
const std::string HTTPResponse::HTTP_REASON_METHOD_NOT_ALLOWED              = "Method Not Allowed";
const std::string HTTPResponse::HTTP_REASON_NOT_ACCEPTABLE                  = "Not Acceptable";
const std::string HTTPResponse::HTTP_REASON_PROXY_AUTHENTICATION_REQUIRED   = "Proxy Authentication Required";
const std::string HTTPResponse::HTTP_REASON_REQUEST_TIMEOUT                 = "Request Time-out";
const std::string HTTPResponse::HTTP_REASON_CONFLICT                        = "Conflict";
const std::string HTTPResponse::HTTP_REASON_GONE                            = "Gone";
const std::string HTTPResponse::HTTP_REASON_LENGTH_REQUIRED                 = "Length Required";
const std::string HTTPResponse::HTTP_REASON_PRECONDITION_FAILED             = "Precondition Failed";
const std::string HTTPResponse::HTTP_REASON_REQUEST_ENTITY_TOO_LARGE        = "Request Entity Too Large";
const std::string HTTPResponse::HTTP_REASON_REQUEST_URI_TOO_LONG            = "Request-URI Too Large";
const std::string HTTPResponse::HTTP_REASON_UNSUPPORTED_MEDIA_TYPE          = "Unsupported Media Type";
const std::string HTTPResponse::HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE = "Requested Range Not Satisfiable";
const std::string HTTPResponse::HTTP_REASON_EXPECTATION_FAILED              = "Expectation Failed";
const std::string HTTPResponse::HTTP_REASON_IM_A_TEAPOT                     = "I'm a Teapot";
const std::string HTTPResponse::HTTP_REASON_ENCHANCE_YOUR_CALM              = "Enchance Your Calm";
const std::string HTTPResponse::HTTP_REASON_MISDIRECTED_REQUEST             = "Misdirected Request";
const std::string HTTPResponse::HTTP_REASON_UNPROCESSABLE_ENTITY            = "Unprocessable Entity";
const std::string HTTPResponse::HTTP_REASON_LOCKED                          = "Locked";
const std::string HTTPResponse::HTTP_REASON_FAILED_DEPENDENCY               = "Failed Dependency";
const std::string HTTPResponse::HTTP_REASON_UPGRADE_REQUIRED                = "Upgrade Required";
const std::string HTTPResponse::HTTP_REASON_PRECONDITION_REQUIRED           = "Precondition Required";
const std::string HTTPResponse::HTTP_REASON_TOO_MANY_REQUESTS               = "Too Many Requests";
const std::string HTTPResponse::HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE = "Request Header Fields Too Large";
const std::string HTTPResponse::HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS   = "Unavailable For Legal Reasons";
const std::string HTTPResponse::HTTP_REASON_INTERNAL_SERVER_ERROR           = "Internal Server Error";
const std::string HTTPResponse::HTTP_REASON_NOT_IMPLEMENTED                 = "Not Implemented";
const std::string HTTPResponse::HTTP_REASON_BAD_GATEWAY                     = "Bad Gateway";
const std::string HTTPResponse::HTTP_REASON_SERVICE_UNAVAILABLE             = "Service Unavailable";
const std::string HTTPResponse::HTTP_REASON_GATEWAY_TIMEOUT                 = "Gateway Time-Out";
const std::string HTTPResponse::HTTP_REASON_VERSION_NOT_SUPPORTED           = "HTTP Version Not Supported";
const std::string HTTPResponse::HTTP_REASON_VARIANT_ALSO_NEGOTIATES         = "Variant Also Negotiates";
const std::string HTTPResponse::HTTP_REASON_INSUFFICIENT_STORAGE            = "Insufficient Storage";
const std::string HTTPResponse::HTTP_REASON_LOOP_DETECTED                   = "Loop Detected";
const std::string HTTPResponse::HTTP_REASON_NOT_EXTENDED                    = "Not Extended";
const std::string HTTPResponse::HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED = "Network Authentication Required";
const std::string HTTPResponse::HTTP_REASON_UNKNOWN                         = "???";
const std::string HTTPResponse::DATE       = "Date";
const std::string HTTPResponse::SET_COOKIE = "Set-Cookie";


HTTPResponse::HTTPResponse():
	_status(HTTP_OK),
	_reason(getReasonForStatus(HTTP_OK))
{
}

	
HTTPResponse::HTTPResponse(HTTPStatus status, const std::string& reason):
	_status(status),
	_reason(reason)
{
}


	
HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status, const std::string& reason):
	HTTPMessage(version),
	_status(status),
	_reason(reason)
{
}

	
HTTPResponse::HTTPResponse(HTTPStatus status):
	_status(status),
	_reason(getReasonForStatus(status))
{
}


HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status):
	HTTPMessage(version),
	_status(status),
	_reason(getReasonForStatus(status))
{
}


HTTPResponse::~HTTPResponse()
{
}


void HTTPResponse::setStatus(HTTPStatus status)
{
	_status = status;
}


void HTTPResponse::setStatus(const std::string& status)
{
	setStatus((HTTPStatus) NumberParser::parse(status));
}
	
	
void HTTPResponse::setReason(const std::string& reason)
{
	_reason = reason;
}


void HTTPResponse::setStatusAndReason(HTTPStatus status, const std::string& reason)
{
	_status = status;
	_reason = reason;
}

	
void HTTPResponse::setStatusAndReason(HTTPStatus status)
{
	setStatusAndReason(status, getReasonForStatus(status));
}


void HTTPResponse::setDate(const Poco::Timestamp& dateTime)
{
	set(DATE, DateTimeFormatter::format(dateTime, DateTimeFormat::HTTP_FORMAT));
}

	
Poco::Timestamp HTTPResponse::getDate() const
{
	const std::string& dateTime = get(DATE);
	int tzd;
	return DateTimeParser::parse(dateTime, tzd).timestamp();
}


void HTTPResponse::addCookie(const HTTPCookie& cookie)
{
	add(SET_COOKIE, cookie.toString());
}


void HTTPResponse::getCookies(std::vector<HTTPCookie>& cookies) const
{
	cookies.clear();
	NameValueCollection::ConstIterator it = find(SET_COOKIE);
	while (it != end() && Poco::icompare(it->first, SET_COOKIE) == 0)
	{
		NameValueCollection nvc;
		splitParameters(it->second.begin(), it->second.end(), nvc);
		cookies.push_back(HTTPCookie(nvc));
		++it;
	}
}


void HTTPResponse::write(std::ostream& ostr) const
{
	beginWrite(ostr);
	ostr << "\r\n";
}


void HTTPResponse::beginWrite(std::ostream& ostr) const
{
	ostr << getVersion() << " " << static_cast<int>(_status) << " " << _reason << "\r\n";
	HTTPMessage::write(ostr);
}


void HTTPResponse::read(std::istream& istr)
{
	static const int eof = std::char_traits<char>::eof();

	std::string version;
	std::string status;
	std::string reason;
	
	int ch =  istr.get();
	if (istr.bad()) throw NetException("Error reading HTTP response header");
	if (ch == eof) throw NoMessageException();
	while (Poco::Ascii::isSpace(ch)) ch = istr.get();
	if (ch == eof) throw MessageException("No HTTP response header");
	while (!Poco::Ascii::isSpace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
	if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP version string");
	while (Poco::Ascii::isSpace(ch)) ch = istr.get();
	while (!Poco::Ascii::isSpace(ch) && ch != eof && status.length() < MAX_STATUS_LENGTH) { status += (char) ch; ch = istr.get(); }
	if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP status code");
	while (Poco::Ascii::isSpace(ch) && ch != '\r' && ch != '\n' && ch != eof) ch = istr.get();
	while (ch != '\r' && ch != '\n' && ch != eof && reason.length() < MAX_REASON_LENGTH) { reason += (char) ch; ch = istr.get(); }
	if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP reason string too long");
	if (ch == '\r') ch = istr.get();
	if (ch != '\n') throw MessageException("Unterminated HTTP response line");

	HTTPMessage::read(istr);
	ch = istr.get();
	while (ch != '\n' && ch != eof) { ch = istr.get(); }
	setVersion(version);
	setStatus(status);
	setReason(reason);
}


const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
{
	switch (status)
	{
	case HTTP_CONTINUE: 
		return HTTP_REASON_CONTINUE;
	case HTTP_SWITCHING_PROTOCOLS: 
		return HTTP_REASON_SWITCHING_PROTOCOLS;
	case HTTP_PROCESSING:
		return HTTP_REASON_PROCESSING;
	case HTTP_OK: 
		return HTTP_REASON_OK;
	case HTTP_CREATED: 
		return HTTP_REASON_CREATED;
	case HTTP_ACCEPTED: 
		return HTTP_REASON_ACCEPTED;
	case HTTP_NONAUTHORITATIVE:	
		return HTTP_REASON_NONAUTHORITATIVE;
	case HTTP_NO_CONTENT: 
		return HTTP_REASON_NO_CONTENT;
	case HTTP_RESET_CONTENT: 
		return HTTP_REASON_RESET_CONTENT;
	case HTTP_PARTIAL_CONTENT: 
		return HTTP_REASON_PARTIAL_CONTENT;
	case HTTP_MULTI_STATUS:
		return HTTP_REASON_MULTI_STATUS;
	case HTTP_ALREADY_REPORTED:
		return HTTP_REASON_ALREADY_REPORTED;
	case HTTP_IM_USED:
		return HTTP_REASON_IM_USED;
	case HTTP_MULTIPLE_CHOICES: 
		return HTTP_REASON_MULTIPLE_CHOICES;
	case HTTP_MOVED_PERMANENTLY: 
		return HTTP_REASON_MOVED_PERMANENTLY;
	case HTTP_FOUND: 
		return HTTP_REASON_FOUND;
	case HTTP_SEE_OTHER: 
		return HTTP_REASON_SEE_OTHER;
	case HTTP_NOT_MODIFIED: 
		return HTTP_REASON_NOT_MODIFIED;
	case HTTP_USE_PROXY: 
		return HTTP_REASON_USE_PROXY;
	case HTTP_TEMPORARY_REDIRECT: 
		return HTTP_REASON_TEMPORARY_REDIRECT;
	case HTTP_BAD_REQUEST: 
		return HTTP_REASON_BAD_REQUEST;
	case HTTP_UNAUTHORIZED: 
		return HTTP_REASON_UNAUTHORIZED;
	case HTTP_PAYMENT_REQUIRED: 
		return HTTP_REASON_PAYMENT_REQUIRED;
	case HTTP_FORBIDDEN: 
		return HTTP_REASON_FORBIDDEN;
	case HTTP_NOT_FOUND: 
		return HTTP_REASON_NOT_FOUND;
	case HTTP_METHOD_NOT_ALLOWED:
		return HTTP_REASON_METHOD_NOT_ALLOWED;
	case HTTP_NOT_ACCEPTABLE: 
		return HTTP_REASON_NOT_ACCEPTABLE;
	case HTTP_PROXY_AUTHENTICATION_REQUIRED: 
		return HTTP_REASON_PROXY_AUTHENTICATION_REQUIRED;
	case HTTP_REQUEST_TIMEOUT: 
		return HTTP_REASON_REQUEST_TIMEOUT;
	case HTTP_CONFLICT: 
		return HTTP_REASON_CONFLICT;
	case HTTP_GONE: 
		return HTTP_REASON_GONE;
	case HTTP_LENGTH_REQUIRED: 
		return HTTP_REASON_LENGTH_REQUIRED;
	case HTTP_PRECONDITION_FAILED: 
		return HTTP_REASON_PRECONDITION_FAILED;
	case HTTP_REQUEST_ENTITY_TOO_LARGE: 
		return HTTP_REASON_REQUEST_ENTITY_TOO_LARGE;
	case HTTP_REQUEST_URI_TOO_LONG: 
		return HTTP_REASON_REQUEST_URI_TOO_LONG;
	case HTTP_UNSUPPORTED_MEDIA_TYPE: 
		return HTTP_REASON_UNSUPPORTED_MEDIA_TYPE;
	case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: 
		return HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE;
	case HTTP_EXPECTATION_FAILED: 
		return HTTP_REASON_EXPECTATION_FAILED;
	case HTTP_IM_A_TEAPOT:
		return HTTP_REASON_IM_A_TEAPOT;            
	case HTTP_ENCHANCE_YOUR_CALM:
		return HTTP_REASON_ENCHANCE_YOUR_CALM;
	case HTTP_MISDIRECTED_REQUEST:
		return HTTP_REASON_MISDIRECTED_REQUEST;
	case HTTP_UNPROCESSABLE_ENTITY:
		return HTTP_REASON_UNPROCESSABLE_ENTITY;
	case HTTP_LOCKED:
		return HTTP_REASON_LOCKED;
	case HTTP_FAILED_DEPENDENCY:
		return HTTP_REASON_FAILED_DEPENDENCY;
	case HTTP_UPGRADE_REQUIRED:
		return HTTP_REASON_UPGRADE_REQUIRED;
	case HTTP_PRECONDITION_REQUIRED:
		return HTTP_REASON_PRECONDITION_REQUIRED;
	case HTTP_TOO_MANY_REQUESTS:
		return HTTP_REASON_TOO_MANY_REQUESTS;
	case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE:
		return HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE;
	case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
		return HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS;
	case HTTP_INTERNAL_SERVER_ERROR: 
		return HTTP_REASON_INTERNAL_SERVER_ERROR;
	case HTTP_NOT_IMPLEMENTED: 
		return HTTP_REASON_NOT_IMPLEMENTED;
	case HTTP_BAD_GATEWAY: 
		return HTTP_REASON_BAD_GATEWAY;
	case HTTP_SERVICE_UNAVAILABLE:
		return HTTP_REASON_SERVICE_UNAVAILABLE;
	case HTTP_GATEWAY_TIMEOUT: 
		return HTTP_REASON_GATEWAY_TIMEOUT;
	case HTTP_VERSION_NOT_SUPPORTED: 
		return HTTP_REASON_VERSION_NOT_SUPPORTED;
	case HTTP_VARIANT_ALSO_NEGOTIATES:
		return HTTP_REASON_VARIANT_ALSO_NEGOTIATES;
	case HTTP_INSUFFICIENT_STORAGE:
		return HTTP_REASON_INSUFFICIENT_STORAGE;
	case HTTP_LOOP_DETECTED:
		return HTTP_REASON_LOOP_DETECTED;
	case HTTP_NOT_EXTENDED:
		return HTTP_REASON_NOT_EXTENDED;
	case HTTP_NETWORK_AUTHENTICATION_REQUIRED:
		return HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED;
	default: 
		return HTTP_REASON_UNKNOWN;
	}
}


} } // namespace Poco::Net