2 * @file http_message.cpp
3 * @brief module of HTTP Message
4 * @brief HTTP Message 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_message.h"
28 * HTTP Message constructor.
30 http_message::http_message()
34 /*-------- DEBUG LOG --------*/
35 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
36 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 1,
37 "in/out_function : Constructor http_message::http_message(void)");
39 /*------ DEBUG LOG END ------*/
43 * HTTP Message constructor.
44 * Parse HTTP message header.
46 * @param[in] header full http message header string
48 http_message::http_message(std::string header)
52 /*-------- DEBUG LOG --------*/
53 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
54 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 2,
55 "in/out_function : Constructor http_message::http_message(std::string header) : "
56 "header(%s)", header.c_str());
58 /*------ DEBUG LOG END ------*/
63 * HTTP Message destructor.
65 http_message::~http_message()
67 /*-------- DEBUG LOG --------*/
68 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
69 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3,
70 "in/out_function : Destructor http_message::~http_message(void)");
72 /*------ DEBUG LOG END ------*/
76 * Get HTTP header field function.
78 * @param[in] field_name lookup field name
79 * @return header field value
81 field_range http_message::header(std::string field_name) const
83 /*-------- DEBUG LOG --------*/
84 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
85 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 4,
86 "in_function : field_range http_message::header(std::string field_name) : "
87 "field_name(%s)", field_name.c_str());
89 /*------ DEBUG LOG END ------*/
91 std::string name = convert_upper_camel_case(field_name);
92 field_range ret = this->_header.get<field_map>().equal_range(name);
94 /*-------- DEBUG LOG --------*/
95 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
96 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 5,
97 "out_function : field_range http_message::header(std::string field_name)");
99 /*------ DEBUG LOG END ------*/
105 * Set HTTP header field function.
106 * Set new HTTP header field and return old HTTP header field.
108 * @param[in] field_name lookup field name
109 * @param[in] field_value field value
111 void http_message::header(std::string field_name, std::string field_value)
113 /*-------- DEBUG LOG --------*/
114 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
115 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 6,
116 "in_function : field_range http_message::header(std::string field_name, std::string field_value) : "
117 "field_name(%s), field_value(%s)", field_name.c_str(), field_value.c_str());
119 /*------ DEBUG LOG END ------*/
121 bool changed = false;
122 std::string name = convert_upper_camel_case(field_name);
123 field_range ret = this->_header.get<field_map>().equal_range(name);
124 field_map_iterator it = ret.first;
125 field_map_iterator it_end = ret.second;
127 for (;it != it_end; ++it) {
128 if (field_value != "") {
129 if ( _header.get<field_map>().replace(it, field(name, field_value)) ) {
131 this->_modified = true;
135 _header.get<field_map>().erase(it);
137 this->_modified = true;
140 if (!changed && field_value != "") {
141 _header.get<field_map>().insert( field(name, field_value) );
142 this->_modified = true;
146 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 1,
147 "Exception occured by inserting or replacing boost::multi_index.");
150 /*-------- DEBUG LOG --------*/
151 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
152 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 7,
153 "out_function : field_range http_message::header(std::string field_name, std::string field_value)");
155 /*------ DEBUG LOG END ------*/
159 * Get message body function.
161 * @return message body
163 std::string http_message::body() const
165 /*-------- DEBUG LOG --------*/
166 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
167 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 8,
168 "in_function : std::string http_message::body(void)");
169 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 9,
170 "out_function : std::string http_message::body(void) : "
171 "return(%s)", this->_body.c_str());
173 /*------ DEBUG LOG END ------*/
179 * Set message body function.
180 * Set new message body and return old message body.
182 * @param[in] _body new message body
183 * @return old message body
185 std::string http_message::body(std::string _body)
187 /*-------- DEBUG LOG --------*/
188 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
189 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 10,
190 "in_function : std::string http_message::http_version(std::string _message) : "
191 "_body(%s)", _body.c_str());
193 /*------ DEBUG LOG END ------*/
195 std::string ret = this->_body;
197 this->_modified = true;
199 /*-------- DEBUG LOG --------*/
200 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
201 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 11,
202 "out_function : std::string http_message::body(std::string _body) : "
203 "return(%s)", ret.c_str());
205 /*------ DEBUG LOG END ------*/
211 * Get modified flag function.
213 * @return modified flag
215 bool http_message::modified() const
217 /*-------- DEBUG LOG --------*/
218 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
219 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 66,
220 "in_function : bool http_message::modified(void)");
221 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 67,
222 "out_function : bool http_message::modified(void) : "
223 "return(%s)", this->_modified ? "true" : "false");
225 /*------ DEBUG LOG END ------*/
227 return this->_modified;
231 * Get full HTTP message function.
233 * @return HTTP message
235 std::string http_message::as_string()
237 /*-------- DEBUG LOG --------*/
238 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
239 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 12,
240 "in_function : std::string http_message::as_string(void)");
242 /*------ DEBUG LOG END ------*/
247 /*-------- DEBUG LOG --------*/
248 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
249 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 13,
250 "out_function : std::string http_message::as_string(void) : "
251 "return(%s)", this->raw_message.c_str());
253 /*------ DEBUG LOG END ------*/
255 return this->raw_message;
259 * Parse HTTP header function.
261 * @param[in] message full HTTP message header
263 void http_message::parse(std::string message)
265 /*-------- DEBUG LOG --------*/
266 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
267 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 14,
268 "in_function : void http_message::parse(std::string message) : "
269 "message(%s)", message.c_str());
271 /*------ DEBUG LOG END ------*/
274 if (this->raw_message.length() == 0)
275 this->raw_message = message;
278 HTTP_MESSAGE_POSITION pos = MESSAGE_TOP;
283 * CHAR : US-ASCII(0-127)
286 * ALPHA : UPALPHA | LOALPHA
288 * HEXDIG : A-F | a-f | DIGIT
290 * HT : Horizontal Tab(9)
291 * CR : Carriage Return(13)
293 * CTL : ConTLol char(0-31,127)
294 * LWS : [CRLF] 1*(SP|HT)
295 * separators : ()<>@,;:\"/[]?={} and SP, HT
296 * token : 1*(CHAR not CTL, separators)
298 std::string::iterator ptr = message.begin();
299 std::string::iterator end = message.end();
300 std::string::iterator start = ptr;
301 std::pair<std::string, std::string> field_pair;
306 * MESSAGE-HEADER : field-name ":" [ field-value ]
308 * field-value : *( field-content | LWS )
309 * field-content : <the OCTETs making up the field-value and
310 * consisting of either *TEXT or combinations
311 * of token, separators, and quoted-string>
312 * TEXT : <any OCTET except CTLs, but including LWS>
313 * quoted-string : ( <"> *(qdtext | quoted-pair ) <"> )
314 * qdtext : <any TEXT except <">>
315 * quoted-pair : "\" CHAR
318 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) ||
319 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
320 *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
323 pos = MESSAGE_FIELD_NAME;
324 } else if (*ptr == '\r') { // CRLF + CRLF
325 pos = MESSAGE_LAST_CR;
327 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 32,
328 "Parse error: Invalid header field name.(%c)", *ptr);
338 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 33,
339 "Parse error: No LF.(%c)", *ptr);
345 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) ||
346 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
347 *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
349 if (field_pair.first.length()) {
350 field_pair.first = convert_upper_camel_case(field_pair.first);
351 boost::trim(field_pair.second);
352 _header.get<field_map>().insert(field_pair);
353 field_pair.first.clear();
356 pos = MESSAGE_FIELD_NAME;
357 } else if (*ptr == ' ' || *ptr == '\t') {
358 pos = MESSAGE_FIELD_VALUE;
359 } else if (*ptr == '\r') { // CRLF + CRLF
360 if (field_pair.first.length()) {
361 field_pair.first = convert_upper_camel_case(field_pair.first);
362 boost::trim(field_pair.second);
363 _header.get<field_map>().insert(field_pair);
364 field_pair.first.clear();
366 pos = MESSAGE_LAST_CR;
368 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 34,
369 "Parse error: Invalid header field name.(%c)", *ptr);
374 case MESSAGE_FIELD_NAME:
375 // field-name end with ':'
377 pos = MESSAGE_FIELD_NAME_COLON;
378 field_pair.first.assign(start, ptr);
379 } else if (!isalpha(*ptr) && *ptr != '-' && !isdigit(*ptr) &&
380 *ptr != '.' && *ptr != '_' && *ptr != '~' && *ptr != '!' &&
381 *ptr != '$' && *ptr != '&' && *ptr != '*' && *ptr != '+' &&
383 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 35,
384 "Parse error: Invalid header field name.(%c)", *ptr);
389 case MESSAGE_FIELD_NAME_COLON:
390 if (*ptr == ' ' || isalpha(*ptr) || isdigit(*ptr) || *ptr == '-' ||
391 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == ':' ||
392 *ptr == '@' || *ptr == '!' || *ptr == '$' || *ptr == '&' ||
393 *ptr == '(' || *ptr == ')' || *ptr == '*' || *ptr == '+' ||
394 *ptr == ',' || *ptr == ';' || *ptr == '=' || *ptr == '%' ||
395 *ptr == '<' || *ptr == '>' || *ptr == '[' || *ptr == ']' ||
396 *ptr == '{' || *ptr == '}' || *ptr == '?' || *ptr == '"' ||
397 *ptr == '|' || *ptr == '/' || *ptr == '\\' || *ptr == '\t') {
399 pos = MESSAGE_FIELD_VALUE;
400 } else if (*ptr == '\r') { // omit field value
401 field_pair.second.clear();
403 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 36,
404 "Parse error: Invalid header field value.(%c)", *ptr);
409 case MESSAGE_FIELD_VALUE:
410 // field-value end with CR
413 field_pair.second.assign(start, ptr);
414 } else if (*ptr != ' ' && !isalpha(*ptr) && !isdigit(*ptr) && *ptr != '-' &&
415 *ptr != '.' && *ptr != '_' && *ptr != '~' && *ptr != ':' &&
416 *ptr != '@' && *ptr != '!' && *ptr != '$' && *ptr != '&' &&
417 *ptr != '(' && *ptr != ')' && *ptr != '*' && *ptr != '+' &&
418 *ptr != ',' && *ptr != ';' && *ptr != '=' && *ptr != '%' &&
419 *ptr != '<' && *ptr != '>' && *ptr != '[' && *ptr != ']' &&
420 *ptr != '{' && *ptr != '}' && *ptr != '?' && *ptr != '"' &&
421 *ptr != '|' && *ptr != '/' && *ptr != '\\'&& *ptr != '\t' ) {
422 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 37,
423 "Parse error: Invalid header field value.(%c)", *ptr);
428 case MESSAGE_LAST_CR:
431 pos = MESSAGE_LAST_LF;
433 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 38,
434 "Parse error: No LF.(%c)", *ptr);
440 * MESSAGE-BODY : *OCTET
442 case MESSAGE_LAST_LF:
455 this->_body.assign(start, ptr);
460 LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 39,
461 "Exception occured by parsing HTTP message.");
464 /*-------- DEBUG LOG --------*/
465 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
466 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 15,
467 "out_function : void http_message::parse(std::string message)");
469 /*------ DEBUG LOG END ------*/
473 * Rebuild HTTP header function.
475 void http_message::rebuild()
477 /*-------- DEBUG LOG --------*/
478 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
479 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 16,
480 "in_function : void http_message::rebuild()");
482 /*------ DEBUG LOG END ------*/
485 header_container::iterator it = this->_header.begin();
486 header_container::iterator it_end = this->_header.end();
488 while (it != it_end) {
489 this->raw_message += it->first + ": " + it->second + "\r\n";
493 this->raw_message += "\r\n" + this->body();
495 /*-------- DEBUG LOG --------*/
496 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
497 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 17,
498 "out_function : void http_message::rebuild()");
500 /*------ DEBUG LOG END ------*/
504 * Field name convert function.
505 * Convert upper camelcase
506 * ex. connecTION => Connection
507 * usEr-aGeNT => User-Agent
510 * @param[in] field_name field name
511 * @return converted to camel case
513 std::string http_message::convert_upper_camel_case(std::string field_name) const
515 /*-------- DEBUG LOG --------*/
516 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
517 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 18,
518 "in_function : std::string http_message::upper_camel_case(std::string field_name) : "
519 "field_name(%s)", field_name.c_str());
521 /*------ DEBUG LOG END ------*/
524 boost::char_separator<char> sep("-_0123456789", "-_0123456789", boost::keep_empty_tokens);
525 boost::tokenizer<boost::char_separator<char> > tokens(field_name, sep);
526 boost::tokenizer<boost::char_separator<char> >::iterator tok_it = tokens.begin();
527 boost::tokenizer<boost::char_separator<char> >::iterator tok_end = tokens.end();
528 for (; tok_it != tok_end; ++tok_it) {
529 std::string token(*tok_it);
530 boost::to_lower(token);
531 token.at(0) = std::toupper(token.at(0));
535 /*-------- DEBUG LOG --------*/
536 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
537 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 19,
538 "out_function : std::string http_message::upper_camel_case(std::string field_name) : "
539 "return(%s)", ret.c_str());
541 /*------ DEBUG LOG END ------*/