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 <zlib.h> 00012 #include <iostream> 00013 #include <fstream> 00014 #include <boost/asio/detail/socket_ops.hpp> 00015 #include <pion/spdy/decompressor.hpp> 00016 00017 00018 namespace pion { // begin namespace pion 00019 namespace spdy { // begin namespace spdy 00020 00021 00022 // decompressor static members 00023 00024 const char decompressor::SPDY_ZLIB_DICTIONARY[] = 00025 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" 00026 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" 00027 "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" 00028 "-agent10010120020120220320420520630030130230330430530630740040140240340440" 00029 "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" 00030 "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" 00031 "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" 00032 "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" 00033 "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" 00034 "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" 00035 "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" 00036 "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" 00037 ".1statusversionurl"; 00038 00039 00040 // decompressor member functions 00041 00042 decompressor::decompressor() 00043 : m_request_zstream(NULL), m_response_zstream(NULL) 00044 { 00045 m_request_zstream = (z_streamp)malloc(sizeof(z_stream)); 00046 BOOST_ASSERT(m_request_zstream); 00047 00048 m_request_zstream->zalloc = Z_NULL; 00049 m_request_zstream->zfree = Z_NULL; 00050 m_request_zstream->opaque = Z_NULL; 00051 m_request_zstream->next_in = Z_NULL; 00052 m_request_zstream->next_out = Z_NULL; 00053 m_request_zstream->avail_in = 0; 00054 m_request_zstream->avail_out = 0; 00055 00056 m_response_zstream = (z_streamp)malloc(sizeof(z_stream)); 00057 BOOST_ASSERT(m_response_zstream); 00058 00059 m_response_zstream->zalloc = Z_NULL; 00060 m_response_zstream->zfree = Z_NULL; 00061 m_response_zstream->opaque = Z_NULL; 00062 m_response_zstream->next_in = Z_NULL; 00063 m_response_zstream->next_out = Z_NULL; 00064 m_response_zstream->avail_in = 0; 00065 m_response_zstream->avail_out = 0; 00066 00067 int retcode = inflateInit2(m_request_zstream, MAX_WBITS); 00068 if (retcode == Z_OK) { 00069 retcode = inflateInit2(m_response_zstream, MAX_WBITS); 00070 if (retcode == Z_OK) { 00071 // Get the dictionary id 00072 m_dictionary_id = adler32(0L, Z_NULL, 0); 00073 00074 m_dictionary_id = adler32(m_dictionary_id, 00075 (const Bytef *)SPDY_ZLIB_DICTIONARY, 00076 sizeof(SPDY_ZLIB_DICTIONARY)); 00077 } 00078 } 00079 } 00080 00081 decompressor::~decompressor() 00082 { 00083 inflateEnd(m_request_zstream); 00084 inflateEnd(m_response_zstream); 00085 free(m_request_zstream); 00086 free(m_response_zstream); 00087 } 00088 00089 char* decompressor::decompress(const char *compressed_data_ptr, 00090 boost::uint32_t stream_id, 00091 const spdy_control_frame_info& frame, 00092 boost::uint32_t header_block_length) 00093 { 00095 z_streamp decomp = NULL; 00096 if (stream_id % 2 == 0) { 00097 // Even streams are server-initiated and should never get a 00098 // client-initiated header block. Use reply decompressor. 00099 decomp = m_response_zstream; 00100 } else if (frame.type == SPDY_HEADERS) { 00101 // Odd streams are client-initiated, but may have HEADERS from either 00102 // side. Currently, no known clients send HEADERS so we assume they are 00103 // all from the server. 00104 decomp = m_response_zstream; 00105 } else if (frame.type == SPDY_SYN_STREAM) { 00106 decomp = m_request_zstream; 00107 } else if (frame.type == SPDY_SYN_REPLY) { 00108 decomp = m_response_zstream; 00109 } else { 00110 // Unhandled case. This should never happen. 00111 BOOST_ASSERT(false); 00112 } 00113 BOOST_ASSERT(decomp); 00114 00115 // Decompress the data 00116 boost::uint32_t uncomp_length = 0; 00117 00118 // Catch decompression failures. 00119 if (!spdy_decompress_header(compressed_data_ptr, decomp, 00120 header_block_length, uncomp_length)) 00121 { 00122 // Error in decompressing 00123 // This error is not catastrophic as many times we might get inconsistent 00124 // spdy header frames and we should just log error and continue. 00125 // No need to call SetError() 00126 return NULL; 00127 } 00128 return reinterpret_cast<char*>(m_uncompressed_header); 00129 } 00130 00131 bool decompressor::spdy_decompress_header(const char *compressed_data_ptr, 00132 z_streamp decomp, 00133 boost::uint32_t length, 00134 boost::uint32_t& uncomp_length) { 00135 int retcode; 00136 const boost::uint8_t *hptr = (boost::uint8_t *)compressed_data_ptr; 00137 00138 decomp->next_in = (Bytef *)hptr; 00139 decomp->avail_in = length; 00140 decomp->next_out = m_uncompressed_header; 00141 decomp->avail_out = MAX_UNCOMPRESSED_DATA_BUF_SIZE; 00142 00143 retcode = inflate(decomp, Z_SYNC_FLUSH); 00144 00145 if (retcode == Z_NEED_DICT) { 00146 if (decomp->adler != m_dictionary_id) { 00147 // Decompressor wants a different dictionary id 00148 } else { 00149 retcode = inflateSetDictionary(decomp, 00150 (const Bytef *)SPDY_ZLIB_DICTIONARY, 00151 sizeof(SPDY_ZLIB_DICTIONARY)); 00152 if (retcode == Z_OK) { 00153 retcode = inflate(decomp, Z_SYNC_FLUSH); 00154 } 00155 } 00156 } 00157 00158 // Handle Errors. 00159 if (retcode != Z_OK) { 00160 // This error is not catastrophic as many times we might get inconsistent 00161 // spdy header frames and we should just log error and continue. 00162 // No need to call SetError() 00163 return false; 00164 } 00165 00166 // Handle successful inflation. 00167 uncomp_length = MAX_UNCOMPRESSED_DATA_BUF_SIZE - decomp->avail_out; 00168 if (decomp->avail_in != 0) { 00169 // Error condition 00170 // This error is not catastrophic as many times we might get inconsistent 00171 // spdy header frames and we should just log error and continue. 00172 // No need to call SetError() 00173 return false; 00174 } 00175 00176 return true; 00177 } 00178 00179 } // end namespace spdy 00180 } // end namespace pion