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 full HTTP message function.
213 * @return HTTP message
215 std::string http_message::as_string()
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, 12,
220 "in_function : std::string http_message::as_string(void)");
222 /*------ DEBUG LOG END ------*/
227 /*-------- DEBUG LOG --------*/
228 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
229 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 13,
230 "out_function : std::string http_message::as_string(void) : "
231 "return(%s)", this->raw_message.c_str());
233 /*------ DEBUG LOG END ------*/
235 return this->raw_message;
239 * Parse HTTP header function.
241 * @param[in] message full HTTP message header
243 void http_message::parse(std::string message)
245 /*-------- DEBUG LOG --------*/
246 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
247 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 14,
248 "in_function : void http_message::parse(std::string message) : "
249 "message(%s)", message.c_str());
251 /*------ DEBUG LOG END ------*/
254 if (this->raw_message.length() == 0)
255 this->raw_message = message;
258 HTTP_MESSAGE_POSITION pos = MESSAGE_TOP;
263 * CHAR : US-ASCII(0-127)
266 * ALPHA : UPALPHA | LOALPHA
268 * HEXDIG : A-F | a-f | DIGIT
270 * HT : Horizontal Tab(9)
271 * CR : Carriage Return(13)
273 * CTL : ConTLol char(0-31,127)
274 * LWS : [CRLF] 1*(SP|HT)
275 * separators : ()<>@,;:\"/[]?={} and SP, HT
276 * token : 1*(CHAR not CTL, separators)
278 std::string::iterator ptr = message.begin();
279 std::string::iterator end = message.end();
280 std::string::iterator start = ptr;
281 std::pair<std::string, std::string> field_pair;
286 * MESSAGE-HEADER : field-name ":" [ field-value ]
288 * field-value : *( field-content | LWS )
289 * field-content : <the OCTETs making up the field-value and
290 * consisting of either *TEXT or combinations
291 * of token, separators, and quoted-string>
292 * TEXT : <any OCTET except CTLs, but including LWS>
293 * quoted-string : ( <"> *(qdtext | quoted-pair ) <"> )
294 * qdtext : <any TEXT except <">>
295 * quoted-pair : "\" CHAR
298 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) ||
299 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
300 *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
303 pos = MESSAGE_FIELD_NAME;
304 } else if (*ptr == '\r') { // CRLF + CRLF
305 pos = MESSAGE_LAST_CR;
307 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 2,
308 "Parse error: Invalid header field name.(%c)", *ptr);
318 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 3,
319 "Parse error: No LF.(%c)", *ptr);
325 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) ||
326 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
327 *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
329 if (field_pair.first.length()) {
330 field_pair.first = convert_upper_camel_case(field_pair.first);
331 boost::trim(field_pair.second);
332 _header.get<field_map>().insert(field_pair);
333 field_pair.first.clear();
336 pos = MESSAGE_FIELD_NAME;
337 } else if (*ptr == ' ' || *ptr == '\t') {
338 pos = MESSAGE_FIELD_VALUE;
339 } else if (*ptr == '\r') { // CRLF + CRLF
340 if (field_pair.first.length()) {
341 field_pair.first = convert_upper_camel_case(field_pair.first);
342 boost::trim(field_pair.second);
343 _header.get<field_map>().insert(field_pair);
344 field_pair.first.clear();
346 pos = MESSAGE_LAST_CR;
348 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 4,
349 "Parse error: Invalid header field name.(%c)", *ptr);
354 case MESSAGE_FIELD_NAME:
355 // field-name end with ':'
357 pos = MESSAGE_FIELD_NAME_COLON;
358 field_pair.first.assign(start, ptr);
359 } else if (!isalpha(*ptr) && *ptr != '-' && !isdigit(*ptr) &&
360 *ptr != '.' && *ptr != '_' && *ptr != '~' && *ptr != '!' &&
361 *ptr != '$' && *ptr != '&' && *ptr != '*' && *ptr != '+' &&
363 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 5,
364 "Parse error: Invalid header field name.(%c)", *ptr);
369 case MESSAGE_FIELD_NAME_COLON:
370 if (*ptr == ' ' || isalpha(*ptr) || isdigit(*ptr) || *ptr == '-' ||
371 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == ':' ||
372 *ptr == '@' || *ptr == '!' || *ptr == '$' || *ptr == '&' ||
373 *ptr == '(' || *ptr == ')' || *ptr == '*' || *ptr == '+' ||
374 *ptr == ',' || *ptr == ';' || *ptr == '=' || *ptr == '%' ||
375 *ptr == '<' || *ptr == '>' || *ptr == '[' || *ptr == ']' ||
376 *ptr == '{' || *ptr == '}' || *ptr == '?' || *ptr == '"' ||
377 *ptr == '|' || *ptr == '/' || *ptr == '\\' || *ptr == '\t') {
379 pos = MESSAGE_FIELD_VALUE;
380 } else if (*ptr == '\r') { // omit field value
381 field_pair.second.clear();
383 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 6,
384 "Parse error: Invalid header field value.(%c)", *ptr);
389 case MESSAGE_FIELD_VALUE:
390 // field-value end with CR
393 field_pair.second.assign(start, ptr);
394 } else if (*ptr != ' ' && !isalpha(*ptr) && !isdigit(*ptr) && *ptr != '-' &&
395 *ptr != '.' && *ptr != '_' && *ptr != '~' && *ptr != ':' &&
396 *ptr != '@' && *ptr != '!' && *ptr != '$' && *ptr != '&' &&
397 *ptr != '(' && *ptr != ')' && *ptr != '*' && *ptr != '+' &&
398 *ptr != ',' && *ptr != ';' && *ptr != '=' && *ptr != '%' &&
399 *ptr != '<' && *ptr != '>' && *ptr != '[' && *ptr != ']' &&
400 *ptr != '{' && *ptr != '}' && *ptr != '?' && *ptr != '"' &&
401 *ptr != '|' && *ptr != '/' && *ptr != '\\'&& *ptr != '\t' ) {
402 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 7,
403 "Parse error: Invalid header field value.(%c)", *ptr);
408 case MESSAGE_LAST_CR:
411 pos = MESSAGE_LAST_LF;
413 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 8,
414 "Parse error: No LF.(%c)", *ptr);
420 * MESSAGE-BODY : *OCTET
422 case MESSAGE_LAST_LF:
435 this->_body.assign(start, ptr);
439 LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 9,
440 "Exception occured by parsing HTTP message.");
443 /*-------- DEBUG LOG --------*/
444 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
445 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 15,
446 "out_function : void http_message::parse(std::string message)");
448 /*------ DEBUG LOG END ------*/
452 * Rebuild HTTP header function.
454 void http_message::rebuild()
456 /*-------- DEBUG LOG --------*/
457 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
458 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 16,
459 "in_function : void http_message::rebuild()");
461 /*------ DEBUG LOG END ------*/
464 header_container::iterator it = this->_header.begin();
465 header_container::iterator it_end = this->_header.end();
467 while (it != it_end) {
468 this->raw_message += it->first + ": " + it->second + "\r\n";
472 this->raw_message += "\r\n" + this->body();
474 /*-------- DEBUG LOG --------*/
475 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
476 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 17,
477 "out_function : void http_message::rebuild()");
479 /*------ DEBUG LOG END ------*/
483 * Field name convert function.
484 * Convert upper camelcase
485 * ex. connecTION => Connection
486 * usEr-aGeNT => User-Agent
489 * @param[in] field_name field name
490 * @return converted to camel case
492 std::string http_message::convert_upper_camel_case(std::string field_name) const
494 /*-------- DEBUG LOG --------*/
495 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
496 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 18,
497 "in_function : std::string http_message::upper_camel_case(std::string field_name) : "
498 "field_name(%s)", field_name.c_str());
500 /*------ DEBUG LOG END ------*/
503 boost::char_separator<char> sep("-_0123456789", "-_0123456789", boost::keep_empty_tokens);
504 boost::tokenizer<boost::char_separator<char> > tokens(field_name, sep);
505 boost::tokenizer<boost::char_separator<char> >::iterator tok_it = tokens.begin();
506 boost::tokenizer<boost::char_separator<char> >::iterator tok_end = tokens.end();
507 for (; tok_it != tok_end; ++tok_it) {
508 std::string token(*tok_it);
509 boost::to_lower(token);
510 token.at(0) = std::toupper(token.at(0));
514 /*-------- DEBUG LOG --------*/
515 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
516 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 19,
517 "out_function : std::string http_message::upper_camel_case(std::string field_name) : "
518 "return(%s)", ret.c_str());
520 /*------ DEBUG LOG END ------*/