OSDN Git Service

Refactoring HTTP parser.
[ultramonkey-l7/sslproxy.git] / include / http_request.cpp
1 /*
2  * @file  http_request.cpp
3  * @brief module of HTTP Request
4  * @brief HTTP Request 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 //#define DEBUG
26 #include "http_request.h"
27
28 /*!
29  * HTTP Request constructor.
30  */
31 http_request::http_request()
32     :
33     modified(false)
34 {
35     /*-------- DEBUG LOG --------*/
36     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
37         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 1, // XXX log
38         "in/out_function : Constructor http_request::http_request(void)");
39     }
40     /*------ DEBUG LOG END ------*/
41 }
42
43 /*!
44  * HTTP Request constructor.
45  * Parse HTTP request header.
46  *
47  * @param[in]   header  full http request header string
48  */
49 http_request::http_request(std::string header)
50     :
51     modified(false)
52 {
53     /*-------- DEBUG LOG --------*/
54     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
55         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 1, // XXX log
56         "in/out_function : Constructor http_request::http_request(std::string header) : "
57         "header(%s)", header.c_str());
58     }
59     /*------ DEBUG LOG END ------*/
60     this->parse(header);
61 }
62
63 /*!
64  * HTTP Request destructor.
65  */
66 http_request::~http_request()
67 {
68     /*-------- DEBUG LOG --------*/
69     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
70         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 2, // XXX log
71         "in/out_function : Destructor http_request::~http_request(void)");
72     }
73     /*------ DEBUG LOG END ------*/
74 }
75
76 /*!
77  * Get method function.
78  *
79  * @return    method
80  */
81 std::string http_request::method()
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, 3, // XXX log
86         "in_function : std::string http_request::method(void)");
87         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
88         "out_function : std::string http_request::method(void) : "
89         "return(%s)", this->_method.c_str());
90     }
91     /*------ DEBUG LOG END ------*/
92
93     return this->_method;
94 }
95
96 /*!
97  * Set method function.
98  * Set new method and return old method.
99  *
100  * @param[in]   method  new method
101  * @return  old method
102  */
103 std::string http_request::method(std::string _method)
104 {
105     /*-------- DEBUG LOG --------*/
106     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
107         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
108         "in_function : std::string http_request::method(std::string _method) : "
109         "_method(%s)", _method.c_str());
110     }
111     /*------ DEBUG LOG END ------*/
112
113     std::string ret = this->_method;
114     this->_method = _method;
115     this->modified = true;
116
117     /*-------- DEBUG LOG --------*/
118     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
119         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
120         "out_function : std::string http_request::method(std::string _method) : "
121         "return(%s)", ret.c_str());
122     }
123     /*------ DEBUG LOG END ------*/
124
125     return ret;
126 }
127
128 /*!
129  * Get request URI function.
130  *
131  * @return    request URI
132  */
133 std::string http_request::request_uri()
134 {
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         "in_function : std::string http_request::request_uri(void)");
139         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
140         "out_function : std::string http_request::request_uri(void) : "
141         "return(%s)", this->_request_uri.c_str());
142     }
143     /*------ DEBUG LOG END ------*/
144
145     return this->_request_uri;
146 }
147
148 /*!
149  * Set request URI function.
150  * Set new request URI and return old request URI.
151  *
152  * @param[in]   _request_uri    new request URI
153  * @return  old request URI
154  */
155 std::string http_request::request_uri(std::string _request_uri)
156 {
157     /*-------- DEBUG LOG --------*/
158     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
159         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
160         "in_function : std::string http_request::request_uri(std::string _request_uri) : "
161         "_request_uri(%s)", _request_uri.c_str());
162     }
163     /*------ DEBUG LOG END ------*/
164
165     std::string ret = this->_request_uri;
166     this->_request_uri = _request_uri;
167     this->modified = true;
168
169     /*-------- DEBUG LOG --------*/
170     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
171         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
172         "out_function : std::string http_request::_request_uri(std::string _request_uri) : "
173         "return(%s)", ret.c_str());
174     }
175     /*------ DEBUG LOG END ------*/
176
177     return ret;
178 }
179
180 /*!
181  * Get HTTP version function.
182  *
183  * @return    HTTP version
184  */
185 std::string http_request::http_version()
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, 3, // XXX log
190         "in_function : std::string http_request::http_version(void)");
191         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
192         "out_function : std::string http_request::http_version(void) : "
193         "return(%s)", this->_http_version.c_str());
194     }
195     /*------ DEBUG LOG END ------*/
196
197     return this->_http_version;
198 }
199
200 /*!
201  * Set HTTP version function.
202  * Set new HTTP version and return old HTTP version.
203  *
204  * @param[in]   _http_version   new HTTP version
205  * @return  old HTTP version
206  */
207 std::string http_request::http_version(std::string _http_version)
208 {
209     /*-------- DEBUG LOG --------*/
210     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
211         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
212         "in_function : std::string http_request::http_version(std::string _http_version) : "
213         "_http_version(%s)", _http_version.c_str());
214     }
215     /*------ DEBUG LOG END ------*/
216
217     std::string ret = this->_http_version;
218     this->_http_version = _http_version;
219     this->modified = true;
220
221     /*-------- DEBUG LOG --------*/
222     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
223         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
224         "out_function : std::string http_request::http_version(std::string _http_version) : "
225         "return(%s)", ret.c_str());
226     }
227     /*------ DEBUG LOG END ------*/
228
229     return ret;
230 }
231
232 /*!
233  * Get HTTP header field function.
234  *
235  * @param[in]   field_name  lookup field name
236  * @return      header field value
237  */
238 field_range http_request::header(std::string field_name)
239 {
240     /*-------- DEBUG LOG --------*/
241     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
242         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
243         "in_function : field_range http_request::header(std::string field_name) : "
244         "field_name(%s)", field_name.c_str());
245     }
246     /*------ DEBUG LOG END ------*/
247
248     field_range ret = this->_header.get<field_map>().equal_range(field_name);
249
250     /*-------- DEBUG LOG --------*/
251     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
252         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
253         "out_function : field_range http_request::header(std::string field_name)");
254     }
255     /*------ DEBUG LOG END ------*/
256
257     return ret;
258 }
259
260 /*!
261  * Set HTTP header field function.
262  * Set new HTTP header field and return old HTTP header field.
263  *
264  * @param[in]   field_name  lookup field name
265  * @param[in]   field_value field value
266  */
267 void http_request::header(std::string field_name, std::string field_value)
268 {
269     /*-------- DEBUG LOG --------*/
270     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
271         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
272         "in_function : field_range http_request::header(std::string field_name, std::string field_value) : "
273         "field_name(%s), field_value(%s)", field_name.c_str(), field_value.c_str());
274     }
275     /*------ DEBUG LOG END ------*/
276
277     bool replaced = false;
278     field_range ret = this->_header.get<field_map>().equal_range(field_name);
279     field_map_iterator it = ret.first;
280     field_map_iterator it_end = ret.second;
281     for (;it != it_end; ++it) {
282         if ( _header.get<field_map>().replace(it, field(field_name, field_value)) ) {
283             replaced = true;
284             this->modified = true;
285         }
286     }
287     if (!replaced) {
288         _header.get<field_map>().insert( field(field_name, field_value) );
289         this->modified = true;
290     }
291
292     /*-------- DEBUG LOG --------*/
293     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
294         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
295         "out_function : field_range http_request::header(std::string field_name, std::string field_value)");
296     }
297     /*------ DEBUG LOG END ------*/
298 }
299
300 /*!
301  * Get message body function.
302  *
303  * @return    message body
304  */
305 std::string http_request::message()
306 {
307     /*-------- DEBUG LOG --------*/
308     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
309         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
310         "in_function : std::string http_request::message(void)");
311         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
312         "out_function : std::string http_request::message(void) : "
313         "return(%s)", this->_message.c_str());
314     }
315     /*------ DEBUG LOG END ------*/
316
317     return this->_message;
318 }
319
320 /*!
321  * Set message body function.
322  * Set new message body and return old message body.
323  *
324  * @param[in]   _message    new message body
325  * @return  old message body
326  */
327 std::string http_request::message(std::string _message)
328 {
329     /*-------- DEBUG LOG --------*/
330     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
331         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
332         "in_function : std::string http_request::http_version(std::string _message) : "
333         "_message(%s)", _message.c_str());
334     }
335     /*------ DEBUG LOG END ------*/
336
337     std::string ret = this->_message;
338     this->_message = _message;
339     this->modified = true;
340
341     /*-------- DEBUG LOG --------*/
342     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
343         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
344         "out_function : std::string http_request::message(std::string _message) : "
345         "return(%s)", ret.c_str());
346     }
347     /*------ DEBUG LOG END ------*/
348
349     return ret;
350 }
351
352 /*!
353  * Get request line function.
354  *
355  * @return    request line
356  */
357 std::string http_request::request_line()
358 {
359     /*-------- DEBUG LOG --------*/
360     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
361         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
362         "in_function : std::string http_request::request_line(void)");
363     }
364     /*------ DEBUG LOG END ------*/
365
366     std::string ret = this->method() + " " + this->request_uri() + " " + this->http_version() + "\r\n";
367
368     /*-------- DEBUG LOG --------*/
369     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
370         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
371         "out_function : std::string http_request::request_line(void) : "
372         "return(%s)", ret.c_str());
373     }
374     /*------ DEBUG LOG END ------*/
375
376     return ret;
377 }
378
379 /*!
380  * Get full HTTP request function.
381  *
382  * @return    HTTP request
383  */
384 std::string http_request::as_string()
385 {
386     /*-------- DEBUG LOG --------*/
387     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
388         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
389         "in_function : std::string http_request::as_string(void)");
390     }
391     /*------ DEBUG LOG END ------*/
392
393     if (this->modified)
394         this->rebuild();
395
396     /*-------- DEBUG LOG --------*/
397     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
398         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
399         "out_function : std::string http_request::as_string(void) : "
400         "return(%s)", this->raw_request.c_str());
401     }
402     /*------ DEBUG LOG END ------*/
403
404     return this->raw_request;
405 }
406
407 /*!
408  * Parse HTTP header function.
409  *
410  * @param[in]   request     full HTTP request header
411  */
412 void http_request::parse(std::string request)
413 {
414     /*-------- DEBUG LOG --------*/
415     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
416         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
417         "in_function : void http_request::parse(std::string request) : "
418         "request(%s)", request.c_str());
419     }
420     /*------ DEBUG LOG END ------*/
421
422     // save raw request
423     this->raw_request = request;
424
425     // parse request
426     HTTP_REQUEST_POSITION pos = REQUEST_METHOD;
427
428     /*
429      * RFC2616
430      *  OCTET       : 8bit data
431      *  CHAR        : US-ASCII(0-127)
432      *  UPALPHA     : A-Z
433      *  LOALPHA     : a-z
434      *  ALPHA       : UPALPHA | LOALPHA
435      *  DIGIT       : 0-9
436      *  HEXDIG      : A-F | a-f | DIGIT
437      *  SP          : SPace(32)
438      *  HT          : Horizontal Tab(9)
439      *  CR          : Carriage Return(13)
440      *  LF          : Line Feed(10)
441      *  CTL         : ConTLol char(0-31,127)
442      *  LWS         : [CRLF] 1*(SP|HT)
443      *  separators  : ()<>@,;:\"/[]?={} and SP, HT
444      *  token       : 1*(CHAR not CTL, separators)
445      */
446     std::string::iterator ptr = request.begin();
447     std::string::iterator end = request.end();
448     std::string::iterator start = ptr;
449     std::pair<std::string, std::string> field_pair;
450     while (ptr != end) {
451         switch(pos) {
452         /*
453          * REQUEST-LINE :
454          *      METHOD SP REQUEST-URI SP HTTP-VERSION CRLF
455          */
456         /*
457          * METHOD : token
458          */
459         case REQUEST_METHOD:
460             if (*ptr == ' ') { // METHOD end with SP
461                 this->_method.assign(start, ptr);
462                 pos = REQUEST_METHOD_SP;
463             } else if (!isalpha(*ptr) && !isdigit(*ptr)) { // XXX not enough
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, 3, // XXX log
467                     "out_function : void http_request::parse(std::string request) : Invalid Method");
468                 }
469                 /*------ DEBUG LOG END ------*/
470                 throw -1;
471             }
472             break;
473         /*
474          * REQUEST-URI : * | absolute-URI | path-absolute | authority
475          *
476          * RFC3986
477          *  absolute-URI    : scheme ":" hier-part [ "?" query ]
478          *  path-absolute   : "/" [ segment-nz *( "/" segment ) ]
479          *  authority       : [ userinfo "@" ] host [ ":" port ]
480          *  scheme          : ALPHA *( ALPHA | DIGIT | "+" | "-" | "." )
481          *  hier-part       : "//" authority path-abempty
482          *                  / path-absolute
483          *                  / path-rootless
484          *                  / path-empty
485          *  query           : *( pchar | "/" | "?" )
486          *  path-abempty    : *( "/" segment )
487          *  path-rootless   : segment-nz *( "/" segment )
488          *  path-empty      : no char
489          *  segment-nz      : 1*pchar
490          *  segment         : *pchar
491          *  userinfo        : *( unreserved | pct-encoded | sub-delims | ":" )
492          *  host            : IP-literal | IPv4address | reg-name
493          *  port            : *DIGIT
494          *  unreserved      : ALPHA | DIGIT | "-" | "." | "_" | "~"
495          *  pct-encoded     : "%" HEXDIG HEXDIG
496          *  sub-delims      : !$&'()*+,;=
497          *  pchar           : unreserved | pct-encoded | subdelims | ":" | "@"
498          *  IP-literal      : "[" ( IPv6address | IPvFuture ) "]"
499          *  IPvFuture       : "v" 1*HEXDIG "." 1*( unreserved | sub-delims | ":" )
500          *  IPv6address     :                            6( h16 ":" ) ls32
501          *                  /                       "::" 5( h16 ":" ) ls32
502          *                  / [               h16 ] "::" 4( h16 ":" ) ls32
503          *                  / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
504          *                  / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
505          *                  / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
506          *                  / [ *4( h16 ":" ) h16 ] "::"              ls32
507          *                  / [ *5( h16 ":" ) h16 ] "::"              h16
508          *                  / [ *6( h16 ":" ) h16 ] "::"
509          *  h16             : 1*4HEXDIG
510          *  ls32            : ( h16 ":" h16 ) | IPv4address
511          *  IPv4address     : dec-octet "." dec-octet "." dec-octet "." dec-octet
512          *  dec-octet       : 0-255
513          *  reg-name        : *( unreserved | pct-encoded | sub-delims )
514          */
515         case REQUEST_METHOD_SP:
516             // Request-URI start
517             // XXX not enough?
518             if (*ptr == '/' || isalpha(*ptr) || isdigit(*ptr) || *ptr == '-' ||
519                 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == ':' || 
520                 *ptr == '@' || *ptr == '!' || *ptr == '$' || *ptr == '&' ||
521                 *ptr == '(' || *ptr == ')' || *ptr == '*' || *ptr == '+' ||
522                 *ptr == ',' || *ptr == ';' || *ptr == '=' || *ptr == '%') {
523                 pos = REQUEST_REQUEST_URI;
524                 start = ptr;
525             } else {
526                 /*-------- DEBUG LOG --------*/
527                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
528                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
529                     "out_function : void http_request::parse(std::string request) : Invalid Request-URI");
530                 }
531                 /*------ DEBUG LOG END ------*/
532                 throw -1;
533             }
534             break;
535
536         case REQUEST_REQUEST_URI:
537             if (*ptr == ' ') { // Request-URI end with SP
538                 this->_request_uri.assign(start, ptr);
539                 pos = REQUEST_REQUEST_URI_SP;
540             } else if (!isalpha(*ptr) && !isdigit(*ptr) && *ptr != '/' && // XXX not enough?
541                 *ptr != '.' && *ptr != '=' && *ptr != '%' && *ptr != '?' &&
542                 *ptr != '&' && *ptr != '+' && *ptr != '~' && *ptr != ',' && 
543                 *ptr != '@' && *ptr != '!' && *ptr != '$' && *ptr != '-' &&
544                 *ptr != '(' && *ptr != ')' && *ptr != '*' && *ptr != '_' &&
545                 *ptr != ':' && *ptr != ';') {
546                 /*-------- DEBUG LOG --------*/
547                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
548                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
549                     "out_function : void http_request::parse(std::string request) : Invalid Request-URI");
550                 }
551                 /*------ DEBUG LOG END ------*/
552                 throw -1;
553             }
554             break;
555
556         /*
557          * HTTP-VERSION     : "HTTP" "/" 1*DIGIT "." 1*DIGIT
558          */
559         case REQUEST_REQUEST_URI_SP:
560             // HTTP-VERSION start
561             if (*ptr == 'H') {
562                 pos = REQUEST_HTTP_VERSION_H;
563                 start = ptr;
564             } else {
565                 /*-------- DEBUG LOG --------*/
566                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
567                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
568                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
569                 }
570                 /*------ DEBUG LOG END ------*/
571                 throw -1;
572             }
573             break;
574
575         case REQUEST_HTTP_VERSION_H:
576             // HTTP-VERSION next
577             if (*ptr == 'T') {
578                 pos = REQUEST_HTTP_VERSION_T1;
579             } else {
580                 /*-------- DEBUG LOG --------*/
581                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
582                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
583                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
584                 }
585                 /*------ DEBUG LOG END ------*/
586                 throw -1;
587             }
588             break;
589
590         case REQUEST_HTTP_VERSION_T1:
591             // HTTP-VERSION next
592             if (*ptr == 'T') {
593                 pos = REQUEST_HTTP_VERSION_T2;
594             } else {
595                 /*-------- DEBUG LOG --------*/
596                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
597                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
598                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
599                 }
600                 /*------ DEBUG LOG END ------*/
601                 throw -1;
602             }
603             break;
604
605         case REQUEST_HTTP_VERSION_T2:
606             // HTTP-VERSION next
607             if (*ptr == 'P') {
608                 pos = REQUEST_HTTP_VERSION_P;
609             } else {
610                 /*-------- DEBUG LOG --------*/
611                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
612                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
613                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
614                 }
615                 /*------ DEBUG LOG END ------*/
616                 throw -1;
617             }
618             break;
619
620         case REQUEST_HTTP_VERSION_P:
621             // HTTP-VERSION next
622             if (*ptr == '/') {
623                 pos = REQUEST_HTTP_VERSION_SLASH;
624             } else {
625                 /*-------- DEBUG LOG --------*/
626                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
627                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
628                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
629                 }
630                 /*------ DEBUG LOG END ------*/
631                 throw -1;
632             }
633             break;
634
635         case REQUEST_HTTP_VERSION_SLASH:
636             // HTTP-VERSION Mejor number
637             if (isdigit(*ptr)) {
638                 pos = REQUEST_HTTP_VERSION_MAJOR;
639             } else {
640                 /*-------- DEBUG LOG --------*/
641                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
642                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
643                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
644                 }
645                 /*------ DEBUG LOG END ------*/
646                 throw -1;
647             }
648             break;
649
650         case REQUEST_HTTP_VERSION_MAJOR:
651             // HTTP-VERSION next dot
652             if (*ptr == '.') {
653                 pos = REQUEST_HTTP_VERSION_DOT;
654             } else if (!isdigit(*ptr)) {
655                 /*-------- DEBUG LOG --------*/
656                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
657                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
658                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
659                 }
660                 /*------ DEBUG LOG END ------*/
661                 throw -1;
662             }
663             break;
664
665         case REQUEST_HTTP_VERSION_DOT:
666             // HTTP-VERSION Minor number
667             if (isdigit(*ptr)) {
668                 pos = REQUEST_HTTP_VERSION_MINOR;
669             } else {
670                 /*-------- DEBUG LOG --------*/
671                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
672                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
673                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
674                 }
675                 /*------ DEBUG LOG END ------*/
676                 throw -1;
677             }
678             break;
679
680         case REQUEST_HTTP_VERSION_MINOR:
681             // HTTP-VERSION end with CR
682             if (*ptr == '\r') {
683                 pos = REQUEST_CR;
684                 this->_http_version.assign(start, ptr);
685             } else if (!isdigit(*ptr)) {
686                 /*-------- DEBUG LOG --------*/
687                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
688                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
689                     "out_function : void http_request::parse(std::string request) : Invalid HTTP-Version");
690                 }
691                 /*------ DEBUG LOG END ------*/
692                 throw -1;
693             }
694             break;
695
696         case REQUEST_CR:
697             // LF only
698             if (*ptr == '\n') {
699                 pos = REQUEST_LF;
700             } else {
701                 /*-------- DEBUG LOG --------*/
702                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
703                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
704                     "out_function : void http_request::parse(std::string request) : not CRLF");
705                 }
706                 /*------ DEBUG LOG END ------*/
707                 throw -1;
708             }
709             break;
710
711         /*
712          * MESSAGE-HEADER   : field-name ":" [ field-value ]
713          * field-name       : token
714          * field-value      : *( field-content | LWS )
715          * field-content    : <the OCTETs making up the field-value and
716          *                    consisting of either *TEXT or combinations
717          *                    of token, separators, and quoted-string>
718          * TEXT             : <any OCTET except CTLs, but including LWS>
719          * quoted-string    : ( <"> *(qdtext | quoted-pair ) <"> )
720          * qdtext           : <any TEXT except <">>
721          * quoted-pair      : "\" CHAR
722          */
723         case REQUEST_LF:
724             if (isalpha(*ptr) || *ptr == '-' || isdigit(*ptr) || 
725                 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == '!' ||
726                 *ptr == '$' || *ptr == '&' || *ptr == '*' || *ptr == '+' ||
727                 *ptr == '%') {
728                 if (field_pair.first.length()) {
729                     _header.get<field_map>().insert(field_pair);
730                     field_pair.first.clear();
731                 }
732                 start = ptr;
733                 pos = REQUEST_FIELD_NAME;
734             } else if (*ptr == ' ' || *ptr == '\t') {
735                 pos = REQUEST_FIELD_VALUE;
736             } else if (*ptr == '\r') { // CRLF + CRLF
737                 if (field_pair.first.length()) {
738                     _header.get<field_map>().insert(field_pair);
739                     field_pair.first.clear();
740                 }
741                 pos = REQUEST_LAST_CR;
742             } else {
743                 /*-------- DEBUG LOG --------*/
744                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
745                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
746                     "out_function : void http_request::parse(std::string request) : not CRLF");
747                 }
748                 /*------ DEBUG LOG END ------*/
749                 throw -1;
750             }
751             break;
752
753         case REQUEST_FIELD_NAME:
754             // field-name end with ':'
755             if (*ptr == ':') {
756                 pos = REQUEST_FIELD_NAME_COLON;
757                 field_pair.first.assign(start, ptr);
758             } else if (!isalpha(*ptr) && *ptr != '-' && !isdigit(*ptr) && 
759                 *ptr != '.' && *ptr != '_' && *ptr != '~' && *ptr != '!' &&
760                 *ptr != '$' && *ptr != '&' && *ptr != '*' && *ptr != '+' &&
761                 *ptr != '%') {
762                 /*-------- DEBUG LOG --------*/
763                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
764                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
765                     "out_function : void http_request::parse(std::string request) : Invalid header field name.");
766                 }
767                 /*------ DEBUG LOG END ------*/
768                 throw -1;
769             }
770             break;
771
772         case REQUEST_FIELD_NAME_COLON:
773             if (*ptr == ' ' || isalpha(*ptr) || isdigit(*ptr) || *ptr == '-' ||
774                 *ptr == '.' || *ptr == '_' || *ptr == '~' || *ptr == ':' || 
775                 *ptr == '@' || *ptr == '!' || *ptr == '$' || *ptr == '&' ||
776                 *ptr == '(' || *ptr == ')' || *ptr == '*' || *ptr == '+' ||
777                 *ptr == ',' || *ptr == ';' || *ptr == '=' || *ptr == '%' ||
778                 *ptr == '<' || *ptr == '>' || *ptr == '[' || *ptr == ']' ||
779                 *ptr == '{' || *ptr == '}' || *ptr == '?' || *ptr == '"' ||
780                 *ptr == '|' || *ptr == '/' || *ptr == '\\' || *ptr == '\t') {
781                 start = ptr;
782                 pos = REQUEST_FIELD_VALUE;
783             } else if (*ptr == '\r') { // omit field value
784                 field_pair.second.clear();
785             } else {
786                 /*-------- DEBUG LOG --------*/
787                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
788                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
789                     "out_function : void http_request::parse(std::string request) : Invalid header field value.('%c')", *ptr);
790                 }
791                 /*------ DEBUG LOG END ------*/
792             }
793             break;
794
795         case REQUEST_FIELD_VALUE:
796             // field-value end with CR
797             if (*ptr == '\r') {
798                 pos = REQUEST_CR;
799                 field_pair.second.assign(start, ptr);
800             } else if (*ptr != ' ' && !isalpha(*ptr) && !isdigit(*ptr) && *ptr != '-' &&
801                 *ptr != '.' && *ptr != '_' && *ptr != '~' && *ptr != ':' && 
802                 *ptr != '@' && *ptr != '!' && *ptr != '$' && *ptr != '&' &&
803                 *ptr != '(' && *ptr != ')' && *ptr != '*' && *ptr != '+' &&
804                 *ptr != ',' && *ptr != ';' && *ptr != '=' && *ptr != '%' &&
805                 *ptr != '<' && *ptr != '>' && *ptr != '[' && *ptr != ']' &&
806                 *ptr != '{' && *ptr != '}' && *ptr != '?' && *ptr != '"' &&
807                 *ptr != '|' && *ptr != '/' && *ptr != '\\'&& *ptr != '\t' ) {
808                 /*-------- DEBUG LOG --------*/
809                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
810                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
811                     "out_function : void http_request::parse(std::string request) : Invalid header field value.('%c')", *ptr);
812                 }
813                 /*------ DEBUG LOG END ------*/
814                 throw -1;
815             }
816             break;
817
818         case REQUEST_LAST_CR:
819             // LF only
820             if (*ptr == '\n') {
821                 pos = REQUEST_LAST_LF;
822             } else {
823                 /*-------- DEBUG LOG --------*/
824                 if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
825                     LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
826                     "out_function : void http_request::parse(std::string request) : not CRLF");
827                 }
828                 /*------ DEBUG LOG END ------*/
829                 throw -1;
830             }
831             break;
832
833         /*
834          * MESSAGE-BODY     : *OCTET
835          */
836         case REQUEST_LAST_LF:
837             pos = REQUEST_MESSAGE;
838             start = ptr;
839             break;
840
841         case REQUEST_MESSAGE:
842             break;
843         }
844         ptr++;
845     }
846
847     switch (pos) {
848     case REQUEST_MESSAGE:
849         this->_message.assign(start, ptr);
850     }
851
852     /*-------- DEBUG LOG --------*/
853     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
854         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
855         "out_function : void http_request::parse(std::string request)");
856     }
857     /*------ DEBUG LOG END ------*/
858 }
859
860 /*!
861  * Rebuild HTTP header function.
862  */
863 void http_request::rebuild()
864 {
865     /*-------- DEBUG LOG --------*/
866     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
867         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
868         "in_function : void http_request::rebuild()");
869     }
870     /*------ DEBUG LOG END ------*/
871
872     this->raw_request = this->request_line();
873     // insertion order
874     header_container::iterator it = this->_header.begin();
875     header_container::iterator it_end = this->_header.end();
876
877     while (it != it_end) {
878         this->raw_request += it->first + ": " + it->second + "\r\n";
879         it++;
880     }
881
882     this->raw_request += "\r\n" + this->message();
883
884     /*-------- DEBUG LOG --------*/
885     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
886         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 3, // XXX log
887         "out_function : void http_request::rebuild()");
888     }
889     /*------ DEBUG LOG END ------*/
890 }
891
892 void printheader(http_request& request, std::string name) {
893         field_range r;
894         r = request.header(name);
895         while (r.first != r.second) {
896             std::cout << "=======> HEADER(" << r.first->first << "): " << r.first->second<< std::endl;
897             r.first++;
898         }
899 }
900
901 void changeheader(http_request& request, std::string name, std::string value) {
902         request.header(name, value);
903         printheader(request, name);
904 }
905
906 int main() {
907 /*
908     try {
909         http_request req;
910         req.parse("GET / HTTP/1.0\n");
911         std::cout << "=======> METHOD: " << req.method() << std::endl;
912     }
913     catch(...) {}
914 */
915
916     try {
917         http_request request("POST /index HTTP/1.1\r\nHost: localhost\r\nX-Forwarded-For: localhost\r\n  foobar\r\nAccept: */*\r\n\r\nMessageBODY");
918         std::cout << request.as_string() << std::endl;
919         std::cout << "=======> METHOD: " << request.method() << std::endl;
920         std::cout << "=======> URI: " << request.request_uri() << std::endl;
921         std::cout << "=======> VERSION: " << request.http_version() << std::endl;
922         printheader(request, "Host");
923         printheader(request, "X-Forwarded-For");
924         printheader(request, "Accept");
925         printheader(request, "Test");
926         changeheader(request, "Test", "new test");
927         changeheader(request, "Host", "new host");
928         std::cout << request.as_string() << std::endl;
929         std::cout << request.request_line() << std::endl;
930 //        std::cout << request.method("TRACE") << std::endl;
931 //        std::cout << request.request_uri("/?type=project&id=393") << std::endl;
932 //        std::cout << request.http_version("HTTP/1.0") << std::endl;
933         std::cout << request.request_line() << std::endl;
934         std::cout << request.message("type=project&id=303") << std::endl;
935         std::cout << request.message() << std::endl;
936         std::cout << request.as_string() << std::endl;
937     }
938     catch(...) {}
939
940     try {
941         http_request r;
942         r.method("GET");
943         r.request_uri("/index.html");
944         r.http_version("HTTP/1.1");
945         r.header("Host", "img.unitcom.co.jp");
946         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)");
947         r.header("Accept", "image/png,image/*;q=0.8,*/*;q=0.5");
948         r.header("Accept-Language", "ja,en-us;q=0.7,en;q=0.3");
949         r.header("Accept-Encoding", "gzip,deflate");
950         r.header("Accept-Charset", "Shift_JIS,utf-8;q=0.7,*;q=0.7");
951         r.header("Keep-Alive", "300");
952         r.header("Connection", "keep-alive");
953         r.header("Referer", "http://www.faith-go.co.jp/special/");
954         r.header("Cookie", "ASPSESSIONIDQCCQBQBR=HHKHICIACCKKHPIIECCOBOJG");
955         r.message("TEST__TEST");
956         std::cout << r.as_string() << std::endl;
957     }
958     catch(...) {}
959
960     try {
961 std::string text = 
962 "GET /cgi-bin/env.cgi HTTP/1.1\r\n"
963 "Host: 192.168.0.4:7780\r\n"
964 "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"
965 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
966 "Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n"
967 "Accept-Encoding: gzip,deflate\r\n"
968 "Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n"
969 "Keep-Alive: 300\r\n"
970 "Connection: keep-alive\r\n"
971 "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"
972 "Cache-Control: max-age=0\r\n"
973 "\r\n";
974         http_request re(text);
975         std::cout << re.as_string() << std::endl;
976     }
977     catch(...){}
978     return 0;
979 }