OSDN Git Service

12f9262444d02d9665b344f8fff759ccd810a5fe
[ultramonkey-l7/sslproxy.git] / src / http_response.cpp
1 /*
2  * @file  http_response.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 #include "http_response.h"
26
27 /*!
28  * HTTP Request constructor.
29  */
30 http_response::http_response()
31 {
32     /*-------- DEBUG LOG --------*/
33     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
34         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 43,
35         "in/out_function : Constructor http_response::http_response(void)");
36     }
37     /*------ DEBUG LOG END ------*/
38 }
39
40 /*!
41  * HTTP Request constructor.
42  * Parse HTTP response header.
43  *
44  * @param[in]   header  full http response header string
45  */
46 http_response::http_response(std::string header)
47 {
48     /*-------- DEBUG LOG --------*/
49     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
50         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 44,
51         "in/out_function : Constructor http_response::http_response(std::string header) : "
52         "header(%s)", header.c_str());
53     }
54     /*------ DEBUG LOG END ------*/
55     this->parse(header);
56 }
57
58 /*!
59  * HTTP Request destructor.
60  */
61 http_response::~http_response()
62 {
63     /*-------- DEBUG LOG --------*/
64     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
65         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 45,
66         "in/out_function : Destructor http_response::~http_response(void)");
67     }
68     /*------ DEBUG LOG END ------*/
69 }
70
71 /*!
72  * Get HTTP version function.
73  *
74  * @return    HTTP version
75  */
76 std::string http_response::http_version() const
77 {
78     /*-------- DEBUG LOG --------*/
79     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
80         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 46,
81         "in_function : std::string http_response::http_version(void)");
82         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 47,
83         "out_function : std::string http_response::http_version(void) : "
84         "return(%s)", this->_http_version.c_str());
85     }
86     /*------ DEBUG LOG END ------*/
87
88     return this->_http_version;
89 }
90
91 /*!
92  * Set HTTP version function.
93  * Set new HTTP version and return old HTTP version.
94  *
95  * @param[in]   _http_version   new HTTP version
96  * @return  old HTTP version
97  */
98 std::string http_response::http_version(std::string _http_version)
99 {
100     /*-------- DEBUG LOG --------*/
101     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
102         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 48,
103         "in_function : std::string http_response::http_version(std::string _http_version) : "
104         "_http_version(%s)", _http_version.c_str());
105     }
106     /*------ DEBUG LOG END ------*/
107
108     std::string ret = this->_http_version;
109     this->_http_version = _http_version;
110     this->_modified = true;
111
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, 49,
115         "out_function : std::string http_response::http_version(std::string _http_version) : "
116         "return(%s)", ret.c_str());
117     }
118     /*------ DEBUG LOG END ------*/
119
120     return ret;
121 }
122
123 /*!
124  * Get status code function.
125  *
126  * @return    status code
127  */
128 std::string http_response::status_code() const
129 {
130     /*-------- DEBUG LOG --------*/
131     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
132         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 50,
133         "in_function : std::string http_response::status_code(void)");
134         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 51,
135         "out_function : std::string http_response::status_code(void) : "
136         "return(%s)", this->_status_code.c_str());
137     }
138     /*------ DEBUG LOG END ------*/
139
140     return this->_status_code;
141 }
142
143 /*!
144  * Set status code function.
145  * Set new status code and return old status code.
146  *
147  * @param[in]   _status_code   new status code
148  * @return  old status code
149  */
150 std::string http_response::status_code(std::string _status_code)
151 {
152     /*-------- DEBUG LOG --------*/
153     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
154         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 52,
155         "in_function : std::string http_response::status_code(std::string _status_code) : "
156         "_status_code(%s)", _status_code.c_str());
157     }
158     /*------ DEBUG LOG END ------*/
159
160     std::string ret = this->_status_code;
161     this->_status_code = _status_code;
162     this->_modified = true;
163
164     /*-------- DEBUG LOG --------*/
165     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
166         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 53,
167         "out_function : std::string http_response::status_code(std::string _status_code) : "
168         "return(%s)", ret.c_str());
169     }
170     /*------ DEBUG LOG END ------*/
171
172     return ret;
173 }
174
175 /*!
176  * Get reason phrase function.
177  *
178  * @return    reason phrase
179  */
180 std::string http_response::reason_phrase() const
181 {
182     /*-------- DEBUG LOG --------*/
183     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
184         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 54,
185         "in_function : std::string http_response::reason_phrase(void)");
186         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 55,
187         "out_function : std::string http_response::reason_phrase(void) : "
188         "return(%s)", this->_reason_phrase.c_str());
189     }
190     /*------ DEBUG LOG END ------*/
191
192     return this->_reason_phrase;
193 }
194
195 /*!
196  * Set reason phrase function.
197  * Set new reason phrase and return old reason phrase.
198  *
199  * @param[in]   _reason_phrase   new reason phrase
200  * @return  old reason phrase
201  */
202 std::string http_response::reason_phrase(std::string _reason_phrase)
203 {
204     /*-------- DEBUG LOG --------*/
205     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
206         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 56,
207         "in_function : std::string http_response::reason_phrase(std::string _reason_phrase) : "
208         "_reason_phrase(%s)", _reason_phrase.c_str());
209     }
210     /*------ DEBUG LOG END ------*/
211
212     std::string ret = this->_reason_phrase;
213     this->_reason_phrase = _reason_phrase;
214     this->_modified = true;
215
216     /*-------- DEBUG LOG --------*/
217     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
218         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 57,
219         "out_function : std::string http_response::reason_phrase(std::string _reason_phrase) : "
220         "return(%s)", ret.c_str());
221     }
222     /*------ DEBUG LOG END ------*/
223
224     return ret;
225 }
226
227 /*!
228  * Get status line function.
229  *
230  * @return    status line
231  */
232 std::string http_response::status_line() const
233 {
234     /*-------- DEBUG LOG --------*/
235     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
236         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 58,
237         "in_function : std::string http_response::status_line(void)");
238     }
239     /*------ DEBUG LOG END ------*/
240
241     std::string ret = this->http_version() + " " + this->status_code() + " " + this->reason_phrase() + "\r\n";
242
243     /*-------- DEBUG LOG --------*/
244     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
245         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 59,
246         "out_function : std::string http_response::status_line(void) : "
247         "return(%s)", ret.c_str());
248     }
249     /*------ DEBUG LOG END ------*/
250
251     return ret;
252 }
253
254 /*!
255  * Get full HTTP response function.
256  *
257  * @return    HTTP response
258  */
259 std::string http_response::as_string()
260 {
261     /*-------- DEBUG LOG --------*/
262     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
263         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 60,
264         "in_function : std::string http_response::as_string(void)");
265     }
266     /*------ DEBUG LOG END ------*/
267
268     if (this->_modified)
269         this->rebuild();
270
271     /*-------- DEBUG LOG --------*/
272     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
273         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 61,
274         "out_function : std::string http_response::as_string(void) : "
275         "return(%s)", this->raw_message.c_str());
276     }
277     /*------ DEBUG LOG END ------*/
278
279     return this->raw_message;
280 }
281
282 /*!
283  * Parse HTTP response header function.
284  *
285  * @param[in]   request     full HTTP response header
286  */
287 void http_response::parse(std::string response)
288 {
289     /*-------- DEBUG LOG --------*/
290     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
291         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 62,
292         "in_function : void http_response::parse(std::string response) : "
293         "response(%s)", response.c_str());
294     }
295     /*------ DEBUG LOG END ------*/
296
297     // save raw response
298     this->raw_message = response;
299
300     // parse response
301     HTTP_RESPONSE_POSITION pos = RESPONSE_TOP;
302
303     /*
304      * RFC2616
305      *  OCTET       : 8bit data
306      *  CHAR        : US-ASCII(0-127)
307      *  UPALPHA     : A-Z
308      *  LOALPHA     : a-z
309      *  ALPHA       : UPALPHA | LOALPHA
310      *  DIGIT       : 0-9
311      *  HEXDIG      : A-F | a-f | DIGIT
312      *  SP          : SPace(32)
313      *  HT          : Horizontal Tab(9)
314      *  CR          : Carriage Return(13)
315      *  LF          : Line Feed(10)
316      *  CTL         : ConTLol char(0-31,127)
317      *  LWS         : [CRLF] 1*(SP|HT)
318      *  separators  : ()<>@,;:\"/[]?={} and SP, HT
319      *  token       : 1*(CHAR not CTL, separators)
320      */
321     std::string::iterator ptr = response.begin();
322     std::string::iterator end = response.end();
323     std::string::iterator start = ptr;
324     std::pair<std::string, std::string> field_pair;
325     try {
326         while (ptr != end) {
327             switch(pos) {
328             /*
329              * STATUS-LINE :
330              *      HTTP-VERSION SP STATUS-CODE SP REASON-PHRASE CRLF
331              */
332             /*
333              * HTTP-VERSION     : "HTTP" "/" 1*DIGIT "." 1*DIGIT
334              */
335             case RESPONSE_TOP:
336                 // HTTP-VERSION start
337                 if (*ptr == 'H') {
338                     pos = RESPONSE_HTTP_VERSION_H;
339                     start = ptr;
340                 } else {
341                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 15,
342                     "Parse error: Invalid http-version.(%c)", *ptr);
343                     throw -1;
344                 }
345                 break;
346     
347             case RESPONSE_HTTP_VERSION_H:
348                 // HTTP-VERSION next
349                 if (*ptr == 'T') {
350                     pos = RESPONSE_HTTP_VERSION_T1;
351                 } else {
352                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 16,
353                     "Parse error: Invalid http-version.(%c)", *ptr);
354                     throw -1;
355                 }
356                 break;
357     
358             case RESPONSE_HTTP_VERSION_T1:
359                 // HTTP-VERSION next
360                 if (*ptr == 'T') {
361                     pos = RESPONSE_HTTP_VERSION_T2;
362                 } else {
363                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 17,
364                     "Parse error: Invalid http-version.(%c)", *ptr);
365                     throw -1;
366                 }
367                 break;
368     
369             case RESPONSE_HTTP_VERSION_T2:
370                 // HTTP-VERSION next
371                 if (*ptr == 'P') {
372                     pos = RESPONSE_HTTP_VERSION_P;
373                 } else {
374                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 18,
375                     "Parse error: Invalid http-version.(%c)", *ptr);
376                     throw -1;
377                 }
378                 break;
379     
380             case RESPONSE_HTTP_VERSION_P:
381                 // HTTP-VERSION next
382                 if (*ptr == '/') {
383                     pos = RESPONSE_HTTP_VERSION_SLASH;
384                 } else {
385                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 19,
386                     "Parse error: Invalid http-version.(%c)", *ptr);
387                     throw -1;
388                 }
389                 break;
390     
391             case RESPONSE_HTTP_VERSION_SLASH:
392                 // HTTP-VERSION Mejor number
393                 if (isdigit(*ptr)) {
394                     pos = RESPONSE_HTTP_VERSION_MAJOR;
395                 } else {
396                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 20,
397                     "Parse error: Invalid http-version.(%c)", *ptr);
398                     throw -1;
399                 }
400                 break;
401     
402             case RESPONSE_HTTP_VERSION_MAJOR:
403                 // HTTP-VERSION next dot
404                 if (*ptr == '.') {
405                     pos = RESPONSE_HTTP_VERSION_DOT;
406                 } else if (!isdigit(*ptr)) {
407                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 21,
408                     "Parse error: Invalid http-version.(%c)", *ptr);
409                     throw -1;
410                 }
411                 break;
412     
413             case RESPONSE_HTTP_VERSION_DOT:
414                 // HTTP-VERSION Minor number
415                 if (isdigit(*ptr)) {
416                     pos = RESPONSE_HTTP_VERSION_MINOR;
417                 } else {
418                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 22,
419                     "Parse error: Invalid http-version.(%c)", *ptr);
420                     throw -1;
421                 }
422                 break;
423     
424             case RESPONSE_HTTP_VERSION_MINOR:
425                 // HTTP-VERSION end with SP
426                 if (*ptr == ' ') {
427                     pos = RESPONSE_HTTP_VERSION_SP;
428                     this->_http_version.assign(start, ptr);
429                 } else if (!isdigit(*ptr)) {
430                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 23,
431                     "Parse error: Invalid http-version.(%c)", *ptr);
432                     throw -1;
433                 }
434                 break;
435     
436             /*
437              * Status-Code  : 3DIGIT
438              */
439             case RESPONSE_HTTP_VERSION_SP:
440                 // STATUS-CODE start
441                 if (isdigit(*ptr)) {
442                     pos = RESPONSE_STATUS_CODE1;
443                     start = ptr;
444                 } else {
445                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 24,
446                     "Parse error: Invalid status-code.(%c)", *ptr);
447                     throw -1;
448                 }
449                 break;
450     
451             case RESPONSE_STATUS_CODE1:
452                 // STATUS-CODE next
453                 if (isdigit(*ptr)) {
454                     pos = RESPONSE_STATUS_CODE2;
455                 } else {
456                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 25,
457                     "Parse error: Invalid status-code.(%c)", *ptr);
458                     throw -1;
459                 }
460                 break;
461     
462             case RESPONSE_STATUS_CODE2:
463                 // STATUS-CODE next
464                 if (isdigit(*ptr)) {
465                     pos = RESPONSE_STATUS_CODE3;
466                 } else {
467                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 26,
468                     "Parse error: Invalid status-code.(%c)", *ptr);
469                     throw -1;
470                 }
471                 break;
472     
473             case RESPONSE_STATUS_CODE3:
474                 // Status-Code end with SP
475                 if (*ptr == ' ') {
476                     pos = RESPONSE_STATUS_CODE_SP;
477                     this->_status_code.assign(start, ptr);
478                 } else {
479                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 27,
480                     "Parse error: Invalid status-code.(%c)", *ptr);
481                     throw -1;
482                 }
483                 break;
484     
485             /*
486              * Reason-Phrase    : *<TEXT, excluding CR, LF>
487              */
488             case RESPONSE_STATUS_CODE_SP:
489                 // Reason-Phrase is OCTET
490                 if (*ptr == '\r') { // omit reason-phrase
491                     pos = RESPONSE_CR;
492                     this->_reason_phrase.clear();
493                 } else if (*ptr != '\n') {
494                     pos = RESPONSE_REASON_PHRASE;
495                     start = ptr;
496                 } else  {
497                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 28,
498                     "Parse error: Invalid reason-phrase.(%c)", *ptr);
499                     throw -1;
500                 }
501                 break;
502     
503             case RESPONSE_REASON_PHRASE:
504                 // Reason-Phrase end with CR
505                 if (*ptr == '\r') {
506                     pos = RESPONSE_CR;
507                     this->_reason_phrase.assign(start, ptr);
508                 } else if (*ptr == '\n') {
509                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 29,
510                     "Parse error: Invalid reason-phrase.(%c)", *ptr);
511                     throw -1;
512                 }
513                 break;
514     
515             case RESPONSE_CR:
516                 // LF only
517                 if (*ptr == '\n') {
518                     pos = RESPONSE_LF;
519                     http_message::parse(std::string(ptr + 1, end));
520                 } else {
521                     LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 30,
522                     "Parse error: No LF.(%c)", *ptr);
523                     throw -1;
524                 }
525                 break;
526             }
527             if (pos == RESPONSE_LF)
528                 break;
529             ptr++;
530         }
531     }
532     catch (...) {
533         LOGGER_PUT_LOG_INFO(LOG_CAT_PACKET_EDIT_HTTP, 31,
534         "Exception occured by parsing HTTP response.");
535     }
536
537     /*-------- DEBUG LOG --------*/
538     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
539         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 63,
540         "out_function : void http_response::parse(std::string response)");
541     }
542     /*------ DEBUG LOG END ------*/
543 }
544
545 /*!
546  * Rebuild HTTP response header function.
547  */
548 void http_response::rebuild()
549 {
550     /*-------- DEBUG LOG --------*/
551     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
552         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 64,
553         "in_function : void http_response::rebuild()");
554     }
555     /*------ DEBUG LOG END ------*/
556
557     this->raw_message = this->status_line();
558     http_message::rebuild();
559
560     /*-------- DEBUG LOG --------*/
561     if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
562         LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 65,
563         "out_function : void http_response::rebuild()");
564     }
565     /*------ DEBUG LOG END ------*/
566 }