15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/spdy/spdy_frame_builder.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/spdy/spdy_framer.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_protocol.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A special structure for the 8 bit flags and 24 bit length fields.
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)union FlagsAndLength {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint8 flags_[4];  // 8 bits
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint32 length_;   // 24 bits
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates a FlagsAndLength.
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FlagsAndLength CreateFlagsAndLength(uint8 flags, size_t length) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(0u, length & ~static_cast<size_t>(kLengthMask));
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FlagsAndLength flags_length;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  flags_length.length_ = htonl(static_cast<uint32>(length));
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(0, flags & ~kControlFlagsMask);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  flags_length.flags_[0] = flags;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return flags_length;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpdyFrameBuilder::SpdyFrameBuilder(size_t size)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : buffer_(new char[size]),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      capacity_(size),
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      length_(0) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpdyFrameBuilder::~SpdyFrameBuilder() {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)char* SpdyFrameBuilder::GetWritableBuffer(size_t length) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CanWrite(length)) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return buffer_.get() + length_;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdyFrameBuilder::Seek(size_t length) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CanWrite(length)) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  length_ += length;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdyFrameBuilder::WriteControlFrameHeader(const SpdyFramer& framer,
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               SpdyFrameType type,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               uint8 flags) {
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GE(type, FIRST_CONTROL_TYPE);
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_LE(type, LAST_CONTROL_TYPE);
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GT(4, framer.protocol_version());
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = true;
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FlagsAndLength flags_length = CreateFlagsAndLength(
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      flags, capacity_ - framer.GetControlFrameHeaderSize());
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteUInt16(kControlFlagMask | framer.protocol_version());
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteUInt16(type);
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteBytes(&flags_length, sizeof(flags_length));
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(framer.GetControlFrameHeaderSize(), length());
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success;
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdyFrameBuilder::WriteDataFrameHeader(const SpdyFramer& framer,
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            SpdyStreamId stream_id,
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            SpdyDataFlags flags) {
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (framer.protocol_version() >= 4) {
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return WriteFramePrefix(framer, DATA, flags, stream_id);
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = true;
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteUInt32(stream_id);
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t length_field = capacity_ - framer.GetDataFrameMinimumSize();
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(0u, length_field & ~static_cast<size_t>(kLengthMask));
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FlagsAndLength flags_length;
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  flags_length.length_ = htonl(length_field);
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(0, flags & ~kDataFlagsMask);
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  flags_length.flags_[0] = flags;
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteBytes(&flags_length, sizeof(flags_length));
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(framer.GetDataFrameMinimumSize(), length());
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return success;
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SpdyFrameBuilder::WriteFramePrefix(const SpdyFramer& framer,
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                        SpdyFrameType type,
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                        uint8 flags,
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                        SpdyStreamId stream_id) {
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_LE(DATA, type);
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GE(LAST_CONTROL_TYPE, type);
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_LE(4, framer.protocol_version());
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool success = true;
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GT(1u<<16, capacity_);  // Make sure length fits in 2B.
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteUInt16(capacity_);
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteUInt8(type);
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteUInt8(flags);
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  success &= WriteUInt32(stream_id);
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(framer.GetDataFrameMinimumSize(), length());
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyFrameBuilder::WriteString(const std::string& value) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (value.size() > 0xffff) {
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(false) << "Tried to write string with length > 16bit.";
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WriteUInt16(static_cast<int>(value.size())))
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WriteBytes(value.data(), static_cast<uint16>(value.size()));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpdyFrameBuilder::WriteStringPiece32(const base::StringPiece& value) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!WriteUInt32(value.size())) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WriteBytes(value.data(), value.size());
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdyFrameBuilder::WriteBytes(const void* data, uint32 data_len) {
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CanWrite(data_len)) {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  char* dest = GetWritableBuffer(data_len);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memcpy(dest, data, data_len);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Seek(data_len);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdyFrameBuilder::RewriteLength(const SpdyFramer& framer) {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (framer.protocol_version() < 4) {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OverwriteLength(framer,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           length_ - framer.GetControlFrameHeaderSize());
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OverwriteLength(framer, length_);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer,
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       size_t length) {
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool success = false;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t old_length = length_;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (framer.protocol_version() < 4) {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FlagsAndLength flags_length = CreateFlagsAndLength(
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        0,  // We're not writing over the flags value anyway.
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        length);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Write into the correct location by temporarily faking the offset.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    length_ = 5;  // Offset at which the length field occurs.
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    success = WriteBytes(reinterpret_cast<char*>(&flags_length) + 1,
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         sizeof(flags_length) - 1);
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    length_ = 0;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    success = WriteUInt16(length);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  length_ = old_length;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success;
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SpdyFrameBuilder::CanWrite(size_t length) const {
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (length > kLengthMask) {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(false);
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (length_ + length > capacity_) {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(false);
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
192