1
// ---------------------------------------------------------------------
2
// pion: a Boost C++ framework for building lightweight HTTP interfaces
3
// ---------------------------------------------------------------------
4
// Copyright (C) 2007-2012 Cloudmeter, Inc. (http://www.cloudmeter.com)
6
// Distributed under the Boost Software License, Version 1.0.
7
// See http://www.boost.org/LICENSE_1_0.txt
14
#include <boost/asio/detail/socket_ops.hpp>
15
#include <pion/spdy/decompressor.hpp>
18
namespace pion { // begin namespace pion
19
namespace spdy { // begin namespace spdy
22
// decompressor static members
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"
40
// decompressor member functions
42
decompressor::decompressor()
43
: m_request_zstream(NULL), m_response_zstream(NULL)
45
m_request_zstream = (z_streamp)malloc(sizeof(z_stream));
46
BOOST_ASSERT(m_request_zstream);
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;
56
m_response_zstream = (z_streamp)malloc(sizeof(z_stream));
57
BOOST_ASSERT(m_response_zstream);
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;
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);
74
m_dictionary_id = adler32(m_dictionary_id,
75
(const Bytef *)SPDY_ZLIB_DICTIONARY,
76
sizeof(SPDY_ZLIB_DICTIONARY));
81
decompressor::~decompressor()
83
inflateEnd(m_request_zstream);
84
inflateEnd(m_response_zstream);
85
free(m_request_zstream);
86
free(m_response_zstream);
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)
94
/// Get our decompressor.
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;
110
// Unhandled case. This should never happen.
113
BOOST_ASSERT(decomp);
115
// Decompress the data
116
boost::uint32_t uncomp_length = 0;
118
// Catch decompression failures.
119
if (!spdy_decompress_header(compressed_data_ptr, decomp,
120
header_block_length, uncomp_length))
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()
128
return reinterpret_cast<char*>(m_uncompressed_header);
131
bool decompressor::spdy_decompress_header(const char *compressed_data_ptr,
133
boost::uint32_t length,
134
boost::uint32_t& uncomp_length) {
136
const boost::uint8_t *hptr = (boost::uint8_t *)compressed_data_ptr;
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;
143
retcode = inflate(decomp, Z_SYNC_FLUSH);
145
if (retcode == Z_NEED_DICT) {
146
if (decomp->adler != m_dictionary_id) {
147
// Decompressor wants a different dictionary id
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);
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()
166
// Handle successful inflation.
167
uncomp_length = MAX_UNCOMPRESSED_DATA_BUF_SIZE - decomp->avail_out;
168
if (decomp->avail_in != 0) {
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()
179
} // end namespace spdy
180
} // end namespace pion