11 #include <boost/regex.hpp> 12 #include <boost/logic/tribool.hpp> 13 #include <boost/asio/detail/socket_ops.hpp> 14 #include <pion/algorithm.hpp> 15 #include <pion/spdy/parser.hpp> 16 #include <pion/spdy/decompressor.hpp> 17 #include <pion/spdy/types.hpp> 24 static char const* rst_stream_status(boost::uint32_t rst_stream_status_code)
26 switch (rst_stream_status_code)
28 case 1:
return "PROTOCOL_ERROR";
29 case 2:
return "INVALID_STREAM";
30 case 3:
return "REFUSED_STREAM";
31 case 4:
return "UNSUPPORTED_VERSION";
32 case 5:
return "CANCEL";
33 case 6:
return "INTERNAL_ERROR";
34 case 7:
return "FLOW_CONTROL_ERROR";
35 case 8:
return "STREAM_IN_USE";
36 case 9:
return "STREAM_ALREADY_CLOSED";
37 case 10:
return "INVALID_CREDENTIALS";
38 case 11:
return "FRAME_TOO_LARGE";
39 case 12:
return "INVALID";
44 parser::error_category_t * parser::m_error_category_ptr = NULL;
45 boost::once_flag parser::m_instance_flag = BOOST_ONCE_INIT;
51 m_uncompressed_ptr(NULL),
52 m_current_data_chunk_ptr(NULL),
53 m_last_data_chunk_ptr(NULL),
54 m_logger(PION_GET_LOGGER(
"pion.spdy.parser"))
58 boost::system::error_code& ec,
60 const char *packet_ptr,
61 boost::uint32_t& length_packet,
62 boost::uint32_t current_stream_count)
68 return parse_spdy_frame(ec, decompressor, http_info, length_packet, current_stream_count);
76 boost::uint8_t control_bit;
77 boost::uint16_t version, type;
79 control_bit = byte_value >> (
sizeof(short) * CHAR_BIT - 1);
81 if (!control_bit)
return false;
87 version = two_bytes & 0x7FFF;
89 if(version < 1 || version > 3){
99 if (type >= SPDY_INVALID) {
121 spdy_frame_type spdy_frame;
122 boost::uint8_t first_byte = *((
unsigned char *)ptr);
123 if(first_byte == 0x80){
124 spdy_frame = spdy_control_frame;
125 }
else if(first_byte == 0x0){
126 spdy_frame = spdy_data_frame;
128 spdy_frame = spdy_invalid_frame;
139 return four_bytes & 0x7FFFFFFF;
145 boost::uint32_t& length_packet,
146 boost::uint32_t current_stream_count)
148 boost::tribool rc =
true;
152 BOOST_ASSERT(m_read_ptr);
153 boost::uint8_t first_byte = (boost::uint8_t)*m_read_ptr;
154 if (first_byte != 0x80 && first_byte != 0x0) {
156 PION_LOG_ERROR(m_logger,
"Invalid SPDY Frame");
161 boost::uint8_t control_bit;
163 boost::uint32_t stream_id = 0;
168 bool populate_frame_result =
populate_frame(ec, frame, length_packet, stream_id, http_info);
170 if(!populate_frame_result){
175 BOOST_ASSERT(stream_id != 0);
177 control_bit = (boost::uint8_t)frame.control_bit;
180 if(length_packet > frame.length){
181 m_current_data_chunk_ptr = m_read_ptr + frame.length;
182 length_packet -= frame.length;
183 rc = boost::indeterminate;
193 if (frame.version > MIN_SPDY_VERSION) {
195 PION_LOG_ERROR(m_logger,
"Invalid SPDY Version Number");
196 set_error(ec, ERROR_INVALID_SPDY_VERSION);
200 if(frame.type == SPDY_SYN_STREAM){
201 http_info.http_type = HTTP_REQUEST;
202 }
else if (frame.type == SPDY_SYN_REPLY){
203 http_info.http_type = HTTP_RESPONSE;
204 }
else if (frame.type == SPDY_DATA){
205 http_info.http_type = HTTP_DATA;
208 switch (frame.type) {
209 case SPDY_SYN_STREAM:
215 case SPDY_RST_STREAM:
217 http_info.http_type = SPDY_CONTROL;
222 http_info.http_type = SPDY_CONTROL;
227 http_info.http_type = SPDY_CONTROL;
232 http_info.http_type = SPDY_CONTROL;
235 case SPDY_WINDOW_UPDATE:
237 http_info.http_type = SPDY_CONTROL;
240 case SPDY_CREDENTIAL:
242 http_info.http_type = SPDY_CONTROL;
252 m_last_data_chunk_ptr = m_read_ptr;
253 m_read_ptr = m_current_data_chunk_ptr;
261 m_error_category_ptr = &UNIQUE_ERROR_CATEGORY;
266 boost::uint32_t& length_packet,
267 boost::uint32_t& stream_id,
271 boost::uint8_t control_bit;
273 control_bit = byte_value >> (
sizeof(short) * CHAR_BIT - 1);
275 frame.control_bit = (control_bit != 0);
283 frame.version = two_bytes & 0x7FFF;
288 http_info.data_offset +=2;
293 if (frame.type >= SPDY_INVALID) {
297 PION_LOG_ERROR(m_logger,
"Invalid SPDY Frame");
305 frame.type = SPDY_DATA;
309 stream_id = four_bytes & 0x7FFFFFFF;
311 http_info.stream_id = stream_id;
314 http_info.data_offset +=2;
322 http_info.data_offset +=2;
325 frame.flags = (boost::uint8_t)*m_read_ptr;
331 frame.length = four_bytes & 0xFFFFFF;
336 http_info.data_offset +=4;
338 http_info.data_size = frame.length;
342 stream_id = four_bytes & 0x7FFFFFFF;
352 boost::uint32_t current_stream_count)
354 boost::uint32_t stream_id = 0;
355 boost::uint32_t associated_stream_id;
356 boost::uint32_t header_block_length = frame.length;
361 stream_id = four_bytes & 0x7FFFFFFF;
365 http_info.stream_id = stream_id;
369 if (frame.type == SPDY_SYN_STREAM) {
374 associated_stream_id = four_bytes & 0x7FFFFFFF;
383 }
else if( frame.type == SPDY_SYN_REPLY || frame.type == SPDY_HEADERS ) {
391 switch (frame.type) {
392 case SPDY_SYN_STREAM:
393 header_block_length -= 10;
399 header_block_length -= 6;
403 PION_LOG_ERROR(m_logger,
"Invalid SPDY Frame Type");
409 m_uncompressed_ptr = decompressor->decompress(m_read_ptr,
412 header_block_length);
414 if (!m_uncompressed_ptr) {
427 m_uncompressed_ptr += 2;
429 std::string content_type =
"";
430 std::string content_encoding =
"";
432 for(boost::uint16_t count = 0; count < num_name_val_pairs; ++count){
437 std::string name =
"";
439 m_uncompressed_ptr += 2;
442 for(boost::uint16_t count = 0; count < length_name; ++count){
443 name.push_back(*(m_uncompressed_ptr+count));
445 m_uncompressed_ptr += length_name;
450 std::string value =
"";
452 m_uncompressed_ptr += 2;
455 for(boost::uint16_t count = 0; count < length_value; ++count){
456 value.push_back(*(m_uncompressed_ptr+count));
458 m_uncompressed_ptr += length_value;
462 http_info.http_headers.insert(std::make_pair(name, value));
468 boost::uint32_t stream_id,
472 if (frame.flags & SPDY_FLAG_FIN){
473 http_info.last_chunk =
true;
480 boost::uint32_t stream_id = 0;
481 boost::uint32_t status_code = 0;
485 if(frame.flags != 0 || frame.length != 8 ){
492 stream_id = four_bytes & 0x7FFFFFFF;
500 char const*
const status_code_str = rst_stream_status(status_code);
502 PION_LOG_INFO(m_logger,
"SPDY Status Code is : " << status_code_str);
504 PION_LOG_INFO(m_logger,
"SPDY RST Invalid status code : " << status_code);
513 if(frame.length != 4){
517 boost::uint32_t ping_id = 0;
525 PION_LOG_INFO(m_logger,
"SPDY " <<
"Ping ID is : " << ping_id);
539 if(frame.length != 4){
543 boost::uint32_t last_good_stream_id = 0;
544 boost::uint32_t status_code = 0;
549 last_good_stream_id = four_bytes & 0x7FFFFFFF;
558 if(status_code == 1){
560 PION_LOG_ERROR(m_logger,
"There was a Protocol Error");
563 }
else if (status_code == 11) {
565 PION_LOG_ERROR(m_logger,
"There was an Internal Error");
566 set_error(ec, ERROR_INTERNAL_SPDY_ERROR);
570 PION_LOG_INFO(m_logger,
"SPDY " <<
"Status Code is : " << status_code);
static void create_error_category(void)
creates the unique parser error_category_t
boost::tribool parse_spdy_frame(boost::system::error_code &ec, const decompressor_ptr &decompressor, http_protocol_info &http_headers, boost::uint32_t &length_packet, boost::uint32_t current_stream_count)
void set_read_ptr(const char *ptr)
resets the read pointer
void parse_spdy_data(boost::system::error_code &ec, const spdy_control_frame_info &frame, boost::uint32_t stream_id, http_protocol_info &http_info)
This structure contains the HTTP Protocol information.
static boost::uint16_t to_uint16(unsigned char high, unsigned char low)
convert sequence of two bytes to 16-bit unsigned integer
void parse_spdy_settings_frame(boost::system::error_code &ec, const spdy_control_frame_info &frame)
void parse_spdy_rst_stream(boost::system::error_code &ec, const spdy_control_frame_info &frame)
class-specific error category
static boost::uint32_t get_control_frame_stream_id(const char *ptr)
parser()
constructs a new parser object (default constructor)
void parse_header_payload(boost::system::error_code &ec, const decompressor_ptr &decompressor, const spdy_control_frame_info &frame, http_protocol_info &http_headers, boost::uint32_t current_stream_count)
boost::tribool parse(http_protocol_info &http_headers, boost::system::error_code &ec, const decompressor_ptr &decompressor, const char *packet_ptr, boost::uint32_t &length_packet, boost::uint32_t current_stream_count)
bool populate_frame(boost::system::error_code &ec, spdy_control_frame_info &frame, boost::uint32_t &length_packet, boost::uint32_t &stream_id, http_protocol_info &http_headers)
static bool is_spdy_control_frame(const char *ptr)
void parse_spdy_goaway_frame(boost::system::error_code &ec, const spdy_control_frame_info &frame)
void parse_spdy_window_update_frame(boost::system::error_code &ec, const spdy_control_frame_info &frame)
void parse_spdy_ping_frame(boost::system::error_code &ec, const spdy_control_frame_info &frame)
static spdy_frame_type get_spdy_frame_type(const char *ptr)
static void set_error(boost::system::error_code &ec, error_value_t ev)
This structure will be tied to each SPDY frame.
static boost::uint32_t to_uint32(unsigned char high, unsigned char mid1, unsigned char mid2, unsigned char low)
convert sequence of four bytes to 32-bit unsigned integer