OSDN Git Service

Merge branch 'packet_edit' into autotools-fix(releng)
[ultramonkey-l7/sslproxy.git] / src / http_response.cpp
diff --git a/src/http_response.cpp b/src/http_response.cpp
new file mode 100644 (file)
index 0000000..17b7fe5
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * @file  http_response.cpp
+ * @brief module of HTTP Request
+ * @brief HTTP Request parser
+ *
+ * Copyright (C) 2009  NTT COMWARE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ **********************************************************************/
+
+#include "http_response.h"
+
+/*!
+ * HTTP Request constructor.
+ */
+http_response::http_response()
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 43,
+        "in/out_function : Constructor http_response::http_response(void)");
+    }
+    /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * HTTP Request constructor.
+ * Parse HTTP response header.
+ *
+ * @param[in]   header  full http response header string
+ */
+http_response::http_response(std::string header)
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 44,
+        "in/out_function : Constructor http_response::http_response(std::string header) : "
+        "header(%s)", header.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+    this->parse(header);
+}
+
+/*!
+ * HTTP Request destructor.
+ */
+http_response::~http_response()
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 45,
+        "in/out_function : Destructor http_response::~http_response(void)");
+    }
+    /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * Get HTTP version function.
+ *
+ * @return    HTTP version
+ */
+std::string http_response::http_version() const
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 46,
+        "in_function : std::string http_response::http_version(void)");
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 47,
+        "out_function : std::string http_response::http_version(void) : "
+        "return(%s)", this->_http_version.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return this->_http_version;
+}
+
+/*!
+ * Set HTTP version function.
+ * Set new HTTP version and return old HTTP version.
+ *
+ * @param[in]   _http_version   new HTTP version
+ * @return  old HTTP version
+ */
+std::string http_response::http_version(std::string _http_version)
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 48,
+        "in_function : std::string http_response::http_version(std::string _http_version) : "
+        "_http_version(%s)", _http_version.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    std::string ret = this->_http_version;
+    this->_http_version = _http_version;
+    this->modified = true;
+
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 49,
+        "out_function : std::string http_response::http_version(std::string _http_version) : "
+        "return(%s)", ret.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return ret;
+}
+
+/*!
+ * Get status code function.
+ *
+ * @return    status code
+ */
+std::string http_response::status_code() const
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 50,
+        "in_function : std::string http_response::status_code(void)");
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 51,
+        "out_function : std::string http_response::status_code(void) : "
+        "return(%s)", this->_status_code.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return this->_status_code;
+}
+
+/*!
+ * Set status code function.
+ * Set new status code and return old status code.
+ *
+ * @param[in]   _status_code   new status code
+ * @return  old status code
+ */
+std::string http_response::status_code(std::string _status_code)
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 52,
+        "in_function : std::string http_response::status_code(std::string _status_code) : "
+        "_status_code(%s)", _status_code.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    std::string ret = this->_status_code;
+    this->_status_code = _status_code;
+    this->modified = true;
+
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 53,
+        "out_function : std::string http_response::status_code(std::string _status_code) : "
+        "return(%s)", ret.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return ret;
+}
+
+/*!
+ * Get reason phrase function.
+ *
+ * @return    reason phrase
+ */
+std::string http_response::reason_phrase() const
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 54,
+        "in_function : std::string http_response::reason_phrase(void)");
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 55,
+        "out_function : std::string http_response::reason_phrase(void) : "
+        "return(%s)", this->_reason_phrase.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return this->_reason_phrase;
+}
+
+/*!
+ * Set reason phrase function.
+ * Set new reason phrase and return old reason phrase.
+ *
+ * @param[in]   _reason_phrase   new reason phrase
+ * @return  old reason phrase
+ */
+std::string http_response::reason_phrase(std::string _reason_phrase)
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 56,
+        "in_function : std::string http_response::reason_phrase(std::string _reason_phrase) : "
+        "_reason_phrase(%s)", _reason_phrase.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    std::string ret = this->_reason_phrase;
+    this->_reason_phrase = _reason_phrase;
+    this->modified = true;
+
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 57,
+        "out_function : std::string http_response::reason_phrase(std::string _reason_phrase) : "
+        "return(%s)", ret.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return ret;
+}
+
+/*!
+ * Get status line function.
+ *
+ * @return    status line
+ */
+std::string http_response::status_line() const
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 58,
+        "in_function : std::string http_response::status_line(void)");
+    }
+    /*------ DEBUG LOG END ------*/
+
+    std::string ret = this->http_version() + " " + this->status_code() + " " + this->reason_phrase() + "\r\n";
+
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 59,
+        "out_function : std::string http_response::status_line(void) : "
+        "return(%s)", ret.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return ret;
+}
+
+/*!
+ * Get full HTTP response function.
+ *
+ * @return    HTTP response
+ */
+std::string http_response::as_string()
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 60,
+        "in_function : std::string http_response::as_string(void)");
+    }
+    /*------ DEBUG LOG END ------*/
+
+    if (this->modified)
+        this->rebuild();
+
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 61,
+        "out_function : std::string http_response::as_string(void) : "
+        "return(%s)", this->raw_message.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    return this->raw_message;
+}
+
+/*!
+ * Parse HTTP response header function.
+ *
+ * @param[in]   request     full HTTP response header
+ */
+void http_response::parse(std::string response)
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 62,
+        "in_function : void http_response::parse(std::string response) : "
+        "response(%s)", response.c_str());
+    }
+    /*------ DEBUG LOG END ------*/
+
+    // save raw response
+    this->raw_message = response;
+
+    // parse response
+    HTTP_RESPONSE_POSITION pos = RESPONSE_TOP;
+
+    /*
+     * RFC2616
+     *  OCTET       : 8bit data
+     *  CHAR        : US-ASCII(0-127)
+     *  UPALPHA     : A-Z
+     *  LOALPHA     : a-z
+     *  ALPHA       : UPALPHA | LOALPHA
+     *  DIGIT       : 0-9
+     *  HEXDIG      : A-F | a-f | DIGIT
+     *  SP          : SPace(32)
+     *  HT          : Horizontal Tab(9)
+     *  CR          : Carriage Return(13)
+     *  LF          : Line Feed(10)
+     *  CTL         : ConTLol char(0-31,127)
+     *  LWS         : [CRLF] 1*(SP|HT)
+     *  separators  : ()<>@,;:\"/[]?={} and SP, HT
+     *  token       : 1*(CHAR not CTL, separators)
+     */
+    std::string::iterator ptr = response.begin();
+    std::string::iterator end = response.end();
+    std::string::iterator start = ptr;
+    std::pair<std::string, std::string> field_pair;
+    try {
+        while (ptr != end) {
+            switch(pos) {
+            /*
+             * STATUS-LINE :
+             *      HTTP-VERSION SP STATUS-CODE SP REASON-PHRASE CRLF
+             */
+            /*
+             * HTTP-VERSION     : "HTTP" "/" 1*DIGIT "." 1*DIGIT
+             */
+            case RESPONSE_TOP:
+                // HTTP-VERSION start
+                if (*ptr == 'H') {
+                    pos = RESPONSE_HTTP_VERSION_H;
+                    start = ptr;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 24,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_H:
+                // HTTP-VERSION next
+                if (*ptr == 'T') {
+                    pos = RESPONSE_HTTP_VERSION_T1;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 25,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_T1:
+                // HTTP-VERSION next
+                if (*ptr == 'T') {
+                    pos = RESPONSE_HTTP_VERSION_T2;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 26,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_T2:
+                // HTTP-VERSION next
+                if (*ptr == 'P') {
+                    pos = RESPONSE_HTTP_VERSION_P;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 27,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_P:
+                // HTTP-VERSION next
+                if (*ptr == '/') {
+                    pos = RESPONSE_HTTP_VERSION_SLASH;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 28,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_SLASH:
+                // HTTP-VERSION Mejor number
+                if (isdigit(*ptr)) {
+                    pos = RESPONSE_HTTP_VERSION_MAJOR;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 29,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_MAJOR:
+                // HTTP-VERSION next dot
+                if (*ptr == '.') {
+                    pos = RESPONSE_HTTP_VERSION_DOT;
+                } else if (!isdigit(*ptr)) {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 30,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_DOT:
+                // HTTP-VERSION Minor number
+                if (isdigit(*ptr)) {
+                    pos = RESPONSE_HTTP_VERSION_MINOR;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 31,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_HTTP_VERSION_MINOR:
+                // HTTP-VERSION end with SP
+                if (*ptr == ' ') {
+                    pos = RESPONSE_HTTP_VERSION_SP;
+                    this->_http_version.assign(start, ptr);
+                } else if (!isdigit(*ptr)) {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 32,
+                    "Parse error: Invalid http-version.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            /*
+             * Status-Code  : 3DIGIT
+             */
+            case RESPONSE_HTTP_VERSION_SP:
+                // STATUS-CODE start
+                if (isdigit(*ptr)) {
+                    pos = RESPONSE_STATUS_CODE1;
+                    start = ptr;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 33,
+                    "Parse error: Invalid status-code.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_STATUS_CODE1:
+                // STATUS-CODE next
+                if (isdigit(*ptr)) {
+                    pos = RESPONSE_STATUS_CODE2;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 34,
+                    "Parse error: Invalid status-code.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_STATUS_CODE2:
+                // STATUS-CODE next
+                if (isdigit(*ptr)) {
+                    pos = RESPONSE_STATUS_CODE3;
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 35,
+                    "Parse error: Invalid status-code.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_STATUS_CODE3:
+                // Status-Code end with SP
+                if (*ptr == ' ') {
+                    pos = RESPONSE_STATUS_CODE_SP;
+                    this->_status_code.assign(start, ptr);
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 36,
+                    "Parse error: Invalid status-code.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            /*
+             * Reason-Phrase    : *<TEXT, excluding CR, LF>
+             */
+            case RESPONSE_STATUS_CODE_SP:
+                // Reason-Phrase is OCTET
+                if (*ptr == '\r') { // omit reason-phrase
+                    pos = RESPONSE_CR;
+                    this->_reason_phrase.clear();
+                } else if (*ptr != '\n') {
+                    pos = RESPONSE_REASON_PHRASE;
+                    start = ptr;
+                } else  {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 37,
+                    "Parse error: Invalid reason-phrase.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_REASON_PHRASE:
+                // Reason-Phrase end with CR
+                if (*ptr == '\r') {
+                    pos = RESPONSE_CR;
+                    this->_reason_phrase.assign(start, ptr);
+                } else if (*ptr == '\n') {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 38,
+                    "Parse error: Invalid reason-phrase.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+    
+            case RESPONSE_CR:
+                // LF only
+                if (*ptr == '\n') {
+                    pos = RESPONSE_LF;
+                    http_message::parse(std::string(ptr + 1, end));
+                } else {
+                    LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 39,
+                    "Parse error: No LF.(%c)", *ptr);
+                    throw -1;
+                }
+                break;
+            }
+            if (pos == RESPONSE_LF)
+                break;
+            ptr++;
+        }
+    }
+    catch (...) {
+        LOGGER_PUT_LOG_ERROR(LOG_CAT_PACKET_EDIT_HTTP, 40,
+        "Exception occured by parsing HTTP response.");
+    }
+
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 63,
+        "out_function : void http_response::parse(std::string response)");
+    }
+    /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * Rebuild HTTP response header function.
+ */
+void http_response::rebuild()
+{
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 64,
+        "in_function : void http_response::rebuild()");
+    }
+    /*------ DEBUG LOG END ------*/
+
+    this->raw_message = this->status_line();
+    http_message::rebuild();
+
+    /*-------- DEBUG LOG --------*/
+    if (LOG_LV_DEBUG == logger_get_log_level(LOG_CAT_PACKET_EDIT_HTTP)) {
+        LOGGER_PUT_LOG_DEBUG(LOG_CAT_PACKET_EDIT_HTTP, 65,
+        "out_function : void http_response::rebuild()");
+    }
+    /*------ DEBUG LOG END ------*/
+}