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.
5 #include "net/websockets/websocket_deflater.h"
12 #include "base/logging.h"
13 #include "net/base/io_buffer.h"
14 #include "third_party/zlib/zlib.h"
18 WebSocketDeflater::WebSocketDeflater(ContextTakeOverMode mode
)
19 : mode_(mode
), are_bytes_added_(false) {}
21 WebSocketDeflater::~WebSocketDeflater() {
23 deflateEnd(stream_
.get());
28 bool WebSocketDeflater::Initialize(int window_bits
) {
30 stream_
.reset(new z_stream
);
32 DCHECK_LE(8, window_bits
);
33 DCHECK_GE(15, window_bits
);
34 memset(stream_
.get(), 0, sizeof(*stream_
));
35 int result
= deflateInit2(stream_
.get(),
36 Z_DEFAULT_COMPRESSION
,
38 -window_bits
, // Negative value for raw deflate
39 8, // default mem level
42 deflateEnd(stream_
.get());
46 const size_t kFixedBufferSize
= 4096;
47 fixed_buffer_
.resize(kFixedBufferSize
);
51 bool WebSocketDeflater::AddBytes(const char* data
, size_t size
) {
55 are_bytes_added_
= true;
56 stream_
->next_in
= reinterpret_cast<Bytef
*>(const_cast<char*>(data
));
57 stream_
->avail_in
= size
;
59 int result
= Deflate(Z_NO_FLUSH
);
60 DCHECK(result
!= Z_BUF_ERROR
|| !stream_
->avail_in
);
61 return result
== Z_BUF_ERROR
;
64 bool WebSocketDeflater::Finish() {
65 if (!are_bytes_added_
) {
66 // Since consecutive calls of deflate with Z_SYNC_FLUSH and no input
67 // lead to an error, we create and return the output for the empty input
69 buffer_
.push_back('\x00');
73 stream_
->next_in
= NULL
;
74 stream_
->avail_in
= 0;
76 int result
= Deflate(Z_SYNC_FLUSH
);
77 // Deflate returning Z_BUF_ERROR means that it's successfully flushed and
78 // blocked for input data.
79 if (result
!= Z_BUF_ERROR
) {
83 // Remove 4 octets from the tail as the specification requires.
84 if (CurrentOutputSize() < 4) {
88 buffer_
.resize(buffer_
.size() - 4);
93 void WebSocketDeflater::PushSyncMark() {
94 DCHECK(!are_bytes_added_
);
95 const char data
[] = {'\x00', '\x00', '\xff', '\xff'};
96 buffer_
.insert(buffer_
.end(), &data
[0], &data
[sizeof(data
)]);
99 scoped_refptr
<IOBufferWithSize
> WebSocketDeflater::GetOutput(size_t size
) {
100 size_t length_to_copy
= std::min(size
, buffer_
.size());
101 std::deque
<char>::iterator begin
= buffer_
.begin();
102 std::deque
<char>::iterator end
= begin
+ length_to_copy
;
104 scoped_refptr
<IOBufferWithSize
> result
= new IOBufferWithSize(length_to_copy
);
105 std::copy(begin
, end
, result
->data());
106 buffer_
.erase(begin
, end
);
110 void WebSocketDeflater::ResetContext() {
111 if (mode_
== DO_NOT_TAKE_OVER_CONTEXT
)
112 deflateReset(stream_
.get());
113 are_bytes_added_
= false;
116 int WebSocketDeflater::Deflate(int flush
) {
119 stream_
->next_out
= reinterpret_cast<Bytef
*>(&fixed_buffer_
[0]);
120 stream_
->avail_out
= fixed_buffer_
.size();
121 result
= deflate(stream_
.get(), flush
);
122 size_t size
= fixed_buffer_
.size() - stream_
->avail_out
;
123 buffer_
.insert(buffer_
.end(), &fixed_buffer_
[0], &fixed_buffer_
[0] + size
);
124 } while (result
== Z_OK
);