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