Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <limits>
      6 
      7 #include "net/spdy/spdy_frame_builder.h"
      8 #include "net/spdy/spdy_protocol.h"
      9 
     10 namespace spdy {
     11 
     12 // We mark a read only SpdyFrameBuilder with a special capacity_.
     13 static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
     14 
     15 SpdyFrameBuilder::SpdyFrameBuilder()
     16     : buffer_(NULL),
     17       capacity_(0),
     18       length_(0),
     19       variable_buffer_offset_(0) {
     20   Resize(kInitialPayload);
     21 }
     22 
     23 SpdyFrameBuilder::SpdyFrameBuilder(const char* data, int data_len)
     24     : buffer_(const_cast<char*>(data)),
     25       capacity_(kCapacityReadOnly),
     26       length_(data_len),
     27       variable_buffer_offset_(0) {
     28 }
     29 
     30 SpdyFrameBuilder::~SpdyFrameBuilder() {
     31   if (capacity_ != kCapacityReadOnly)
     32     delete[] buffer_;
     33 }
     34 
     35 bool SpdyFrameBuilder::ReadUInt16(void** iter, uint16* result) const {
     36   DCHECK(iter);
     37   if (!*iter)
     38     *iter = const_cast<char*>(buffer_);
     39 
     40   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     41     return false;
     42 
     43   *result = ntohs(*(reinterpret_cast<uint16*>(*iter)));
     44 
     45   UpdateIter(iter, sizeof(*result));
     46   return true;
     47 }
     48 
     49 bool SpdyFrameBuilder::ReadUInt32(void** iter, uint32* result) const {
     50   DCHECK(iter);
     51   if (!*iter)
     52     *iter = const_cast<char*>(buffer_);
     53 
     54   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     55     return false;
     56 
     57   *result = ntohl(*(reinterpret_cast<uint32*>(*iter)));
     58 
     59   UpdateIter(iter, sizeof(*result));
     60   return true;
     61 }
     62 
     63 bool SpdyFrameBuilder::ReadString(void** iter, std::string* result) const {
     64   DCHECK(iter);
     65 
     66   uint16 len;
     67   if (!ReadUInt16(iter, &len))
     68     return false;
     69 
     70   if (!IteratorHasRoomFor(*iter, len))
     71     return false;
     72 
     73   char* chars = reinterpret_cast<char*>(*iter);
     74   result->assign(chars, len);
     75 
     76   UpdateIter(iter, len);
     77   return true;
     78 }
     79 
     80 bool SpdyFrameBuilder::ReadBytes(void** iter, const char** data,
     81                                  uint16 length) const {
     82   DCHECK(iter);
     83   DCHECK(data);
     84 
     85   if (!IteratorHasRoomFor(*iter, length))
     86     return false;
     87 
     88   *data = reinterpret_cast<const char*>(*iter);
     89 
     90   UpdateIter(iter, length);
     91   return true;
     92 }
     93 
     94 bool SpdyFrameBuilder::ReadData(void** iter, const char** data,
     95                                 uint16* length) const {
     96   DCHECK(iter);
     97   DCHECK(data);
     98   DCHECK(length);
     99 
    100   if (!ReadUInt16(iter, length))
    101     return false;
    102 
    103   return ReadBytes(iter, data, *length);
    104 }
    105 
    106 bool SpdyFrameBuilder::WriteString(const std::string& value) {
    107   if (value.size() > 0xffff)
    108     return false;
    109 
    110   if (!WriteUInt16(static_cast<int>(value.size())))
    111     return false;
    112 
    113   return WriteBytes(value.data(), static_cast<uint16>(value.size()));
    114 }
    115 
    116 bool SpdyFrameBuilder::WriteBytes(const void* data, uint16 data_len) {
    117   DCHECK(capacity_ != kCapacityReadOnly);
    118 
    119   char* dest = BeginWrite(data_len);
    120   if (!dest)
    121     return false;
    122 
    123   memcpy(dest, data, data_len);
    124 
    125   EndWrite(dest, data_len);
    126   length_ += data_len;
    127   return true;
    128 }
    129 
    130 char* SpdyFrameBuilder::BeginWriteData(uint16 length) {
    131   DCHECK_EQ(variable_buffer_offset_, 0U) <<
    132     "There can only be one variable buffer in a SpdyFrameBuilder";
    133 
    134   if (!WriteUInt16(length))
    135     return NULL;
    136 
    137   char *data_ptr = BeginWrite(length);
    138   if (!data_ptr)
    139     return NULL;
    140 
    141   variable_buffer_offset_ = data_ptr - buffer_ - sizeof(int);
    142 
    143   // EndWrite doesn't necessarily have to be called after the write operation,
    144   // so we call it here to pad out what the caller will eventually write.
    145   EndWrite(data_ptr, length);
    146   return data_ptr;
    147 }
    148 
    149 char* SpdyFrameBuilder::BeginWrite(size_t length) {
    150   size_t needed_size = length_ + length;
    151   if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
    152     return NULL;
    153 
    154 #ifdef ARCH_CPU_64_BITS
    155   DCHECK_LE(length, std::numeric_limits<uint32>::max());
    156 #endif
    157 
    158   return buffer_ + length_;
    159 }
    160 
    161 void SpdyFrameBuilder::EndWrite(char* dest, int length) {
    162 }
    163 
    164 bool SpdyFrameBuilder::Resize(size_t new_capacity) {
    165   if (new_capacity <= capacity_)
    166     return true;
    167 
    168   char* p = new char[new_capacity];
    169   if (!p)
    170     return false;
    171   if (buffer_) {
    172     memcpy(p, buffer_, capacity_);
    173     delete[] buffer_;
    174   }
    175   buffer_ = p;
    176   capacity_ = new_capacity;
    177   return true;
    178 }
    179 
    180 }  // namespace spdy
    181