pion-net  4.0.9
HTTPWriter.hpp
1 // ------------------------------------------------------------------
2 // pion-net: a C++ framework for building lightweight HTTP interfaces
3 // ------------------------------------------------------------------
4 // Copyright (C) 2007-2008 Atomic Labs, Inc. (http://www.atomiclabs.com)
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
8 //
9 
10 #ifndef __PION_HTTPWRITER_HEADER__
11 #define __PION_HTTPWRITER_HEADER__
12 
13 #include <vector>
14 #include <string>
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>
25 
26 
27 namespace pion { // begin namespace pion
28 namespace net { // begin namespace net (Pion Network Library)
29 
33 class PION_NET_API HTTPWriter :
34  private boost::noncopyable
35 {
36 protected:
37 
39  typedef boost::function1<void,const boost::system::error_code&> FinishedHandler;
40 
42  typedef boost::function2<void,const boost::system::error_code&,std::size_t> WriteHandler;
43 
44 
51  HTTPWriter(TCPConnectionPtr& tcp_conn, FinishedHandler handler)
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)
56  {}
57 
64  virtual void handleWrite(const boost::system::error_code& write_error,
65  std::size_t bytes_written) = 0;
66 
67 
73  virtual void prepareBuffersForSend(HTTPMessage::WriteBuffers& write_buffers) = 0;
74 
76  virtual WriteHandler bindToWriteHandler(void) = 0;
77 
79  inline void finishedWriting(const boost::system::error_code& ec) {
80  if (m_finished) m_finished(ec);
81  }
82 
83 
84 public:
85 
87  virtual ~HTTPWriter() {}
88 
90  inline void clear(void) {
91  m_content_buffers.clear();
92  m_binary_cache.clear();
93  m_text_cache.clear();
94  m_content_stream.str("");
95  m_stream_is_empty = true;
96  m_content_length = 0;
97  }
98 
104  template <typename T>
105  inline void write(const T& data) {
106  m_content_stream << data;
107  if (m_stream_is_empty) m_stream_is_empty = false;
108  }
109 
116  inline void write(const void *data, size_t length) {
117  if (length != 0) {
118  flushContentStream();
119  m_content_buffers.push_back(m_binary_cache.add(data, length));
120  m_content_length += length;
121  }
122  }
123 
131  inline void writeNoCopy(const std::string& data) {
132  if (! data.empty()) {
133  flushContentStream();
134  m_content_buffers.push_back(boost::asio::buffer(data));
135  m_content_length += data.size();
136  }
137  }
138 
146  inline void writeNoCopy(void *data, size_t length) {
147  if (length > 0) {
148  flushContentStream();
149  m_content_buffers.push_back(boost::asio::buffer(data, length));
150  m_content_length += length;
151  }
152  }
153 
154 
160  inline void send(void) {
161  sendMoreData(false, bindToWriteHandler());
162  }
163 
173  template <typename SendHandler>
174  inline void send(SendHandler send_handler) {
175  sendMoreData(false, send_handler);
176  }
177 
188  template <typename SendHandler>
189  inline void sendChunk(SendHandler send_handler) {
190  m_sending_chunks = true;
191  if (!supportsChunkedMessages()) {
192  // sending data in chunks, but the client does not support chunking;
193  // make sure that the connection will be closed when we are all done
194  m_tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);
195  }
196  // send more data
197  sendMoreData(false, send_handler);
198  }
199 
211  template <typename SendHandler>
212  inline void sendFinalChunk(SendHandler send_handler) {
213  m_sending_chunks = true;
214  sendMoreData(true, send_handler);
215  }
216 
224  inline void sendFinalChunk(void) {
225  m_sending_chunks = true;
226  sendMoreData(true, bindToWriteHandler());
227  }
228 
229 
231  inline TCPConnectionPtr& getTCPConnection(void) { return m_tcp_conn; }
232 
234  inline size_t getContentLength(void) const { return m_content_length; }
235 
237  inline void supportsChunkedMessages(bool b) { m_client_supports_chunks = b; }
238 
240  inline bool supportsChunkedMessages() const { return m_client_supports_chunks; }
241 
243  inline bool sendingChunkedMessage() const { return m_sending_chunks; }
244 
246  inline void setLogger(PionLogger log_ptr) { m_logger = log_ptr; }
247 
249  inline PionLogger getLogger(void) { return m_logger; }
250 
251 
252 private:
253 
260  template <typename SendHandler>
261  inline void sendMoreData(const bool send_final_chunk, SendHandler send_handler)
262  {
263  // make sure that we did not lose the TCP connection
264  if (! m_tcp_conn->is_open())
265  finishedWriting(boost::asio::error::connection_reset);
266  // make sure that the content-length is up-to-date
267  flushContentStream();
268  // prepare the write buffers to be sent
269  HTTPMessage::WriteBuffers write_buffers;
270  prepareWriteBuffers(write_buffers, send_final_chunk);
271  // send data in the write buffers
272  m_tcp_conn->async_write(write_buffers, send_handler);
273  }
274 
281  void prepareWriteBuffers(HTTPMessage::WriteBuffers &write_buffers,
282  const bool send_final_chunk);
283 
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()));
293  }
294  m_stream_is_empty = true;
295  }
296  }
297 
298 
300  class BinaryCache : public std::vector<std::pair<const char *, size_t> > {
301  public:
302  ~BinaryCache() {
303  for (iterator i=begin(); i!=end(); ++i) {
304  delete[] i->first;
305  }
306  }
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);
312  }
313  };
314 
316  typedef std::list<std::string> TextCache;
317 
318 
320  PionLogger m_logger;
321 
323  TCPConnectionPtr m_tcp_conn;
324 
326  HTTPMessage::WriteBuffers m_content_buffers;
327 
329  BinaryCache m_binary_cache;
330 
332  TextCache m_text_cache;
333 
335  std::ostringstream m_content_stream;
336 
338  size_t m_content_length;
339 
341  bool m_stream_is_empty;
342 
344  bool m_client_supports_chunks;
345 
347  bool m_sending_chunks;
348 
350  bool m_sent_headers;
351 
353  FinishedHandler m_finished;
354 };
355 
356 
358 typedef boost::shared_ptr<HTTPWriter> HTTPWriterPtr;
359 
360 
362 template <typename T>
363 HTTPWriterPtr& operator<<(HTTPWriterPtr& writer, const T& data) {
364  writer->write(data);
365  return writer;
366 }
367 
368 
369 } // end namespace net
370 } // end namespace pion
371 
372 #endif
void sendChunk(SendHandler send_handler)
Definition: HTTPWriter.hpp:189
void supportsChunkedMessages(bool b)
sets whether or not the client supports chunked messages
Definition: HTTPWriter.hpp:237
void finishedWriting(const boost::system::error_code &ec)
called after we have finished sending the HTTP message
Definition: HTTPWriter.hpp:79
bool sendingChunkedMessage() const
returns true if we are sending a chunked message to the client
Definition: HTTPWriter.hpp:243
void writeNoCopy(const std::string &data)
Definition: HTTPWriter.hpp:131
void sendFinalChunk(SendHandler send_handler)
Definition: HTTPWriter.hpp:212
void setLogger(PionLogger log_ptr)
sets the logger to be used
Definition: HTTPWriter.hpp:246
boost::function1< void, const boost::system::error_code & > FinishedHandler
function called after the HTTP message has been sent
Definition: HTTPWriter.hpp:39
std::vector< boost::asio::const_buffer > WriteBuffers
data type for I/O write buffers (these wrap existing data to be sent)
Definition: HTTPMessage.hpp:43
void write(const void *data, size_t length)
Definition: HTTPWriter.hpp:116
void sendFinalChunk(void)
Definition: HTTPWriter.hpp:224
size_t getContentLength(void) const
returns the length of the payload content (in bytes)
Definition: HTTPWriter.hpp:234
bool supportsChunkedMessages() const
returns true if the client supports chunked messages
Definition: HTTPWriter.hpp:240
virtual ~HTTPWriter()
default destructor
Definition: HTTPWriter.hpp:87
boost::function2< void, const boost::system::error_code &, std::size_t > WriteHandler
data type for a function that handles write operations
Definition: HTTPWriter.hpp:42
PionLogger getLogger(void)
returns the logger currently in use
Definition: HTTPWriter.hpp:249
void write(const T &data)
Definition: HTTPWriter.hpp:105
the following enables use of the lock-free cache
HTTPWriter(TCPConnectionPtr &tcp_conn, FinishedHandler handler)
Definition: HTTPWriter.hpp:51
void send(SendHandler send_handler)
Definition: HTTPWriter.hpp:174
void clear(void)
clears out all of the memory buffers used to cache payload content data
Definition: HTTPWriter.hpp:90
void writeNoCopy(void *data, size_t length)
Definition: HTTPWriter.hpp:146
TCPConnectionPtr & getTCPConnection(void)
returns a shared pointer to the TCP connection
Definition: HTTPWriter.hpp:231