gzip_source_stream.cc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/filter/gzip_source_stream.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/bit_cast.h"
  10. #include "base/check_op.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/memory/ref_counted.h"
  13. #include "base/notreached.h"
  14. #include "base/numerics/checked_math.h"
  15. #include "net/base/io_buffer.h"
  16. #include "third_party/zlib/zlib.h"
  17. namespace net {
  18. namespace {
  19. const char kDeflate[] = "DEFLATE";
  20. const char kGzip[] = "GZIP";
  21. // For deflate streams, if more than this many bytes have been received without
  22. // an error and without adding a Zlib header, assume the original stream had a
  23. // Zlib header. In practice, don't need nearly this much data, but since the
  24. // detection logic is a heuristic, best to be safe. Data is freed once it's been
  25. // determined whether the stream has a zlib header or not, so larger values
  26. // shouldn't affect memory usage, in practice.
  27. const int kMaxZlibHeaderSniffBytes = 1000;
  28. } // namespace
  29. GzipSourceStream::~GzipSourceStream() {
  30. if (zlib_stream_)
  31. inflateEnd(zlib_stream_.get());
  32. }
  33. std::unique_ptr<GzipSourceStream> GzipSourceStream::Create(
  34. std::unique_ptr<SourceStream> upstream,
  35. SourceStream::SourceType type) {
  36. DCHECK(type == TYPE_GZIP || type == TYPE_DEFLATE);
  37. auto source =
  38. base::WrapUnique(new GzipSourceStream(std::move(upstream), type));
  39. if (!source->Init())
  40. return nullptr;
  41. return source;
  42. }
  43. GzipSourceStream::GzipSourceStream(std::unique_ptr<SourceStream> upstream,
  44. SourceStream::SourceType type)
  45. : FilterSourceStream(type, std::move(upstream)) {}
  46. bool GzipSourceStream::Init() {
  47. zlib_stream_ = std::make_unique<z_stream>();
  48. if (!zlib_stream_)
  49. return false;
  50. memset(zlib_stream_.get(), 0, sizeof(z_stream));
  51. int ret;
  52. if (type() == TYPE_GZIP) {
  53. ret = inflateInit2(zlib_stream_.get(), -MAX_WBITS);
  54. } else {
  55. ret = inflateInit(zlib_stream_.get());
  56. }
  57. DCHECK_NE(Z_VERSION_ERROR, ret);
  58. return ret == Z_OK;
  59. }
  60. std::string GzipSourceStream::GetTypeAsString() const {
  61. switch (type()) {
  62. case TYPE_GZIP:
  63. return kGzip;
  64. case TYPE_DEFLATE:
  65. return kDeflate;
  66. default:
  67. NOTREACHED();
  68. return "";
  69. }
  70. }
  71. base::expected<size_t, Error> GzipSourceStream::FilterData(
  72. IOBuffer* output_buffer,
  73. size_t output_buffer_size,
  74. IOBuffer* input_buffer,
  75. size_t input_buffer_size,
  76. size_t* consumed_bytes,
  77. bool upstream_end_reached) {
  78. *consumed_bytes = 0;
  79. char* input_data = input_buffer->data();
  80. size_t input_data_size = input_buffer_size;
  81. size_t bytes_out = 0;
  82. bool state_compressed_entered = false;
  83. while (input_data_size > 0 && bytes_out < output_buffer_size) {
  84. InputState state = input_state_;
  85. switch (state) {
  86. case STATE_START: {
  87. if (type() == TYPE_DEFLATE) {
  88. input_state_ = STATE_SNIFFING_DEFLATE_HEADER;
  89. break;
  90. }
  91. DCHECK_GT(input_data_size, 0u);
  92. input_state_ = STATE_GZIP_HEADER;
  93. break;
  94. }
  95. case STATE_GZIP_HEADER: {
  96. DCHECK_NE(TYPE_DEFLATE, type());
  97. const size_t kGzipFooterBytes = 8;
  98. const char* end = nullptr;
  99. GZipHeader::Status status =
  100. gzip_header_.ReadMore(input_data, input_data_size, &end);
  101. if (status == GZipHeader::INCOMPLETE_HEADER) {
  102. input_data += input_data_size;
  103. input_data_size = 0;
  104. } else if (status == GZipHeader::COMPLETE_HEADER) {
  105. // If there is a valid header, there should also be a valid footer.
  106. gzip_footer_bytes_left_ = kGzipFooterBytes;
  107. size_t bytes_consumed = static_cast<size_t>(end - input_data);
  108. input_data += bytes_consumed;
  109. input_data_size -= bytes_consumed;
  110. input_state_ = STATE_COMPRESSED_BODY;
  111. } else if (status == GZipHeader::INVALID_HEADER) {
  112. return base::unexpected(ERR_CONTENT_DECODING_FAILED);
  113. }
  114. break;
  115. }
  116. case STATE_SNIFFING_DEFLATE_HEADER: {
  117. DCHECK_EQ(TYPE_DEFLATE, type());
  118. zlib_stream_.get()->next_in = base::bit_cast<Bytef*>(input_data);
  119. zlib_stream_.get()->avail_in = input_data_size;
  120. zlib_stream_.get()->next_out =
  121. base::bit_cast<Bytef*>(output_buffer->data());
  122. zlib_stream_.get()->avail_out = output_buffer_size;
  123. int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
  124. // On error, try adding a zlib header and replaying the response. Note
  125. // that data just received doesn't have to be replayed, since it hasn't
  126. // been removed from input_data yet, only data from previous FilterData
  127. // calls needs to be replayed.
  128. if (ret != Z_STREAM_END && ret != Z_OK) {
  129. if (!InsertZlibHeader())
  130. return base::unexpected(ERR_CONTENT_DECODING_FAILED);
  131. input_state_ = STATE_REPLAY_DATA;
  132. // |replay_state_| should still have its initial value.
  133. DCHECK_EQ(STATE_COMPRESSED_BODY, replay_state_);
  134. break;
  135. }
  136. size_t bytes_used = input_data_size - zlib_stream_.get()->avail_in;
  137. bytes_out = output_buffer_size - zlib_stream_.get()->avail_out;
  138. // If any bytes are output, enough total bytes have been received, or at
  139. // the end of the stream, assume the response had a valid Zlib header.
  140. if (bytes_out > 0 ||
  141. bytes_used + replay_data_.size() >= kMaxZlibHeaderSniffBytes ||
  142. ret == Z_STREAM_END) {
  143. replay_data_.clear();
  144. if (ret == Z_STREAM_END) {
  145. input_state_ = STATE_GZIP_FOOTER;
  146. } else {
  147. input_state_ = STATE_COMPRESSED_BODY;
  148. }
  149. } else {
  150. replay_data_.append(input_data, bytes_used);
  151. }
  152. input_data_size -= bytes_used;
  153. input_data += bytes_used;
  154. break;
  155. }
  156. case STATE_REPLAY_DATA: {
  157. DCHECK_EQ(TYPE_DEFLATE, type());
  158. if (replay_data_.empty()) {
  159. input_state_ = replay_state_;
  160. break;
  161. }
  162. // Call FilterData recursively, after updating |input_state_|, with
  163. // |replay_data_|. This recursive call makes handling data from
  164. // |replay_data_| and |input_buffer| much simpler than the alternative
  165. // operations, though it's not pretty.
  166. input_state_ = replay_state_;
  167. size_t bytes_used;
  168. scoped_refptr<IOBuffer> replay_buffer =
  169. base::MakeRefCounted<WrappedIOBuffer>(replay_data_.data());
  170. base::expected<size_t, Error> result =
  171. FilterData(output_buffer, output_buffer_size, replay_buffer.get(),
  172. replay_data_.size(), &bytes_used, upstream_end_reached);
  173. replay_data_.erase(0, bytes_used);
  174. // Back up resulting state, and return state to STATE_REPLAY_DATA.
  175. replay_state_ = input_state_;
  176. input_state_ = STATE_REPLAY_DATA;
  177. // Could continue consuming data in the success case, but simplest not
  178. // to.
  179. if (!result.has_value() || result.value() != 0)
  180. return result;
  181. break;
  182. }
  183. case STATE_COMPRESSED_BODY: {
  184. DCHECK(!state_compressed_entered);
  185. state_compressed_entered = true;
  186. zlib_stream_.get()->next_in = base::bit_cast<Bytef*>(input_data);
  187. zlib_stream_.get()->avail_in = input_data_size;
  188. zlib_stream_.get()->next_out =
  189. base::bit_cast<Bytef*>(output_buffer->data());
  190. zlib_stream_.get()->avail_out = output_buffer_size;
  191. int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
  192. if (ret != Z_STREAM_END && ret != Z_OK)
  193. return base::unexpected(ERR_CONTENT_DECODING_FAILED);
  194. size_t bytes_used = input_data_size - zlib_stream_.get()->avail_in;
  195. bytes_out = output_buffer_size - zlib_stream_.get()->avail_out;
  196. input_data_size -= bytes_used;
  197. input_data += bytes_used;
  198. if (ret == Z_STREAM_END)
  199. input_state_ = STATE_GZIP_FOOTER;
  200. // zlib has written as much data to |output_buffer| as it could.
  201. // There might still be some unconsumed data in |input_buffer| if there
  202. // is no space in |output_buffer|.
  203. break;
  204. }
  205. case STATE_GZIP_FOOTER: {
  206. size_t to_read = std::min(gzip_footer_bytes_left_, input_data_size);
  207. gzip_footer_bytes_left_ -= to_read;
  208. input_data_size -= to_read;
  209. input_data += to_read;
  210. if (gzip_footer_bytes_left_ == 0)
  211. input_state_ = STATE_IGNORING_EXTRA_BYTES;
  212. break;
  213. }
  214. case STATE_IGNORING_EXTRA_BYTES: {
  215. input_data_size = 0;
  216. break;
  217. }
  218. }
  219. }
  220. *consumed_bytes = input_buffer_size - input_data_size;
  221. return bytes_out;
  222. }
  223. bool GzipSourceStream::InsertZlibHeader() {
  224. char dummy_header[] = {0x78, 0x01};
  225. char dummy_output[4];
  226. inflateReset(zlib_stream_.get());
  227. zlib_stream_.get()->next_in = base::bit_cast<Bytef*>(&dummy_header[0]);
  228. zlib_stream_.get()->avail_in = sizeof(dummy_header);
  229. zlib_stream_.get()->next_out = base::bit_cast<Bytef*>(&dummy_output[0]);
  230. zlib_stream_.get()->avail_out = sizeof(dummy_output);
  231. int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
  232. return ret == Z_OK;
  233. }
  234. } // namespace net