00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef __PION_HTTPMESSAGE_HEADER__
00011 #define __PION_HTTPMESSAGE_HEADER__
00012
00013 #include <vector>
00014 #include <boost/cstdint.hpp>
00015 #include <boost/asio.hpp>
00016 #include <boost/scoped_array.hpp>
00017 #include <boost/lexical_cast.hpp>
00018 #include <boost/algorithm/string/trim.hpp>
00019 #include <boost/regex.hpp>
00020 #include <pion/PionConfig.hpp>
00021 #include <pion/net/HTTPTypes.hpp>
00022
00023
00024 namespace pion {
00025 namespace net {
00026
00027
00028
00029 class TCPConnection;
00030
00031
00035 class PION_NET_API HTTPMessage
00036 : public HTTPTypes
00037 {
00038 public:
00039
00041 typedef std::vector<boost::asio::const_buffer> WriteBuffers;
00042
00044 typedef std::vector<char> ChunkCache;
00045
00047 struct ReceiveError
00048 : public boost::system::error_category
00049 {
00050 virtual ~ReceiveError() {}
00051 virtual inline const char *name() const { return "ReceiveError"; }
00052 virtual inline std::string message(int ev) const {
00053 std::string result;
00054 switch(ev) {
00055 case 1:
00056 result = "HTTP message parsing error";
00057 break;
00058 default:
00059 result = "Unknown receive error";
00060 break;
00061 }
00062 return result;
00063 }
00064 };
00065
00066
00068 HTTPMessage(void)
00069 : m_is_valid(false), m_is_chunked(false), m_chunks_supported(false),
00070 m_do_not_send_content_length(false),
00071 m_version_major(1), m_version_minor(1), m_content_length(0)
00072 {}
00073
00075 HTTPMessage(const HTTPMessage& http_msg)
00076 : m_first_line(http_msg.m_first_line),
00077 m_is_valid(http_msg.m_is_valid),
00078 m_is_chunked(http_msg.m_is_chunked),
00079 m_chunks_supported(http_msg.m_chunks_supported),
00080 m_do_not_send_content_length(http_msg.m_do_not_send_content_length),
00081 m_remote_ip(http_msg.m_remote_ip),
00082 m_version_major(http_msg.m_version_major),
00083 m_version_minor(http_msg.m_version_minor),
00084 m_content_length(http_msg.m_content_length),
00085 m_chunk_cache(http_msg.m_chunk_cache),
00086 m_headers(http_msg.m_headers)
00087 {
00088 if (http_msg.m_content_buf) {
00089 char *ptr = createContentBuffer();
00090 memcpy(ptr, http_msg.m_content_buf.get(), m_content_length);
00091 }
00092 }
00093
00095 inline HTTPMessage& operator=(const HTTPMessage& http_msg) {
00096 m_first_line = http_msg.m_first_line;
00097 m_is_valid = http_msg.m_is_valid;
00098 m_is_chunked = http_msg.m_is_chunked;
00099 m_chunks_supported = http_msg.m_chunks_supported;
00100 m_do_not_send_content_length = http_msg.m_do_not_send_content_length;
00101 m_remote_ip = http_msg.m_remote_ip;
00102 m_version_major = http_msg.m_version_major;
00103 m_version_minor = http_msg.m_version_minor;
00104 m_content_length = http_msg.m_content_length;
00105 m_chunk_cache = http_msg.m_chunk_cache;
00106 m_headers = http_msg.m_headers;
00107 if (http_msg.m_content_buf) {
00108 char *ptr = createContentBuffer();
00109 memcpy(ptr, http_msg.m_content_buf.get(), m_content_length);
00110 }
00111 return *this;
00112 }
00113
00115 virtual ~HTTPMessage() {}
00116
00118 virtual void clear(void) {
00119 clearFirstLine();
00120 m_is_valid = m_is_chunked = m_chunks_supported
00121 = m_do_not_send_content_length = false;
00122 m_remote_ip = boost::asio::ip::address_v4(0);
00123 m_version_major = m_version_minor = 1;
00124 m_content_length = 0;
00125 m_content_buf.reset();
00126 m_chunk_cache.clear();
00127 m_headers.clear();
00128 }
00129
00131 virtual bool isContentLengthImplied(void) const = 0;
00132
00134 inline bool isValid(void) const { return m_is_valid; }
00135
00137 inline bool getChunksSupported(void) const { return m_chunks_supported; }
00138
00140 inline boost::asio::ip::address& getRemoteIp(void) {
00141 return m_remote_ip;
00142 }
00143
00145 inline boost::uint16_t getVersionMajor(void) const { return m_version_major; }
00146
00148 inline boost::uint16_t getVersionMinor(void) const { return m_version_minor; }
00149
00151 inline std::string getVersionString(void) const {
00152 std::string http_version(STRING_HTTP_VERSION);
00153 http_version += boost::lexical_cast<std::string>(getVersionMajor());
00154 http_version += '.';
00155 http_version += boost::lexical_cast<std::string>(getVersionMinor());
00156 return http_version;
00157 }
00158
00160 inline std::size_t getContentLength(void) const { return m_content_length; }
00161
00163 inline bool isChunked(void) const { return m_is_chunked; }
00164
00166 inline char *getContent(void) { return m_content_buf.get(); }
00167
00169 inline const char *getContent(void) const { return m_content_buf.get(); }
00170
00172 inline ChunkCache& getChunkCache(void) { return m_chunk_cache; }
00173
00175 inline const std::string& getHeader(const std::string& key) const {
00176 return getValue(m_headers, key);
00177 }
00178
00180 inline Headers& getHeaders(void) {
00181 return m_headers;
00182 }
00183
00185 inline bool hasHeader(const std::string& key) const {
00186 return(m_headers.find(key) != m_headers.end());
00187 }
00188
00190 inline const std::string& getFirstLine(void) const {
00191 if (m_first_line.empty())
00192 updateFirstLine();
00193 return m_first_line;
00194 }
00195
00196
00198 inline void setIsValid(bool b = true) { m_is_valid = b; }
00199
00201 inline void setChunksSupported(bool b) { m_chunks_supported = b; }
00202
00204 inline void setRemoteIp(const boost::asio::ip::address& ip) { m_remote_ip = ip; }
00205
00207 inline void setVersionMajor(const boost::uint16_t n) {
00208 m_version_major = n;
00209 clearFirstLine();
00210 }
00211
00213 inline void setVersionMinor(const boost::uint16_t n) {
00214 m_version_minor = n;
00215 clearFirstLine();
00216 }
00217
00219 inline void setContentLength(const std::size_t n) { m_content_length = n; }
00220
00222 inline void setDoNotSendContentLength(void) { m_do_not_send_content_length = true; }
00223
00225 inline void updateContentLengthUsingHeader(void) {
00226 Headers::const_iterator i = m_headers.find(HEADER_CONTENT_LENGTH);
00227 if (i == m_headers.end()) {
00228 m_content_length = 0;
00229 } else {
00230 std::string trimmed_length(i->second);
00231 boost::algorithm::trim(trimmed_length);
00232 m_content_length = boost::lexical_cast<std::size_t>(trimmed_length);
00233 }
00234 }
00235
00237 inline void updateTransferCodingUsingHeader(void) {
00238 m_is_chunked = false;
00239 Headers::const_iterator i = m_headers.find(HEADER_TRANSFER_ENCODING);
00240 if (i != m_headers.end()) {
00241
00242 m_is_chunked = boost::regex_match(i->second, REGEX_ICASE_CHUNKED);
00243
00244 }
00245 }
00246
00249 inline char *createContentBuffer(void) {
00250 m_content_buf.reset(new char[m_content_length + 1]);
00251 m_content_buf[m_content_length] = '\0';
00252 return m_content_buf.get();
00253 }
00254
00256 inline void setContentType(const std::string& type) {
00257 changeValue(m_headers, HEADER_CONTENT_TYPE, type);
00258 }
00259
00261 inline void addHeader(const std::string& key, const std::string& value) {
00262 m_headers.insert(std::make_pair(key, value));
00263 }
00264
00266 inline void changeHeader(const std::string& key, const std::string& value) {
00267 changeValue(m_headers, key, value);
00268 }
00269
00271 inline void deleteHeader(const std::string& key) {
00272 deleteValue(m_headers, key);
00273 }
00274
00276 inline bool checkKeepAlive(void) const {
00277 return (getHeader(HEADER_CONNECTION) != "close"
00278 && (getVersionMajor() > 1
00279 || (getVersionMajor() >= 1 && getVersionMinor() >= 1)) );
00280 }
00281
00289 inline void prepareBuffersForSend(WriteBuffers& write_buffers,
00290 const bool keep_alive,
00291 const bool using_chunks)
00292 {
00293
00294 prepareHeadersForSend(keep_alive, using_chunks);
00295
00296 write_buffers.push_back(boost::asio::buffer(getFirstLine()));
00297 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00298
00299 appendHeaders(write_buffers);
00300 }
00301
00302
00309 std::size_t send(TCPConnection& tcp_conn, boost::system::error_code& ec);
00310
00317 std::size_t receive(TCPConnection& tcp_conn, boost::system::error_code& ec);
00318
00322 void concatenateChunks(void);
00323
00324
00325 protected:
00326
00333 inline void prepareHeadersForSend(const bool keep_alive,
00334 const bool using_chunks)
00335 {
00336 changeHeader(HEADER_CONNECTION, (keep_alive ? "Keep-Alive" : "close") );
00337 if (using_chunks) {
00338 if (getChunksSupported())
00339 changeHeader(HEADER_TRANSFER_ENCODING, "chunked");
00340 } else if (! m_do_not_send_content_length) {
00341 changeHeader(HEADER_CONTENT_LENGTH, boost::lexical_cast<std::string>(getContentLength()));
00342 }
00343 }
00344
00350 inline void appendHeaders(WriteBuffers& write_buffers) {
00351
00352 for (Headers::const_iterator i = m_headers.begin(); i != m_headers.end(); ++i) {
00353 write_buffers.push_back(boost::asio::buffer(i->first));
00354 write_buffers.push_back(boost::asio::buffer(HEADER_NAME_VALUE_DELIMITER));
00355 write_buffers.push_back(boost::asio::buffer(i->second));
00356 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00357 }
00358
00359 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00360 }
00361
00370 template <typename DictionaryType>
00371 inline static const std::string& getValue(const DictionaryType& dict,
00372 const std::string& key)
00373 {
00374 typename DictionaryType::const_iterator i = dict.find(key);
00375 return ( (i==dict.end()) ? STRING_EMPTY : i->second );
00376 }
00377
00387 template <typename DictionaryType>
00388 inline static void changeValue(DictionaryType& dict,
00389 const std::string& key, const std::string& value)
00390
00391 {
00392
00393 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
00394 result_pair = dict.equal_range(key);
00395 if (result_pair.first == dict.end()) {
00396
00397 dict.insert(std::make_pair(key, value));
00398 } else {
00399
00400 result_pair.first->second = value;
00401
00402 typename DictionaryType::iterator i;
00403 ++(result_pair.first);
00404 while (result_pair.first != result_pair.second) {
00405 i = result_pair.first;
00406 ++(result_pair.first);
00407 dict.erase(i);
00408 }
00409 }
00410 }
00411
00418 template <typename DictionaryType>
00419 inline static void deleteValue(DictionaryType& dict,
00420 const std::string& key)
00421 {
00422 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
00423 result_pair = dict.equal_range(key);
00424 if (result_pair.first != dict.end())
00425 dict.erase(result_pair.first, result_pair.second);
00426 }
00427
00430 inline void clearFirstLine(void) const {
00431 if (! m_first_line.empty())
00432 m_first_line.clear();
00433 }
00434
00436 virtual void updateFirstLine(void) const = 0;
00437
00438
00441 mutable std::string m_first_line;
00442
00443
00444 private:
00445
00447 static const boost::regex REGEX_ICASE_CHUNKED;
00448
00450 bool m_is_valid;
00451
00453 bool m_is_chunked;
00454
00456 bool m_chunks_supported;
00457
00459 bool m_do_not_send_content_length;
00460
00462 boost::asio::ip::address m_remote_ip;
00463
00465 boost::uint16_t m_version_major;
00466
00468 boost::uint16_t m_version_minor;
00469
00471 std::size_t m_content_length;
00472
00474 boost::scoped_array<char> m_content_buf;
00475
00477 ChunkCache m_chunk_cache;
00478
00480 Headers m_headers;
00481 };
00482
00483
00484 }
00485 }
00486
00487 #endif