10 #ifndef __PION_HTTP_WRITER_HEADER__ 11 #define __PION_HTTP_WRITER_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/config.hpp> 22 #include <pion/logger.hpp> 23 #include <pion/tcp/connection.hpp> 24 #include <pion/http/message.hpp> 35 private boost::noncopyable
43 typedef boost::function2<void,const boost::system::error_code&,std::size_t>
write_handler_t;
52 writer(
const tcp::connection_ptr& tcp_conn, finished_handler_t handler)
53 : m_logger(PION_GET_LOGGER(
"pion.http.writer")),
54 m_tcp_conn(tcp_conn), m_content_length(0), m_stream_is_empty(true),
55 m_client_supports_chunks(true), m_sending_chunks(false),
56 m_sent_headers(false), m_finished(handler)
65 virtual void handle_write(
const boost::system::error_code& write_error,
66 std::size_t bytes_written) = 0;
77 virtual write_handler_t bind_to_write_handler(
void) = 0;
81 if (m_finished) m_finished(ec);
92 m_content_buffers.clear();
93 m_binary_cache.clear();
95 m_content_stream.str(
"");
96 m_stream_is_empty =
true;
105 template <
typename T>
107 m_content_stream << data;
108 if (m_stream_is_empty) m_stream_is_empty =
false;
111 inline void write(std::ostream& (*iomanip)(std::ostream&)) {
112 m_content_stream << iomanip;
113 if (m_stream_is_empty) m_stream_is_empty =
false;
122 inline void write(
const void *data,
size_t length) {
124 flush_content_stream();
125 m_content_buffers.push_back(m_binary_cache.add(data, length));
126 m_content_length += length;
138 if (! data.empty()) {
139 flush_content_stream();
140 m_content_buffers.push_back(boost::asio::buffer(data));
141 m_content_length += data.size();
154 flush_content_stream();
155 m_content_buffers.push_back(boost::asio::buffer(data, length));
156 m_content_length += length;
167 send_more_data(
false, bind_to_write_handler());
179 template <
typename SendHandler>
180 inline void send(SendHandler send_handler) {
181 send_more_data(
false, send_handler);
194 template <
typename SendHandler>
196 m_sending_chunks =
true;
197 if (!supports_chunked_messages()) {
200 m_tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
203 send_more_data(
false, send_handler);
217 template <
typename SendHandler>
219 m_sending_chunks =
true;
220 send_more_data(
true, send_handler);
231 m_sending_chunks =
true;
232 send_more_data(
true, bind_to_write_handler());
266 template <
typename SendHandler>
267 inline void send_more_data(
const bool send_final_chunk, SendHandler send_handler)
270 if (m_tcp_conn->is_open()) {
272 flush_content_stream();
275 prepare_write_buffers(write_buffers, send_final_chunk);
277 m_tcp_conn->async_write(write_buffers, send_handler);
279 finished_writing(boost::asio::error::connection_reset);
290 const bool send_final_chunk);
293 inline void flush_content_stream(
void) {
294 if (! m_stream_is_empty) {
295 std::string string_to_add(m_content_stream.str());
296 if (! string_to_add.empty()) {
297 m_content_stream.str(
"");
298 m_content_length += string_to_add.size();
299 m_text_cache.push_back(string_to_add);
300 m_content_buffers.push_back(boost::asio::buffer(m_text_cache.back()));
302 m_stream_is_empty =
true;
308 class binary_cache_t :
public std::vector<std::pair<const char *, size_t> > {
311 for (iterator i=begin(); i!=end(); ++i) {
315 inline boost::asio::const_buffer add(
const void *ptr,
const size_t size) {
316 char *data_ptr =
new char[size];
317 memcpy(data_ptr, ptr, size);
318 push_back( std::make_pair(data_ptr, size) );
319 return boost::asio::buffer(data_ptr, size);
324 typedef std::list<std::string> text_cache_t;
331 tcp::connection_ptr m_tcp_conn;
337 binary_cache_t m_binary_cache;
340 text_cache_t m_text_cache;
343 std::ostringstream m_content_stream;
346 size_t m_content_length;
349 bool m_stream_is_empty;
352 bool m_client_supports_chunks;
355 bool m_sending_chunks;
361 finished_handler_t m_finished;
366 typedef boost::shared_ptr<writer> writer_ptr;
370 template <
typename T>
371 inline const writer_ptr& operator<<(
const writer_ptr&
writer,
const T& data) {
376 inline const writer_ptr& operator<<(
const writer_ptr& writer, std::ostream& (*iomanip)(std::ostream&)) {
377 writer->write(iomanip);
void clear(void)
clears out all of the memory buffers used to cache payload content data
boost::function2< void, const boost::system::error_code &, std::size_t > write_handler_t
data type for a function that handles write operations
size_t get_content_length(void) const
returns the length of the payload content (in bytes)
void write(const void *data, size_t length)
writer(const tcp::connection_ptr &tcp_conn, finished_handler_t handler)
logger get_logger(void)
returns the logger currently in use
void write(const T &data)
void finished_writing(const boost::system::error_code &ec)
called after we have finished sending the HTTP message
tcp::connection_ptr & get_connection(void)
returns a shared pointer to the TCP connection
boost::function1< void, const boost::system::error_code & > finished_handler_t
function called after the HTTP message has been sent
void send(SendHandler send_handler)
void supports_chunked_messages(bool b)
sets whether or not the client supports chunked messages
void write_no_copy(void *data, size_t length)
void write_no_copy(const std::string &data)
void set_logger(logger log_ptr)
sets the logger to be used
void send_final_chunk(SendHandler send_handler)
virtual ~writer()
default destructor
void send_final_chunk(void)
bool sending_chunked_message() const
returns true if we are sending a chunked message to the client
void send_chunk(SendHandler send_handler)
std::vector< boost::asio::const_buffer > write_buffers_t
data type for I/O write buffers (these wrap existing data to be sent)
bool supports_chunked_messages() const
returns true if the client supports chunked messages