- Main Page
- Classes
- Files

- File List

# src/spdy_decompressor.cpp

    00001 // ---------------------------------------------------------------------
    00002 // pion:  a Boost C++ framework for building lightweight HTTP interfaces
    00003 // ---------------------------------------------------------------------
    00004 // Copyright (C) 2007-2012 Cloudmeter, Inc.  (http://www.cloudmeter.com)
    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