2 * @file http_request.cpp
3 * @brief module of HTTP Request
4 * @brief HTTP Request parser
6 * Copyright (C) 2009 NTT COMWARE Corporation.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 **********************************************************************/
25 #include "http_request.h"
28 * HTTP Request constructor.
30 http_request::http_request()
32 /*-------- DEBUG LOG --------*/
33 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
34 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 20,
35 "in/out_function : Constructor http_request::http_request(void)");
37 /*------ DEBUG LOG END ------*/
41 * HTTP Request constructor.
42 * Parse HTTP request header.
44 * @param[in] header full http request header string
46 http_request::http_request(std::string header)
48 /*-------- DEBUG LOG --------*/
49 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
50 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 21,
51 "in/out_function : Constructor http_request::http_request(std::string header) : "
52 "header(%s)", header.c_str());
54 /*------ DEBUG LOG END ------*/
59 * HTTP Request destructor.
61 http_request::~http_request()
63 /*-------- DEBUG LOG --------*/
64 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
65 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 22,
66 "in/out_function : Destructor http_request::~http_request(void)");
68 /*------ DEBUG LOG END ------*/
72 * Get method function.
76 std::string http_request::method() const
78 /*-------- DEBUG LOG --------*/
79 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
80 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 23,
81 "in_function : std::string http_request::method(void)");
82 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 24,
83 "out_function : std::string http_request::method(void) : "
84 "return(%s)", this->_method.c_str());
86 /*------ DEBUG LOG END ------*/
92 * Set method function.
93 * Set new method and return old method.
95 * @param[in] method new method
98 std::string http_request::method(std::string _method)
100 /*-------- DEBUG LOG --------*/
101 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
102 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 25,
103 "in_function : std::string http_request::method(std::string _method) : "
104 "_method(%s)", _method.c_str());
106 /*------ DEBUG LOG END ------*/
108 std::string ret = this->_method;
109 this->_method = _method;
110 this->_modified = true;
112 /*-------- DEBUG LOG --------*/
113 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
114 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 26,
115 "out_function : std::string http_request::method(std::string _method) : "
116 "return(%s)", ret.c_str());
118 /*------ DEBUG LOG END ------*/
124 * Get request URI function.
126 * @return request URI
128 std::string http_request::request_uri() const
130 /*-------- DEBUG LOG --------*/
131 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
132 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 27,
133 "in_function : std::string http_request::request_uri(void)");
134 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 28,
135 "out_function : std::string http_request::request_uri(void) : "
136 "return(%s)", this->_request_uri.c_str());
138 /*------ DEBUG LOG END ------*/
140 return this->_request_uri;
144 * Set request URI function.
145 * Set new request URI and return old request URI.
147 * @param[in] _request_uri new request URI
148 * @return old request URI
150 std::string http_request::request_uri(std::string _request_uri)
152 /*-------- DEBUG LOG --------*/
153 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
154 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 29,
155 "in_function : std::string http_request::request_uri(std::string _request_uri) : "
156 "_request_uri(%s)", _request_uri.c_str());
158 /*------ DEBUG LOG END ------*/
160 std::string ret = this->_request_uri;
161 this->_request_uri = _request_uri;
162 this->_modified = true;
164 /*-------- DEBUG LOG --------*/
165 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
166 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 30,
167 "out_function : std::string http_request::_request_uri(std::string _request_uri) : "
168 "return(%s)", ret.c_str());
170 /*------ DEBUG LOG END ------*/
176 * Get HTTP version function.
178 * @return HTTP version
180 std::string http_request::http_version() const
182 /*-------- DEBUG LOG --------*/
183 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
184 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 31,
185 "in_function : std::string http_request::http_version(void)");
186 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 32,
187 "out_function : std::string http_request::http_version(void) : "
188 "return(%s)", this->_http_version.c_str());
190 /*------ DEBUG LOG END ------*/
192 return this->_http_version;
196 * Set HTTP version function.
197 * Set new HTTP version and return old HTTP version.
199 * @param[in] _http_version new HTTP version
200 * @return old HTTP version
202 std::string http_request::http_version(std::string _http_version)
204 /*-------- DEBUG LOG --------*/
205 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
206 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 33,
207 "in_function : std::string http_request::http_version(std::string _http_version) : "
208 "_http_version(%s)", _http_version.c_str());
210 /*------ DEBUG LOG END ------*/
212 std::string ret = this->_http_version;
213 this->_http_version = _http_version;
214 this->_modified = true;
216 /*-------- DEBUG LOG --------*/
217 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
218 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 34,
219 "out_function : std::string http_request::http_version(std::string _http_version) : "
220 "return(%s)", ret.c_str());
222 /*------ DEBUG LOG END ------*/
228 * Get request line function.
230 * @return request line
232 std::string http_request::request_line() const
234 /*-------- DEBUG LOG --------*/
235 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
236 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 35,
237 "in_function : std::string http_request::request_line(void)");
239 /*------ DEBUG LOG END ------*/
241 std::string ret = this->method() + " " + this->request_uri() + " " + this->http_version() + "\r\n";
243 /*-------- DEBUG LOG --------*/
244 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
245 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 36,
246 "out_function : std::string http_request::request_line(void) : "
247 "return(%s)", ret.c_str());
249 /*------ DEBUG LOG END ------*/
255 * Get full HTTP request function.
257 * @return HTTP request
259 std::string http_request::as_string()
261 /*-------- DEBUG LOG --------*/
262 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
263 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 37,
264 "in_function : std::string http_request::as_string(void)");
266 /*------ DEBUG LOG END ------*/
271 /*-------- DEBUG LOG --------*/
272 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
273 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 38,
274 "out_function : std::string http_request::as_string(void) : "
275 "return(%s)", this->raw_message.c_str());
277 /*------ DEBUG LOG END ------*/
279 return this->raw_message;
283 * Parse HTTP request header function.
285 * @param[in] request full HTTP request header
287 void http_request::parse(std::string request)
289 /*-------- DEBUG LOG --------*/
290 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
291 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 39,
292 "in_function : void http_request::parse(std::string request) : "
293 "request(%s)", request.c_str());
295 /*------ DEBUG LOG END ------*/
298 this->raw_message = request;
301 HTTP_REQUEST_POSITION pos = REQUEST_METHOD;
306 * CHAR : US-ASCII(0-127)
309 * ALPHA : UPALPHA | LOALPHA
311 * HEXDIG : A-F | a-f | DIGIT
313 * HT : Horizontal Tab(9)
314 * CR : Carriage Return(13)
316 * CTL : ConTLol char(0-31,127)
317 * LWS : [CRLF] 1*(SP|HT)
318 * separators : ()<>@,;:\"/[]?={} and SP, HT
319 * token : 1*(CHAR not CTL, separators)
320 * DIGIT, ALPHA and !#$%&'*+-.^_`|~
322 std::string::iterator ptr = request.begin();
323 std::string::iterator end = request.end();
324 std::string::iterator start = ptr;
325 std::pair<std::string, std::string> field_pair;
331 * METHOD SP REQUEST-URI SP HTTP-VERSION CRLF
337 if (*ptr == ' ') { // METHOD end with SP
338 this->_method.assign(start, ptr);
339 pos = REQUEST_METHOD_SP;
340 } else if (!isalpha(*ptr) && !isdigit(*ptr) &&
341 *ptr != '!' && *ptr != '#' && *ptr != '$' && *ptr != '%' &&
342 *ptr != '&' && *ptr != '\'' && *ptr != '*' && *ptr != '+' &&
343 *ptr != '-' && *ptr != '.' && *ptr != '^' && *ptr != '_' &&
344 *ptr != '`' && *ptr != '|' && *ptr != '~') {
345 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 1,
346 "Parse error: Invalid request method.(%c)", *ptr);
351 * REQUEST-URI : * | absolute-URI | path-absolute | authority
354 * absolute-URI : scheme ":" hier-part [ "?" query ]
355 * path-absolute : "/" [ segment-nz *( "/" segment ) ]
356 * authority : [ userinfo "@" ] host [ ":" port ]
357 * scheme : ALPHA *( ALPHA | DIGIT | "+" | "-" | "." )
358 * hier-part : "//" authority path-abempty
362 * query : *( pchar | "/" | "?" )
363 * path-abempty : *( "/" segment )
364 * path-rootless : segment-nz *( "/" segment )
365 * path-empty : no char
366 * segment-nz : 1*pchar
368 * userinfo : *( unreserved | pct-encoded | sub-delims | ":" )
369 * host : IP-literal | IPv4address | reg-name
371 * unreserved : ALPHA | DIGIT | "-" | "." | "_" | "~"
372 * pct-encoded : "%" HEXDIG HEXDIG
373 * sub-delims : !$&'()*+,;=
374 * pchar : unreserved | pct-encoded | subdelims | ":" | "@"
375 * IP-literal : "[" ( IPv6address | IPvFuture ) "]"
376 * IPvFuture : "v" 1*HEXDIG "." 1*( unreserved | sub-delims | ":" )
377 * IPv6address : 6( h16 ":" ) ls32
378 * / "::" 5( h16 ":" ) ls32
379 * / [ h16 ] "::" 4( h16 ":" ) ls32
380 * / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
381 * / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
382 * / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
383 * / [ *4( h16 ":" ) h16 ] "::" ls32
384 * / [ *5( h16 ":" ) h16 ] "::" h16
385 * / [ *6( h16 ":" ) h16 ] "::"
387 * ls32 : ( h16 ":" h16 ) | IPv4address
388 * IPv4address : dec-octet "." dec-octet "." dec-octet "." dec-octet
390 * reg-name : *( unreserved | pct-encoded | sub-delims )
392 case REQUEST_METHOD_SP:
395 if (*ptr == '/' || isalpha(*ptr) || isdigit(*ptr) || *ptr == '-' ||
396 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == ':' ||
397 *ptr == '@' || *ptr == '!' || *ptr == '$' || *ptr == '&' ||
398 *ptr == '(' || *ptr == ')' || *ptr == '*' || *ptr == '+' ||
399 *ptr == ',' || *ptr == ';' || *ptr == '=' || *ptr == '%') {
400 pos = REQUEST_REQUEST_URI;
403 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 2,
404 "Parse error: Invalid request-uri.(%c)", *ptr);
409 case REQUEST_REQUEST_URI:
410 if (*ptr == ' ') { // Request-URI end with SP
411 this->_request_uri.assign(start, ptr);
412 pos = REQUEST_REQUEST_URI_SP;
413 } else if (!isalpha(*ptr) && !isdigit(*ptr) && *ptr != '/' && // XXX not enough?
414 *ptr != '.' && *ptr != '=' && *ptr != '%' && *ptr != '?' &&
415 *ptr != '&' && *ptr != '+' && *ptr != '~' && *ptr != ',' &&
416 *ptr != '@' && *ptr != '!' && *ptr != '$' && *ptr != '-' &&
417 *ptr != '(' && *ptr != ')' && *ptr != '*' && *ptr != '_' &&
418 *ptr != ':' && *ptr != ';') {
419 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 3,
420 "Parse error: Invalid request-uri.(%c)", *ptr);
426 * HTTP-VERSION : "HTTP" "/" 1*DIGIT "." 1*DIGIT
428 case REQUEST_REQUEST_URI_SP:
429 // HTTP-VERSION start
431 pos = REQUEST_HTTP_VERSION_H;
434 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 4,
435 "Parse error: Invalid http-version.(%c)", *ptr);
440 case REQUEST_HTTP_VERSION_H:
443 pos = REQUEST_HTTP_VERSION_T1;
445 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 5,
446 "Parse error: Invalid http-version.(%c)", *ptr);
451 case REQUEST_HTTP_VERSION_T1:
454 pos = REQUEST_HTTP_VERSION_T2;
456 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 6,
457 "Parse error: Invalid http-version.(%c)", *ptr);
462 case REQUEST_HTTP_VERSION_T2:
465 pos = REQUEST_HTTP_VERSION_P;
467 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 7,
468 "Parse error: Invalid http-version.(%c)", *ptr);
473 case REQUEST_HTTP_VERSION_P:
476 pos = REQUEST_HTTP_VERSION_SLASH;
478 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 8,
479 "Parse error: Invalid http-version.(%c)", *ptr);
484 case REQUEST_HTTP_VERSION_SLASH:
485 // HTTP-VERSION Mejor number
487 pos = REQUEST_HTTP_VERSION_MAJOR;
489 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 9,
490 "Parse error: Invalid http-version.(%c)", *ptr);
495 case REQUEST_HTTP_VERSION_MAJOR:
496 // HTTP-VERSION next dot
498 pos = REQUEST_HTTP_VERSION_DOT;
499 } else if (!isdigit(*ptr)) {
500 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 10,
501 "Parse error: Invalid http-version.(%c)", *ptr);
506 case REQUEST_HTTP_VERSION_DOT:
507 // HTTP-VERSION Minor number
509 pos = REQUEST_HTTP_VERSION_MINOR;
511 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 11,
512 "Parse error: Invalid http-version.(%c)", *ptr);
517 case REQUEST_HTTP_VERSION_MINOR:
518 // HTTP-VERSION end with CR
521 this->_http_version.assign(start, ptr);
522 } else if (!isdigit(*ptr)) {
523 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 12,
524 "Parse error: Invalid http-version.(%c)", *ptr);
533 http_message::parse(std::string(ptr + 1, end));
535 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 13,
536 "Parse error: No LF.(%c)", *ptr);
541 if (pos == REQUEST_LF)
547 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 14,
548 "Exception occured by parsing HTTP request.");
551 /*-------- DEBUG LOG --------*/
552 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
553 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 40,
554 "out_function : void http_request::parse(std::string request)");
556 /*------ DEBUG LOG END ------*/
560 * Rebuild HTTP request header function.
562 void http_request::rebuild()
564 /*-------- DEBUG LOG --------*/
565 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
566 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 41,
567 "in_function : void http_request::rebuild()");
569 /*------ DEBUG LOG END ------*/
571 this->raw_message = this->request_line();
572 http_message::rebuild();
574 /*-------- DEBUG LOG --------*/
575 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
576 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 42,
577 "out_function : void http_request::rebuild()");
579 /*------ DEBUG LOG END ------*/