00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <iostream>
00011 #include <algorithm>
00012 #include <boost/asio.hpp>
00013 #include <boost/assert.hpp>
00014 #include <boost/regex.hpp>
00015 #include <boost/logic/tribool.hpp>
00016 #include <pion/http/message.hpp>
00017 #include <pion/http/request.hpp>
00018 #include <pion/http/parser.hpp>
00019 #include <pion/tcp/connection.hpp>
00020
00021
00022 namespace pion {
00023 namespace http {
00024
00025
00026
00027
00028 const boost::regex message::REGEX_ICASE_CHUNKED(".*chunked.*", boost::regex::icase);
00029
00030
00031
00032
00033 std::size_t message::send(tcp::connection& tcp_conn,
00034 boost::system::error_code& ec, bool headers_only)
00035 {
00036
00037 write_buffers_t write_buffers;
00038 prepare_buffers_for_send(write_buffers, tcp_conn.get_keep_alive(), false);
00039
00040
00041 if (!headers_only && get_content_length() > 0 && get_content() != NULL)
00042 write_buffers.push_back(boost::asio::buffer(get_content(), get_content_length()));
00043
00044
00045 return tcp_conn.write(write_buffers, ec);
00046 }
00047
00048 std::size_t message::receive(tcp::connection& tcp_conn,
00049 boost::system::error_code& ec,
00050 parser& http_parser)
00051 {
00052 std::size_t last_bytes_read = 0;
00053
00054
00055 clear();
00056
00057 if (tcp_conn.get_pipelined()) {
00058
00059 const char *read_ptr;
00060 const char *read_end_ptr;
00061 tcp_conn.load_read_pos(read_ptr, read_end_ptr);
00062 last_bytes_read = (read_end_ptr - read_ptr);
00063 http_parser.set_read_buffer(read_ptr, last_bytes_read);
00064 } else {
00065
00066 last_bytes_read = tcp_conn.read_some(ec);
00067 if (ec) return 0;
00068 BOOST_ASSERT(last_bytes_read > 0);
00069 http_parser.set_read_buffer(tcp_conn.get_read_buffer().data(), last_bytes_read);
00070 }
00071
00072
00073 bool force_connection_closed = false;
00074 boost::tribool parse_result;
00075 while (true) {
00076
00077 parse_result = http_parser.parse(*this, ec);
00078 if (! boost::indeterminate(parse_result)) break;
00079
00080
00081 last_bytes_read = tcp_conn.read_some(ec);
00082 if (ec || last_bytes_read == 0) {
00083 if (http_parser.check_premature_eof(*this)) {
00084
00085 if (! ec)
00086 ec = make_error_code(boost::system::errc::io_error);
00087 return http_parser.get_total_bytes_read();
00088 } else {
00089
00090
00091
00092 force_connection_closed = true;
00093 parse_result = true;
00094 ec.clear();
00095 break;
00096 }
00097 break;
00098 }
00099
00100
00101 http_parser.set_read_buffer(tcp_conn.get_read_buffer().data(), last_bytes_read);
00102 }
00103
00104 if (parse_result == false) {
00105
00106 return http_parser.get_total_bytes_read();
00107 }
00108
00109
00110 if (!force_connection_closed && check_keep_alive()) {
00111 if ( http_parser.eof() ) {
00112
00113 tcp_conn.set_lifecycle(tcp::connection::LIFECYCLE_KEEPALIVE);
00114 } else {
00115
00116 tcp_conn.set_lifecycle(tcp::connection::LIFECYCLE_PIPELINED);
00117
00118
00119
00120
00121 const char *read_ptr;
00122 const char *read_end_ptr;
00123 http_parser.load_read_pos(read_ptr, read_end_ptr);
00124 tcp_conn.save_read_pos(read_ptr, read_end_ptr);
00125 }
00126 } else {
00127
00128 tcp_conn.set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
00129
00130
00131
00132 if (http_parser.get_parse_headers_only()) {
00133 const char *read_ptr;
00134 const char *read_end_ptr;
00135 http_parser.load_read_pos(read_ptr, read_end_ptr);
00136 tcp_conn.save_read_pos(read_ptr, read_end_ptr);
00137 }
00138 }
00139
00140 return (http_parser.get_total_bytes_read());
00141 }
00142
00143 std::size_t message::receive(tcp::connection& tcp_conn,
00144 boost::system::error_code& ec,
00145 bool headers_only,
00146 std::size_t max_content_length)
00147 {
00148 http::parser http_parser(dynamic_cast<http::request*>(this) != NULL);
00149 http_parser.parse_headers_only(headers_only);
00150 http_parser.set_max_content_length(max_content_length);
00151 return receive(tcp_conn, ec, http_parser);
00152 }
00153
00154 std::size_t message::write(std::ostream& out,
00155 boost::system::error_code& ec, bool headers_only)
00156 {
00157
00158 ec.clear();
00159
00160
00161 write_buffers_t write_buffers;
00162 prepare_buffers_for_send(write_buffers, true, false);
00163
00164
00165 if (!headers_only && get_content_length() > 0 && get_content() != NULL)
00166 write_buffers.push_back(boost::asio::buffer(get_content(), get_content_length()));
00167
00168
00169 std::size_t bytes_out = 0;
00170 for (write_buffers_t::const_iterator i=write_buffers.begin(); i!=write_buffers.end(); ++i) {
00171 const char *ptr = boost::asio::buffer_cast<const char*>(*i);
00172 size_t len = boost::asio::buffer_size(*i);
00173 out.write(ptr, len);
00174 bytes_out += len;
00175 }
00176
00177 return bytes_out;
00178 }
00179
00180 std::size_t message::read(std::istream& in,
00181 boost::system::error_code& ec,
00182 parser& http_parser)
00183 {
00184
00185 clear();
00186 ec.clear();
00187
00188
00189 boost::tribool parse_result;
00190 char c;
00191 while (in) {
00192 in.read(&c, 1);
00193 if ( ! in ) {
00194 ec = make_error_code(boost::system::errc::io_error);
00195 break;
00196 }
00197 http_parser.set_read_buffer(&c, 1);
00198 parse_result = http_parser.parse(*this, ec);
00199 if (! boost::indeterminate(parse_result)) break;
00200 }
00201
00202 if (boost::indeterminate(parse_result)) {
00203 if (http_parser.check_premature_eof(*this)) {
00204
00205 if (! ec)
00206 ec = make_error_code(boost::system::errc::io_error);
00207 } else {
00208
00209
00210
00211 parse_result = true;
00212 ec.clear();
00213 }
00214 }
00215
00216 return (http_parser.get_total_bytes_read());
00217 }
00218
00219 std::size_t message::read(std::istream& in,
00220 boost::system::error_code& ec,
00221 bool headers_only,
00222 std::size_t max_content_length)
00223 {
00224 http::parser http_parser(dynamic_cast<http::request*>(this) != NULL);
00225 http_parser.parse_headers_only(headers_only);
00226 http_parser.set_max_content_length(max_content_length);
00227 return read(in, ec, http_parser);
00228 }
00229
00230 void message::concatenate_chunks(void)
00231 {
00232 set_content_length(m_chunk_cache.size());
00233 char *post_buffer = create_content_buffer();
00234 if (m_chunk_cache.size() > 0)
00235 std::copy(m_chunk_cache.begin(), m_chunk_cache.end(), post_buffer);
00236 }
00237
00238
00239 }
00240 }