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