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 26 #define BOOST_SYSTEM_NOEXCEPT BOOST_NOEXCEPT 62 :
public boost::system::error_category
65 virtual inline const char *name()
const BOOST_SYSTEM_NOEXCEPT {
return "receive_error_t"; }
66 virtual inline std::string
message(
int ev)
const {
70 result =
"HTTP message parsing error";
73 result =
"Unknown receive error";
91 : m_is_valid(false), m_is_chunked(false), m_chunks_supported(false),
92 m_do_not_send_content_length(false),
93 m_version_major(1), m_version_minor(1), m_content_length(0), m_content_buf(),
94 m_status(STATUS_NONE), m_has_missing_packets(false), m_has_data_after_missing(false)
99 : m_first_line(http_msg.m_first_line),
100 m_is_valid(http_msg.m_is_valid),
101 m_is_chunked(http_msg.m_is_chunked),
102 m_chunks_supported(http_msg.m_chunks_supported),
103 m_do_not_send_content_length(http_msg.m_do_not_send_content_length),
104 m_remote_ip(http_msg.m_remote_ip),
105 m_version_major(http_msg.m_version_major),
106 m_version_minor(http_msg.m_version_minor),
107 m_content_length(http_msg.m_content_length),
108 m_content_buf(http_msg.m_content_buf),
109 m_chunk_cache(http_msg.m_chunk_cache),
110 m_headers(http_msg.m_headers),
111 m_status(http_msg.m_status),
112 m_has_missing_packets(http_msg.m_has_missing_packets),
113 m_has_data_after_missing(http_msg.m_has_data_after_missing)
119 m_is_valid = http_msg.m_is_valid;
120 m_is_chunked = http_msg.m_is_chunked;
121 m_chunks_supported = http_msg.m_chunks_supported;
122 m_do_not_send_content_length = http_msg.m_do_not_send_content_length;
123 m_remote_ip = http_msg.m_remote_ip;
124 m_version_major = http_msg.m_version_major;
125 m_version_minor = http_msg.m_version_minor;
126 m_content_length = http_msg.m_content_length;
127 m_content_buf = http_msg.m_content_buf;
128 m_chunk_cache = http_msg.m_chunk_cache;
129 m_headers = http_msg.m_headers;
130 m_status = http_msg.m_status;
131 m_has_missing_packets = http_msg.m_has_missing_packets;
132 m_has_data_after_missing = http_msg.m_has_data_after_missing;
142 m_is_valid = m_is_chunked = m_chunks_supported
143 = m_do_not_send_content_length =
false;
144 m_remote_ip = boost::asio::ip::address_v4(0);
145 m_version_major = m_version_minor = 1;
146 m_content_length = 0;
147 m_content_buf.clear();
148 m_chunk_cache.clear();
150 m_cookie_params.clear();
151 m_status = STATUS_NONE;
152 m_has_missing_packets =
false;
153 m_has_data_after_missing =
false;
157 virtual bool is_content_length_implied(
void)
const = 0;
160 inline bool is_valid(
void)
const {
return m_is_valid; }
178 std::string http_version(STRING_HTTP_VERSION);
179 http_version += boost::lexical_cast<std::string>(get_version_major());
181 http_version += boost::lexical_cast<std::string>(get_version_minor());
201 inline const char *
get_content(
void)
const {
return m_content_buf.get(); }
207 inline const std::string&
get_header(
const std::string& key)
const {
208 return get_value(m_headers, key);
218 return(m_headers.find(key) != m_headers.end());
223 inline const std::string&
get_cookie(
const std::string& key)
const {
224 return get_value(m_cookie_params, key);
229 return m_cookie_params;
235 return(m_cookie_params.find(key) != m_cookie_params.end());
240 inline void add_cookie(
const std::string& key,
const std::string& value) {
241 m_cookie_params.insert(std::make_pair(key, value));
246 inline void change_cookie(
const std::string& key,
const std::string& value) {
247 change_value(m_cookie_params, key, value);
253 delete_value(m_cookie_params, key);
258 if (m_first_line.empty())
272 inline void set_data_after_missing_packet(
bool newVal) { m_has_data_after_missing = newVal; }
281 inline void set_remote_ip(
const boost::asio::ip::address& ip) { m_remote_ip = ip; }
305 inline void set_status(
data_status_t newVal) { m_status = newVal; }
309 ihash_multimap::const_iterator i = m_headers.find(HEADER_CONTENT_LENGTH);
310 if (i == m_headers.end()) {
311 m_content_length = 0;
313 std::string trimmed_length(i->second);
314 boost::algorithm::trim(trimmed_length);
315 m_content_length = boost::lexical_cast<
size_t>(trimmed_length);
321 m_is_chunked =
false;
322 ihash_multimap::const_iterator i = m_headers.find(HEADER_TRANSFER_ENCODING);
323 if (i != m_headers.end()) {
325 m_is_chunked = boost::regex_match(i->second, REGEX_ICASE_CHUNKED);
333 m_content_buf.resize(m_content_length);
334 return m_content_buf.get();
339 set_content_length(content.size());
340 create_content_buffer();
341 memcpy(m_content_buf.get(), content.c_str(), content.size());
346 set_content_length(0);
347 create_content_buffer();
348 delete_value(m_headers, HEADER_CONTENT_TYPE);
353 change_value(m_headers, HEADER_CONTENT_TYPE, type);
357 inline void add_header(
const std::string& key,
const std::string& value) {
358 m_headers.insert(std::make_pair(key, value));
362 inline void change_header(
const std::string& key,
const std::string& value) {
363 change_value(m_headers, key, value);
368 delete_value(m_headers, key);
373 return (get_header(HEADER_CONNECTION) !=
"close" 374 && (get_version_major() > 1
375 || (get_version_major() >= 1 && get_version_minor() >= 1)) );
386 const bool keep_alive,
387 const bool using_chunks)
390 prepare_headers_for_send(keep_alive, using_chunks);
392 write_buffers.push_back(boost::asio::buffer(get_first_line()));
393 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
395 append_cookie_headers();
397 append_headers(write_buffers);
411 boost::system::error_code& ec,
412 bool headers_only =
false);
424 boost::system::error_code& ec,
438 boost::system::error_code& ec,
439 bool headers_only =
false,
440 std::size_t max_content_length = static_cast<size_t>(-1));
451 std::size_t write(std::ostream& out,
452 boost::system::error_code& ec,
453 bool headers_only =
false);
464 std::size_t read(std::istream& in,
465 boost::system::error_code& ec,
478 std::size_t read(std::istream& in,
479 boost::system::error_code& ec,
480 bool headers_only =
false,
481 std::size_t max_content_length = static_cast<size_t>(-1));
486 void concatenate_chunks(
void);
502 : m_buf(), m_len(0), m_empty(0), m_ptr(&m_empty)
506 memcpy(
get(), buf.
get(), buf.
size());
514 memcpy(
get(), buf.
get(), buf.
size());
522 inline bool is_empty()
const {
return m_len == 0; }
525 inline std::size_t
size()
const {
return m_len; }
528 inline const char *
get()
const {
return m_ptr; }
531 inline char *
get() {
return m_ptr; }
540 m_buf.reset(
new char[len+1]);
550 boost::scoped_array<char> m_buf;
563 const bool using_chunks)
565 change_header(HEADER_CONNECTION, (keep_alive ?
"Keep-Alive" :
"close") );
567 if (get_chunks_supported())
568 change_header(HEADER_TRANSFER_ENCODING,
"chunked");
569 }
else if (! m_do_not_send_content_length) {
570 change_header(HEADER_CONTENT_LENGTH, boost::lexical_cast<std::string>(get_content_length()));
581 for (ihash_multimap::const_iterator i = m_headers.begin(); i != m_headers.end(); ++i) {
582 write_buffers.push_back(boost::asio::buffer(i->first));
583 write_buffers.push_back(boost::asio::buffer(HEADER_NAME_VALUE_DELIMITER));
584 write_buffers.push_back(boost::asio::buffer(i->second));
585 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
588 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
602 template <
typename DictionaryType>
603 inline static const std::string&
get_value(
const DictionaryType& dict,
604 const std::string& key)
606 typename DictionaryType::const_iterator i = dict.find(key);
607 return ( (i==dict.end()) ? STRING_EMPTY : i->second );
619 template <
typename DictionaryType>
621 const std::string& key,
const std::string& value)
625 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
626 result_pair = dict.equal_range(key);
627 if (result_pair.first == dict.end()) {
629 dict.insert(std::make_pair(key, value));
632 result_pair.first->second = value;
634 typename DictionaryType::iterator i;
635 ++(result_pair.first);
636 while (result_pair.first != result_pair.second) {
637 i = result_pair.first;
638 ++(result_pair.first);
650 template <
typename DictionaryType>
652 const std::string& key)
654 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
655 result_pair = dict.equal_range(key);
656 if (result_pair.first != dict.end())
657 dict.erase(result_pair.first, result_pair.second);
663 if (! m_first_line.empty())
664 m_first_line.clear();
668 virtual void update_first_line(
void)
const = 0;
678 static const boost::regex REGEX_ICASE_CHUNKED;
687 bool m_chunks_supported;
690 bool m_do_not_send_content_length;
693 boost::asio::ip::address m_remote_ip;
696 boost::uint16_t m_version_major;
699 boost::uint16_t m_version_minor;
702 size_t m_content_length;
708 chunk_cache_t m_chunk_cache;
711 ihash_multimap m_headers;
714 ihash_multimap m_cookie_params;
720 bool m_has_missing_packets;
723 bool m_has_data_after_missing;
bool check_keep_alive(void) const
returns true if the HTTP connection may be kept alive
void update_content_length_using_header(void)
sets the length of the payload content using the Content-Length header
virtual ~message()
virtual destructor
std::size_t get_content_buffer_size() const
returns size of allocated buffer
message & operator=(const message &http_msg)
assignment operator
data_status_t get_status() const
return the data receival status
void change_cookie(const std::string &key, const std::string &value)
const char * get() const
returns const pointer to data
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 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_version_minor(const boost::uint16_t n)
sets the minor HTTP version number
void set_version_major(const boost::uint16_t n)
sets the major HTTP version number
boost::uint16_t get_version_major(void) const
returns the major HTTP version number
void set_remote_ip(const boost::asio::ip::address &ip)
sets IP address of the remote endpoint
void clear_first_line(void) const
size_t get_content_length(void) const
returns the length of the payload content (in bytes)
void set_missing_packets(bool newVal)
set to true when missing packets detected
void append_headers(write_buffers_t &write_buffers)
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)
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
bool has_cookie(const std::string &key) const
void set_content(const std::string &content)
resets payload content to match the value of a string
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
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
~content_buffer_t()
simple destructor
std::string get_version_string(void) const
returns a string representation of the HTTP version (i.e. "HTTP/1.1")
content_buffer_t()
default constructor
bool is_valid(void) const
returns true if the message is valid
a simple helper class used to manage a fixed-size payload content buffer
bool has_missing_packets() const
true if there were missing packets
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
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
boost::uint16_t get_version_minor(void) const
returns the minor HTTP version number
bool is_content_buffer_allocated() const
returns true if buffer for content is allocated
const char * get_content(void) const
returns a const pointer to the payload content, or empty string if there is none
bool get_chunks_supported(void) const
returns true if chunked transfer encodings are supported
virtual void append_cookie_headers(void)
appends HTTP headers for any cookies defined by the http::message
std::size_t size() const
returns size in bytes
content_buffer_t(const content_buffer_t &buf)
copy constructor
void delete_cookie(const std::string &key)
bool is_empty() const
returns true if buffer is empty
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
const std::string & get_first_line(void) const
returns a string containing the first line for the HTTP message
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 has_header(const std::string &key) const
returns true if at least one value for the header is defined
const std::string & get_cookie(const std::string &key) const
void prepare_buffers_for_send(write_buffers_t &write_buffers, const bool keep_alive, const bool using_chunks)
bool has_data_after_missing_packets() const
true if more data seen after the missing packets
void clear()
clears the content buffer
ihash_multimap & get_cookies(void)
returns the cookie parameters
std::vector< boost::asio::const_buffer > write_buffers_t
data type for I/O write buffers (these wrap existing data to be sent)