10 #ifndef __PION_HTTPWRITER_HEADER__
11 #define __PION_HTTPWRITER_HEADER__
15 #include <boost/shared_ptr.hpp>
16 #include <boost/function.hpp>
17 #include <boost/function/function0.hpp>
18 #include <boost/function/function2.hpp>
19 #include <boost/asio.hpp>
20 #include <boost/noncopyable.hpp>
21 #include <pion/PionConfig.hpp>
22 #include <pion/PionLogger.hpp>
23 #include <pion/net/HTTPMessage.hpp>
24 #include <pion/net/TCPConnection.hpp>
34 private boost::noncopyable
42 typedef boost::function2<void,const boost::system::error_code&,std::size_t>
WriteHandler;
52 : m_logger(PION_GET_LOGGER(
"pion.net.HTTPWriter")),
53 m_tcp_conn(tcp_conn), m_content_length(0), m_stream_is_empty(true),
54 m_client_supports_chunks(true), m_sending_chunks(false),
55 m_sent_headers(false), m_finished(handler)
64 virtual void handleWrite(
const boost::system::error_code& write_error,
65 std::size_t bytes_written) = 0;
76 virtual WriteHandler bindToWriteHandler(
void) = 0;
80 if (m_finished) m_finished(ec);
91 m_content_buffers.clear();
92 m_binary_cache.clear();
94 m_content_stream.str(
"");
95 m_stream_is_empty =
true;
104 template <
typename T>
106 m_content_stream << data;
107 if (m_stream_is_empty) m_stream_is_empty =
false;
116 inline void write(
const void *data,
size_t length) {
118 flushContentStream();
119 m_content_buffers.push_back(m_binary_cache.add(data, length));
120 m_content_length += length;
132 if (! data.empty()) {
133 flushContentStream();
134 m_content_buffers.push_back(boost::asio::buffer(data));
135 m_content_length += data.size();
148 flushContentStream();
149 m_content_buffers.push_back(boost::asio::buffer(data, length));
150 m_content_length += length;
161 sendMoreData(
false, bindToWriteHandler());
173 template <
typename SendHandler>
174 inline void send(SendHandler send_handler) {
175 sendMoreData(
false, send_handler);
188 template <
typename SendHandler>
190 m_sending_chunks =
true;
191 if (!supportsChunkedMessages()) {
194 m_tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);
197 sendMoreData(
false, send_handler);
211 template <
typename SendHandler>
213 m_sending_chunks =
true;
214 sendMoreData(
true, send_handler);
225 m_sending_chunks =
true;
226 sendMoreData(
true, bindToWriteHandler());
260 template <
typename SendHandler>
261 inline void sendMoreData(
const bool send_final_chunk, SendHandler send_handler)
264 if (! m_tcp_conn->is_open())
265 finishedWriting(boost::asio::error::connection_reset);
267 flushContentStream();
270 prepareWriteBuffers(write_buffers, send_final_chunk);
272 m_tcp_conn->async_write(write_buffers, send_handler);
282 const bool send_final_chunk);
285 inline void flushContentStream(
void) {
286 if (! m_stream_is_empty) {
287 std::string string_to_add(m_content_stream.str());
288 if (! string_to_add.empty()) {
289 m_content_stream.str(
"");
290 m_content_length += string_to_add.size();
291 m_text_cache.push_back(string_to_add);
292 m_content_buffers.push_back(boost::asio::buffer(m_text_cache.back()));
294 m_stream_is_empty =
true;
300 class BinaryCache :
public std::vector<std::pair<const char *, size_t> > {
303 for (iterator i=begin(); i!=end(); ++i) {
307 inline boost::asio::const_buffer add(
const void *ptr,
const size_t size) {
308 char *data_ptr =
new char[size];
309 memcpy(data_ptr, ptr, size);
310 push_back( std::make_pair(data_ptr, size) );
311 return boost::asio::buffer(data_ptr, size);
316 typedef std::list<std::string> TextCache;
323 TCPConnectionPtr m_tcp_conn;
329 BinaryCache m_binary_cache;
332 TextCache m_text_cache;
335 std::ostringstream m_content_stream;
338 size_t m_content_length;
341 bool m_stream_is_empty;
344 bool m_client_supports_chunks;
347 bool m_sending_chunks;
353 FinishedHandler m_finished;
358 typedef boost::shared_ptr<HTTPWriter> HTTPWriterPtr;
362 template <
typename T>
363 HTTPWriterPtr& operator<<(HTTPWriterPtr& writer,
const T& data) {
void sendChunk(SendHandler send_handler)
void supportsChunkedMessages(bool b)
sets whether or not the client supports chunked messages
void finishedWriting(const boost::system::error_code &ec)
called after we have finished sending the HTTP message
bool sendingChunkedMessage() const
returns true if we are sending a chunked message to the client
void writeNoCopy(const std::string &data)
void sendFinalChunk(SendHandler send_handler)
void setLogger(PionLogger log_ptr)
sets the logger to be used
boost::function1< void, const boost::system::error_code & > FinishedHandler
function called after the HTTP message has been sent
std::vector< boost::asio::const_buffer > WriteBuffers
data type for I/O write buffers (these wrap existing data to be sent)
void write(const void *data, size_t length)
void sendFinalChunk(void)
size_t getContentLength(void) const
returns the length of the payload content (in bytes)
bool supportsChunkedMessages() const
returns true if the client supports chunked messages
virtual ~HTTPWriter()
default destructor
boost::function2< void, const boost::system::error_code &, std::size_t > WriteHandler
data type for a function that handles write operations
PionLogger getLogger(void)
returns the logger currently in use
void write(const T &data)
HTTPWriter(TCPConnectionPtr &tcp_conn, FinishedHandler handler)
void send(SendHandler send_handler)
void clear(void)
clears out all of the memory buffers used to cache payload content data
void writeNoCopy(void *data, size_t length)
TCPConnectionPtr & getTCPConnection(void)
returns a shared pointer to the TCP connection