00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <algorithm>
00011 #include <boost/asio.hpp>
00012 #include <boost/regex.hpp>
00013 #include <boost/logic/tribool.hpp>
00014 #include <pion/net/HTTPMessage.hpp>
00015 #include <pion/net/HTTPRequest.hpp>
00016 #include <pion/net/HTTPParser.hpp>
00017 #include <pion/net/TCPConnection.hpp>
00018
00019
00020 namespace pion {
00021 namespace net {
00022
00023
00024
00025 const boost::regex HTTPMessage::REGEX_ICASE_CHUNKED("chunked", boost::regex::icase);
00026
00027
00028
00029
00030 std::size_t HTTPMessage::send(TCPConnection& tcp_conn,
00031 boost::system::error_code& ec)
00032 {
00033
00034 WriteBuffers write_buffers;
00035 prepareBuffersForSend(write_buffers, tcp_conn.getKeepAlive(), false);
00036
00037
00038 if (getContentLength() > 0 && getContent() != NULL)
00039 write_buffers.push_back(boost::asio::buffer(getContent(), getContentLength()));
00040
00041
00042 return tcp_conn.write(write_buffers, ec);
00043 }
00044
00045 std::size_t HTTPMessage::receive(TCPConnection& tcp_conn,
00046 boost::system::error_code& ec)
00047 {
00048 static ReceiveError RECEIVE_ERROR;
00049
00050 const bool is_request = (dynamic_cast<HTTPRequest*>(this) != NULL);
00051 HTTPParser http_parser(is_request);
00052 std::size_t last_bytes_read = 0;
00053
00054
00055 clear();
00056
00057 if (tcp_conn.getPipelined()) {
00058
00059 const char *read_ptr;
00060 const char *read_end_ptr;
00061 tcp_conn.loadReadPosition(read_ptr, read_end_ptr);
00062 last_bytes_read = (read_end_ptr - read_ptr);
00063 http_parser.setReadBuffer(read_ptr, last_bytes_read);
00064 } else {
00065
00066 last_bytes_read = tcp_conn.read_some(ec);
00067 if (ec) return 0;
00068 PION_ASSERT(last_bytes_read > 0);
00069 http_parser.setReadBuffer(tcp_conn.getReadBuffer().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);
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.checkPrematureEOF(*this)) {
00084
00085 if (! ec)
00086 ec.assign(1, RECEIVE_ERROR);
00087 return http_parser.getTotalBytesRead();
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.setReadBuffer(tcp_conn.getReadBuffer().data(), last_bytes_read);
00102 }
00103
00104 if (parse_result == false) {
00105
00106 ec.assign(1, RECEIVE_ERROR);
00107 return http_parser.getTotalBytesRead();
00108 }
00109
00110
00111 if (!force_connection_closed && checkKeepAlive()) {
00112 if ( http_parser.eof() ) {
00113
00114 tcp_conn.setLifecycle(TCPConnection::LIFECYCLE_KEEPALIVE);
00115 } else {
00116
00117 tcp_conn.setLifecycle(TCPConnection::LIFECYCLE_PIPELINED);
00118
00119
00120
00121
00122 const char *read_ptr;
00123 const char *read_end_ptr;
00124 http_parser.loadReadPosition(read_ptr, read_end_ptr);
00125 tcp_conn.saveReadPosition(read_ptr, read_end_ptr);
00126 }
00127 } else {
00128
00129 tcp_conn.setLifecycle(TCPConnection::LIFECYCLE_CLOSE);
00130 }
00131
00132 return (http_parser.getTotalBytesRead());
00133 }
00134
00135 void HTTPMessage::concatenateChunks(void)
00136 {
00137 setContentLength(m_chunk_cache.size());
00138 char *post_buffer = createContentBuffer();
00139 if (m_chunk_cache.size() > 0)
00140 std::copy(m_chunk_cache.begin(), m_chunk_cache.end(), post_buffer);
00141 }
00142
00143 }
00144 }