xref: /aosp_15_r20/external/cronet/net/websockets/websocket_inflater.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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_WEBSOCKETS_WEBSOCKET_INFLATER_H_
6 #define NET_WEBSOCKETS_WEBSOCKET_INFLATER_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/containers/circular_deque.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "net/base/net_export.h"
17 
18 extern "C" struct z_stream_s;
19 
20 namespace net {
21 
22 class IOBufferWithSize;
23 
24 // WebSocketInflater uncompresses data compressed by DEFLATE algorithm.
25 class NET_EXPORT_PRIVATE WebSocketInflater {
26  public:
27   WebSocketInflater();
28   // |input_queue_capacity| is a capacity for each contiguous block in the
29   // input queue. The input queue can grow without limit.
30   WebSocketInflater(size_t input_queue_capacity, size_t output_buffer_capacity);
31 
32   WebSocketInflater(const WebSocketInflater&) = delete;
33   WebSocketInflater& operator=(const WebSocketInflater&) = delete;
34 
35   ~WebSocketInflater();
36 
37   // Returns true if there is no error.
38   // |window_bits| must be between 8 and 15 (both inclusive).
39   // This function must be called exactly once before calling any of the
40   // following functions.
41   bool Initialize(int window_bits);
42 
43   // Adds bytes to |stream_|.
44   // Returns true if there is no error.
45   // If the size of the output data reaches the capacity of the output buffer,
46   // the following input data will be "choked", i.e. stored in the input queue,
47   // staying compressed.
48   bool AddBytes(const char* data, size_t size);
49 
50   // Flushes the input.
51   // Returns true if there is no error.
52   bool Finish();
53 
54   // Returns up to |size| bytes of the decompressed output.
55   // Returns null if there is an inflation error.
56   // The returned bytes will be dropped from the current output and never be
57   // returned again.
58   // If some input data is choked, calling this function may restart the
59   // inflation process.
60   // This means that even if you call |Finish()| and call |GetOutput()| with
61   // size = |CurrentOutputSize()|, the inflater may have some remaining data.
62   // To confirm the inflater emptiness, you should check whether
63   // |CurrentOutputSize()| is zero.
64   scoped_refptr<IOBufferWithSize> GetOutput(size_t size);
65 
66   // Returns the size of the current inflated output.
CurrentOutputSize()67   size_t CurrentOutputSize() const { return output_buffer_.Size(); }
68 
69   static constexpr size_t kDefaultBufferCapacity = 512;
70   static constexpr size_t kDefaultInputIOBufferCapacity = 512;
71 
72  private:
73   // Ring buffer with fixed capacity.
74   class NET_EXPORT_PRIVATE OutputBuffer {
75    public:
76     explicit OutputBuffer(size_t capacity);
77     ~OutputBuffer();
78 
79     size_t Size() const;
80     // Returns (tail pointer, availabe size).
81     // A user can push data to the queue by writing the data to
82     // the area returned by this function and calling AdvanceTail.
83     std::pair<char*, size_t> GetTail();
84     void Read(char* dest, size_t size);
85     void AdvanceTail(size_t advance);
86 
87    private:
88     void AdvanceHead(size_t advance);
89 
90     const size_t capacity_;
91     std::vector<char> buffer_;
92     size_t head_ = 0;
93     size_t tail_ = 0;
94   };
95 
96   class InputQueue {
97    public:
98     // |capacity| is used for the capacity of each IOBuffer in this queue.
99     // this queue itself can grow without limit.
100     explicit InputQueue(size_t capacity);
101     ~InputQueue();
102 
103     // Returns (data pointer, size), the first component of unconsumed data.
104     // The type of data pointer is non-const because |inflate| function
105     // requires so.
106     std::pair<char*, size_t> Top();
IsEmpty()107     bool IsEmpty() const { return buffers_.empty(); }
108     void Push(const char* data, size_t size);
109     // Consumes the topmost |size| bytes.
110     // |size| must be less than or equal to the first buffer size.
111     void Consume(size_t size);
112 
113    private:
114     size_t PushToLastBuffer(const char* data, size_t size);
115 
116     const size_t capacity_;
117     size_t head_of_first_buffer_ = 0;
118     size_t tail_of_last_buffer_ = 0;
119     base::circular_deque<scoped_refptr<IOBufferWithSize>> buffers_;
120   };
121 
122   int InflateWithFlush(const char* next_in, size_t avail_in);
123   int Inflate(const char* next_in, size_t avail_in, int flush);
124   int InflateChokedInput();
125 
126   std::unique_ptr<z_stream_s> stream_;
127   InputQueue input_queue_;
128   OutputBuffer output_buffer_;
129 };
130 
131 }  // namespace net
132 
133 #endif  // NET_WEBSOCKETS_WEBSOCKET_INFLATER_H_
134