10 #ifndef __PION_HTTP_MESSAGE_HEADER__ 11 #define __PION_HTTP_MESSAGE_HEADER__ 16 #include <boost/cstdint.hpp> 17 #include <boost/asio.hpp> 18 #include <boost/scoped_array.hpp> 19 #include <boost/lexical_cast.hpp> 20 #include <boost/algorithm/string/trim.hpp> 21 #include <boost/regex.hpp> 22 #include <pion/config.hpp> 23 #include <pion/http/types.hpp> 25 #ifndef BOOST_SYSTEM_NOEXCEPT 28 #ifndef BOOST_NOEXCEPT 29 #define BOOST_SYSTEM_NOEXCEPT 31 #define BOOST_SYSTEM_NOEXCEPT BOOST_NOEXCEPT 68 :
public boost::system::error_category
71 virtual inline const char *name()
const BOOST_SYSTEM_NOEXCEPT {
return "receive_error_t"; }
72 virtual inline std::string
message(
int ev)
const {
76 result =
"HTTP message parsing error";
79 result =
"Unknown receive error";
97 : m_is_valid(false), m_is_chunked(false), m_chunks_supported(false),
98 m_do_not_send_content_length(false),
99 m_version_major(1), m_version_minor(1), m_content_length(0), m_content_buf(),
100 m_status(STATUS_NONE), m_has_missing_packets(false), m_has_data_after_missing(false)
105 : m_first_line(http_msg.m_first_line),
106 m_is_valid(http_msg.m_is_valid),
107 m_is_chunked(http_msg.m_is_chunked),
108 m_chunks_supported(http_msg.m_chunks_supported),
109 m_do_not_send_content_length(http_msg.m_do_not_send_content_length),
110 m_remote_ip(http_msg.m_remote_ip),
111 m_version_major(http_msg.m_version_major),
112 m_version_minor(http_msg.m_version_minor),
113 m_content_length(http_msg.m_content_length),
114 m_content_buf(http_msg.m_content_buf),
115 m_chunk_cache(http_msg.m_chunk_cache),
116 m_headers(http_msg.m_headers),
117 m_status(http_msg.m_status),
118 m_has_missing_packets(http_msg.m_has_missing_packets),
119 m_has_data_after_missing(http_msg.m_has_data_after_missing)
125 m_is_valid = http_msg.m_is_valid;
126 m_is_chunked = http_msg.m_is_chunked;
127 m_chunks_supported = http_msg.m_chunks_supported;
128 m_do_not_send_content_length = http_msg.m_do_not_send_content_length;
129 m_remote_ip = http_msg.m_remote_ip;
130 m_version_major = http_msg.m_version_major;
131 m_version_minor = http_msg.m_version_minor;
132 m_content_length = http_msg.m_content_length;
133 m_content_buf = http_msg.m_content_buf;
134 m_chunk_cache = http_msg.m_chunk_cache;
135 m_headers = http_msg.m_headers;
136 m_status = http_msg.m_status;
137 m_has_missing_packets = http_msg.m_has_missing_packets;
138 m_has_data_after_missing = http_msg.m_has_data_after_missing;
148 m_is_valid = m_is_chunked = m_chunks_supported
149 = m_do_not_send_content_length =
false;
150 m_remote_ip = boost::asio::ip::address_v4(0);
151 m_version_major = m_version_minor = 1;
152 m_content_length = 0;
153 m_content_buf.clear();
154 m_chunk_cache.clear();
156 m_cookie_params.clear();
157 m_status = STATUS_NONE;
158 m_has_missing_packets =
false;
159 m_has_data_after_missing =
false;
163 virtual bool is_content_length_implied(
void)
const = 0;
166 inline bool is_valid(
void)
const {
return m_is_valid; }
184 std::string http_version(STRING_HTTP_VERSION);
185 http_version += boost::lexical_cast<std::string>(get_version_major());
187 http_version += boost::lexical_cast<std::string>(get_version_minor());
207 inline const char *
get_content(
void)
const {
return m_content_buf.get(); }
213 inline const std::string&
get_header(
const std::string& key)
const {
214 return get_value(m_headers, key);
224 return(m_headers.find(key) != m_headers.end());
229 inline const std::string&
get_cookie(
const std::string& key)
const {
230 return get_value(m_cookie_params, key);
235 return m_cookie_params;
241 return(m_cookie_params.find(key) != m_cookie_params.end());
246 inline void add_cookie(
const std::string& key,
const std::string& value) {
247 m_cookie_params.insert(std::make_pair(key, value));
252 inline void change_cookie(
const std::string& key,
const std::string& value) {
253 change_value(m_cookie_params, key, value);
259 delete_value(m_cookie_params, key);
264 if (m_first_line.empty())
278 inline void set_data_after_missing_packet(
bool newVal) { m_has_data_after_missing = newVal; }
287 inline void set_remote_ip(
const boost::asio::ip::address& ip) { m_remote_ip = ip; }
311 inline void set_status(
data_status_t newVal) { m_status = newVal; }
315 ihash_multimap::const_iterator i = m_headers.find(HEADER_CONTENT_LENGTH);
316 if (i == m_headers.end()) {
317 m_content_length = 0;
319 std::string trimmed_length(i->second);
320 boost::algorithm::trim(trimmed_length);
321 m_content_length = boost::lexical_cast<
size_t>(trimmed_length);
327 m_is_chunked =
false;
328 ihash_multimap::const_iterator i = m_headers.find(HEADER_TRANSFER_ENCODING);
329 if (i != m_headers.end()) {
331 m_is_chunked = boost::regex_match(i->second, REGEX_ICASE_CHUNKED);
339 m_content_buf.resize(m_content_length);
340 return m_content_buf.get();
345 set_content_length(content.size());
346 create_content_buffer();
347 memcpy(m_content_buf.get(), content.c_str(), content.size());
352 set_content_length(0);
353 create_content_buffer();
354 delete_value(m_headers, HEADER_CONTENT_TYPE);
359 change_value(m_headers, HEADER_CONTENT_TYPE, type);
363 inline void add_header(
const std::string& key,
const std::string& value) {
364 m_headers.insert(std::make_pair(key, value));
368 inline void change_header(
const std::string& key,
const std::string& value) {
369 change_value(m_headers, key, value);
374 delete_value(m_headers, key);
379 return (get_header(HEADER_CONNECTION) !=
"close" 380 && (get_version_major() > 1
381 || (get_version_major() >= 1 && get_version_minor() >= 1)) );
392 const bool keep_alive,
393 const bool using_chunks)
396 prepare_headers_for_send(keep_alive, using_chunks);
398 write_buffers.push_back(boost::asio::buffer(get_first_line()));
399 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
401 append_cookie_headers();
403 append_headers(write_buffers);
417 boost::system::error_code& ec,
418 bool headers_only =
false);
430 boost::system::error_code& ec,
444 boost::system::error_code& ec,
445 bool headers_only =
false,
446 std::size_t max_content_length = static_cast<size_t>(-1));
457 std::size_t write(std::ostream& out,
458 boost::system::error_code& ec,
459 bool headers_only =
false);
470 std::size_t read(std::istream& in,
471 boost::system::error_code& ec,
484 std::size_t read(std::istream& in,
485 boost::system::error_code& ec,
486 bool headers_only =
false,
487 std::size_t max_content_length = static_cast<size_t>(-1));
492 void concatenate_chunks(
void);
508 : m_buf(), m_len(0), m_empty(0), m_ptr(&m_empty)
512 memcpy(
get(), buf.
get(), buf.
size());
520 memcpy(
get(), buf.
get(), buf.
size());
528 inline bool is_empty()
const {
return m_len == 0; }
531 inline std::size_t
size()
const {
return m_len; }
534 inline const char *
get()
const {
return m_ptr; }
537 inline char *
get() {
return m_ptr; }
546 m_buf.reset(
new char[len+1]);
556 boost::scoped_array<char> m_buf;
569 const bool using_chunks)
571 change_header(HEADER_CONNECTION, (keep_alive ?
"Keep-Alive" :
"close") );
573 if (get_chunks_supported())
574 change_header(HEADER_TRANSFER_ENCODING,
"chunked");
575 }
else if (! m_do_not_send_content_length) {
576 change_header(HEADER_CONTENT_LENGTH, boost::lexical_cast<std::string>(get_content_length()));
587 for (ihash_multimap::const_iterator i = m_headers.begin(); i != m_headers.end(); ++i) {
588 write_buffers.push_back(boost::asio::buffer(i->first));
589 write_buffers.push_back(boost::asio::buffer(HEADER_NAME_VALUE_DELIMITER));
590 write_buffers.push_back(boost::asio::buffer(i->second));
591 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
594 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
608 template <
typename DictionaryType>
609 inline static const std::string&
get_value(
const DictionaryType& dict,
610 const std::string& key)
612 typename DictionaryType::const_iterator i = dict.find(key);
613 return ( (i==dict.end()) ? STRING_EMPTY : i->second );
625 template <
typename DictionaryType>
627 const std::string& key,
const std::string& value)
631 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
632 result_pair = dict.equal_range(key);
633 if (result_pair.first == dict.end()) {
635 dict.insert(std::make_pair(key, value));
638 result_pair.first->second = value;
640 typename DictionaryType::iterator i;
641 ++(result_pair.first);
642 while (result_pair.first != result_pair.second) {
643 i = result_pair.first;
644 ++(result_pair.first);
656 template <
typename DictionaryType>
658 const std::string& key)
660 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
661 result_pair = dict.equal_range(key);
662 if (result_pair.first != dict.end())
663 dict.erase(result_pair.first, result_pair.second);
669 if (! m_first_line.empty())
670 m_first_line.clear();
674 virtual void update_first_line(
void)
const = 0;
684 static const boost::regex REGEX_ICASE_CHUNKED;
693 bool m_chunks_supported;
696 bool m_do_not_send_content_length;
699 boost::asio::ip::address m_remote_ip;
702 boost::uint16_t m_version_major;
705 boost::uint16_t m_version_minor;
708 size_t m_content_length;
714 chunk_cache_t m_chunk_cache;
717 ihash_multimap m_headers;
720 ihash_multimap m_cookie_params;
726 bool m_has_missing_packets;
729 bool m_has_data_after_missing;
bool check_keep_alive(void) const
returns true if the HTTP connection may be kept alive
void clear_first_line(void) const
bool get_chunks_supported(void) const
returns true if chunked transfer encodings are supported
void update_content_length_using_header(void)
sets the length of the payload content using the Content-Length header
virtual ~message()
virtual destructor
bool is_empty() const
returns true if buffer is empty
message & operator=(const message &http_msg)
assignment operator
void change_cookie(const std::string &key, const std::string &value)
void add_header(const std::string &key, const std::string &value)
adds a value for the HTTP header named key
void add_cookie(const std::string &key, const std::string &value)
virtual void clear(void)
clears all message data
boost::asio::ip::address & get_remote_ip(void)
returns IP address of the remote endpoint
void set_is_valid(bool b=true)
sets whether or not the message is valid
const char * get_content(void) const
returns a const pointer to the payload content, or empty string if there is none
void set_version_minor(const boost::uint16_t n)
sets the minor HTTP version number
bool is_valid(void) const
returns true if the message is valid
void set_version_major(const boost::uint16_t n)
sets the major HTTP version number
void set_remote_ip(const boost::asio::ip::address &ip)
sets IP address of the remote endpoint
void set_missing_packets(bool newVal)
set to true when missing packets detected
void append_headers(write_buffers_t &write_buffers)
bool has_data_after_missing_packets() const
true if more data seen after the missing packets
void change_header(const std::string &key, const std::string &value)
changes the value for the HTTP header named key
static const std::string & get_value(const DictionaryType &dict, const std::string &key)
const std::string & get_header(const std::string &key) const
returns a value for the header if any are defined; otherwise, an empty string
void set_chunks_supported(bool b)
set to true if chunked transfer encodings are supported
ihash_multimap & get_headers(void)
returns a reference to the HTTP headers
const char * get() const
returns const pointer to data
void set_content(const std::string &content)
resets payload content to match the value of a string
boost::uint16_t get_version_minor(void) const
returns the minor HTTP version number
void set_content_length(size_t n)
sets the length of the payload content (in bytes)
content_buffer_t & operator=(const content_buffer_t &buf)
assignment operator
const std::string & get_first_line(void) const
returns a string containing the first line for the HTTP message
void set_content_type(const std::string &type)
sets the content type for the message payload
std::vector< char > chunk_cache_t
used to cache chunked data
static void change_value(DictionaryType &dict, const std::string &key, const std::string &value)
message(const message &http_msg)
copy constructor
bool has_cookie(const std::string &key) const
~content_buffer_t()
simple destructor
content_buffer_t()
default constructor
a simple helper class used to manage a fixed-size payload content buffer
bool has_missing_packets() const
true if there were missing packets
std::string get_version_string(void) const
returns a string representation of the HTTP version (i.e. "HTTP/1.1")
void delete_header(const std::string &key)
removes all values for the HTTP header named key
message(void)
constructs a new HTTP message object
void prepare_headers_for_send(const bool keep_alive, const bool using_chunks)
chunk_cache_t & get_chunk_cache(void)
returns a reference to the chunk cache
const std::string & get_cookie(const std::string &key) const
void resize(std::size_t len)
changes the size of the content buffer
void set_do_not_send_content_length(void)
if called, the content-length will not be sent in the HTTP headers
size_t get_content_length(void) const
returns the length of the payload content (in bytes)
virtual void append_cookie_headers(void)
appends HTTP headers for any cookies defined by the http::message
content_buffer_t(const content_buffer_t &buf)
copy constructor
void delete_cookie(const std::string &key)
std::size_t get_content_buffer_size() const
returns size of allocated buffer
void update_transfer_encoding_using_header(void)
sets the transfer coding using the Transfer-Encoding header
data type for library errors returned during receive() operations
char * create_content_buffer(void)
static void delete_value(DictionaryType &dict, const std::string &key)
data_status_t
defines message data integrity status codes
void clear_content(void)
clears payload content buffer
char * get_content(void)
returns a pointer to the payload content, or empty string if there is none
bool is_chunked(void) const
returns true if the message content is chunked
bool is_content_buffer_allocated() const
returns true if buffer for content is allocated
boost::uint16_t get_version_major(void) const
returns the major HTTP version number
std::size_t size() const
returns size in bytes
void prepare_buffers_for_send(write_buffers_t &write_buffers, const bool keep_alive, const bool using_chunks)
data_status_t get_status() const
return the data receival status
void clear()
clears the content buffer
ihash_multimap & get_cookies(void)
returns the cookie parameters
bool has_header(const std::string &key) const
returns true if at least one value for the header is defined
std::vector< boost::asio::const_buffer > write_buffers_t
data type for I/O write buffers (these wrap existing data to be sent)