10 #ifndef __PION_HTTPPARSER_HEADER__
11 #define __PION_HTTPPARSER_HEADER__
14 #include <boost/noncopyable.hpp>
15 #include <boost/logic/tribool.hpp>
16 #include <boost/system/error_code.hpp>
17 #include <boost/thread/once.hpp>
18 #include <pion/PionConfig.hpp>
19 #include <pion/PionLogger.hpp>
20 #include <pion/net/HTTPMessage.hpp>
34 private boost::noncopyable
44 ERROR_METHOD_CHAR = 1,
55 ERROR_HEADER_NAME_SIZE,
56 ERROR_HEADER_VALUE_SIZE,
57 ERROR_INVALID_CONTENT_LENGTH,
59 ERROR_MISSING_CHUNK_DATA,
60 ERROR_MISSING_HEADER_DATA,
61 ERROR_MISSING_TOO_MUCH_CONTENT,
66 :
public boost::system::error_category
69 const char *name()
const {
return "HTTPParser"; }
70 std::string message(
int ev)
const {
72 case ERROR_METHOD_CHAR:
73 return "invalid method character";
74 case ERROR_METHOD_SIZE:
75 return "method exceeds maximum size";
77 return "invalid URI character";
79 return "method exceeds maximum size";
80 case ERROR_QUERY_CHAR:
81 return "invalid query string character";
82 case ERROR_QUERY_SIZE:
83 return "query string exceeds maximum size";
84 case ERROR_VERSION_EMPTY:
85 return "HTTP version undefined";
86 case ERROR_VERSION_CHAR:
87 return "invalid version character";
88 case ERROR_STATUS_EMPTY:
89 return "HTTP status undefined";
90 case ERROR_STATUS_CHAR:
91 return "invalid status character";
92 case ERROR_HEADER_CHAR:
93 return "invalid header character";
94 case ERROR_HEADER_NAME_SIZE:
95 return "header name exceeds maximum size";
96 case ERROR_HEADER_VALUE_SIZE:
97 return "header value exceeds maximum size";
98 case ERROR_INVALID_CONTENT_LENGTH:
99 return "invalid Content-Length header";
100 case ERROR_CHUNK_CHAR:
101 return "invalid chunk character";
102 case ERROR_MISSING_HEADER_DATA:
103 return "missing header data";
104 case ERROR_MISSING_CHUNK_DATA:
105 return "missing chunk data";
106 case ERROR_MISSING_TOO_MUCH_CONTENT:
107 return "missing too much content";
109 return "HTTPParser error";
120 HTTPParser(
const bool is_request, std::size_t max_content_length = DEFAULT_CONTENT_MAX)
121 : m_logger(PION_GET_LOGGER(
"pion.net.HTTPParser")), m_is_request(is_request),
122 m_read_ptr(NULL), m_read_end_ptr(NULL), m_message_parse_state(PARSE_START),
123 m_headers_parse_state(is_request ? PARSE_METHOD_START : PARSE_HTTP_VERSION_H),
124 m_chunked_content_parse_state(PARSE_CHUNK_SIZE_START), m_status_code(0),
125 m_bytes_content_remaining(0), m_bytes_content_read(0),
126 m_bytes_last_read(0), m_bytes_total_read(0),
127 m_max_content_length(max_content_length),
128 m_parse_headers_only(false), m_save_raw_headers(false)
145 boost::tribool parse(
HTTPMessage& http_msg, boost::system::error_code& ec);
159 boost::tribool parseMissingData(
HTTPMessage& http_msg, std::size_t len,
160 boost::system::error_code& ec);
177 m_read_end_ptr = ptr + len;
187 read_ptr = m_read_ptr;
188 read_end_ptr = m_read_end_ptr;
200 if (m_message_parse_state != PARSE_CONTENT_NO_LENGTH)
202 m_message_parse_state = PARSE_END;
221 boost::system::error_code ec;
222 finishHeaderParsing(http_msg, ec);
227 m_message_parse_state = PARSE_START;
228 m_headers_parse_state = (m_is_request ? PARSE_METHOD_START : PARSE_HTTP_VERSION_H);
229 m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START;
231 m_status_message.erase();
234 m_query_string.erase();
235 m_raw_headers.erase();
236 m_bytes_content_read = m_bytes_last_read = m_bytes_total_read = 0;
240 inline bool eof(
void)
const {
return m_read_ptr == NULL || m_read_ptr >= m_read_end_ptr; }
243 inline std::size_t
bytes_available(
void)
const {
return (eof() ? 0 : (std::size_t)(m_read_end_ptr - m_read_ptr)); }
246 inline std::size_t
gcount(
void)
const {
return m_bytes_last_read; }
258 inline const std::string&
getRawHeaders(
void)
const {
return m_raw_headers; }
296 const char *ptr,
const std::size_t len);
310 const char *ptr,
const std::size_t len,
311 bool set_cookie_header);
324 const std::string& cookie_header,
bool set_cookie_header)
326 return parseCookieHeader(dict, cookie_header.c_str(), cookie_header.size(), set_cookie_header);
339 const std::string& query)
341 return parseURLEncoded(dict, query.c_str(), query.size());
353 static bool parseForwardedFor(
const std::string& header, std::string& public_ip);
358 return *m_error_category_ptr;
376 boost::tribool parseHeaders(
HTTPMessage& http_msg, boost::system::error_code& ec);
383 void updateMessageWithHeaderData(
HTTPMessage& http_msg)
const;
397 boost::tribool finishHeaderParsing(
HTTPMessage& http_msg,
398 boost::system::error_code& ec);
412 boost::system::error_code& ec);
425 boost::tribool consumeContent(
HTTPMessage& http_msg,
426 boost::system::error_code& ec);
442 static void computeMsgStatus(
HTTPMessage& http_msg,
bool msg_parsed_ok);
451 ec = boost::system::error_code(static_cast<int>(ev), getErrorCategory());
455 static void createErrorCategory(
void);
459 inline static bool isChar(
int c);
460 inline static bool isControl(
int c);
461 inline static bool isSpecial(
int c);
462 inline static bool isDigit(
int c);
463 inline static bool isHexDigit(
int c);
464 inline static bool isCookieAttribute(
const std::string& name,
bool set_cookie_header);
514 enum MessageParseState {
515 PARSE_START, PARSE_HEADERS, PARSE_CONTENT,
516 PARSE_CONTENT_NO_LENGTH, PARSE_CHUNKS, PARSE_END
521 enum HeadersParseState {
522 PARSE_METHOD_START, PARSE_METHOD, PARSE_URI_STEM, PARSE_URI_QUERY,
523 PARSE_HTTP_VERSION_H, PARSE_HTTP_VERSION_T_1, PARSE_HTTP_VERSION_T_2,
524 PARSE_HTTP_VERSION_P, PARSE_HTTP_VERSION_SLASH,
525 PARSE_HTTP_VERSION_MAJOR_START, PARSE_HTTP_VERSION_MAJOR,
526 PARSE_HTTP_VERSION_MINOR_START, PARSE_HTTP_VERSION_MINOR,
527 PARSE_STATUS_CODE_START, PARSE_STATUS_CODE, PARSE_STATUS_MESSAGE,
528 PARSE_EXPECTING_NEWLINE, PARSE_EXPECTING_CR,
529 PARSE_HEADER_WHITESPACE, PARSE_HEADER_START, PARSE_HEADER_NAME,
530 PARSE_SPACE_BEFORE_HEADER_VALUE, PARSE_HEADER_VALUE,
531 PARSE_EXPECTING_FINAL_NEWLINE, PARSE_EXPECTING_FINAL_CR
536 enum ChunkedContentParseState {
537 PARSE_CHUNK_SIZE_START, PARSE_CHUNK_SIZE,
538 PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE,
539 PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE, PARSE_CHUNK,
540 PARSE_EXPECTING_CR_AFTER_CHUNK, PARSE_EXPECTING_LF_AFTER_CHUNK,
541 PARSE_EXPECTING_FINAL_CR_AFTER_LAST_CHUNK,
542 PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK
547 MessageParseState m_message_parse_state;
550 HeadersParseState m_headers_parse_state;
553 ChunkedContentParseState m_chunked_content_parse_state;
556 boost::uint16_t m_status_code;
559 std::string m_status_message;
562 std::string m_method;
565 std::string m_resource;
568 std::string m_query_string;
571 std::string m_raw_headers;
574 std::string m_header_name;
577 std::string m_header_value;
580 std::string m_chunk_size_str;
583 std::size_t m_size_of_current_chunk;
586 std::size_t m_bytes_read_in_current_chunk;
589 std::size_t m_bytes_content_remaining;
592 std::size_t m_bytes_content_read;
595 std::size_t m_bytes_last_read;
598 std::size_t m_bytes_total_read;
601 std::size_t m_max_content_length;
604 bool m_parse_headers_only;
607 bool m_save_raw_headers;
610 static ErrorCategory * m_error_category_ptr;
613 static boost::once_flag m_instance_flag;
619 inline bool HTTPParser::isChar(
int c)
621 return(c >= 0 && c <= 127);
624 inline bool HTTPParser::isControl(
int c)
626 return( (c >= 0 && c <= 31) || c == 127);
629 inline bool HTTPParser::isSpecial(
int c)
632 case '(':
case ')':
case '<':
case '>':
case '@':
633 case ',':
case ';':
case ':':
case '\\':
case '"':
634 case '/':
case '[':
case ']':
case '?':
case '=':
635 case '{':
case '}':
case ' ':
case '\t':
642 inline bool HTTPParser::isDigit(
int c)
644 return(c >=
'0' && c <=
'9');
647 inline bool HTTPParser::isHexDigit(
int c)
649 return((c >=
'0' && c <=
'9') || (c >=
'a' && c <=
'f') || (c >=
'A' && c <=
'F'));
652 inline bool HTTPParser::isCookieAttribute(
const std::string& name,
bool set_cookie_header)
654 return (name.empty() || name[0] ==
'$' || (set_cookie_header &&
655 (name==
"Comment" || name==
"Domain" || name==
"Max-Age" || name==
"Path" || name==
"Secure" || name==
"Version" || name==
"Expires")