00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef __PION_HTTPRESPONSEWRITER_HEADER__
00011 #define __PION_HTTPRESPONSEWRITER_HEADER__
00012
00013 #include <boost/asio.hpp>
00014 #include <boost/bind.hpp>
00015 #include <boost/noncopyable.hpp>
00016 #include <boost/shared_ptr.hpp>
00017 #include <boost/enable_shared_from_this.hpp>
00018 #include <pion/PionConfig.hpp>
00019 #include <pion/net/HTTPWriter.hpp>
00020 #include <pion/net/HTTPRequest.hpp>
00021 #include <pion/net/HTTPResponse.hpp>
00022
00023
00024 namespace pion {
00025 namespace net {
00026
00030 class PION_NET_API HTTPResponseWriter :
00031 public HTTPWriter,
00032 public boost::enable_shared_from_this<HTTPResponseWriter>
00033 {
00034 public:
00035
00037 virtual ~HTTPResponseWriter() {}
00038
00049 static inline boost::shared_ptr<HTTPResponseWriter> create(TCPConnectionPtr& tcp_conn,
00050 HTTPResponsePtr& http_response,
00051 FinishedHandler handler = FinishedHandler())
00052 {
00053 return boost::shared_ptr<HTTPResponseWriter>(new HTTPResponseWriter(tcp_conn, http_response, handler));
00054 }
00055
00066 static inline boost::shared_ptr<HTTPResponseWriter> create(TCPConnectionPtr& tcp_conn,
00067 const HTTPRequest& http_request,
00068 FinishedHandler handler = FinishedHandler())
00069 {
00070 return boost::shared_ptr<HTTPResponseWriter>(new HTTPResponseWriter(tcp_conn, http_request, handler));
00071 }
00072
00074 inline HTTPResponse& getResponse(void) { return *m_http_response; }
00075
00076
00077 protected:
00078
00086 HTTPResponseWriter(TCPConnectionPtr& tcp_conn, HTTPResponsePtr& http_response,
00087 FinishedHandler handler)
00088 : HTTPWriter(tcp_conn, handler), m_http_response(http_response)
00089 {
00090 setLogger(PION_GET_LOGGER("pion.net.HTTPResponseWriter"));
00091
00092 supportsChunkedMessages(m_http_response->getChunksSupported());
00093
00094
00095 if (http_response->getContentLength() > 0
00096 && http_response->getContent() != NULL
00097 && http_response->getContent()[0] != '\0')
00098 {
00099 writeNoCopy(http_response->getContent(), http_response->getContentLength());
00100 }
00101 }
00102
00110 HTTPResponseWriter(TCPConnectionPtr& tcp_conn, const HTTPRequest& http_request,
00111 FinishedHandler handler)
00112 : HTTPWriter(tcp_conn, handler), m_http_response(new HTTPResponse(http_request))
00113 {
00114 setLogger(PION_GET_LOGGER("pion.net.HTTPResponseWriter"));
00115
00116 supportsChunkedMessages(m_http_response->getChunksSupported());
00117 }
00118
00119
00125 virtual void prepareBuffersForSend(HTTPMessage::WriteBuffers& write_buffers) {
00126 if (getContentLength() > 0)
00127 m_http_response->setContentLength(getContentLength());
00128 m_http_response->prepareBuffersForSend(write_buffers,
00129 getTCPConnection()->getKeepAlive(),
00130 sendingChunkedMessage());
00131 }
00132
00134 virtual WriteHandler bindToWriteHandler(void) {
00135 return boost::bind(&HTTPResponseWriter::handleWrite, shared_from_this(),
00136 boost::asio::placeholders::error,
00137 boost::asio::placeholders::bytes_transferred);
00138 }
00139
00146 virtual void handleWrite(const boost::system::error_code& write_error,
00147 std::size_t bytes_written)
00148 {
00149 PionLogger log_ptr(getLogger());
00150 if (write_error) {
00151
00152 getTCPConnection()->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);
00153 PION_LOG_WARN(log_ptr, "Unable to send HTTP response (" << write_error.message() << ')');
00154 } else {
00155
00156 if (sendingChunkedMessage()) {
00157 PION_LOG_DEBUG(log_ptr, "Sent HTTP response chunk of " << bytes_written << " bytes");
00158 } else {
00159 PION_LOG_DEBUG(log_ptr, "Sent HTTP response of " << bytes_written << " bytes ("
00160 << (getTCPConnection()->getKeepAlive() ? "keeping alive)" : "closing)"));
00161 }
00162 }
00163 finishedWriting();
00164 }
00165
00166
00167 private:
00168
00170 HTTPResponsePtr m_http_response;
00171
00173 std::string m_response_line;
00174 };
00175
00176
00178 typedef boost::shared_ptr<HTTPResponseWriter> HTTPResponseWriterPtr;
00179
00180
00182 template <typename T>
00183 HTTPResponseWriterPtr& operator<<(HTTPResponseWriterPtr& writer, const T& data) {
00184 writer->write(data);
00185 return writer;
00186 }
00187
00188
00189 }
00190 }
00191
00192 #endif