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 
00023 
00024 parser::error_category_t *  parser::m_error_category_ptr = NULL;
00025 boost::once_flag            parser::m_instance_flag = BOOST_ONCE_INIT;
00026 
00027 
00028 
00029 parser::parser()
00030     : m_read_ptr(NULL),
00031     m_uncompressed_ptr(NULL),
00032     m_current_data_chunk_ptr(NULL),
00033     m_last_data_chunk_ptr(NULL),
00034     m_logger(PION_GET_LOGGER("pion.spdy.parser"))
00035 {}
00036 
00037 boost::tribool parser::parse(http_protocol_info& http_info,
00038                              boost::system::error_code& ec,
00039                              decompressor_ptr& decompressor,
00040                              const char *packet_ptr,
00041                              boost::uint32_t& length_packet,
00042                              boost::uint32_t current_stream_count)
00043 {
00044     
00045     set_read_ptr(packet_ptr);
00046     
00047     
00048     return parse_spdy_frame(ec, decompressor, http_info, length_packet, current_stream_count);
00049 }
00050 
00051 bool parser::is_spdy_control_frame(const char *ptr)
00052 {
00053     
00054     
00055     
00056     boost::uint8_t control_bit;
00057     boost::uint16_t version, type;
00058     boost::uint16_t byte_value = algorithm::to_uint16(ptr);
00059     control_bit = byte_value >> (sizeof(short) * CHAR_BIT - 1);
00060 
00061     if (!control_bit) return false;
00062     
00063     
00064     
00065     
00066     boost::uint16_t two_bytes = algorithm::to_uint16(ptr);
00067     version = two_bytes & 0x7FFF;
00068     
00069     if(version < 1 || version > 3){
00070         
00071         return false;
00072     }
00073     
00074     
00075     ptr += 2;
00076     
00077     type = algorithm::to_uint16(ptr);
00078     
00079     if (type >= SPDY_INVALID) {
00080         
00081         return false;
00082     }
00083     
00084     return true;
00085 }
00086 
00087 spdy_frame_type parser::get_spdy_frame_type(const char *ptr)
00088 {
00089     
00090     BOOST_ASSERT(ptr);
00091 
00092     
00093 
00094 
00095 
00096 
00097 
00098 
00099 
00100     
00101     spdy_frame_type spdy_frame;
00102     boost::uint8_t first_byte = *((unsigned char *)ptr);
00103     if(first_byte == 0x80){
00104         spdy_frame = spdy_control_frame;
00105     }else if(first_byte == 0x0){
00106         spdy_frame = spdy_data_frame;
00107     }else{
00108         spdy_frame = spdy_invalid_frame;
00109     }
00110     return spdy_frame;
00111 }
00112     
00113 boost::uint32_t parser::get_control_frame_stream_id(const char *ptr)
00114 {
00115     
00116     ptr += 8;
00117 
00118     boost::uint32_t four_bytes = algorithm::to_uint32(ptr);
00119     return four_bytes & 0x7FFFFFFF;
00120 }
00121     
00122 boost::tribool parser::parse_spdy_frame(boost::system::error_code& ec,
00123                                         decompressor_ptr& decompressor,
00124                                         http_protocol_info& http_info,
00125                                         boost::uint32_t& length_packet,
00126                                         boost::uint32_t current_stream_count)
00127 {
00128     boost::tribool rc = true;
00129     
00130     
00131     
00132     BOOST_ASSERT(m_read_ptr);
00133     boost::uint8_t first_byte = (boost::uint8_t)*m_read_ptr;
00134     if (first_byte != 0x80 && first_byte != 0x0) {
00135         
00136         PION_LOG_ERROR(m_logger, "Invalid SPDY Frame");
00137         set_error(ec, ERROR_INVALID_SPDY_FRAME);
00138         return false;
00139     }
00140     
00141     boost::uint8_t              control_bit;
00142     spdy_control_frame_info     frame;
00143     boost::uint32_t             stream_id = 0;
00144     
00145     ec.clear();
00146 
00147     
00148     bool populate_frame_result = populate_frame(ec, frame, length_packet, stream_id, http_info);
00149     
00150     if(!populate_frame_result){
00152         return false;
00153     }
00154     
00155     BOOST_ASSERT(stream_id != 0);
00156     
00157     control_bit = (boost::uint8_t)frame.control_bit;
00158     
00159     
00160     if(length_packet > frame.length){
00161         m_current_data_chunk_ptr = m_read_ptr + frame.length;
00162         length_packet -= frame.length;
00163         rc = boost::indeterminate;
00164     }
00165     
00166     if (!control_bit) {
00167         
00168         parse_spdy_data(ec, frame, stream_id, http_info);
00169     }
00170     
00171     
00172     
00173     if (frame.version > MIN_SPDY_VERSION) {
00174         
00175         PION_LOG_ERROR(m_logger, "Invalid SPDY Version Number");
00176         set_error(ec, ERROR_INVALID_SPDY_VERSION);
00177         return false;
00178     }
00179     
00180     if(frame.type ==  SPDY_SYN_STREAM){
00181         http_info.http_type = HTTP_REQUEST;
00182     }else if (frame.type == SPDY_SYN_REPLY){
00183         http_info.http_type = HTTP_RESPONSE;
00184     }else if (frame.type == SPDY_DATA){
00185         http_info.http_type = HTTP_DATA;
00186     }
00187 
00188     switch (frame.type) {
00189         case SPDY_SYN_STREAM:
00190         case SPDY_SYN_REPLY:
00191         case SPDY_HEADERS:
00192             parse_header_payload(ec, decompressor, frame, http_info, current_stream_count);
00193             break;
00194             
00195         case SPDY_RST_STREAM:
00196             parse_spdy_rst_stream(ec, frame);
00197             http_info.http_type = SPDY_CONTROL;
00198             break;
00199             
00200         case SPDY_SETTINGS:
00201             parse_spdy_settings_frame(ec, frame);
00202             http_info.http_type = SPDY_CONTROL;
00203             break;
00204             
00205         case SPDY_PING:
00206             parse_spdy_ping_frame(ec, frame);
00207             http_info.http_type = SPDY_CONTROL;
00208             break;
00209             
00210         case SPDY_GOAWAY:
00211             parse_spdy_goaway_frame(ec, frame);
00212             http_info.http_type = SPDY_CONTROL;
00213             break;
00214             
00215         case SPDY_WINDOW_UPDATE:
00216             parse_spdy_window_update_frame(ec, frame);
00217             http_info.http_type = SPDY_CONTROL;
00218             break;
00219             
00220         case SPDY_CREDENTIAL:
00221             
00222             http_info.http_type = SPDY_CONTROL;
00223             break;
00224             
00225         default:
00226             break;
00227     }
00228     
00229     if (ec)
00230         return false;
00231     
00232     m_last_data_chunk_ptr = m_read_ptr;
00233     m_read_ptr = m_current_data_chunk_ptr;
00234     
00235     return rc;
00236 }
00237 
00238 void parser::create_error_category(void)
00239 {
00240     static error_category_t UNIQUE_ERROR_CATEGORY;
00241     m_error_category_ptr = &UNIQUE_ERROR_CATEGORY;
00242 }
00243 
00244 bool parser::populate_frame(boost::system::error_code& ec,
00245                             spdy_control_frame_info& frame,
00246                             boost::uint32_t& length_packet,
00247                             boost::uint32_t& stream_id,
00248                             http_protocol_info& http_info)
00249 {
00250     
00251     boost::uint8_t control_bit;
00252     boost::uint16_t byte_value = algorithm::to_uint16(m_read_ptr);
00253     control_bit = byte_value >> (sizeof(short) * CHAR_BIT - 1);
00254     
00255     frame.control_bit = (bool)control_bit;
00256     
00257     if(control_bit){
00258         
00259         
00260         
00261         
00262         boost::uint16_t two_bytes = algorithm::to_uint16(m_read_ptr);
00263         frame.version = two_bytes & 0x7FFF;
00264         
00265         
00266         m_read_ptr += 2;
00267         length_packet -= 2;
00268         http_info.data_offset +=2;
00269         
00270         
00271         frame.type = algorithm::to_uint16(m_read_ptr);
00272         
00273         if (frame.type >= SPDY_INVALID) {
00274             
00275             
00276             
00277             PION_LOG_ERROR(m_logger, "Invalid SPDY Frame");
00278             set_error(ec, ERROR_INVALID_SPDY_FRAME);
00279             return false;
00280         }
00281     }else {
00282         
00283         
00284         
00285         frame.type = SPDY_DATA;
00286         frame.version = 0; 
00287         
00288         boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr);
00289         stream_id = four_bytes & 0x7FFFFFFF;
00290         
00291         http_info.stream_id = stream_id;
00292         
00293         m_read_ptr +=2;
00294         http_info.data_offset +=2;
00295         length_packet -= 2;
00296         
00297     }
00298     
00299     
00300     m_read_ptr += 2;
00301     length_packet -= 2;
00302     http_info.data_offset +=2;
00303     
00304     
00305     frame.flags = (boost::uint8_t)*m_read_ptr;
00306     
00307     
00308     
00309     
00310     boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr);
00311     frame.length = four_bytes & 0xFFFFFF;
00312     
00313     
00314     m_read_ptr += 4;
00315     length_packet -= 4;
00316     http_info.data_offset +=4;
00317     
00318     http_info.data_size = frame.length;
00319     
00320     if(control_bit){
00321         four_bytes = algorithm::to_uint32(m_read_ptr);
00322         stream_id = four_bytes & 0x7FFFFFFF;
00323     }
00324     
00325     return true;
00326 }
00327 
00328 void parser::parse_header_payload(boost::system::error_code &ec,
00329                                   decompressor_ptr& decompressor,
00330                                   const spdy_control_frame_info& frame,
00331                                   http_protocol_info& http_info,
00332                                   boost::uint32_t current_stream_count)
00333 {
00334     boost::uint32_t stream_id = 0;
00335     boost::uint32_t associated_stream_id;
00336     boost::uint32_t header_block_length = frame.length;
00337     
00338     
00339     
00340     boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr);
00341     stream_id = four_bytes & 0x7FFFFFFF;
00342     
00343     m_read_ptr += 4;
00344     
00345     http_info.stream_id = stream_id;
00346     
00347     
00348     
00349     if (frame.type == SPDY_SYN_STREAM) {
00350         
00351         
00352         
00353         boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr);
00354         associated_stream_id = four_bytes & 0x7FFFFFFF;
00355         
00356         m_read_ptr += 4;
00357         
00358         
00359         
00360         
00361         m_read_ptr +=2 ;
00362         
00363     } else if( frame.type == SPDY_SYN_REPLY || frame.type == SPDY_HEADERS ) {
00364         
00365         
00366         m_read_ptr +=2 ;
00367     }
00368     
00369     
00370     
00371     switch (frame.type) {
00372         case SPDY_SYN_STREAM:
00373             header_block_length -= 10;
00374             break;
00375         case SPDY_SYN_REPLY:
00376         case SPDY_HEADERS:
00377             
00378             
00379             header_block_length -= 6;
00380             break;
00381         default:
00382             
00383             PION_LOG_ERROR(m_logger, "Invalid SPDY Frame Type");
00384             set_error(ec, ERROR_INVALID_SPDY_FRAME);
00385             return;
00386     }
00387     
00388     
00389     m_uncompressed_ptr = decompressor->decompress(m_read_ptr,
00390                                                   stream_id,
00391                                                   frame,
00392                                                   header_block_length);
00393     
00394     if (!m_uncompressed_ptr) {
00395         set_error(ec, ERROR_DECOMPRESSION);
00396         return;
00397     }
00398         
00399     
00400     
00401     
00402     
00403     
00404     
00405     boost::uint16_t num_name_val_pairs = algorithm::to_uint16(m_uncompressed_ptr);
00406     
00407     m_uncompressed_ptr += 2;
00408     
00409     std::string content_type = "";
00410     std::string content_encoding = "";
00411     
00412     for(boost::uint16_t count = 0; count < num_name_val_pairs; ++count){
00413         
00414         
00415         
00416         boost::uint16_t length_name = algorithm::to_uint16(m_uncompressed_ptr);
00417         std::string name = "";
00418         
00419         m_uncompressed_ptr += 2;
00420         
00421         {
00422             for(boost::uint16_t count = 0; count < length_name; ++count){
00423                 name.push_back(*(m_uncompressed_ptr+count));
00424             }
00425             m_uncompressed_ptr += length_name;
00426         }
00427         
00428         
00429         boost::uint16_t length_value = algorithm::to_uint16(m_uncompressed_ptr);
00430         std::string value = "";
00431         
00432         m_uncompressed_ptr += 2;
00433         
00434         {
00435             for(boost::uint16_t count = 0; count < length_value; ++count){
00436                 value.push_back(*(m_uncompressed_ptr+count));
00437             }
00438             m_uncompressed_ptr += length_value;
00439         }
00440         
00441         
00442         http_info.http_headers.insert(std::make_pair(name, value));
00443     }
00444 }
00445 
00446 void parser::parse_spdy_data(boost::system::error_code &ec,
00447                              const spdy_control_frame_info& frame,
00448                              boost::uint32_t stream_id,
00449                              http_protocol_info& http_info)
00450 {
00451     
00452     if (frame.flags & SPDY_FLAG_FIN){
00453         http_info.last_chunk = true;
00454     }
00455 }
00456 
00457 void parser::parse_spdy_rst_stream(boost::system::error_code &ec,
00458                                    const spdy_control_frame_info& frame)
00459 {
00460     boost::uint32_t stream_id = 0;
00461     boost::uint32_t status_code = 0;
00462     
00463     
00464     
00465     if(frame.flags != 0 || frame.length != 8 ){
00466         return;
00467     }
00468 
00469     
00470     
00471     boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr);
00472     stream_id = four_bytes & 0x7FFFFFFF;
00473     
00474     m_read_ptr += 4;
00475     
00476     
00477     
00478     status_code = algorithm::to_uint32(m_read_ptr);
00479     
00480     
00481     
00482     if(status_code >=1 && status_code <= 12){
00483     
00484         PION_LOG_INFO(m_logger,
00485                       "SPDY " << "Status Code is : "
00486                       << rst_stream_status_names[status_code].str);
00487     }else{
00488         PION_LOG_INFO(m_logger, "SPDY RST Invalid status code : " << status_code);
00489     }
00490 }
00491 
00492 void parser::parse_spdy_ping_frame(boost::system::error_code &ec,
00493                                    const spdy_control_frame_info& frame)
00494 {
00495     
00496     
00497     if(frame.length != 4){
00498         return;
00499     }
00500   
00501     boost::uint32_t ping_id = 0;
00502     
00503     
00504     
00505     ping_id = algorithm::to_uint32(m_read_ptr);
00506     
00507     m_read_ptr += 4;
00508     
00509     PION_LOG_INFO(m_logger, "SPDY " << "Ping ID is : " << ping_id);
00510 }
00511 
00512 void parser::parse_spdy_settings_frame(boost::system::error_code &ec,
00513                                        const spdy_control_frame_info& frame)
00514 {
00515     
00516 }
00517 
00518 void parser::parse_spdy_goaway_frame(boost::system::error_code &ec,
00519                                      const spdy_control_frame_info& frame)
00520 {
00521     
00522     
00523     if(frame.length != 4){
00524         return;
00525     }
00526     
00527     boost::uint32_t last_good_stream_id = 0;
00528     boost::uint32_t status_code = 0;
00529     
00530     
00531     
00532     boost::uint32_t four_bytes = algorithm::to_uint32(m_read_ptr);
00533     last_good_stream_id = four_bytes & 0x7FFFFFFF;
00534     
00535     m_read_ptr += 4;
00536     
00537     
00538     
00539     status_code = algorithm::to_uint32(m_read_ptr);
00540     
00541     
00542     if(status_code == 1){
00543         
00544         PION_LOG_ERROR(m_logger, "There was a Protocol Error");
00545         set_error(ec, ERROR_PROTOCOL_ERROR);
00546         return;
00547     }else if (status_code == 11) {
00548         
00549         PION_LOG_ERROR(m_logger, "There was an Internal Error");
00550         set_error(ec, ERROR_INTERNAL_SPDY_ERROR);
00551         return;
00552     }
00553     
00554     PION_LOG_INFO(m_logger, "SPDY " << "Status Code is : " << status_code);
00555     
00556 }
00557 
00558 void parser::parse_spdy_window_update_frame(boost::system::error_code &ec,
00559                                             const spdy_control_frame_info& frame)
00560 {
00561     
00562 }
00563     
00564 }   
00565 }