00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #ifndef __PION_HTTP_MESSAGE_HEADER__
00011 #define __PION_HTTP_MESSAGE_HEADER__
00012 
00013 #include <iosfwd>
00014 #include <vector>
00015 #include <cstring>
00016 #include <boost/cstdint.hpp>
00017 #include <boost/asio.hpp>
00018 #include <boost/scoped_array.hpp>
00019 #include <boost/lexical_cast.hpp>
00020 #include <boost/algorithm/string/trim.hpp>
00021 #include <boost/regex.hpp>
00022 #include <pion/config.hpp>
00023 #include <pion/http/types.hpp>
00024 
00025 #ifndef BOOST_SYSTEM_NOEXCEPT
00026     #define BOOST_SYSTEM_NOEXCEPT BOOST_NOEXCEPT
00027 #endif
00028 
00029 
00030 namespace pion {    
00031     
00032     
00033 namespace tcp {
00034     
00035     class connection;
00036 }
00037 
00038 
00039 namespace http {    
00040 
00041 
00042 
00043 class parser;
00044 
00045     
00049 class PION_API message
00050     : public http::types
00051 {
00052 public:
00053 
00055     typedef std::vector<boost::asio::const_buffer>  write_buffers_t;
00056 
00058     typedef std::vector<char>   chunk_cache_t;
00059 
00061     struct receive_error_t
00062         : public boost::system::error_category
00063     {
00064         virtual ~receive_error_t() {}
00065         virtual inline const char *name() const BOOST_SYSTEM_NOEXCEPT { return "receive_error_t"; }
00066         virtual inline std::string message(int ev) const {
00067             std::string result;
00068             switch(ev) {
00069                 case 1:
00070                     result = "HTTP message parsing error";
00071                     break;
00072                 default:
00073                     result = "Unknown receive error";
00074                     break;
00075             }
00076             return result;
00077         }
00078     };
00079 
00081     enum data_status_t
00082     {
00083         STATUS_NONE,        
00084         STATUS_TRUNCATED,   
00085         STATUS_PARTIAL,     
00086         STATUS_OK           
00087     };
00088 
00090     message(void)
00091         : m_is_valid(false), m_is_chunked(false), m_chunks_supported(false),
00092         m_do_not_send_content_length(false),
00093         m_version_major(1), m_version_minor(1), m_content_length(0), m_content_buf(),
00094         m_status(STATUS_NONE), m_has_missing_packets(false), m_has_data_after_missing(false)
00095     {}
00096 
00098     message(const message& http_msg)
00099         : m_first_line(http_msg.m_first_line),
00100         m_is_valid(http_msg.m_is_valid),
00101         m_is_chunked(http_msg.m_is_chunked),
00102         m_chunks_supported(http_msg.m_chunks_supported),
00103         m_do_not_send_content_length(http_msg.m_do_not_send_content_length),
00104         m_remote_ip(http_msg.m_remote_ip),
00105         m_version_major(http_msg.m_version_major),
00106         m_version_minor(http_msg.m_version_minor),
00107         m_content_length(http_msg.m_content_length),
00108         m_content_buf(http_msg.m_content_buf),
00109         m_chunk_cache(http_msg.m_chunk_cache),
00110         m_headers(http_msg.m_headers),
00111         m_status(http_msg.m_status),
00112         m_has_missing_packets(http_msg.m_has_missing_packets),
00113         m_has_data_after_missing(http_msg.m_has_data_after_missing)
00114     {}
00115 
00117     inline message& operator=(const message& http_msg) {
00118         m_first_line = http_msg.m_first_line;
00119         m_is_valid = http_msg.m_is_valid;
00120         m_is_chunked = http_msg.m_is_chunked;
00121         m_chunks_supported = http_msg.m_chunks_supported;
00122         m_do_not_send_content_length = http_msg.m_do_not_send_content_length;
00123         m_remote_ip = http_msg.m_remote_ip;
00124         m_version_major = http_msg.m_version_major;
00125         m_version_minor = http_msg.m_version_minor;
00126         m_content_length = http_msg.m_content_length;
00127         m_content_buf = http_msg.m_content_buf;
00128         m_chunk_cache = http_msg.m_chunk_cache;
00129         m_headers = http_msg.m_headers;
00130         m_status = http_msg.m_status;
00131         m_has_missing_packets = http_msg.m_has_missing_packets;
00132         m_has_data_after_missing = http_msg.m_has_data_after_missing;
00133         return *this;
00134     }
00135 
00137     virtual ~message() {}
00138 
00140     virtual void clear(void) {
00141         clear_first_line();
00142         m_is_valid = m_is_chunked = m_chunks_supported
00143             = m_do_not_send_content_length = false;
00144         m_remote_ip = boost::asio::ip::address_v4(0);
00145         m_version_major = m_version_minor = 1;
00146         m_content_length = 0;
00147         m_content_buf.clear();
00148         m_chunk_cache.clear();
00149         m_headers.clear();
00150         m_cookie_params.clear();
00151         m_status = STATUS_NONE;
00152         m_has_missing_packets = false;
00153         m_has_data_after_missing = false;
00154     }
00155 
00157     virtual bool is_content_length_implied(void) const = 0;
00158 
00160     inline bool is_valid(void) const { return m_is_valid; }
00161 
00163     inline bool get_chunks_supported(void) const { return m_chunks_supported; }
00164 
00166     inline boost::asio::ip::address& get_remote_ip(void) {
00167         return m_remote_ip;
00168     }
00169 
00171     inline boost::uint16_t get_version_major(void) const { return m_version_major; }
00172 
00174     inline boost::uint16_t get_version_minor(void) const { return m_version_minor; }
00175 
00177     inline std::string get_version_string(void) const {
00178         std::string http_version(STRING_HTTP_VERSION);
00179         http_version += boost::lexical_cast<std::string>(get_version_major());
00180         http_version += '.';
00181         http_version += boost::lexical_cast<std::string>(get_version_minor());
00182         return http_version;
00183     }
00184 
00186     inline boost::uint64_t get_content_length(void) const { return m_content_length; }
00187 
00189     inline bool is_chunked(void) const { return m_is_chunked; }
00190 
00192     bool is_content_buffer_allocated() const { return !m_content_buf.is_empty(); }
00193     
00195     inline std::size_t get_content_buffer_size() const { return m_content_buf.size(); }
00196     
00198     inline char *get_content(void) { return m_content_buf.get(); }
00199 
00201     inline const char *get_content(void) const { return m_content_buf.get(); }
00202 
00204     inline chunk_cache_t& get_chunk_cache(void) { return m_chunk_cache; }
00205 
00207     inline const std::string& get_header(const std::string& key) const {
00208         return get_value(m_headers, key);
00209     }
00210 
00212     inline ihash_multimap& get_headers(void) {
00213         return m_headers;
00214     }
00215 
00217     inline bool has_header(const std::string& key) const {
00218         return(m_headers.find(key) != m_headers.end());
00219     }
00220 
00223     inline const std::string& get_cookie(const std::string& key) const {
00224         return get_value(m_cookie_params, key);
00225     }
00226     
00228     inline ihash_multimap& get_cookies(void) {
00229         return m_cookie_params;
00230     }
00231 
00234     inline bool has_cookie(const std::string& key) const {
00235         return(m_cookie_params.find(key) != m_cookie_params.end());
00236     }
00237     
00240     inline void add_cookie(const std::string& key, const std::string& value) {
00241         m_cookie_params.insert(std::make_pair(key, value));
00242     }
00243 
00246     inline void change_cookie(const std::string& key, const std::string& value) {
00247         change_value(m_cookie_params, key, value);
00248     }
00249 
00252     inline void delete_cookie(const std::string& key) {
00253         delete_value(m_cookie_params, key);
00254     }
00255     
00257     inline const std::string& get_first_line(void) const {
00258         if (m_first_line.empty())
00259             update_first_line();
00260         return m_first_line;
00261     }
00262 
00264     inline bool has_missing_packets() const { return m_has_missing_packets; }
00265     
00267     inline void set_missing_packets(bool newVal) { m_has_missing_packets = newVal; }
00268 
00270     inline bool has_data_after_missing_packets() const { return m_has_data_after_missing; }
00271 
00272     inline void set_data_after_missing_packet(bool newVal) { m_has_data_after_missing = newVal; }
00273 
00275     inline void set_is_valid(bool b = true) { m_is_valid = b; }
00276 
00278     inline void set_chunks_supported(bool b) { m_chunks_supported = b; }
00279 
00281     inline void set_remote_ip(const boost::asio::ip::address& ip) { m_remote_ip = ip; }
00282 
00284     inline void set_version_major(const boost::uint16_t n) {
00285         m_version_major = n;
00286         clear_first_line();
00287     }
00288 
00290     inline void set_version_minor(const boost::uint16_t n) {
00291         m_version_minor = n;
00292         clear_first_line();
00293     }
00294 
00296     inline void set_content_length(const boost::uint64_t n) { m_content_length = n; }
00297 
00299     inline void set_do_not_send_content_length(void) { m_do_not_send_content_length = true; }
00300 
00302     inline data_status_t get_status() const { return m_status; }
00303 
00305     inline void set_status(data_status_t newVal) { m_status = newVal; }
00306 
00308     inline void update_content_length_using_header(void) {
00309         ihash_multimap::const_iterator i = m_headers.find(HEADER_CONTENT_LENGTH);
00310         if (i == m_headers.end()) {
00311             m_content_length = 0;
00312         } else {
00313             std::string trimmed_length(i->second);
00314             boost::algorithm::trim(trimmed_length);
00315             m_content_length = boost::lexical_cast<boost::uint64_t>(trimmed_length);
00316         }
00317     }
00318 
00320     inline void update_transfer_encoding_using_header(void) {
00321         m_is_chunked = false;
00322         ihash_multimap::const_iterator i = m_headers.find(HEADER_TRANSFER_ENCODING);
00323         if (i != m_headers.end()) {
00324             
00325             m_is_chunked = boost::regex_match(i->second, REGEX_ICASE_CHUNKED);
00326             
00327         }
00328     }
00329 
00332     inline char *create_content_buffer(void) {
00333         m_content_buf.resize(m_content_length);
00334         return m_content_buf.get();
00335     }
00336     
00338     inline void set_content(const std::string& content) {
00339         set_content_length(content.size());
00340         create_content_buffer();
00341         memcpy(m_content_buf.get(), content.c_str(), content.size());
00342     }
00343 
00345     inline void clear_content(void) {
00346         set_content_length(0);
00347         create_content_buffer();
00348         delete_value(m_headers, HEADER_CONTENT_TYPE);
00349     }
00350 
00352     inline void set_content_type(const std::string& type) {
00353         change_value(m_headers, HEADER_CONTENT_TYPE, type);
00354     }
00355 
00357     inline void add_header(const std::string& key, const std::string& value) {
00358         m_headers.insert(std::make_pair(key, value));
00359     }
00360 
00362     inline void change_header(const std::string& key, const std::string& value) {
00363         change_value(m_headers, key, value);
00364     }
00365 
00367     inline void delete_header(const std::string& key) {
00368         delete_value(m_headers, key);
00369     }
00370 
00372     inline bool check_keep_alive(void) const {
00373         return (get_header(HEADER_CONNECTION) != "close"
00374                 && (get_version_major() > 1
00375                     || (get_version_major() >= 1 && get_version_minor() >= 1)) );
00376     }
00377 
00385     inline void prepare_buffers_for_send(write_buffers_t& write_buffers,
00386                                       const bool keep_alive,
00387                                       const bool using_chunks)
00388     {
00389         
00390         prepare_headers_for_send(keep_alive, using_chunks);
00391         
00392         write_buffers.push_back(boost::asio::buffer(get_first_line()));
00393         write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00394         
00395         append_cookie_headers();
00396         
00397         append_headers(write_buffers);
00398     }
00399 
00400 
00410     std::size_t send(tcp::connection& tcp_conn,
00411                      boost::system::error_code& ec,
00412                      bool headers_only = false);
00413 
00423     std::size_t receive(tcp::connection& tcp_conn,
00424                         boost::system::error_code& ec,
00425                         parser& http_parser);
00426     
00437     std::size_t receive(tcp::connection& tcp_conn,
00438                         boost::system::error_code& ec,
00439                         bool headers_only = false,
00440                         std::size_t max_content_length = static_cast<size_t>(-1));
00441 
00451     std::size_t write(std::ostream& out,
00452                       boost::system::error_code& ec,
00453                       bool headers_only = false);
00454 
00464     std::size_t read(std::istream& in,
00465                      boost::system::error_code& ec,
00466                      parser& http_parser);
00467     
00478     std::size_t read(std::istream& in,
00479                      boost::system::error_code& ec,
00480                      bool headers_only = false,
00481                      std::size_t max_content_length = static_cast<size_t>(-1));
00482 
00486     void concatenate_chunks(void);
00487 
00488 
00489 protected:
00490     
00492     class content_buffer_t {
00493     public:
00495         ~content_buffer_t() {}
00496 
00498         content_buffer_t() : m_buf(), m_len(0), m_empty(0), m_ptr(&m_empty) {}
00499 
00501         content_buffer_t(const content_buffer_t& buf)
00502             : m_buf(), m_len(0), m_empty(0), m_ptr(&m_empty)
00503         {
00504             if (buf.size()) {
00505                 resize(buf.size());
00506                 memcpy(get(), buf.get(), buf.size());
00507             }
00508         }
00509 
00511         content_buffer_t& operator=(const content_buffer_t& buf) {
00512             if (buf.size()) {
00513                 resize(buf.size());
00514                 memcpy(get(), buf.get(), buf.size());
00515             } else {
00516                 clear();
00517             }
00518             return *this;
00519         }
00520         
00522         inline bool is_empty() const { return m_len == 0; }
00523         
00525         inline std::size_t size() const { return m_len; }
00526         
00528         inline const char *get() const { return m_ptr; }
00529         
00531         inline char *get() { return m_ptr; }
00532         
00534         inline void resize(std::size_t len) {
00535             m_len = len;
00536             if (len == 0) {
00537                 m_buf.reset();
00538                 m_ptr = &m_empty;
00539             } else {
00540                 m_buf.reset(new char[len+1]);
00541                 m_buf[len] = '\0';
00542                 m_ptr = m_buf.get();
00543             }
00544         }
00545         
00547         inline void clear() { resize(0); }
00548         
00549     private:
00550         boost::scoped_array<char>   m_buf;
00551         std::size_t                 m_len;
00552         char                        m_empty;
00553         char                        *m_ptr;
00554     };
00555 
00562     inline void prepare_headers_for_send(const bool keep_alive,
00563                                       const bool using_chunks)
00564     {
00565         change_header(HEADER_CONNECTION, (keep_alive ? "Keep-Alive" : "close") );
00566         if (using_chunks) {
00567             if (get_chunks_supported())
00568                 change_header(HEADER_TRANSFER_ENCODING, "chunked");
00569         } else if (! m_do_not_send_content_length) {
00570             change_header(HEADER_CONTENT_LENGTH, boost::lexical_cast<std::string>(get_content_length()));
00571         }
00572     }
00573 
00579     inline void append_headers(write_buffers_t& write_buffers) {
00580         
00581         for (ihash_multimap::const_iterator i = m_headers.begin(); i != m_headers.end(); ++i) {
00582             write_buffers.push_back(boost::asio::buffer(i->first));
00583             write_buffers.push_back(boost::asio::buffer(HEADER_NAME_VALUE_DELIMITER));
00584             write_buffers.push_back(boost::asio::buffer(i->second));
00585             write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00586         }
00587         
00588         write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
00589     }
00590 
00592     virtual void append_cookie_headers(void) {}
00593 
00602     template <typename DictionaryType>
00603     inline static const std::string& get_value(const DictionaryType& dict,
00604                                               const std::string& key)
00605     {
00606         typename DictionaryType::const_iterator i = dict.find(key);
00607         return ( (i==dict.end()) ? STRING_EMPTY : i->second );
00608     }
00609 
00619     template <typename DictionaryType>
00620     inline static void change_value(DictionaryType& dict,
00621                                    const std::string& key, const std::string& value)
00622 
00623     {
00624         
00625         std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
00626             result_pair = dict.equal_range(key);
00627         if (result_pair.first == dict.end()) {
00628             
00629             dict.insert(std::make_pair(key, value));
00630         } else {
00631             
00632             result_pair.first->second = value;
00633             
00634             typename DictionaryType::iterator i;
00635             ++(result_pair.first);
00636             while (result_pair.first != result_pair.second) {
00637                 i = result_pair.first;
00638                 ++(result_pair.first);
00639                 dict.erase(i);
00640             }
00641         }
00642     }
00643 
00650     template <typename DictionaryType>
00651     inline static void delete_value(DictionaryType& dict,
00652                                    const std::string& key)
00653     {
00654         std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
00655             result_pair = dict.equal_range(key);
00656         if (result_pair.first != dict.end())
00657             dict.erase(result_pair.first, result_pair.second);
00658     }
00659 
00662     inline void clear_first_line(void) const {
00663         if (! m_first_line.empty())
00664             m_first_line.clear();
00665     }
00666 
00668     virtual void update_first_line(void) const = 0;
00669 
00672     mutable std::string             m_first_line;
00673 
00674 
00675 private:
00676 
00678     static const boost::regex       REGEX_ICASE_CHUNKED;
00679 
00681     bool                            m_is_valid;
00682 
00684     bool                            m_is_chunked;
00685 
00687     bool                            m_chunks_supported;
00688 
00690     bool                            m_do_not_send_content_length;
00691 
00693     boost::asio::ip::address        m_remote_ip;
00694 
00696     boost::uint16_t                 m_version_major;
00697 
00699     boost::uint16_t                 m_version_minor;
00700 
00702     boost::uint64_t                 m_content_length;
00703 
00705     content_buffer_t                m_content_buf;
00706 
00708     chunk_cache_t                   m_chunk_cache;
00709 
00711     ihash_multimap                  m_headers;
00712 
00714     ihash_multimap                  m_cookie_params;
00715 
00717     data_status_t                   m_status;
00718 
00720     bool                            m_has_missing_packets;
00721 
00723     bool                            m_has_data_after_missing;
00724 };
00725 
00726 
00727 }   
00728 }   
00729 
00730 #endif