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
00067 enum DataStatus
00068 {
00069 STATUS_NONE,
00070 STATUS_TRUNCATED,
00071 STATUS_PARTIAL,
00072 STATUS_OK
00073 };
00074
00076 HTTPMessage(void)
00077 : m_is_valid(false), m_is_chunked(false), m_chunks_supported(false),
00078 m_do_not_send_content_length(false),
00079 m_version_major(1), m_version_minor(1), m_content_length(0),
00080 m_status(STATUS_NONE), m_has_missing_packets(false), m_has_data_after_missing(false)
00081 {}
00082
00084 HTTPMessage(const HTTPMessage& http_msg)
00085 : m_first_line(http_msg.m_first_line),
00086 m_is_valid(http_msg.m_is_valid),
00087 m_is_chunked(http_msg.m_is_chunked),
00088 m_chunks_supported(http_msg.m_chunks_supported),
00089 m_do_not_send_content_length(http_msg.m_do_not_send_content_length),
00090 m_remote_ip(http_msg.m_remote_ip),
00091 m_version_major(http_msg.m_version_major),
00092 m_version_minor(http_msg.m_version_minor),
00093 m_content_length(http_msg.m_content_length),
00094 m_chunk_cache(http_msg.m_chunk_cache),
00095 m_headers(http_msg.m_headers),
00096 m_status(http_msg.m_status),
00097 m_has_missing_packets(http_msg.m_has_missing_packets),
00098 m_has_data_after_missing(http_msg.m_has_data_after_missing)
00099 {
00100 if (http_msg.m_content_buf) {
00101 char *ptr = createContentBuffer();
00102 memcpy(ptr, http_msg.m_content_buf.get(), m_content_length);
00103 }
00104 }
00105
00107 inline HTTPMessage& operator=(const HTTPMessage& http_msg) {
00108 m_first_line = http_msg.m_first_line;
00109 m_is_valid = http_msg.m_is_valid;
00110 m_is_chunked = http_msg.m_is_chunked;
00111 m_chunks_supported = http_msg.m_chunks_supported;
00112 m_do_not_send_content_length = http_msg.m_do_not_send_content_length;
00113 m_remote_ip = http_msg.m_remote_ip;
00114 m_version_major = http_msg.m_version_major;
00115 m_version_minor = http_msg.m_version_minor;
00116 m_content_length = http_msg.m_content_length;
00117 m_chunk_cache = http_msg.m_chunk_cache;
00118 m_headers = http_msg.m_headers;
00119 m_status = http_msg.m_status;
00120 m_has_missing_packets = http_msg.m_has_missing_packets;
00121 m_has_data_after_missing = http_msg.m_has_data_after_missing;
00122 if (http_msg.m_content_buf) {
00123 char *ptr = createContentBuffer();
00124 memcpy(ptr, http_msg.m_content_buf.get(), m_content_length);
00125 }
00126 return *this;
00127 }
00128
00130 virtual ~HTTPMessage() {}
00131
00133 virtual void clear(void) {
00134 clearFirstLine();
00135 m_is_valid = m_is_chunked = m_chunks_supported
00136 = m_do_not_send_content_length = false;
00137 m_remote_ip = boost::asio::ip::address_v4(0);
00138 m_version_major = m_version_minor = 1;
00139 m_content_length = 0;
00140 m_content_buf.reset();
00141 m_chunk_cache.clear();
00142 m_headers.clear();
00143 m_cookie_params.clear();
00144 m_status = STATUS_NONE;
00145 m_has_missing_packets = false;
00146 m_has_data_after_missing = false;
00147 }
00148
00150 virtual bool isContentLengthImplied(void) const = 0;
00151
00153 inline bool isValid(void) const { return m_is_valid; }
00154
00156 inline bool getChunksSupported(void) const { return m_chunks_supported; }
00157
00159 inline boost::asio::ip::address& getRemoteIp(void) {
00160 return m_remote_ip;
00161 }
00162
00164 inline boost::uint16_t getVersionMajor(void) const { return m_version_major; }
00165
00167 inline boost::uint16_t getVersionMinor(void) const { return m_version_minor; }
00168
00170 inline std::string getVersionString(void) const {
00171 std::string http_version(STRING_HTTP_VERSION);
00172 http_version += boost::lexical_cast<std::string>(getVersionMajor());
00173 http_version += '.';
00174 http_version += boost::lexical_cast<std::string>(getVersionMinor());
00175 return http_version;
00176 }
00177
00179 inline std::size_t getContentLength(void) const { return m_content_length; }
00180
00182 inline bool isChunked(void) const { return m_is_chunked; }
00183
00185 inline char *getContent(void) { return m_content_buf.get(); }
00186
00188 inline const char *getContent(void) const { return m_content_buf.get(); }
00189
00191 inline ChunkCache& getChunkCache(void) { return m_chunk_cache; }
00192
00194 inline const std::string& getHeader(const std::string& key) const {
00195 return getValue(m_headers, key);
00196 }
00197
00199 inline Headers& getHeaders(void) {
00200 return m_headers;
00201 }
00202
00204 inline bool hasHeader(const std::string& key) const {
00205 return(m_headers.find(key) != m_headers.end());
00206 }
00207
00210 inline const std::string& getCookie(const std::string& key) const {
00211 return getValue(m_cookie_params, key);
00212 }
00213
00215 inline CookieParams& getCookieParams(void) {
00216 return m_cookie_params;
00217 }
00218
00221 inline bool hasCookie(const std::string& key) const {
00222 return(m_cookie_params.find(key) != m_cookie_params.end());
00223 }
00224
00227 inline void addCookie(const std::string& key, const std::string& value) {
00228 m_cookie_params.insert(std::make_pair(key, value));
00229 }
00230
00233 inline void changeCookie(const std::string& key, const std::string& value) {
00234 changeValue(m_cookie_params, key, value);
00235 }
00236
00239 inline void deleteCookie(const std::string& key) {
00240 deleteValue(m_cookie_params, key);
00241 }
00242
00244 inline const std::string& getFirstLine(void) const {
00245 if (m_first_line.empty())
00246 updateFirstLine();
00247 return m_first_line;
00248 }
00249
00251 inline bool hasMissingPackets() const { return m_has_missing_packets; }
00252
00254 inline void setMissingPackets(bool newVal) { m_has_missing_packets = newVal; }
00255
00257 inline bool hasDataAfterMissingPackets() const { return m_has_data_after_missing; }
00258
00259 inline void setDataAfterMissingPacket(bool newVal) { m_has_data_after_missing = newVal; }
00260
00262 inline void setIsValid(bool b = true) { m_is_valid = b; }
00263
00265 inline void setChunksSupported(bool b) { m_chunks_supported = b; }
00266
00268 inline void setRemoteIp(const boost::asio::ip::address& ip) { m_remote_ip = ip; }
00269
00271 inline void setVersionMajor(const boost::uint16_t n) {
00272 m_version_major = n;
00273 clearFirstLine();
00274 }
00275
00277 inline void setVersionMinor(const boost::uint16_t n) {
00278 m_version_minor = n;
00279 clearFirstLine();
00280 }
00281
00283 inline void setContentLength(const std::size_t n) { m_content_length = n; }
00284
00286 inline void setDoNotSendContentLength(void) { m_do_not_send_content_length = true; }
00287
00289 inline DataStatus getStatus() const { return m_status; }
00290
00292 inline void setStatus(DataStatus newVal) { m_status = newVal; }
00293
00295 inline void updateContentLengthUsingHeader(void) {
00296 Headers::const_iterator i = m_headers.find(HEADER_CONTENT_LENGTH);
00297 if (i == m_headers.end()) {
00298 m_content_length = 0;
00299 } else {
00300 std::string trimmed_length(i->second);
00301 boost::algorithm::trim(trimmed_length);
00302 m_content_length = boost::lexical_cast<std::size_t>(trimmed_length);
00303 }
00304 }
00305
00307 inline void updateTransferCodingUsingHeader(void) {
00308 m_is_chunked = false;
00309 Headers::const_iterator i = m_headers.find(HEADER_TRANSFER_ENCODING);
00310 if (i != m_headers.end()) {
00311
00312 m_is_chunked = boost::regex_match(i->second, REGEX_ICASE_CHUNKED);
00313
00314 }
00315 }
00316
00319 inline char *createContentBuffer(void) {
00320 m_content_buf.reset(new char[m_content_length + 1]);
00321 m_content_buf[m_content_length] = '\0';
00322 return m_content_buf.get();
00323 }
00324
00326 inline void setContentType(const std::string& type) {
00327 changeValue(m_headers, HEADER_CONTENT_TYPE, type);
00328 }
00329
00331 inline void addHeader(const std::string& key, const std::string& value) {
00332 m_headers.insert(std::make_pair(key, value));
00333 }
00334
00336 inline void changeHeader(const std::string& key, const std::string& value) {
00337 changeValue(m_headers, key, value);
00338 }
00339
00341 inline void deleteHeader(const std::string& key) {
00342 deleteValue(m_headers, key);
00343 }
00344
00346 inline bool checkKeepAlive(void) const {
00347 return (getHeader(HEADER_CONNECTION) != "close"
00348 && (getVersionMajor() > 1
00349 || (getVersionMajor() >= 1 && getVersionMinor() >= 1)) );
00350 }
00351
00359 inline void prepareBuffersForSend(WriteBuffers& write_buffers,
00360 const bool keep_alive,
00361 const bool using_chunks)
00362 {
00363
00364 prepareHeadersForSend(keep_alive, using_chunks);
00365
00366 write_buffers.push_back(boost::asio::buffer(getFirstLine()));
00367 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00368
00369 appendHeaders(write_buffers);
00370 }
00371
00372
00379 std::size_t send(TCPConnection& tcp_conn, boost::system::error_code& ec);
00380
00387 std::size_t receive(TCPConnection& tcp_conn, boost::system::error_code& ec);
00388
00392 void concatenateChunks(void);
00393
00394
00395 protected:
00396
00403 inline void prepareHeadersForSend(const bool keep_alive,
00404 const bool using_chunks)
00405 {
00406 changeHeader(HEADER_CONNECTION, (keep_alive ? "Keep-Alive" : "close") );
00407 if (using_chunks) {
00408 if (getChunksSupported())
00409 changeHeader(HEADER_TRANSFER_ENCODING, "chunked");
00410 } else if (! m_do_not_send_content_length) {
00411 changeHeader(HEADER_CONTENT_LENGTH, boost::lexical_cast<std::string>(getContentLength()));
00412 }
00413 }
00414
00420 inline void appendHeaders(WriteBuffers& write_buffers) {
00421
00422 for (Headers::const_iterator i = m_headers.begin(); i != m_headers.end(); ++i) {
00423 write_buffers.push_back(boost::asio::buffer(i->first));
00424 write_buffers.push_back(boost::asio::buffer(HEADER_NAME_VALUE_DELIMITER));
00425 write_buffers.push_back(boost::asio::buffer(i->second));
00426 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00427 }
00428
00429 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00430 }
00431
00440 template <typename DictionaryType>
00441 inline static const std::string& getValue(const DictionaryType& dict,
00442 const std::string& key)
00443 {
00444 typename DictionaryType::const_iterator i = dict.find(key);
00445 return ( (i==dict.end()) ? STRING_EMPTY : i->second );
00446 }
00447
00457 template <typename DictionaryType>
00458 inline static void changeValue(DictionaryType& dict,
00459 const std::string& key, const std::string& value)
00460
00461 {
00462
00463 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
00464 result_pair = dict.equal_range(key);
00465 if (result_pair.first == dict.end()) {
00466
00467 dict.insert(std::make_pair(key, value));
00468 } else {
00469
00470 result_pair.first->second = value;
00471
00472 typename DictionaryType::iterator i;
00473 ++(result_pair.first);
00474 while (result_pair.first != result_pair.second) {
00475 i = result_pair.first;
00476 ++(result_pair.first);
00477 dict.erase(i);
00478 }
00479 }
00480 }
00481
00488 template <typename DictionaryType>
00489 inline static void deleteValue(DictionaryType& dict,
00490 const std::string& key)
00491 {
00492 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
00493 result_pair = dict.equal_range(key);
00494 if (result_pair.first != dict.end())
00495 dict.erase(result_pair.first, result_pair.second);
00496 }
00497
00500 inline void clearFirstLine(void) const {
00501 if (! m_first_line.empty())
00502 m_first_line.clear();
00503 }
00504
00506 virtual void updateFirstLine(void) const = 0;
00507
00508
00511 mutable std::string m_first_line;
00512
00513
00514 private:
00515
00517 static const boost::regex REGEX_ICASE_CHUNKED;
00518
00520 bool m_is_valid;
00521
00523 bool m_is_chunked;
00524
00526 bool m_chunks_supported;
00527
00529 bool m_do_not_send_content_length;
00530
00532 boost::asio::ip::address m_remote_ip;
00533
00535 boost::uint16_t m_version_major;
00536
00538 boost::uint16_t m_version_minor;
00539
00541 std::size_t m_content_length;
00542
00544 boost::scoped_array<char> m_content_buf;
00545
00547 ChunkCache m_chunk_cache;
00548
00550 Headers m_headers;
00551
00553 CookieParams m_cookie_params;
00554
00556 DataStatus m_status;
00557
00559 bool m_has_missing_packets;
00560
00562 bool m_has_data_after_missing;
00563 };
00564
00565
00566 }
00567 }
00568
00569 #endif