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