|  | // Copyright 2013 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef NET_WEBSOCKETS_WEBSOCKET_INFLATER_H_ | 
|  | #define NET_WEBSOCKETS_WEBSOCKET_INFLATER_H_ | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/containers/circular_deque.h" | 
|  | #include "base/memory/scoped_refptr.h" | 
|  | #include "net/base/net_export.h" | 
|  |  | 
|  | extern "C" struct z_stream_s; | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | class IOBufferWithSize; | 
|  |  | 
|  | // WebSocketInflater uncompresses data compressed by DEFLATE algorithm. | 
|  | class NET_EXPORT_PRIVATE WebSocketInflater { | 
|  | public: | 
|  | WebSocketInflater(); | 
|  | // `input_queue_capacity` is a capacity for each contiguous block in the | 
|  | // input queue. The input queue can grow without limit. | 
|  | WebSocketInflater(size_t input_queue_capacity, size_t output_buffer_capacity); | 
|  |  | 
|  | WebSocketInflater(const WebSocketInflater&) = delete; | 
|  | WebSocketInflater& operator=(const WebSocketInflater&) = delete; | 
|  |  | 
|  | ~WebSocketInflater(); | 
|  |  | 
|  | // Returns true if there is no error. | 
|  | // `window_bits` must be between 8 and 15 (both inclusive). | 
|  | // This function must be called exactly once before calling any of the | 
|  | // following functions. | 
|  | bool Initialize(int window_bits); | 
|  |  | 
|  | // Adds bytes from the given span `data` to `stream_`. | 
|  | // Returns true if there is no error. | 
|  | // If the size of the output data reaches the capacity of the output buffer, | 
|  | // the following input data will be "choked", i.e. stored in the input queue, | 
|  | // staying compressed. | 
|  | bool AddBytes(base::span<const uint8_t> data); | 
|  |  | 
|  | // Flushes the input. | 
|  | // Returns true if there is no error. | 
|  | bool Finish(); | 
|  |  | 
|  | // Returns up to `size` bytes of the decompressed output. | 
|  | // Returns null if there is an inflation error. | 
|  | // The returned bytes will be dropped from the current output and never be | 
|  | // returned again. | 
|  | // If some input data is choked, calling this function may restart the | 
|  | // inflation process. | 
|  | // This means that even if you call `Finish()` and call `GetOutput()` with | 
|  | // size = `CurrentOutputSize()`, the inflater may have some remaining data. | 
|  | // To confirm the inflater emptiness, you should check whether | 
|  | // `CurrentOutputSize()` is zero. | 
|  | scoped_refptr<IOBufferWithSize> GetOutput(size_t size); | 
|  |  | 
|  | // Returns the size of the current inflated output. | 
|  | size_t CurrentOutputSize() const { return output_buffer_.Size(); } | 
|  |  | 
|  | static constexpr size_t kDefaultBufferCapacity = 512; | 
|  | static constexpr size_t kDefaultInputIOBufferCapacity = 512; | 
|  |  | 
|  | private: | 
|  | // Ring buffer with fixed capacity. | 
|  | class NET_EXPORT_PRIVATE OutputBuffer { | 
|  | public: | 
|  | explicit OutputBuffer(size_t capacity); | 
|  | ~OutputBuffer(); | 
|  |  | 
|  | size_t Size() const; | 
|  | // Returns a span representing the writable tail area. | 
|  | // A user can push data to the queue by writing the data to | 
|  | // the area returned by this function and calling AdvanceTail. | 
|  | base::span<uint8_t> GetTail(); | 
|  | void Read(base::span<uint8_t> dest); | 
|  | void AdvanceTail(size_t advance); | 
|  |  | 
|  | private: | 
|  | void AdvanceHead(size_t advance); | 
|  |  | 
|  | const size_t capacity_; | 
|  | std::vector<uint8_t> buffer_; | 
|  | size_t head_ = 0; | 
|  | size_t tail_ = 0; | 
|  | }; | 
|  |  | 
|  | class InputQueue { | 
|  | public: | 
|  | // `capacity` is used for the capacity of each IOBuffer in this queue. | 
|  | // this queue itself can grow without limit. | 
|  | explicit InputQueue(size_t capacity); | 
|  | ~InputQueue(); | 
|  |  | 
|  | // Returns a span representing the first component of unconsumed data | 
|  | base::span<const uint8_t> Top(); | 
|  | bool IsEmpty() const { return buffers_.empty(); } | 
|  | void Push(base::span<const uint8_t> data); | 
|  | // Consumes the topmost `size` bytes. | 
|  | // `size` must be less than or equal to the first buffer size. | 
|  | void Consume(size_t size); | 
|  |  | 
|  | private: | 
|  | void TakeAndPushToLastBuffer(base::span<const uint8_t>& data); | 
|  |  | 
|  | const size_t capacity_; | 
|  | size_t head_of_first_buffer_ = 0; | 
|  | size_t tail_of_last_buffer_ = 0; | 
|  | base::circular_deque<scoped_refptr<IOBufferWithSize>> buffers_; | 
|  | }; | 
|  |  | 
|  | int InflateWithFlush(base::span<const uint8_t> next_in); | 
|  | int Inflate(base::span<const uint8_t> next_in, int flush); | 
|  | int InflateExistingInput(int flush); | 
|  | int InflateChokedInput(); | 
|  |  | 
|  | std::unique_ptr<z_stream_s> stream_; | 
|  | InputQueue input_queue_; | 
|  | OutputBuffer output_buffer_; | 
|  | }; | 
|  |  | 
|  | }  // namespace net | 
|  |  | 
|  | #endif  // NET_WEBSOCKETS_WEBSOCKET_INFLATER_H_ |