00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <boost/asio.hpp>
00011 #include <boost/logic/tribool.hpp>
00012 #include <pion/http/reader.hpp>
00013 #include <pion/http/request.hpp>
00014
00015
00016 namespace pion {
00017 namespace http {
00018
00019
00020
00021
00022 const boost::uint32_t reader::DEFAULT_READ_TIMEOUT = 10;
00023
00024
00025
00026
00027 void reader::receive(void)
00028 {
00029 if (m_tcp_conn->get_pipelined()) {
00030
00031 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
00032 m_tcp_conn->load_read_pos(m_read_ptr, m_read_end_ptr);
00033 consume_bytes();
00034 } else {
00035
00036 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
00037 read_bytes_with_timeout();
00038 }
00039 }
00040
00041 void reader::consume_bytes(const boost::system::error_code& read_error,
00042 std::size_t bytes_read)
00043 {
00044
00045 if (m_timer_ptr) {
00046 m_timer_ptr->cancel();
00047 m_timer_ptr.reset();
00048 }
00049
00050 if (read_error) {
00051
00052 handle_read_error(read_error);
00053 return;
00054 }
00055
00056 PION_LOG_DEBUG(m_logger, "Read " << bytes_read << " bytes from HTTP "
00057 << (is_parsing_request() ? "request" : "response"));
00058
00059
00060 set_read_buffer(m_tcp_conn->get_read_buffer().data(), bytes_read);
00061
00062 consume_bytes();
00063 }
00064
00065
00066 void reader::consume_bytes(void)
00067 {
00068
00069
00070
00071
00072
00073
00074
00075
00076 boost::system::error_code ec;
00077 boost::tribool result = parse(get_message(), ec);
00078
00079 if (gcount() > 0) {
00080
00081 PION_LOG_DEBUG(m_logger, "Parsed " << gcount() << " HTTP bytes");
00082 }
00083
00084 if (result == true) {
00085
00086
00087
00088 if (get_message().check_keep_alive()) {
00089 if ( eof() ) {
00090
00091 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_KEEPALIVE);
00092 } else {
00093
00094 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_PIPELINED);
00095
00096
00097
00098
00099 m_tcp_conn->save_read_pos(m_read_ptr, m_read_end_ptr);
00100
00101 PION_LOG_DEBUG(m_logger, "HTTP pipelined "
00102 << (is_parsing_request() ? "request (" : "response (")
00103 << bytes_available() << " bytes available)");
00104 }
00105 } else {
00106 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
00107 }
00108
00109
00110 finished_reading(ec);
00111
00112 } else if (result == false) {
00113
00114 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
00115 get_message().set_is_valid(false);
00116 finished_reading(ec);
00117 } else {
00118
00119 read_bytes_with_timeout();
00120 }
00121 }
00122
00123 void reader::read_bytes_with_timeout(void)
00124 {
00125 if (m_read_timeout > 0) {
00126 m_timer_ptr.reset(new tcp::timer(m_tcp_conn));
00127 m_timer_ptr->start(m_read_timeout);
00128 } else if (m_timer_ptr) {
00129 m_timer_ptr.reset();
00130 }
00131 read_bytes();
00132 }
00133
00134 void reader::handle_read_error(const boost::system::error_code& read_error)
00135 {
00136
00137 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
00138
00139
00140 if (! check_premature_eof(get_message())) {
00141 boost::system::error_code ec;
00142 finished_reading(ec);
00143 return;
00144 }
00145
00146
00147 if (get_total_bytes_read() > 0) {
00148 if (read_error == boost::asio::error::operation_aborted) {
00149
00150
00151 PION_LOG_INFO(m_logger, "HTTP " << (is_parsing_request() ? "request" : "response")
00152 << " parsing aborted (shutting down)");
00153 } else {
00154 PION_LOG_INFO(m_logger, "HTTP " << (is_parsing_request() ? "request" : "response")
00155 << " parsing aborted (" << read_error.message() << ')');
00156 }
00157 }
00158
00159 finished_reading(read_error);
00160 }
00161
00162 }
00163 }