10 #ifndef __PION_HTTPMESSAGE_HEADER__
11 #define __PION_HTTPMESSAGE_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/PionConfig.hpp>
23 #include <pion/net/HTTPTypes.hpp>
50 :
public boost::system::error_category
53 virtual inline const char *name()
const {
return "ReceiveError"; }
54 virtual inline std::string message(
int ev)
const {
58 result =
"HTTP message parsing error";
61 result =
"Unknown receive error";
79 : m_is_valid(false), m_is_chunked(false), m_chunks_supported(false),
80 m_do_not_send_content_length(false),
81 m_version_major(1), m_version_minor(1), m_content_length(0),
82 m_status(STATUS_NONE), m_has_missing_packets(false), m_has_data_after_missing(false)
87 : m_first_line(http_msg.m_first_line),
88 m_is_valid(http_msg.m_is_valid),
89 m_is_chunked(http_msg.m_is_chunked),
90 m_chunks_supported(http_msg.m_chunks_supported),
91 m_do_not_send_content_length(http_msg.m_do_not_send_content_length),
92 m_remote_ip(http_msg.m_remote_ip),
93 m_version_major(http_msg.m_version_major),
94 m_version_minor(http_msg.m_version_minor),
95 m_content_length(http_msg.m_content_length),
96 m_chunk_cache(http_msg.m_chunk_cache),
97 m_headers(http_msg.m_headers),
98 m_status(http_msg.m_status),
99 m_has_missing_packets(http_msg.m_has_missing_packets),
100 m_has_data_after_missing(http_msg.m_has_data_after_missing)
102 if (http_msg.m_content_buf) {
103 char *ptr = createContentBuffer();
104 memcpy(ptr, http_msg.m_content_buf.get(), m_content_length);
111 m_is_valid = http_msg.m_is_valid;
112 m_is_chunked = http_msg.m_is_chunked;
113 m_chunks_supported = http_msg.m_chunks_supported;
114 m_do_not_send_content_length = http_msg.m_do_not_send_content_length;
115 m_remote_ip = http_msg.m_remote_ip;
116 m_version_major = http_msg.m_version_major;
117 m_version_minor = http_msg.m_version_minor;
118 m_content_length = http_msg.m_content_length;
119 m_chunk_cache = http_msg.m_chunk_cache;
120 m_headers = http_msg.m_headers;
121 m_status = http_msg.m_status;
122 m_has_missing_packets = http_msg.m_has_missing_packets;
123 m_has_data_after_missing = http_msg.m_has_data_after_missing;
124 if (http_msg.m_content_buf) {
125 char *ptr = createContentBuffer();
126 memcpy(ptr, http_msg.m_content_buf.get(), m_content_length);
137 m_is_valid = m_is_chunked = m_chunks_supported
138 = m_do_not_send_content_length =
false;
139 m_remote_ip = boost::asio::ip::address_v4(0);
140 m_version_major = m_version_minor = 1;
141 m_content_length = 0;
142 m_content_buf.reset();
143 m_chunk_cache.clear();
145 m_cookie_params.clear();
146 m_status = STATUS_NONE;
147 m_has_missing_packets =
false;
148 m_has_data_after_missing =
false;
152 virtual bool isContentLengthImplied(
void)
const = 0;
155 inline bool isValid(
void)
const {
return m_is_valid; }
173 std::string http_version(STRING_HTTP_VERSION);
174 http_version += boost::lexical_cast<std::string>(getVersionMajor());
176 http_version += boost::lexical_cast<std::string>(getVersionMinor());
184 inline bool isChunked(
void)
const {
return m_is_chunked; }
187 inline char *
getContent(
void) {
return m_content_buf.get(); }
190 inline const char *
getContent(
void)
const {
return m_content_buf.get(); }
196 inline const std::string&
getHeader(
const std::string& key)
const {
197 return getValue(m_headers, key);
207 return(m_headers.find(key) != m_headers.end());
212 inline const std::string&
getCookie(
const std::string& key)
const {
213 return getValue(m_cookie_params, key);
218 return m_cookie_params;
224 return(m_cookie_params.find(key) != m_cookie_params.end());
229 inline void addCookie(
const std::string& key,
const std::string& value) {
230 m_cookie_params.insert(std::make_pair(key, value));
235 inline void changeCookie(
const std::string& key,
const std::string& value) {
236 changeValue(m_cookie_params, key, value);
242 deleteValue(m_cookie_params, key);
247 if (m_first_line.empty())
261 inline void setDataAfterMissingPacket(
bool newVal) { m_has_data_after_missing = newVal; }
270 inline void setRemoteIp(
const boost::asio::ip::address& ip) { m_remote_ip = ip; }
294 inline void setStatus(DataStatus newVal) { m_status = newVal; }
298 Headers::const_iterator i = m_headers.find(HEADER_CONTENT_LENGTH);
299 if (i == m_headers.end()) {
300 m_content_length = 0;
302 std::string trimmed_length(i->second);
303 boost::algorithm::trim(trimmed_length);
304 m_content_length = boost::lexical_cast<std::size_t>(trimmed_length);
310 m_is_chunked =
false;
311 Headers::const_iterator i = m_headers.find(HEADER_TRANSFER_ENCODING);
312 if (i != m_headers.end()) {
314 m_is_chunked = boost::regex_match(i->second, REGEX_ICASE_CHUNKED);
322 m_content_buf.reset(
new char[m_content_length + 1]);
323 m_content_buf[m_content_length] =
'\0';
324 return m_content_buf.get();
329 setContentLength(content.size());
330 createContentBuffer();
331 memcpy(m_content_buf.get(), content.c_str(), content.size());
337 createContentBuffer();
338 deleteValue(m_headers, HEADER_CONTENT_TYPE);
343 changeValue(m_headers, HEADER_CONTENT_TYPE, type);
347 inline void addHeader(
const std::string& key,
const std::string& value) {
348 m_headers.insert(std::make_pair(key, value));
352 inline void changeHeader(
const std::string& key,
const std::string& value) {
353 changeValue(m_headers, key, value);
358 deleteValue(m_headers, key);
363 return (getHeader(HEADER_CONNECTION) !=
"close"
364 && (getVersionMajor() > 1
365 || (getVersionMajor() >= 1 && getVersionMinor() >= 1)) );
376 const bool keep_alive,
377 const bool using_chunks)
380 prepareHeadersForSend(keep_alive, using_chunks);
382 write_buffers.push_back(boost::asio::buffer(getFirstLine()));
383 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
385 appendHeaders(write_buffers);
398 std::size_t send(
TCPConnection& tcp_conn, boost::system::error_code& ec,
399 bool headers_only =
false);
410 std::size_t receive(
TCPConnection& tcp_conn, boost::system::error_code& ec,
411 bool headers_only =
false);
422 std::size_t write(std::ostream& out, boost::system::error_code& ec,
423 bool headers_only =
false);
434 std::size_t read(std::istream& in, boost::system::error_code& ec,
435 bool headers_only =
false);
440 void concatenateChunks(
void);
452 const bool using_chunks)
454 changeHeader(HEADER_CONNECTION, (keep_alive ?
"Keep-Alive" :
"close") );
456 if (getChunksSupported())
457 changeHeader(HEADER_TRANSFER_ENCODING,
"chunked");
458 }
else if (! m_do_not_send_content_length) {
459 changeHeader(HEADER_CONTENT_LENGTH, boost::lexical_cast<std::string>(getContentLength()));
470 for (Headers::const_iterator i = m_headers.begin(); i != m_headers.end(); ++i) {
471 write_buffers.push_back(boost::asio::buffer(i->first));
472 write_buffers.push_back(boost::asio::buffer(HEADER_NAME_VALUE_DELIMITER));
473 write_buffers.push_back(boost::asio::buffer(i->second));
474 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
477 write_buffers.push_back(boost::asio::buffer(STRING_CRLF));
488 template <
typename DictionaryType>
489 inline static const std::string&
getValue(
const DictionaryType& dict,
490 const std::string& key)
492 typename DictionaryType::const_iterator i = dict.find(key);
493 return ( (i==dict.end()) ? STRING_EMPTY : i->second );
505 template <
typename DictionaryType>
507 const std::string& key,
const std::string& value)
511 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
512 result_pair = dict.equal_range(key);
513 if (result_pair.first == dict.end()) {
515 dict.insert(std::make_pair(key, value));
518 result_pair.first->second = value;
520 typename DictionaryType::iterator i;
521 ++(result_pair.first);
522 while (result_pair.first != result_pair.second) {
523 i = result_pair.first;
524 ++(result_pair.first);
536 template <
typename DictionaryType>
538 const std::string& key)
540 std::pair<typename DictionaryType::iterator, typename DictionaryType::iterator>
541 result_pair = dict.equal_range(key);
542 if (result_pair.first != dict.end())
543 dict.erase(result_pair.first, result_pair.second);
549 if (! m_first_line.empty())
550 m_first_line.clear();
554 virtual void updateFirstLine(
void)
const = 0;
565 static const boost::regex REGEX_ICASE_CHUNKED;
574 bool m_chunks_supported;
577 bool m_do_not_send_content_length;
580 boost::asio::ip::address m_remote_ip;
583 boost::uint16_t m_version_major;
586 boost::uint16_t m_version_minor;
589 std::size_t m_content_length;
592 boost::scoped_array<char> m_content_buf;
595 ChunkCache m_chunk_cache;
607 bool m_has_missing_packets;
610 bool m_has_data_after_missing;
void setMissingPackets(bool newVal)
set to true when missing packets detected
void addHeader(const std::string &key, const std::string &value)
adds a value for the HTTP header named key
bool checkKeepAlive(void) const
returns true if the HTTP connection may be kept alive
const std::string & getCookie(const std::string &key) const
HTTPMessage(void)
constructs a new HTTP message object
data type for library errors returned during receive() operations
void addCookie(const std::string &key, const std::string &value)
boost::asio::ip::address & getRemoteIp(void)
returns IP address of the remote endpoint
virtual void clear(void)
clears all message data
bool hasCookie(const std::string &key) const
HTTPMessage & operator=(const HTTPMessage &http_msg)
assignment operator
const std::string & getHeader(const std::string &key) const
returns a value for the header if any are defined; otherwise, an empty string
CookieParams & getCookieParams(void)
returns the cookie parameters
void setRemoteIp(const boost::asio::ip::address &ip)
sets IP address of the remote endpoint
void setContent(const std::string &content)
resets payload content to match the value of a string
static void changeValue(DictionaryType &dict, const std::string &key, const std::string &value)
Headers & getHeaders(void)
returns a reference to the HTTP headers
void clearContent(void)
clears payload content buffer
static void deleteValue(DictionaryType &dict, const std::string &key)
virtual ~HTTPMessage()
virtual destructor
DataStatus getStatus() const
return the data receival status
bool hasDataAfterMissingPackets() const
true if more data seen after the missing packets
void prepareHeadersForSend(const bool keep_alive, const bool using_chunks)
std::vector< boost::asio::const_buffer > WriteBuffers
data type for I/O write buffers (these wrap existing data to be sent)
void setVersionMajor(const boost::uint16_t n)
sets the major HTTP version number
std::size_t getContentLength(void) const
returns the length of the payload content (in bytes)
char * createContentBuffer(void)
void changeHeader(const std::string &key, const std::string &value)
changes the value for the HTTP header named key
StringDictionary CookieParams
data type for HTTP cookie parameters
boost::uint16_t getVersionMajor(void) const
returns the major HTTP version number
void setDoNotSendContentLength(void)
if called, the content-length will not be sent in the HTTP headers
void updateContentLengthUsingHeader(void)
sets the length of the payload content using the Content-Length header
DataStatus
defines message data integrity status codes
ChunkCache & getChunkCache(void)
returns a reference to the chunk cache
bool hasMissingPackets() const
true if there were missing packets
bool hasHeader(const std::string &key) const
returns true if at least one value for the header is defined
HTTPMessage(const HTTPMessage &http_msg)
copy constructor
void setContentLength(const std::size_t n)
sets the length of the payload content (in bytes)
void deleteCookie(const std::string &key)
void setIsValid(bool b=true)
sets whether or not the message is valid
boost::uint16_t getVersionMinor(void) const
returns the minor HTTP version number
void changeCookie(const std::string &key, const std::string &value)
the following enables use of the lock-free cache
static const std::string & getValue(const DictionaryType &dict, const std::string &key)
std::vector< char > ChunkCache
used to cache chunked data
void setContentType(const std::string &type)
sets the content type for the message payload
std::string getVersionString(void) const
returns a string representation of the HTTP version (i.e. "HTTP/1.1")
void updateTransferCodingUsingHeader(void)
sets the transfer coding using the Transfer-Encoding header
void appendHeaders(WriteBuffers &write_buffers)
void setVersionMinor(const boost::uint16_t n)
sets the minor HTTP version number
const std::string & getFirstLine(void) const
returns a string containing the first line for the HTTP message
void setChunksSupported(bool b)
set to true if chunked transfer encodings are supported
void clearFirstLine(void) const
bool getChunksSupported(void) const
returns true if chunked transfer encodings are supported
void deleteHeader(const std::string &key)
removes all values for the HTTP header named key
bool isChunked(void) const
returns true if the message content is chunked
bool isValid(void) const
returns true if the message is valid
void prepareBuffersForSend(WriteBuffers &write_buffers, const bool keep_alive, const bool using_chunks)
const char * getContent(void) const
returns a const pointer to the payload content, or NULL if there is none
char * getContent(void)
returns a pointer to the payload content, or NULL if there is none