1 // Copyright 2016 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_FILTER_GZIP_SOURCE_STREAM_H_ 6 #define NET_FILTER_GZIP_SOURCE_STREAM_H_ 7 8 #include <memory> 9 #include <string> 10 11 #include "net/base/net_export.h" 12 #include "net/filter/filter_source_stream.h" 13 #include "net/filter/gzip_header.h" 14 15 typedef struct z_stream_s z_stream; 16 17 namespace net { 18 19 class IOBuffer; 20 21 // GZipSourceStream applies gzip and deflate content encoding/decoding to a data 22 // stream. As specified by HTTP 1.1, with gzip encoding the content is 23 // wrapped with a gzip header, and with deflate encoding the content is in 24 // a raw, headerless DEFLATE stream. 25 // 26 // Internally GZipSourceStream uses zlib inflate to do decoding. 27 // 28 class NET_EXPORT_PRIVATE GzipSourceStream : public FilterSourceStream { 29 public: 30 GzipSourceStream(const GzipSourceStream&) = delete; 31 GzipSourceStream& operator=(const GzipSourceStream&) = delete; 32 33 ~GzipSourceStream() override; 34 35 // Creates a GzipSourceStream. Return nullptr if initialization fails. 36 static std::unique_ptr<GzipSourceStream> Create( 37 std::unique_ptr<SourceStream> previous, 38 SourceStream::SourceType type); 39 40 private: 41 enum InputState { 42 // Starts processing the input stream. Checks whether the stream is valid 43 // and whether a fallback to plain data is needed. 44 STATE_START, 45 // Gzip header of the input stream is being processed. 46 STATE_GZIP_HEADER, 47 // Deflate responses may or may not have a zlib header. In this state until 48 // enough has been inflated that this stream most likely has a zlib header, 49 // or until a zlib header has been added. Data is appended to |replay_data_| 50 // in case it needs to be replayed after adding a header. 51 STATE_SNIFFING_DEFLATE_HEADER, 52 // If a zlib header has to be added to the response, this state will replay 53 // data passed to inflate before it was determined that no zlib header was 54 // present. 55 // See https://crbug.com/677001 56 STATE_REPLAY_DATA, 57 // The input stream is being decoded. 58 STATE_COMPRESSED_BODY, 59 // Gzip footer of the input stream is being processed. 60 STATE_GZIP_FOOTER, 61 // The end of the gzipped body has been reached. If any extra bytes are 62 // received, just silently ignore them. Doing this, rather than failing the 63 // request or passing the extra bytes alone with the rest of the response 64 // body, matches the behavior of other browsers. 65 STATE_IGNORING_EXTRA_BYTES, 66 }; 67 68 GzipSourceStream(std::unique_ptr<SourceStream> previous, 69 SourceStream::SourceType type); 70 71 // Returns true if initialization is successful, false otherwise. 72 // For instance, this method returns false if there is not enough memory or 73 // if there is a version mismatch. 74 bool Init(); 75 76 // SourceStream implementation 77 std::string GetTypeAsString() const override; 78 base::expected<size_t, Error> FilterData(IOBuffer* output_buffer, 79 size_t output_buffer_size, 80 IOBuffer* input_buffer, 81 size_t input_buffer_size, 82 size_t* consumed_bytes, 83 bool upstream_end_reached) override; 84 85 // Inserts a zlib header to the data stream before calling zlib inflate. 86 // This is used to work around server bugs. The function returns true on 87 // success. 88 bool InsertZlibHeader(); 89 90 // The control block of zlib which actually does the decoding. 91 // This data structure is initialized by Init and updated only by 92 // FilterData(), with InsertZlibHeader() being the exception as a workaround. 93 std::unique_ptr<z_stream> zlib_stream_; 94 95 // While in STATE_SNIFFING_DEFLATE_HEADER, it may be determined that a zlib 96 // header needs to be added, and all received data needs to be replayed. In 97 // that case, this buffer holds the data to be replayed. 98 std::string replay_data_; 99 100 // Used to parse the gzip header in gzip stream. 101 // It is used when the decoding mode is GZIP_SOURCE_STREAM_GZIP. 102 GZipHeader gzip_header_; 103 104 // Tracks how many bytes of gzip footer are yet to be filtered. 105 size_t gzip_footer_bytes_left_ = 0; 106 107 // Tracks the state of the input stream. 108 InputState input_state_ = STATE_START; 109 110 // Used when replaying data. 111 InputState replay_state_ = STATE_COMPRESSED_BODY; 112 }; 113 114 } // namespace net 115 116 #endif // NET_FILTER_GZIP_SOURCE_STREAM_H__ 117