pion
5.0.6
|
00001 // --------------------------------------------------------------------- 00002 // pion: a Boost C++ framework for building lightweight HTTP interfaces 00003 // --------------------------------------------------------------------- 00004 // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 00005 // 00006 // Distributed under the Boost Software License, Version 1.0. 00007 // See http://www.boost.org/LICENSE_1_0.txt 00008 // 00009 00010 #include <cstdlib> 00011 #include <boost/regex.hpp> 00012 #include <boost/logic/tribool.hpp> 00013 #include <boost/asio/detail/socket_ops.hpp> 00014 #include <pion/algorithm.hpp> 00015 #include <pion/spdy/parser.hpp> 00016 #include <pion/spdy/decompressor.hpp> 00017 #include <pion/spdy/types.hpp> 00018 00019 00020 namespace pion { // begin namespace pion 00021 namespace spdy { // begin namespace spdy 00022 00024 static char const* rst_stream_status(boost::uint32_t rst_stream_status_code) 00025 { 00026 switch (rst_stream_status_code) 00027 { 00028 case 1: return "PROTOCOL_ERROR"; 00029 case 2: return "INVALID_STREAM"; 00030 case 3: return "REFUSED_STREAM"; 00031 case 4: return "UNSUPPORTED_VERSION"; 00032 case 5: return "CANCEL"; 00033 case 6: return "INTERNAL_ERROR"; 00034 case 7: return "FLOW_CONTROL_ERROR"; 00035 case 8: return "STREAM_IN_USE"; 00036 case 9: return "STREAM_ALREADY_CLOSED"; 00037 case 10: return "INVALID_CREDENTIALS"; 00038 case 11: return "FRAME_TOO_LARGE"; 00039 case 12: return "INVALID"; 00040 default: return NULL; 00041 } 00042 } 00043 00044 parser::error_category_t * parser::m_error_category_ptr = NULL; 00045 boost::once_flag parser::m_instance_flag = BOOST_ONCE_INIT; 00046 00047 // parser member functions 00048 00049 parser::parser() 00050 : m_read_ptr(NULL), 00051 m_uncompressed_ptr(NULL), 00052 m_current_data_chunk_ptr(NULL), 00053 m_last_data_chunk_ptr(NULL), 00054 m_logger(PION_GET_LOGGER("pion.spdy.parser")) 00055 {} 00056 00057 boost::tribool parser::parse(http_protocol_info& http_info, 00058 boost::system::error_code& ec, 00059 decompressor_ptr& decompressor, 00060 const char *packet_ptr, 00061 boost::uint32_t& length_packet, 00062 boost::uint32_t current_stream_count) 00063 { 00064 // initialize read position 00065 set_read_ptr(packet_ptr); 00066 00067 // Parse the frame 00068 return parse_spdy_frame(ec, decompressor, http_info, length_packet, current_stream_count); 00069 } 00070 00071 bool parser::is_spdy_control_frame(const char *ptr) 00072 { 00073 // Parse further for higher accuracy 00074 00075 // Get the control bit 00076 boost::uint8_t control_bit; 00077 boost::uint16_t version, type; 00078 boost::uint16_t byte_value = algorithm::to_uint16(ptr); 00079 control_bit = byte_value >> (sizeof(short) * CHAR_BIT - 1); 00080 00081 if (!control_bit) return false; 00082 00083 // Control bit is set; This is a control frame 00084 00085 // Get the version number 00086 boost::uint16_t two_bytes = algorithm::to_uint16(ptr); 00087 version = two_bytes & 0x7FFF; 00088 00089 if(version < 1 || version > 3){ 00090 // SPDY does not have a version higher than 3 and lower than 1 at the moment 00091 return false; 00092 } 00093 00094 // Increment the read pointer 00095 ptr += 2; 00096 00097 type = algorithm::to_uint16(ptr); 00098 00099 if (type >= SPDY_INVALID) { 00100 // Not among the recognized SPDY types 00101 return false; 00102 } 00103 00104 return true; 00105 } 00106 00107 spdy_frame_type parser::get_spdy_frame_type(const char *ptr) 00108 { 00109 // Determine if this a SPDY frame 00110 BOOST_ASSERT(ptr); 00111 00112 /* 00113 * The first byte of a SPDY frame must be either 0 or 00114 * 0x80. If it's not, assume that this is not SPDY. 00115 * (In theory, a data frame could have a stream ID 00116 * >= 2^24, in which case it won't have 0 for a first 00117 * byte, but this is a pretty reliable heuristic for 00118 * now.) 00119 */ 00120 00121 spdy_frame_type spdy_frame; 00122 boost::uint8_t first_byte = *((unsigned char *)ptr); 00123 if(first_byte == 0x80){ 00124 spdy_frame = spdy_control_frame; 00125 }else if(first_byte == 0x0){ 00126 spdy_frame = spdy_data_frame; 00127 }else{ 00128 spdy_frame = spdy_invalid_frame; 00129 } 00130 return spdy_frame; 00131 } 00132 00133 boost::uint32_t parser::get_control_frame_stream_id(const char *ptr) 00134 { 00135 // The stream ID for control frames is at a 8 bit offser from start 00136 ptr += 8; 00137 00138 boost::uint32_t four_bytes = algorithm::to_uint32(ptr); 00139 return four_bytes & 0x7FFFFFFF; 00140 } 00141 00142 boost::tribool parser::parse_spdy_frame(boost::system::error_code& ec, 00143 decompressor_ptr& decompressor, 00144 http_protocol_info& http_info, 00145 boost::uint32_t& length_packet, 00146 boost::uint32_t current_stream_count) 00147 { 00148 boost::tribool rc = true; 00149 00150 // Verify that this is a spdy frame 00151 00152 BOOST_ASSERT(m_read_ptr); 00153 boost::uint8_t first_byte = (boost::uint8_t)*m_read_ptr; 00154 if (first_byte != 0x80 && first_byte != 0x0) { 00155 // This is not a SPDY frame, throw an error 00156 PION_LOG_ERROR(m_logger, "Invalid SPDY Frame"); 00157 set_error(ec, ERROR_INVALID_SPDY_FRAME); 00158 return false; 00159 } 00160 00161 boost::uint8_t control_bit; 00162 spdy_control_frame_info frame; 00163 boost::uint32_t stream_id = 0; 00164 00165 ec.clear(); 00166 00167 // Populate the frame 00168 bool populate_frame_result = populate_frame(ec, frame, length_packet, stream_id, http_info); 00169 00170 if(!populate_frame_result){ 00172 return false; 00173 } 00174 00175 BOOST_ASSERT(stream_id != 0); 00176 00177 control_bit = (boost::uint8_t)frame.control_bit; 00178 00179 // There is a possibility that there are more than one SPDY frames in one TCP frame 00180 if(length_packet > frame.length){ 00181 m_current_data_chunk_ptr = m_read_ptr + frame.length; 00182 length_packet -= frame.length; 00183 rc = boost::indeterminate; 00184 } 00185 00186 if (!control_bit) { 00187 // Parse the data packet 00188 parse_spdy_data(ec, frame, stream_id, http_info); 00189 } 00190 00191 /* Abort here if the version is too low. */ 00192 00193 if (frame.version > MIN_SPDY_VERSION) { 00194 // Version less that min SPDY version, throw an error 00195 PION_LOG_ERROR(m_logger, "Invalid SPDY Version Number"); 00196 set_error(ec, ERROR_INVALID_SPDY_VERSION); 00197 return false; 00198 } 00199 00200 if(frame.type == SPDY_SYN_STREAM){ 00201 http_info.http_type = HTTP_REQUEST; 00202 }else if (frame.type == SPDY_SYN_REPLY){ 00203 http_info.http_type = HTTP_RESPONSE; 00204 }else if (frame.type == SPDY_DATA){ 00205 http_info.http_type = HTTP_DATA; 00206 } 00207 00208 switch (frame.type) { 00209 case SPDY_SYN_STREAM: 00210 case SPDY_SYN_REPLY: 00211 case SPDY_HEADERS: 00212 parse_header_payload(ec, decompressor, frame, http_info, current_stream_count); 00213 break; 00214 00215 case SPDY_RST_STREAM: 00216 parse_spdy_rst_stream(ec, frame); 00217 http_info.http_type = SPDY_CONTROL; 00218 break; 00219 00220 case SPDY_SETTINGS: 00221 parse_spdy_settings_frame(ec, frame); 00222 http_info.http_type = SPDY_CONTROL; 00223 break; 00224 00225 case SPDY_PING: 00226 parse_spdy_ping_frame(ec, frame); 00227 http_info.http_type = SPDY_CONTROL; 00228 break; 00229 00230 case SPDY_GOAWAY: 00231 parse_spdy_goaway_frame(ec, frame); 00232 http_info.http_type = SPDY_CONTROL; 00233 break; 00234 00235 case SPDY_WINDOW_UPDATE: 00236 parse_spdy_window_update_frame(ec, frame); 00237 http_info.http_type = SPDY_CONTROL; 00238 break; 00239 00240 case SPDY_CREDENTIAL: 00241 // We dont need to parse this for now 00242 http_info.http_type = SPDY_CONTROL; 00243 break; 00244 00245 default: 00246 break; 00247 } 00248 00249 if (ec) 00250 return false; 00251 00252 m_last_data_chunk_ptr = m_read_ptr; 00253 m_read_ptr = m_current_data_chunk_ptr; 00254 00255 return rc; 00256 } 00257 00258 void parser::create_error_category(void) 00259 { 00260 static error_category_t UNIQUE_ERROR_CATEGORY; 00261 m_error_category_ptr = &UNIQUE_ERROR_CATEGORY; 00262 } 00263 00264 bool parser::populate_frame(boost::system::error_code& ec, 00265 spdy_control_frame_info& frame, 00266 boost::uint32_t& length_packet, 00267 boost::uint32_t& stream_id, 00268 http_protocol_info& http_info) 00269 { 00270 // Get the control bit 00271 boost::uint8_t control_bit; 00272 boost::uint16_t byte_value = algorithm::to_uint16(m_read_ptr); 00273 control_bit = byte_value >> (sizeof(short) * CHAR_BIT - 1); 00274 00275 frame.control_bit = (control_bit != 0); 00276 00277 if(control_bit){ 00278 00279 // Control bit is set; This is a control frame 00280 00281 // Get the version number 00282 boost::uint16_t two_bytes = algorithm::to_uint16(m_read_ptr); 00283 frame.version = two_bytes & 0x7FFF; 00284 00285 // Increment the read pointer 00286 m_read_ptr += 2; 00287 length_packet -= 2; 00288 http_info.data_offset +=2; 00289 00290 // Get the type 00291 frame.type = algorithm::to_uint16(m_read_ptr); 00292 00293 if (frame.type >= SPDY_INVALID) { 00294 // SPDY Frame is invalid 00295 00296 // This is not a SPDY frame, throw an error 00297 PION_LOG_ERROR(m_logger, "Invalid SPDY Frame"); 00298 set_error(ec, ERROR_INVALID_SPDY_FRAME); 00299 return false; 00300 } 00301 }else { 00302 00303 // Control bit is not set; This is a data frame 00304 00305 frame.type = SPDY_DATA; 00306 frame.version = 0; /* Version doesn't apply to DATA. */ 00307 // Get the stream id 00308 boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); 00309 stream_id = four_bytes & 0x7FFFFFFF; 00310 00311 http_info.stream_id = stream_id; 00312 00313 m_read_ptr +=2; 00314 http_info.data_offset +=2; 00315 length_packet -= 2; 00316 00317 } 00318 00319 // Increment the read pointer 00320 m_read_ptr += 2; 00321 length_packet -= 2; 00322 http_info.data_offset +=2; 00323 00324 // Get the flags 00325 frame.flags = (boost::uint8_t)*m_read_ptr; 00326 00327 // Increment the read pointer 00328 00329 // Get the length 00330 boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); 00331 frame.length = four_bytes & 0xFFFFFF; 00332 00333 // Increment the read pointer 00334 m_read_ptr += 4; 00335 length_packet -= 4; 00336 http_info.data_offset +=4; 00337 00338 http_info.data_size = frame.length; 00339 00340 if(control_bit){ 00341 four_bytes = algorithm::to_uint32(m_read_ptr); 00342 stream_id = four_bytes & 0x7FFFFFFF; 00343 } 00344 00345 return true; 00346 } 00347 00348 void parser::parse_header_payload(boost::system::error_code &ec, 00349 decompressor_ptr& decompressor, 00350 const spdy_control_frame_info& frame, 00351 http_protocol_info& http_info, 00352 boost::uint32_t current_stream_count) 00353 { 00354 boost::uint32_t stream_id = 0; 00355 boost::uint32_t associated_stream_id; 00356 boost::uint32_t header_block_length = frame.length; 00357 00358 // Get the 31 bit stream id 00359 00360 boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); 00361 stream_id = four_bytes & 0x7FFFFFFF; 00362 00363 m_read_ptr += 4; 00364 00365 http_info.stream_id = stream_id; 00366 00367 // Get SYN_STREAM-only fields. 00368 00369 if (frame.type == SPDY_SYN_STREAM) { 00370 00371 // Get associated stream ID. 00372 00373 boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); 00374 associated_stream_id = four_bytes & 0x7FFFFFFF; 00375 00376 m_read_ptr += 4; 00377 00378 // The next bits are priority, unused, and slot. 00379 // Disregard these for now as we dont need them 00380 00381 m_read_ptr +=2 ; 00382 00383 } else if( frame.type == SPDY_SYN_REPLY || frame.type == SPDY_HEADERS ) { 00384 00385 // Unused bits 00386 m_read_ptr +=2 ; 00387 } 00388 00389 // Get our header block length. 00390 00391 switch (frame.type) { 00392 case SPDY_SYN_STREAM: 00393 header_block_length -= 10; 00394 break; 00395 case SPDY_SYN_REPLY: 00396 case SPDY_HEADERS: 00397 // This is a very important distinction. 00398 // It should be 6 bytes for SPDYv2 and 4 bytes for SPDYv3. 00399 header_block_length -= 6; 00400 break; 00401 default: 00402 // Unhandled case. This should never happen. 00403 PION_LOG_ERROR(m_logger, "Invalid SPDY Frame Type"); 00404 set_error(ec, ERROR_INVALID_SPDY_FRAME); 00405 return; 00406 } 00407 00408 // Decompress header block as necessary. 00409 m_uncompressed_ptr = decompressor->decompress(m_read_ptr, 00410 stream_id, 00411 frame, 00412 header_block_length); 00413 00414 if (!m_uncompressed_ptr) { 00415 set_error(ec, ERROR_DECOMPRESSION); 00416 return; 00417 } 00418 00419 // Now parse the name/value pairs 00420 00421 // The number of name/value pairs is 16 bit SPDYv2 00422 // and it is 32 bit in SPDYv3 00423 00424 // TBD : Add support for SPDYv3 00425 boost::uint16_t num_name_val_pairs = algorithm::to_uint16(m_uncompressed_ptr); 00426 00427 m_uncompressed_ptr += 2; 00428 00429 std::string content_type = ""; 00430 std::string content_encoding = ""; 00431 00432 for(boost::uint16_t count = 0; count < num_name_val_pairs; ++count){ 00433 00434 00435 // Get the length of the name 00436 boost::uint16_t length_name = algorithm::to_uint16(m_uncompressed_ptr); 00437 std::string name = ""; 00438 00439 m_uncompressed_ptr += 2; 00440 00441 { 00442 for(boost::uint16_t count = 0; count < length_name; ++count){ 00443 name.push_back(*(m_uncompressed_ptr+count)); 00444 } 00445 m_uncompressed_ptr += length_name; 00446 } 00447 00448 // Get the length of the value 00449 boost::uint16_t length_value = algorithm::to_uint16(m_uncompressed_ptr); 00450 std::string value = ""; 00451 00452 m_uncompressed_ptr += 2; 00453 00454 { 00455 for(boost::uint16_t count = 0; count < length_value; ++count){ 00456 value.push_back(*(m_uncompressed_ptr+count)); 00457 } 00458 m_uncompressed_ptr += length_value; 00459 } 00460 00461 // Save these headers 00462 http_info.http_headers.insert(std::make_pair(name, value)); 00463 } 00464 } 00465 00466 void parser::parse_spdy_data(boost::system::error_code &ec, 00467 const spdy_control_frame_info& frame, 00468 boost::uint32_t stream_id, 00469 http_protocol_info& http_info) 00470 { 00471 // This marks the finish flag 00472 if (frame.flags & SPDY_FLAG_FIN){ 00473 http_info.last_chunk = true; 00474 } 00475 } 00476 00477 void parser::parse_spdy_rst_stream(boost::system::error_code &ec, 00478 const spdy_control_frame_info& frame) 00479 { 00480 boost::uint32_t stream_id = 0; 00481 boost::uint32_t status_code = 0; 00482 00483 // First complete the check for size and flag 00484 // The flag for RST frame should be 0, The length should be 8 00485 if(frame.flags != 0 || frame.length != 8 ){ 00486 return; 00487 } 00488 00489 // Get the 31 bit stream id 00490 00491 boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); 00492 stream_id = four_bytes & 0x7FFFFFFF; 00493 00494 m_read_ptr += 4; 00495 00496 // Get the status code 00497 00498 status_code = algorithm::to_uint32(m_read_ptr); 00499 00500 char const* const status_code_str = rst_stream_status(status_code); 00501 if(status_code_str){ 00502 PION_LOG_INFO(m_logger, "SPDY Status Code is : " << status_code_str); 00503 }else{ 00504 PION_LOG_INFO(m_logger, "SPDY RST Invalid status code : " << status_code); 00505 } 00506 } 00507 00508 void parser::parse_spdy_ping_frame(boost::system::error_code &ec, 00509 const spdy_control_frame_info& frame) 00510 { 00511 // First complete the check for size 00512 // The length should be 4 always 00513 if(frame.length != 4){ 00514 return; 00515 } 00516 00517 boost::uint32_t ping_id = 0; 00518 00519 // Get the 32 bit ping id 00520 00521 ping_id = algorithm::to_uint32(m_read_ptr); 00522 00523 m_read_ptr += 4; 00524 00525 PION_LOG_INFO(m_logger, "SPDY " << "Ping ID is : " << ping_id); 00526 } 00527 00528 void parser::parse_spdy_settings_frame(boost::system::error_code &ec, 00529 const spdy_control_frame_info& frame) 00530 { 00531 // Can ignore this frame for our purposes 00532 } 00533 00534 void parser::parse_spdy_goaway_frame(boost::system::error_code &ec, 00535 const spdy_control_frame_info& frame) 00536 { 00537 // First complete the check for size 00538 // The length should be 4 always 00539 if(frame.length != 4){ 00540 return; 00541 } 00542 00543 boost::uint32_t last_good_stream_id = 0; 00544 boost::uint32_t status_code = 0; 00545 00546 // Get the 31 bit stream id 00547 00548 boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr); 00549 last_good_stream_id = four_bytes & 0x7FFFFFFF; 00550 00551 m_read_ptr += 4; 00552 00553 // Get the status code 00554 00555 status_code = algorithm::to_uint32(m_read_ptr); 00556 00557 // Chek if there was an error 00558 if(status_code == 1){ 00559 00560 PION_LOG_ERROR(m_logger, "There was a Protocol Error"); 00561 set_error(ec, ERROR_PROTOCOL_ERROR); 00562 return; 00563 }else if (status_code == 11) { 00564 00565 PION_LOG_ERROR(m_logger, "There was an Internal Error"); 00566 set_error(ec, ERROR_INTERNAL_SPDY_ERROR); 00567 return; 00568 } 00569 00570 PION_LOG_INFO(m_logger, "SPDY " << "Status Code is : " << status_code); 00571 00572 } 00573 00574 void parser::parse_spdy_window_update_frame(boost::system::error_code &ec, 00575 const spdy_control_frame_info& frame) 00576 { 00577 // TBD : Do we really need this for our purpose 00578 } 00579 00580 } // end namespace spdy 00581 } // end namespace pion