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);
451 inline void prepareHeadersForSend(
const bool keep_alive,
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>
506 inline static void changeValue(DictionaryType& dict,
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>
537 inline static void deleteValue(DictionaryType& dict,
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;
607 bool m_has_missing_packets;
610 bool m_has_data_after_missing;