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 <deque>
9#include <utility>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/scoped_ptr.h"
15#include "net/base/net_export.h"
16
17extern "C" struct z_stream_s;
18
19namespace net {
20
21class IOBufferWithSize;
22
23// WebSocketInflater uncompresses data compressed by DEFLATE algorithm.
24class NET_EXPORT_PRIVATE WebSocketInflater {
25 public:
26  WebSocketInflater();
27  // |input_queue_capacity| is a capacity for each contiguous block in the
28  // input queue. The input queue can grow without limit.
29  WebSocketInflater(size_t input_queue_capacity, size_t output_buffer_capacity);
30  ~WebSocketInflater();
31
32  // Returns true if there is no error.
33  // |window_bits| must be between 8 and 15 (both inclusive).
34  // This function must be called exactly once before calling any of the
35  // following functions.
36  bool Initialize(int window_bits);
37
38  // Adds bytes to |stream_|.
39  // Returns true if there is no error.
40  // If the size of the output data reaches the capacity of the output buffer,
41  // the following input data will be "choked", i.e. stored in the input queue,
42  // staying compressed.
43  bool AddBytes(const char* data, size_t size);
44
45  // Flushes the input.
46  // Returns true if there is no error.
47  bool Finish();
48
49  // Returns up to |size| bytes of the decompressed output.
50  // Returns null if there is an inflation error.
51  // The returned bytes will be dropped from the current output and never be
52  // returned again.
53  // If some input data is choked, calling this function may restart the
54  // inflation process.
55  // This means that even if you call |Finish()| and call |GetOutput()| with
56  // size = |CurrentOutputSize()|, the inflater may have some remaining data.
57  // To confirm the inflater emptiness, you should check whether
58  // |CurrentOutputSize()| is zero.
59  scoped_refptr<IOBufferWithSize> GetOutput(size_t size);
60
61  // Returns the size of the current inflated output.
62  size_t CurrentOutputSize() const { return output_buffer_.Size(); }
63
64  static const size_t kDefaultBufferCapacity = 512;
65  static const size_t kDefaultInputIOBufferCapacity = 512;
66
67 private:
68  // Ring buffer with fixed capacity.
69  class NET_EXPORT_PRIVATE OutputBuffer {
70   public:
71    explicit OutputBuffer(size_t capacity);
72    ~OutputBuffer();
73
74    size_t Size() const;
75    // Returns (tail pointer, availabe size).
76    // A user can push data to the queue by writing the data to
77    // the area returned by this function and calling AdvanceTail.
78    std::pair<char*, size_t> GetTail();
79    void Read(char* dest, size_t size);
80    void AdvanceTail(size_t advance);
81
82   private:
83    void AdvanceHead(size_t advance);
84
85    const size_t capacity_;
86    std::vector<char> buffer_;
87    size_t head_;
88    size_t tail_;
89  };
90
91  class InputQueue {
92   public:
93    // |capacity| is used for the capacity of each IOBuffer in this queue.
94    // this queue itself can grow without limit.
95    explicit InputQueue(size_t capacity);
96    ~InputQueue();
97
98    // Returns (data pointer, size), the first component of unconsumed data.
99    // The type of data pointer is non-const because |inflate| function
100    // requires so.
101    std::pair<char*, size_t> Top();
102    bool IsEmpty() const { return buffers_.empty(); }
103    void Push(const char* data, size_t size);
104    // Consumes the topmost |size| bytes.
105    // |size| must be less than or equal to the first buffer size.
106    void Consume(size_t size);
107
108   private:
109    size_t PushToLastBuffer(const char* data, size_t size);
110
111    const size_t capacity_;
112    size_t head_of_first_buffer_;
113    size_t tail_of_last_buffer_;
114    std::deque<scoped_refptr<IOBufferWithSize> > buffers_;
115  };
116
117  int InflateWithFlush(const char* next_in, size_t avail_in);
118  int Inflate(const char* next_in, size_t avail_in, int flush);
119  int InflateChokedInput();
120
121  scoped_ptr<z_stream_s> stream_;
122  InputQueue input_queue_;
123  OutputBuffer output_buffer_;
124
125  DISALLOW_COPY_AND_ASSIGN(WebSocketInflater);
126};
127
128}  // namespace net
129
130#endif  // NET_WEBSOCKETS_WEBSOCKET_INFLATER_H_
131