| // 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_ |