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 }