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