quic_data_stream.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/quic/quic_data_stream.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/quic/quic_session.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/quic/quic_utils.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/quic/quic_write_blocked_list.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::StringPiece;
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using std::min;
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace net {
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define ENDPOINT (session()->is_server() ? "Server: " : " Client: ")
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is somewhat arbitrary.  It's possible, but unlikely, we will either fail
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// to set a priority client-side, or cancel a stream before stripping the
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// priority from the wire server-side.  In either case, start out with a
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// priority in the middle.
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QuicPriority kDefaultPriority = 3;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QuicDataStream::QuicDataStream(QuicStreamId id,
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               QuicSession* session)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : ReliableQuicStream(id, session),
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      visitor_(NULL),
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      headers_decompressed_(false),
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      priority_(kDefaultPriority),
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      decompression_failed_(false),
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      priority_parsed_(false) {
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_NE(kCryptoStreamId, id);
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Don't receive any callbacks from the sequencer until headers
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // are complete.
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  sequencer()->SetBlockedUntilFlush();
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QuicDataStream::~QuicDataStream() {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)size_t QuicDataStream::WriteHeaders(const SpdyHeaderBlock& header_block,
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    bool fin) {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t bytes_written = session()->WriteHeaders(id(), header_block, fin);
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (fin) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    set_fin_sent(true);
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CloseWriteSide();
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return bytes_written;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)size_t QuicDataStream::Readv(const struct iovec* iov, size_t iov_len) {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (FinishedReadingHeaders()) {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If the headers have been read, simply delegate to the sequencer's
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Readv method.
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return sequencer()->Readv(iov, iov_len);
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Otherwise, copy decompressed header data into |iov|.
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t bytes_consumed = 0;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t iov_index = 0;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (iov_index < iov_len &&
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         decompressed_headers_.length() > bytes_consumed) {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    size_t bytes_to_read = min(iov[iov_index].iov_len,
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               decompressed_headers_.length() - bytes_consumed);
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base);
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    memcpy(iov_ptr,
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           decompressed_headers_.data() + bytes_consumed, bytes_to_read);
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bytes_consumed += bytes_to_read;
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ++iov_index;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  decompressed_headers_.erase(0, bytes_consumed);
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (FinishedReadingHeaders()) {
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sequencer()->FlushBufferedFrames();
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return bytes_consumed;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int QuicDataStream::GetReadableRegions(iovec* iov, size_t iov_len) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (FinishedReadingHeaders()) {
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return sequencer()->GetReadableRegions(iov, iov_len);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (iov_len == 0) {
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  iov[0].iov_base = static_cast<void*>(
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const_cast<char*>(decompressed_headers_.data()));
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  iov[0].iov_len = decompressed_headers_.length();
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return 1;
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool QuicDataStream::IsDoneReading() const {
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!headers_decompressed_ || !decompressed_headers_.empty()) {
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return sequencer()->IsClosed();
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool QuicDataStream::HasBytesToRead() const {
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !decompressed_headers_.empty() || sequencer()->HasBytesToRead();
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicDataStream::set_priority(QuicPriority priority) {
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(0u, stream_bytes_written());
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  priority_ = priority;
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QuicPriority QuicDataStream::EffectivePriority() const {
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return priority();
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)uint32 QuicDataStream::ProcessRawData(const char* data, uint32 data_len) {
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!FinishedReadingHeaders()) {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(DFATAL) << "ProcessRawData called before headers have been finished";
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ProcessData(data, data_len);
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const IPEndPoint& QuicDataStream::GetPeerAddress() {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return session()->peer_address();
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool QuicDataStream::GetSSLInfo(SSLInfo* ssl_info) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return session()->GetSSLInfo(ssl_info);
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)uint32 QuicDataStream::ProcessHeaderData() {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (decompressed_headers_.empty()) {
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t bytes_processed = ProcessData(decompressed_headers_.data(),
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       decompressed_headers_.length());
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (bytes_processed == decompressed_headers_.length()) {
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    decompressed_headers_.clear();
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    decompressed_headers_ = decompressed_headers_.erase(0, bytes_processed);
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return bytes_processed;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicDataStream::OnStreamHeaders(StringPiece headers_data) {
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  headers_data.AppendToString(&decompressed_headers_);
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProcessHeaderData();
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicDataStream::OnStreamHeadersPriority(QuicPriority priority) {
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(session()->connection()->is_server());
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_priority(priority);
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicDataStream::OnStreamHeadersComplete(bool fin, size_t frame_len) {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  headers_decompressed_ = true;
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (fin) {
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sequencer()->OnStreamFrame(QuicStreamFrame(id(), fin, 0, IOVector()));
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProcessHeaderData();
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (FinishedReadingHeaders()) {
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sequencer()->FlushBufferedFrames();
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicDataStream::OnClose() {
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ReliableQuicStream::OnClose();
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (visitor_) {
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Visitor* visitor = visitor_;
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Calling Visitor::OnClose() may result the destruction of the visitor,
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // so we need to ensure we don't call it again.
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    visitor_ = NULL;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    visitor->OnClose(this);
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool QuicDataStream::FinishedReadingHeaders() {
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return headers_decompressed_ && decompressed_headers_.empty();
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void QuicDataStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DVLOG(1) << "Received WindowUpdateFrame for stream: " << id()
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           << ", with byte offset: " << frame.byte_offset;
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // TODO(rjshade): Adjust flow control window.
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace net
191