pion  5.0.6
spdy_decompressor.cpp
1 // ---------------------------------------------------------------------
2 // pion: a Boost C++ framework for building lightweight HTTP interfaces
3 // ---------------------------------------------------------------------
4 // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion)
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
8 //
9 
10 #include <cstdlib>
11 #include <zlib.h>
12 #include <iostream>
13 #include <fstream>
14 #include <boost/asio/detail/socket_ops.hpp>
15 #include <pion/spdy/decompressor.hpp>
16 
17 
18 namespace pion { // begin namespace pion
19 namespace spdy { // begin namespace spdy
20 
21 
22 // decompressor static members
23 
24 const char decompressor::SPDY_ZLIB_DICTIONARY[] =
25  "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
26  "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
27  "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
28  "-agent10010120020120220320420520630030130230330430530630740040140240340440"
29  "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
30  "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
31  "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
32  "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
33  "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
34  "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
35  "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
36  "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
37  ".1statusversionurl";
38 
39 
40 // decompressor member functions
41 
43  : m_request_zstream(NULL), m_response_zstream(NULL)
44 {
45  m_request_zstream = (z_streamp)malloc(sizeof(z_stream));
46  BOOST_ASSERT(m_request_zstream);
47 
48  m_request_zstream->zalloc = Z_NULL;
49  m_request_zstream->zfree = Z_NULL;
50  m_request_zstream->opaque = Z_NULL;
51  m_request_zstream->next_in = Z_NULL;
52  m_request_zstream->next_out = Z_NULL;
53  m_request_zstream->avail_in = 0;
54  m_request_zstream->avail_out = 0;
55 
56  m_response_zstream = (z_streamp)malloc(sizeof(z_stream));
57  BOOST_ASSERT(m_response_zstream);
58 
59  m_response_zstream->zalloc = Z_NULL;
60  m_response_zstream->zfree = Z_NULL;
61  m_response_zstream->opaque = Z_NULL;
62  m_response_zstream->next_in = Z_NULL;
63  m_response_zstream->next_out = Z_NULL;
64  m_response_zstream->avail_in = 0;
65  m_response_zstream->avail_out = 0;
66 
67  int retcode = inflateInit2(m_request_zstream, MAX_WBITS);
68  if (retcode == Z_OK) {
69  retcode = inflateInit2(m_response_zstream, MAX_WBITS);
70  if (retcode == Z_OK) {
71  // Get the dictionary id
72  m_dictionary_id = adler32(0L, Z_NULL, 0);
73 
74  m_dictionary_id = adler32(m_dictionary_id,
75  (const Bytef *)SPDY_ZLIB_DICTIONARY,
76  sizeof(SPDY_ZLIB_DICTIONARY));
77  }
78  }
79 }
80 
82 {
83  inflateEnd(m_request_zstream);
84  inflateEnd(m_response_zstream);
85  free(m_request_zstream);
86  free(m_response_zstream);
87 }
88 
89 char* decompressor::decompress(const char *compressed_data_ptr,
90  boost::uint32_t stream_id,
91  const spdy_control_frame_info& frame,
92  boost::uint32_t header_block_length)
93 {
95  z_streamp decomp = NULL;
96  if (stream_id % 2 == 0) {
97  // Even streams are server-initiated and should never get a
98  // client-initiated header block. Use reply decompressor.
99  decomp = m_response_zstream;
100  } else if (frame.type == SPDY_HEADERS) {
101  // Odd streams are client-initiated, but may have HEADERS from either
102  // side. Currently, no known clients send HEADERS so we assume they are
103  // all from the server.
104  decomp = m_response_zstream;
105  } else if (frame.type == SPDY_SYN_STREAM) {
106  decomp = m_request_zstream;
107  } else if (frame.type == SPDY_SYN_REPLY) {
108  decomp = m_response_zstream;
109  } else {
110  // Unhandled case. This should never happen.
111  BOOST_ASSERT(false);
112  }
113  BOOST_ASSERT(decomp);
114 
115  // Decompress the data
116  boost::uint32_t uncomp_length = 0;
117 
118  // Catch decompression failures.
119  if (!spdy_decompress_header(compressed_data_ptr, decomp,
120  header_block_length, uncomp_length))
121  {
122  // Error in decompressing
123  // This error is not catastrophic as many times we might get inconsistent
124  // spdy header frames and we should just log error and continue.
125  // No need to call SetError()
126  return NULL;
127  }
128  return reinterpret_cast<char*>(m_uncompressed_header);
129 }
130 
131 bool decompressor::spdy_decompress_header(const char *compressed_data_ptr,
132  z_streamp decomp,
133  boost::uint32_t length,
134  boost::uint32_t& uncomp_length) {
135  int retcode;
136  const boost::uint8_t *hptr = (boost::uint8_t *)compressed_data_ptr;
137 
138  decomp->next_in = (Bytef *)hptr;
139  decomp->avail_in = length;
140  decomp->next_out = m_uncompressed_header;
141  decomp->avail_out = MAX_UNCOMPRESSED_DATA_BUF_SIZE;
142 
143  retcode = inflate(decomp, Z_SYNC_FLUSH);
144 
145  if (retcode == Z_NEED_DICT) {
146  if (decomp->adler != m_dictionary_id) {
147  // Decompressor wants a different dictionary id
148  } else {
149  retcode = inflateSetDictionary(decomp,
150  (const Bytef *)SPDY_ZLIB_DICTIONARY,
151  sizeof(SPDY_ZLIB_DICTIONARY));
152  if (retcode == Z_OK) {
153  retcode = inflate(decomp, Z_SYNC_FLUSH);
154  }
155  }
156  }
157 
158  // Handle Errors.
159  if (retcode != Z_OK) {
160  // This error is not catastrophic as many times we might get inconsistent
161  // spdy header frames and we should just log error and continue.
162  // No need to call SetError()
163  return false;
164  }
165 
166  // Handle successful inflation.
167  uncomp_length = MAX_UNCOMPRESSED_DATA_BUF_SIZE - decomp->avail_out;
168  if (decomp->avail_in != 0) {
169  // Error condition
170  // This error is not catastrophic as many times we might get inconsistent
171  // spdy header frames and we should just log error and continue.
172  // No need to call SetError()
173  return false;
174  }
175 
176  return true;
177 }
178 
179 } // end namespace spdy
180 } // end namespace pion
char * decompress(const char *compressed_data_ptr, boost::uint32_t stream_id, const spdy_control_frame_info &frame, boost::uint32_t header_block_length)
maximum size of an uncompressed spdy header
bool spdy_decompress_header(const char *compressed_data_ptr, z_streamp decomp, boost::uint32_t length, boost::uint32_t &uncomp_length)
This structure will be tied to each SPDY frame.
Definition: types.hpp:48
decompressor()
constructs a new decompressor object (default constructor)