// Copyright 2013 The Chromium Authors. All rights reserved. // 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 <deque> #include <utility> #include <vector> #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.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(); // 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 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(const char* data, size_t size); // 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 const size_t kDefaultBufferCapacity = 512; static const size_t kDefaultInputIOBufferCapacity = 512; private: // Ring buffer with fixed capacity. class OutputBuffer { public: explicit OutputBuffer(size_t capacity); ~OutputBuffer(); size_t Size() const; // Returns (tail pointer, availabe size). // A user can push data to the queue by writing the data to // the area returned by this function and calling AdvanceTail. std::pair<char*, size_t> GetTail(); void Read(char* dest, size_t size); void AdvanceTail(size_t advance); private: void AdvanceHead(size_t advance); const size_t capacity_; std::vector<char> buffer_; size_t head_; size_t tail_; }; 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 (data pointer, size), the first component of unconsumed data. // The type of data pointer is non-const because |inflate| function // requires so. std::pair<char*, size_t> Top(); bool IsEmpty() const { return buffers_.empty(); } void Push(const char* data, size_t size); // Consumes the topmost |size| bytes. // |size| must be less than or equal to the first buffer size. void Consume(size_t size); private: size_t PushToLastBuffer(const char* data, size_t size); const size_t capacity_; size_t head_of_first_buffer_; size_t tail_of_last_buffer_; std::deque<scoped_refptr<IOBufferWithSize> > buffers_; }; int InflateWithFlush(const char* next_in, size_t avail_in); int Inflate(const char* next_in, size_t avail_in, int flush); int InflateChokedInput(); scoped_ptr<z_stream_s> stream_; InputQueue input_queue_; OutputBuffer output_buffer_; DISALLOW_COPY_AND_ASSIGN(WebSocketInflater); }; } // namespace net #endif // NET_WEBSOCKETS_WEBSOCKET_INFLATER_H_