00001
00002
00003
00004
00005
00006
00007
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 {
00021 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
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
00065 set_read_ptr(packet_ptr);
00066
00067
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
00074
00075
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
00084
00085
00086 boost::uint16_t two_bytes = algorithm::to_uint16(ptr);
00087 version = two_bytes & 0x7FFF;
00088
00089 if(version < 1 || version > 3){
00090
00091 return false;
00092 }
00093
00094
00095 ptr += 2;
00096
00097 type = algorithm::to_uint16(ptr);
00098
00099 if (type >= SPDY_INVALID) {
00100
00101 return false;
00102 }
00103
00104 return true;
00105 }
00106
00107 spdy_frame_type parser::get_spdy_frame_type(const char *ptr)
00108 {
00109
00110 BOOST_ASSERT(ptr);
00111
00112
00113
00114
00115
00116
00117
00118
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
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
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
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
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
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
00188 parse_spdy_data(ec, frame, stream_id, http_info);
00189 }
00190
00191
00192
00193 if (frame.version > MIN_SPDY_VERSION) {
00194
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
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
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
00280
00281
00282 boost::uint16_t two_bytes = algorithm::to_uint16(m_read_ptr);
00283 frame.version = two_bytes & 0x7FFF;
00284
00285
00286 m_read_ptr += 2;
00287 length_packet -= 2;
00288 http_info.data_offset +=2;
00289
00290
00291 frame.type = algorithm::to_uint16(m_read_ptr);
00292
00293 if (frame.type >= SPDY_INVALID) {
00294
00295
00296
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
00304
00305 frame.type = SPDY_DATA;
00306 frame.version = 0;
00307
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
00320 m_read_ptr += 2;
00321 length_packet -= 2;
00322 http_info.data_offset +=2;
00323
00324
00325 frame.flags = (boost::uint8_t)*m_read_ptr;
00326
00327
00328
00329
00330 boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr);
00331 frame.length = four_bytes & 0xFFFFFF;
00332
00333
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
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
00368
00369 if (frame.type == SPDY_SYN_STREAM) {
00370
00371
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
00379
00380
00381 m_read_ptr +=2 ;
00382
00383 } else if( frame.type == SPDY_SYN_REPLY || frame.type == SPDY_HEADERS ) {
00384
00385
00386 m_read_ptr +=2 ;
00387 }
00388
00389
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
00398
00399 header_block_length -= 6;
00400 break;
00401 default:
00402
00403 PION_LOG_ERROR(m_logger, "Invalid SPDY Frame Type");
00404 set_error(ec, ERROR_INVALID_SPDY_FRAME);
00405 return;
00406 }
00407
00408
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
00420
00421
00422
00423
00424
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
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
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
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
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
00484
00485 if(frame.flags != 0 || frame.length != 8 ){
00486 return;
00487 }
00488
00489
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
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
00512
00513 if(frame.length != 4){
00514 return;
00515 }
00516
00517 boost::uint32_t ping_id = 0;
00518
00519
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
00532 }
00533
00534 void parser::parse_spdy_goaway_frame(boost::system::error_code &ec,
00535 const spdy_control_frame_info& frame)
00536 {
00537
00538
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
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
00554
00555 status_code = algorithm::to_uint32(m_read_ptr);
00556
00557
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
00578 }
00579
00580 }
00581 }