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