xref: /aosp_15_r20/external/cronet/net/filter/gzip_source_stream.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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