OSDN Git Service

Ignore packet of not first HTTP header message.
[ultramonkey-l7/sslproxy.git] / src / http_message.cpp
1 /*
2  * @file  http_message.cpp
3  * @brief module of HTTP Message
4  * @brief HTTP Message parser
5  *
6  * Copyright (C) 2009  NTT COMWARE Corporation.
7  *
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.
12  *
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.
17  *
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
21  * 02110-1301 USA
22  *
23  **********************************************************************/
24
25 #include "http_message.h"
26
27 /*!
28  * HTTP Message constructor.
29  */
30 http_message::http_message()
31     :
32     _modified(false)
33 {
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)");
38     }
39     /*------ DEBUG LOG END ------*/
40 }
41
42 /*!
43  * HTTP Message constructor.
44  * Parse HTTP message header.
45  *
46  * @param[in]   header  full http message header string
47  */
48 http_message::http_message(std::string header)
49     :
50     _modified(false)
51 {
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());
57     }
58     /*------ DEBUG LOG END ------*/
59     this->parse(header);
60 }
61
62 /*!
63  * HTTP Message destructor.
64  */
65 http_message::~http_message()
66 {
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)");
71     }
72     /*------ DEBUG LOG END ------*/
73 }
74
75 /*!
76  * Get HTTP header field function.
77  *
78  * @param[in]   field_name  lookup field name
79  * @return      header field value
80  */
81 field_range http_message::header(std::string field_name) const
82 {
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());
88     }
89     /*------ DEBUG LOG END ------*/
90
91     std::string name = convert_upper_camel_case(field_name);
92     field_range ret = this->_header.get<field_map>().equal_range(name);
93
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)");
98     }
99     /*------ DEBUG LOG END ------*/
100
101     return ret;
102 }
103
104 /*!
105  * Set HTTP header field function.
106  * Set new HTTP header field and return old HTTP header field.
107  *
108  * @param[in]   field_name  lookup field name
109  * @param[in]   field_value field value
110  */
111 void http_message::header(std::string field_name, std::string field_value)
112 {
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());
118     }
119     /*------ DEBUG LOG END ------*/
120
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;
126     try {
127         for (;it != it_end; ++it) {
128             if (field_value != "") {
129                 if ( _header.get<field_map>().replace(it, field(name, field_value)) ) {
130                     changed = true;
131                     this->_modified = true;
132                 }
133             }
134             else {
135                 _header.get<field_map>().erase(it);
136                 changed = true;
137                 this->_modified = true;
138             }
139         }
140         if (!changed && field_value != "") {
141             _header.get<field_map>().insert( field(name, field_value) );
142             this->_modified = true;
143         }
144     }
145     catch (...) {
146         LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 1,
147         "Exception occured by inserting or replacing boost::multi_index.");
148     }
149
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)");
154     }
155     /*------ DEBUG LOG END ------*/
156 }
157
158 /*!
159  * Get message body function.
160  *
161  * @return    message body
162  */
163 std::string http_message::body() const
164 {
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());
172     }
173     /*------ DEBUG LOG END ------*/
174
175     return this->_body;
176 }
177
178 /*!
179  * Set message body function.
180  * Set new message body and return old message body.
181  *
182  * @param[in]   _body   new message body
183  * @return  old message body
184  */
185 std::string http_message::body(std::string _body)
186 {
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());
192     }
193     /*------ DEBUG LOG END ------*/
194
195     std::string ret = this->_body;
196     this->_body = _body;
197     this->_modified = true;
198
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());
204     }
205     /*------ DEBUG LOG END ------*/
206
207     return ret;
208 }
209
210 /*!
211  * Get modified flag function.
212  *
213  * @return    modified flag
214  */
215 bool http_message::modified() const
216 {
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");
224     }
225     /*------ DEBUG LOG END ------*/
226
227     return this->_modified;
228 }
229
230 /*!
231  * Get full HTTP message function.
232  *
233  * @return    HTTP message
234  */
235 std::string http_message::as_string()
236 {
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)");
241     }
242     /*------ DEBUG LOG END ------*/
243
244     if (this->_modified)
245         this->rebuild();
246
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());
252     }
253     /*------ DEBUG LOG END ------*/
254
255     return this->raw_message;
256 }
257
258 /*!
259  * Parse HTTP header function.
260  *
261  * @param[in]   message     full HTTP message header
262  */
263 void http_message::parse(std::string message)
264 {
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());
270     }
271     /*------ DEBUG LOG END ------*/
272
273     // save raw message
274     if (this->raw_message.length() == 0)
275         this->raw_message = message;
276
277     // parse message
278     HTTP_MESSAGE_POSITION pos = MESSAGE_TOP;
279
280     /*
281      * RFC2616
282      *  OCTET       : 8bit data
283      *  CHAR        : US-ASCII(0-127)
284      *  UPALPHA     : A-Z
285      *  LOALPHA     : a-z
286      *  ALPHA       : UPALPHA | LOALPHA
287      *  DIGIT       : 0-9
288      *  HEXDIG      : A-F | a-f | DIGIT
289      *  SP          : SPace(32)
290      *  HT          : Horizontal Tab(9)
291      *  CR          : Carriage Return(13)
292      *  LF          : Line Feed(10)
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)
297      */
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;
302     try {
303         while (ptr != end) {
304             switch(pos) {
305             /*
306              * MESSAGE-HEADER   : field-name ":" [ field-value ]
307              * field-name       : token
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
316              */
317             case MESSAGE_TOP:
318                 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) || 
319                     *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
320                     *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
321                     *ptr == '%') {
322                     start = ptr;
323                     pos = MESSAGE_FIELD_NAME;
324                 } else if (*ptr == '\r') { // CRLF + CRLF
325                     pos = MESSAGE_LAST_CR;
326                 } else {
327                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 32,
328                     "Parse error: Invalid header field name.(%c)", *ptr);
329                     throw -1;
330                 }
331                 break;
332     
333             case MESSAGE_CR:
334                 // LF only
335                 if (*ptr == '\n') {
336                     pos = MESSAGE_LF;
337                 } else {
338                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 33,
339                     "Parse error: No LF.(%c)", *ptr);
340                     throw -1;
341                 }
342                 break;
343     
344             case MESSAGE_LF:
345                 if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) || 
346                     *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
347                     *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
348                     *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();
354                     }
355                     start = ptr;
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();
365                     }
366                     pos = MESSAGE_LAST_CR;
367                 } else {
368                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 34,
369                     "Parse error: Invalid header field name.(%c)", *ptr);
370                     throw -1;
371                 }
372                 break;
373     
374             case MESSAGE_FIELD_NAME:
375                 // field-name end with ':'
376                 if (*ptr == ':') {
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 != '+' &&
382                     *ptr != '%') {
383                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 35,
384                     "Parse error: Invalid header field name.(%c)", *ptr);
385                     throw -1;
386                 }
387                 break;
388     
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') {
398                     start = ptr;
399                     pos = MESSAGE_FIELD_VALUE;
400                 } else if (*ptr == '\r') { // omit field value
401                     field_pair.second.clear();
402                 } else {
403                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 36,
404                     "Parse error: Invalid header field value.(%c)", *ptr);
405                     throw -1;
406                 }
407                 break;
408     
409             case MESSAGE_FIELD_VALUE:
410                 // field-value end with CR
411                 if (*ptr == '\r') {
412                     pos = MESSAGE_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);
424                     throw -1;
425                 }
426                 break;
427     
428             case MESSAGE_LAST_CR:
429                 // LF only
430                 if (*ptr == '\n') {
431                     pos = MESSAGE_LAST_LF;
432                 } else {
433                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 38,
434                     "Parse error: No LF.(%c)", *ptr);
435                     throw -1;
436                 }
437                 break;
438     
439             /*
440              * MESSAGE-BODY     : *OCTET
441              */
442             case MESSAGE_LAST_LF:
443                 pos = MESSAGE_BODY;
444                 start = ptr;
445                 break;
446     
447             case MESSAGE_BODY:
448                 break;
449             }
450             ptr++;
451         }
452     
453         switch (pos) {
454         case MESSAGE_BODY:
455             this->_body.assign(start, ptr);
456         }
457     }
458     catch (...) {
459         this->_body.clear();
460         LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 39,
461         "Exception occured by parsing HTTP message.");
462     }
463
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)");
468     }
469     /*------ DEBUG LOG END ------*/
470 }
471
472 /*!
473  * Rebuild HTTP header function.
474  */
475 void http_message::rebuild()
476 {
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()");
481     }
482     /*------ DEBUG LOG END ------*/
483
484     // insertion order
485     header_container::iterator it = this->_header.begin();
486     header_container::iterator it_end = this->_header.end();
487
488     while (it != it_end) {
489         this->raw_message += it->first + ": " + it->second + "\r\n";
490         it++;
491     }
492
493     this->raw_message += "\r\n" + this->body();
494
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()");
499     }
500     /*------ DEBUG LOG END ------*/
501 }
502
503 /*!
504  * Field name convert function.
505  * Convert upper camelcase
506  *     ex. connecTION => Connection
507  *         usEr-aGeNT => User-Agent
508  *         p3p => P3P
509  *
510  * @param[in]   field_name  field name
511  * @return  converted to camel case
512  */
513 std::string http_message::convert_upper_camel_case(std::string field_name) const
514 {
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());
520     }
521     /*------ DEBUG LOG END ------*/
522
523     std::string ret;
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));
532         ret += token;
533     }
534
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());
540     }
541     /*------ DEBUG LOG END ------*/
542     return ret;
543 }