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, // XXX log
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, 1, // XXX log
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, 2, // XXX log
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)
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, 3, // XXX log
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 field_range ret = this->_header.get<field_map>().equal_range(field_name);
93 /*-------- DEBUG LOG --------*/
94 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
95 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
96 "out_function : field_range http_message::header(std::string field_name)");
98 /*------ DEBUG LOG END ------*/
104 * Set HTTP header field function.
105 * Set new HTTP header field and return old HTTP header field.
107 * @param[in] field_name lookup field name
108 * @param[in] field_value field value
110 void http_message::header(std::string field_name, std::string field_value)
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, 3, // XXX log
115 "in_function : field_range http_message::header(std::string field_name, std::string field_value) : "
116 "field_name(%s), field_value(%s)", field_name.c_str(), field_value.c_str());
118 /*------ DEBUG LOG END ------*/
120 bool replaced = false;
121 field_range ret = this->_header.get<field_map>().equal_range(field_name);
122 field_map_iterator it = ret.first;
123 field_map_iterator it_end = ret.second;
124 for (;it != it_end; ++it) {
125 if ( _header.get<field_map>().replace(it, field(field_name, field_value)) ) {
127 this->modified = true;
131 _header.get<field_map>().insert( field(field_name, field_value) );
132 this->modified = true;
135 /*-------- DEBUG LOG --------*/
136 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
137 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
138 "out_function : field_range http_message::header(std::string field_name, std::string field_value)");
140 /*------ DEBUG LOG END ------*/
144 * Get message body function.
146 * @return message body
148 std::string http_message::body()
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, 3, // XXX log
153 "in_function : std::string http_message::body(void)");
154 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
155 "out_function : std::string http_message::body(void) : "
156 "return(%s)", this->_body.c_str());
158 /*------ DEBUG LOG END ------*/
164 * Set message body function.
165 * Set new message body and return old message body.
167 * @param[in] _body new message body
168 * @return old message body
170 std::string http_message::body(std::string _body)
172 /*-------- DEBUG LOG --------*/
173 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
174 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
175 "in_function : std::string http_message::http_version(std::string _message) : "
176 "_body(%s)", _body.c_str());
178 /*------ DEBUG LOG END ------*/
180 std::string ret = this->_body;
182 this->modified = true;
184 /*-------- DEBUG LOG --------*/
185 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
186 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
187 "out_function : std::string http_message::body(std::string _body) : "
188 "return(%s)", ret.c_str());
190 /*------ DEBUG LOG END ------*/
196 * Get full HTTP message function.
198 * @return HTTP message
200 std::string http_message::as_string()
202 /*-------- DEBUG LOG --------*/
203 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
204 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
205 "in_function : std::string http_message::as_string(void)");
207 /*------ DEBUG LOG END ------*/
212 /*-------- DEBUG LOG --------*/
213 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
214 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
215 "out_function : std::string http_message::as_string(void) : "
216 "return(%s)", this->raw_message.c_str());
218 /*------ DEBUG LOG END ------*/
220 return this->raw_message;
224 * Parse HTTP header function.
226 * @param[in] message full HTTP message header
228 void http_message::parse(std::string message)
230 /*-------- DEBUG LOG --------*/
231 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
232 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
233 "in_function : void http_message::parse(std::string message) : "
234 "message(%s)", message.c_str());
236 /*------ DEBUG LOG END ------*/
239 this->raw_message = message;
242 HTTP_MESSAGE_POSITION pos = MESSAGE_TOP;
247 * CHAR : US-ASCII(0-127)
250 * ALPHA : UPALPHA | LOALPHA
252 * HEXDIG : A-F | a-f | DIGIT
254 * HT : Horizontal Tab(9)
255 * CR : Carriage Return(13)
257 * CTL : ConTLol char(0-31,127)
258 * LWS : [CRLF] 1*(SP|HT)
259 * separators : ()<>@,;:\"/[]?={} and SP, HT
260 * token : 1*(CHAR not CTL, separators)
262 std::string::iterator ptr = message.begin();
263 std::string::iterator end = message.end();
264 std::string::iterator start = ptr;
265 std::pair<std::string, std::string> field_pair;
269 * MESSAGE-HEADER : field-name ":" [ field-value ]
271 * field-value : *( field-content | LWS )
272 * field-content : <the OCTETs making up the field-value and
273 * consisting of either *TEXT or combinations
274 * of token, separators, and quoted-string>
275 * TEXT : <any OCTET except CTLs, but including LWS>
276 * quoted-string : ( <"> *(qdtext | quoted-pair ) <"> )
277 * qdtext : <any TEXT except <">>
278 * quoted-pair : "\" CHAR
281 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) ||
282 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
283 *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
286 pos = MESSAGE_FIELD_NAME;
287 } else if (*ptr == '\r') { // CRLF + CRLF
288 pos = MESSAGE_LAST_CR;
290 /*-------- DEBUG LOG --------*/
291 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
292 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
293 "out_function : void http_message::parse(std::string message) : not CRLF");
295 /*------ DEBUG LOG END ------*/
305 /*-------- DEBUG LOG --------*/
306 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
307 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
308 "out_function : void http_request::parse(std::string request) : not CRLF");
310 /*------ DEBUG LOG END ------*/
316 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) ||
317 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
318 *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
320 if (field_pair.first.length()) {
321 _header.get<field_map>().insert(field_pair);
322 field_pair.first.clear();
325 pos = MESSAGE_FIELD_NAME;
326 } else if (*ptr == ' ' || *ptr == '\t') {
327 pos = MESSAGE_FIELD_VALUE;
328 } else if (*ptr == '\r') { // CRLF + CRLF
329 if (field_pair.first.length()) {
330 _header.get<field_map>().insert(field_pair);
331 field_pair.first.clear();
333 pos = MESSAGE_LAST_CR;
335 /*-------- DEBUG LOG --------*/
336 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
337 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
338 "out_function : void http_message::parse(std::string message) : not CRLF");
340 /*------ DEBUG LOG END ------*/
345 case MESSAGE_FIELD_NAME:
346 // field-name end with ':'
348 pos = MESSAGE_FIELD_NAME_COLON;
349 field_pair.first.assign(start, ptr);
350 } else if (!isalpha(*ptr) && *ptr != '-' && !isdigit(*ptr) &&
351 *ptr != '.' && *ptr != '_' && *ptr != '~' && *ptr != '!' &&
352 *ptr != '$' && *ptr != '&' && *ptr != '*' && *ptr != '+' &&
354 /*-------- DEBUG LOG --------*/
355 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
356 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
357 "out_function : void http_message::parse(std::string message) : Invalid header field name.");
359 /*------ DEBUG LOG END ------*/
364 case MESSAGE_FIELD_NAME_COLON:
365 if (*ptr == ' ' || isalpha(*ptr) || isdigit(*ptr) || *ptr == '-' ||
366 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == ':' ||
367 *ptr == '@' || *ptr == '!' || *ptr == '$' || *ptr == '&' ||
368 *ptr == '(' || *ptr == ')' || *ptr == '*' || *ptr == '+' ||
369 *ptr == ',' || *ptr == ';' || *ptr == '=' || *ptr == '%' ||
370 *ptr == '<' || *ptr == '>' || *ptr == '[' || *ptr == ']' ||
371 *ptr == '{' || *ptr == '}' || *ptr == '?' || *ptr == '"' ||
372 *ptr == '|' || *ptr == '/' || *ptr == '\\' || *ptr == '\t') {
374 pos = MESSAGE_FIELD_VALUE;
375 } else if (*ptr == '\r') { // omit field value
376 field_pair.second.clear();
378 /*-------- DEBUG LOG --------*/
379 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
380 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
381 "out_function : void http_message::parse(std::string message) : Invalid header field value.('%c')", *ptr);
383 /*------ DEBUG LOG END ------*/
387 case MESSAGE_FIELD_VALUE:
388 // field-value end with CR
391 field_pair.second.assign(start, ptr);
392 } else if (*ptr != ' ' && !isalpha(*ptr) && !isdigit(*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 != ']' &&
398 *ptr != '{' && *ptr != '}' && *ptr != '?' && *ptr != '"' &&
399 *ptr != '|' && *ptr != '/' && *ptr != '\\'&& *ptr != '\t' ) {
400 /*-------- DEBUG LOG --------*/
401 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
402 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
403 "out_function : void http_message::parse(std::string message) : Invalid header field value.('%c')", *ptr);
405 /*------ DEBUG LOG END ------*/
410 case MESSAGE_LAST_CR:
413 pos = MESSAGE_LAST_LF;
415 /*-------- DEBUG LOG --------*/
416 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
417 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
418 "out_function : void http_message::parse(std::string message) : not CRLF");
420 /*------ DEBUG LOG END ------*/
426 * MESSAGE-BODY : *OCTET
428 case MESSAGE_LAST_LF:
441 this->_body.assign(start, ptr);
444 /*-------- DEBUG LOG --------*/
445 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
446 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
447 "out_function : void http_message::parse(std::string message)");
449 /*------ DEBUG LOG END ------*/
453 * Rebuild HTTP header function.
455 void http_message::rebuild()
457 /*-------- DEBUG LOG --------*/
458 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
459 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
460 "in_function : void http_message::rebuild()");
462 /*------ DEBUG LOG END ------*/
465 header_container::iterator it = this->_header.begin();
466 header_container::iterator it_end = this->_header.end();
468 while (it != it_end) {
469 this->raw_message += it->first + ": " + it->second + "\r\n";
473 this->raw_message += "\r\n" + this->body();
475 /*-------- DEBUG LOG --------*/
476 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
477 LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
478 "out_function : void http_message::rebuild()");
480 /*------ DEBUG LOG END ------*/
485 //============================
487 void printheader(http_message& message, std::string name) {
489 r = message.header(name);
490 while (r.first != r.second) {
491 std::cout << "=======> HEADER(" << r.first->first << "): " << r.first->second<< std::endl;
496 void changeheader(http_message& message, std::string name, std::string value) {
497 message.header(name, value);
498 printheader(message, name);
504 http_message message("POST /index HTTP/1.1\r\nHost: localhost\r\nX-Forwarded-For: localhost\r\n foobar\r\nAccept: */*\r\n\r\nMessageBODY");
505 std::cout << message.as_string() << std::endl;
506 printheader(message, "Host");
507 printheader(message, "X-Forwarded-For");
508 printheader(message, "Accept");
509 printheader(message, "Test");
510 changeheader(message, "Test", "new test");
511 changeheader(message, "Host", "new host");
512 std::cout << message.as_string() << std::endl;
513 std::cout << message.body("type=project&id=303") << std::endl;
514 std::cout << message.body() << std::endl;
515 std::cout << message.as_string() << std::endl;
521 r.header("Host", "img.unitcom.co.jp");
522 r.header("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 (.NET CLR 3.5.30729)");
523 r.header("Accept", "image/png,image/*;q=0.8,*/*;q=0.5");
524 r.header("Accept-Language", "ja,en-us;q=0.7,en;q=0.3");
525 r.header("Accept-Encoding", "gzip,deflate");
526 r.header("Accept-Charset", "Shift_JIS,utf-8;q=0.7,*;q=0.7");
527 r.header("Keep-Alive", "300");
528 r.header("Connection", "keep-alive");
529 r.header("Referer", "http://www.faith-go.co.jp/special/");
530 r.header("Cookie", "ASPSESSIONIDQCCQBQBR=HHKHICIACCKKHPIIECCOBOJG");
531 r.body("TEST__TEST");
532 std::cout << r.as_string() << std::endl;
538 "Host: 192.168.0.4:7780\r\n"
539 "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 (.NET CLR 3.5.30729)\r\n"
540 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
541 "Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n"
542 "Accept-Encoding: gzip,deflate\r\n"
543 "Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n"
544 "Keep-Alive: 300\r\n"
545 "Connection: keep-alive\r\n"
546 "Cookie: rh_omni_tc=70160000000H4AoAAK; __utma=225840474.262789985507525570.1236909895.1236909895.1236909895.1; __utmz=225840474.1236909895.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); sch_target=mygroup; sch_d=3; sch_m=5; sch_y=2009; sch_move=weekly; PHPSESSID=pfn9gu39gkfq3cn16cr70q12b5; circular_kwd=; room_target=all; room_move=weekly; room_y=2009; room_m=4; room_d=27\r\n"
547 "Cache-Control: max-age=0\r\n"
549 http_message re(text);
550 std::cout << re.as_string() << std::endl;