websocket_deflate_stream.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file. 44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/websockets/websocket_deflate_stream.h" 64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <algorithm> 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <string> 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/bind.h" 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h" 124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/ref_counted.h" 134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/scoped_vector.h" 154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/completion_callback.h" 164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/io_buffer.h" 174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/net_errors.h" 181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "net/websockets/websocket_deflate_predictor.h" 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/websockets/websocket_deflater.h" 204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/websockets/websocket_errors.h" 214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/websockets/websocket_frame.h" 224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/websockets/websocket_inflater.h" 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/websockets/websocket_stream.h" 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class GURL; 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace net { 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace { 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kWindowBits = 15; 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const size_t kChunkSize = 4 * 1024; 334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketDeflateStream::WebSocketDeflateStream( 371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_ptr<WebSocketStream> stream, 381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketDeflater::ContextTakeOverMode mode, 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int client_window_bits, 401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_ptr<WebSocketDeflatePredictor> predictor) 414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : stream_(stream.Pass()), 421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) deflater_(mode), 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflater_(kChunkSize, kChunkSize), 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reading_state_(NOT_READING), 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) writing_state_(NOT_WRITING), 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_reading_opcode_(WebSocketFrameHeader::kOpCodeText), 471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) current_writing_opcode_(WebSocketFrameHeader::kOpCodeText), 481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) predictor_(predictor.Pass()) { 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(stream_); 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_GE(client_window_bits, 8); 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_LE(client_window_bits, 15); 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) deflater_.Initialize(client_window_bits); 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflater_.Initialize(kWindowBits); 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)WebSocketDeflateStream::~WebSocketDeflateStream() {} 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)int WebSocketDeflateStream::ReadFrames(ScopedVector<WebSocketFrame>* frames, 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const CompletionCallback& callback) { 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int result = stream_->ReadFrames( 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) frames, 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&WebSocketDeflateStream::OnReadComplete, 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Unretained(this), 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Unretained(frames), 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callback)); 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result < 0) 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return result; 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(OK, result); 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!frames->empty()); 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return InflateAndReadIfNecessary(frames, callback); 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)int WebSocketDeflateStream::WriteFrames(ScopedVector<WebSocketFrame>* frames, 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const CompletionCallback& callback) { 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int result = Deflate(frames); 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result != OK) 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return result; 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frames->empty()) 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return OK; 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return stream_->WriteFrames(frames, callback); 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebSocketDeflateStream::Close() { stream_->Close(); } 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::string WebSocketDeflateStream::GetSubProtocol() const { 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return stream_->GetSubProtocol(); 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::string WebSocketDeflateStream::GetExtensions() const { 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return stream_->GetExtensions(); 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void WebSocketDeflateStream::OnReadComplete( 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ScopedVector<WebSocketFrame>* frames, 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const CompletionCallback& callback, 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int result) { 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result != OK) { 994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames->clear(); 1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) callback.Run(result); 1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int r = InflateAndReadIfNecessary(frames, callback); 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (r != ERR_IO_PENDING) 1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) callback.Run(r); 1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)int WebSocketDeflateStream::Deflate(ScopedVector<WebSocketFrame>* frames) { 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ScopedVector<WebSocketFrame> frames_to_write; 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Store frames of the currently processed message if writing_state_ equals to 1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // WRITING_POSSIBLY_COMPRESSED_MESSAGE. 1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ScopedVector<WebSocketFrame> frames_of_message; 1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (size_t i = 0; i < frames->size(); ++i) { 1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(!(*frames)[i]->header.reserved1); 1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!WebSocketFrameHeader::IsKnownDataOpCode((*frames)[i]->header.opcode)) { 1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frames_to_write.push_back((*frames)[i]); 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) (*frames)[i] = NULL; 1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) continue; 1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (writing_state_ == NOT_WRITING) 1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) OnMessageStart(*frames, i); 1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_ptr<WebSocketFrame> frame((*frames)[i]); 1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) (*frames)[i] = NULL; 1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) predictor_->RecordInputDataFrame(frame.get()); 1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (writing_state_ == WRITING_UNCOMPRESSED_MESSAGE) { 1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frame->header.final) 1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) writing_state_ = NOT_WRITING; 1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) predictor_->RecordWrittenDataFrame(frame.get()); 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames_to_write.push_back(frame.release()); 1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_writing_opcode_ = WebSocketFrameHeader::kOpCodeContinuation; 1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (frame->data.get() && 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci !deflater_.AddBytes(frame->data->data(), 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci frame->header.payload_length)) { 1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << "deflater_.AddBytes() returns an error."; 1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frame->header.final && !deflater_.Finish()) { 1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << "deflater_.Finish() returns an error."; 1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (writing_state_ == WRITING_COMPRESSED_MESSAGE) { 1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (deflater_.CurrentOutputSize() >= kChunkSize || 1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frame->header.final) { 1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int result = AppendCompressedFrame(frame->header, &frames_to_write); 1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (result != OK) 1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return result; 1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (frame->header.final) 1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) writing_state_ = NOT_WRITING; 1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(WRITING_POSSIBLY_COMPRESSED_MESSAGE, writing_state_); 1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool final = frame->header.final; 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frames_of_message.push_back(frame.release()); 1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (final) { 1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int result = AppendPossiblyCompressedMessage(&frames_of_message, 1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) &frames_to_write); 1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (result != OK) 1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return result; 1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frames_of_message.clear(); 1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) writing_state_ = NOT_WRITING; 1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_NE(WRITING_POSSIBLY_COMPRESSED_MESSAGE, writing_state_); 1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames->swap(frames_to_write); 1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return OK; 1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebSocketDeflateStream::OnMessageStart( 1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const ScopedVector<WebSocketFrame>& frames, size_t index) { 1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketFrame* frame = frames[index]; 1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) current_writing_opcode_ = frame->header.opcode; 1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(current_writing_opcode_ == WebSocketFrameHeader::kOpCodeText || 1821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) current_writing_opcode_ == WebSocketFrameHeader::kOpCodeBinary); 1831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketDeflatePredictor::Result prediction = 1841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) predictor_->Predict(frames, index); 1851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) switch (prediction) { 1871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case WebSocketDeflatePredictor::DEFLATE: 1881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) writing_state_ = WRITING_COMPRESSED_MESSAGE; 1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 1901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case WebSocketDeflatePredictor::DO_NOT_DEFLATE: 1911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) writing_state_ = WRITING_UNCOMPRESSED_MESSAGE; 1921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 1931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case WebSocketDeflatePredictor::TRY_DEFLATE: 1941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) writing_state_ = WRITING_POSSIBLY_COMPRESSED_MESSAGE; 1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) NOTREACHED(); 1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int WebSocketDeflateStream::AppendCompressedFrame( 2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const WebSocketFrameHeader& header, 2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ScopedVector<WebSocketFrame>* frames_to_write) { 2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const WebSocketFrameHeader::OpCode opcode = current_writing_opcode_; 2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_refptr<IOBufferWithSize> compressed_payload = 2051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) deflater_.GetOutput(deflater_.CurrentOutputSize()); 2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!compressed_payload.get()) { 2071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) << "deflater_.GetOutput() returns an error."; 2091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_ptr<WebSocketFrame> compressed(new WebSocketFrame(opcode)); 2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.CopyFrom(header); 2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.opcode = opcode; 2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.final = header.final; 2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.reserved1 = 2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) (opcode != WebSocketFrameHeader::kOpCodeContinuation); 2171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->data = compressed_payload; 2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.payload_length = compressed_payload->size(); 2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) current_writing_opcode_ = WebSocketFrameHeader::kOpCodeContinuation; 2211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) predictor_->RecordWrittenDataFrame(compressed.get()); 2221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frames_to_write->push_back(compressed.release()); 2231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return OK; 2241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int WebSocketDeflateStream::AppendPossiblyCompressedMessage( 2271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ScopedVector<WebSocketFrame>* frames, 2281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ScopedVector<WebSocketFrame>* frames_to_write) { 2291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(!frames->empty()); 2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const WebSocketFrameHeader::OpCode opcode = current_writing_opcode_; 2321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_refptr<IOBufferWithSize> compressed_payload = 2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) deflater_.GetOutput(deflater_.CurrentOutputSize()); 2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!compressed_payload.get()) { 2351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 2361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) << "deflater_.GetOutput() returns an error."; 2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint64 original_payload_length = 0; 2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (size_t i = 0; i < frames->size(); ++i) { 2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketFrame* frame = (*frames)[i]; 2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Asserts checking that frames represent one whole data message. 2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode)); 2451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(i == 0, 2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketFrameHeader::kOpCodeContinuation != 2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frame->header.opcode); 2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(i == frames->size() - 1, frame->header.final); 2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) original_payload_length += frame->header.payload_length; 2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (original_payload_length <= 2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) static_cast<uint64>(compressed_payload->size())) { 2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Compression is not effective. Use the original frames. 2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (size_t i = 0; i < frames->size(); ++i) { 2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WebSocketFrame* frame = (*frames)[i]; 2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frames_to_write->push_back(frame); 2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) predictor_->RecordWrittenDataFrame(frame); 2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) (*frames)[i] = NULL; 2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frames->weak_clear(); 2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return OK; 2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_ptr<WebSocketFrame> compressed(new WebSocketFrame(opcode)); 2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.CopyFrom((*frames)[0]->header); 2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.opcode = opcode; 2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.final = true; 2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.reserved1 = true; 2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->data = compressed_payload; 2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) compressed->header.payload_length = compressed_payload->size(); 2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) predictor_->RecordWrittenDataFrame(compressed.get()); 2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) frames_to_write->push_back(compressed.release()); 2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return OK; 2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)int WebSocketDeflateStream::Inflate(ScopedVector<WebSocketFrame>* frames) { 2774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ScopedVector<WebSocketFrame> frames_to_output; 2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ScopedVector<WebSocketFrame> frames_passed; 2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames->swap(frames_passed); 2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (size_t i = 0; i < frames_passed.size(); ++i) { 2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<WebSocketFrame> frame(frames_passed[i]); 2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames_passed[i] = NULL; 283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(3) << "Input frame: opcode=" << frame->header.opcode 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << " final=" << frame->header.final 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << " reserved1=" << frame->header.reserved1 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << " payload_length=" << frame->header.payload_length; 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode)) { 2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames_to_output.push_back(frame.release()); 2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) continue; 2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (reading_state_ == NOT_READING) { 2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frame->header.reserved1) 2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reading_state_ = READING_COMPRESSED_MESSAGE; 2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) else 2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reading_state_ = READING_UNCOMPRESSED_MESSAGE; 2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_reading_opcode_ = frame->header.opcode; 2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frame->header.reserved1) { 3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << "Receiving a non-first frame with RSV1 flag set."; 3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (reading_state_ == READING_UNCOMPRESSED_MESSAGE) { 3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frame->header.final) 3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reading_state_ = NOT_READING; 3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_reading_opcode_ = WebSocketFrameHeader::kOpCodeContinuation; 3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames_to_output.push_back(frame.release()); 3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(reading_state_, READING_COMPRESSED_MESSAGE); 3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (frame->data.get() && 3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci !inflater_.AddBytes(frame->data->data(), 3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci frame->header.payload_length)) { 3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << "inflater_.AddBytes() returns an error."; 3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frame->header.final) { 3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!inflater_.Finish()) { 3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << "inflater_.Finish() returns an error."; 3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(yhirano): Many frames can be generated by the inflater and 3294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // memory consumption can grow. 3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // We could avoid it, but avoiding it makes this class much more 3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // complicated. 3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) while (inflater_.CurrentOutputSize() >= kChunkSize || 3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frame->header.final) { 3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t size = std::min(kChunkSize, inflater_.CurrentOutputSize()); 3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<WebSocketFrame> inflated( 3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) new WebSocketFrame(WebSocketFrameHeader::kOpCodeText)); 3374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_refptr<IOBufferWithSize> data = inflater_.GetOutput(size); 3380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch bool is_final = !inflater_.CurrentOutputSize() && frame->header.final; 3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!data.get()) { 3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DVLOG(1) << "WebSocket protocol error. " 3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) << "inflater_.GetOutput() returns an error."; 3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return ERR_WS_PROTOCOL_ERROR; 3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflated->header.CopyFrom(frame->header); 3454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflated->header.opcode = current_reading_opcode_; 3464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflated->header.final = is_final; 3474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflated->header.reserved1 = false; 3484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflated->data = data; 3494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) inflated->header.payload_length = data->size(); 350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(3) << "Inflated frame: opcode=" << inflated->header.opcode 351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << " final=" << inflated->header.final 352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << " reserved1=" << inflated->header.reserved1 353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << " payload_length=" << inflated->header.payload_length; 3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames_to_output.push_back(inflated.release()); 3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_reading_opcode_ = WebSocketFrameHeader::kOpCodeContinuation; 3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (is_final) 3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frame->header.final) 3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) reading_state_ = NOT_READING; 3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames->swap(frames_to_output); 3644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return frames->empty() ? ERR_IO_PENDING : OK; 3654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 3664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)int WebSocketDeflateStream::InflateAndReadIfNecessary( 3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ScopedVector<WebSocketFrame>* frames, 3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const CompletionCallback& callback) { 3704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int result = Inflate(frames); 3714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) while (result == ERR_IO_PENDING) { 3724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(frames->empty()); 373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) result = stream_->ReadFrames( 375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) frames, 376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&WebSocketDeflateStream::OnReadComplete, 377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Unretained(this), 378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Unretained(frames), 379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callback)); 3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result < 0) 3814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 3824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(OK, result); 3834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(!frames->empty()); 384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) result = Inflate(frames); 3864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result < 0) 3884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) frames->clear(); 3894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return result; 3904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace net 393