std::size_t message::read(std::istream& in, boost::system::error_code& ec, parser& http_parser) { // make sure that we start out with an empty message & clear error_code clear(); ec.clear(); // parse data from file one byte at a time boost::tribool parse_result; char c; while (in) { in.read(&c, 1); if ( ! in ) { ec = make_error_code(boost::system::errc::io_error); break; } http_parser.set_read_buffer(&c, 1); parse_result = http_parser.parse(*this, ec); if (! boost::indeterminate(parse_result)) break; } if (boost::indeterminate(parse_result)) { if (http_parser.check_premature_eof(*this)) { // premature EOF encountered if (! ec) ec = make_error_code(boost::system::errc::io_error); } else { // EOF reached when content length unknown // assume it is the correct end of content // and everything is OK parse_result = true; ec.clear(); } } return (http_parser.get_total_bytes_read()); }
std::size_t message::receive(tcp::connection& tcp_conn, boost::system::error_code& ec, parser& http_parser) { std::size_t last_bytes_read = 0; // make sure that we start out with an empty message clear(); if (tcp_conn.get_pipelined()) { // there are pipelined messages available in the connection's read buffer const char *read_ptr; const char *read_end_ptr; tcp_conn.load_read_pos(read_ptr, read_end_ptr); last_bytes_read = (read_end_ptr - read_ptr); http_parser.set_read_buffer(read_ptr, last_bytes_read); } else { // read buffer is empty (not pipelined) -> read some bytes from the connection last_bytes_read = tcp_conn.read_some(ec); if (ec) return 0; BOOST_ASSERT(last_bytes_read > 0); http_parser.set_read_buffer(tcp_conn.get_read_buffer().data(), last_bytes_read); } // incrementally read and parse bytes from the connection bool force_connection_closed = false; boost::tribool parse_result; while (true) { // parse bytes available in the read buffer parse_result = http_parser.parse(*this, ec); if (! boost::indeterminate(parse_result)) break; // read more bytes from the connection last_bytes_read = tcp_conn.read_some(ec); if (ec || last_bytes_read == 0) { if (http_parser.check_premature_eof(*this)) { // premature EOF encountered if (! ec) ec = make_error_code(boost::system::errc::io_error); return http_parser.get_total_bytes_read(); } else { // EOF reached when content length unknown // assume it is the correct end of content // and everything is OK force_connection_closed = true; parse_result = true; ec.clear(); break; } break; } // update the HTTP parser's read buffer http_parser.set_read_buffer(tcp_conn.get_read_buffer().data(), last_bytes_read); } if (parse_result == false) { // an error occurred while parsing the message headers return http_parser.get_total_bytes_read(); } // set the connection's lifecycle type if (!force_connection_closed && check_keep_alive()) { if ( http_parser.eof() ) { // the connection should be kept alive, but does not have pipelined messages tcp_conn.set_lifecycle(tcp::connection::LIFECYCLE_KEEPALIVE); } else { // the connection has pipelined messages tcp_conn.set_lifecycle(tcp::connection::LIFECYCLE_PIPELINED); // save the read position as a bookmark so that it can be retrieved // by a new HTTP parser, which will be created after the current // message has been handled const char *read_ptr; const char *read_end_ptr; http_parser.load_read_pos(read_ptr, read_end_ptr); tcp_conn.save_read_pos(read_ptr, read_end_ptr); } } else { // default to close the connection tcp_conn.set_lifecycle(tcp::connection::LIFECYCLE_CLOSE); // save the read position as a bookmark so that it can be retrieved // by a new HTTP parser if (http_parser.get_parse_headers_only()) { const char *read_ptr; const char *read_end_ptr; http_parser.load_read_pos(read_ptr, read_end_ptr); tcp_conn.save_read_pos(read_ptr, read_end_ptr); } } return (http_parser.get_total_bytes_read()); }