Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2010 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 #ifndef NET_SPDY_SPDY_FRAME_BUILDER_H_
      6 #define NET_SPDY_SPDY_FRAME_BUILDER_H_
      7 #pragma once
      8 
      9 #include <string>
     10 
     11 #include "base/basictypes.h"
     12 #include "net/base/sys_byteorder.h"
     13 #include "net/spdy/spdy_protocol.h"
     14 
     15 namespace spdy {
     16 
     17 // This class provides facilities for basic binary value packing and unpacking
     18 // into Spdy frames.
     19 //
     20 // The SpdyFrameBuilder supports appending primitive values (int, string, etc)
     21 // to a frame instance.  The SpdyFrameBuilder grows its internal memory buffer
     22 // dynamically to hold the sequence of primitive values.   The internal memory
     23 // buffer is exposed as the "data" of the SpdyFrameBuilder.
     24 //
     25 // When reading from a SpdyFrameBuilder the consumer must know what value types
     26 // to read and in what order to read them as the SpdyFrameBuilder does not keep
     27 // track of the type of data written to it.
     28 class SpdyFrameBuilder {
     29  public:
     30   SpdyFrameBuilder();
     31 
     32   // Initializes a SpdyFrameBuilder from a const block of data.  The data is
     33   // not copied; instead the data is merely referenced by this
     34   // SpdyFrameBuilder.  Only const methods should be used when initialized
     35   // this way.
     36   SpdyFrameBuilder(const char* data, int data_len);
     37 
     38   ~SpdyFrameBuilder();
     39 
     40   // Returns the size of the SpdyFrameBuilder's data.
     41   int length() const { return length_; }
     42 
     43   // Takes the buffer from the SpdyFrameBuilder.
     44   SpdyFrame* take() {
     45     SpdyFrame* rv = new SpdyFrame(buffer_, true);
     46     buffer_ = NULL;
     47     capacity_ = 0;
     48     length_ = 0;
     49     return rv;
     50   }
     51 
     52   // Methods for reading the payload of the SpdyFrameBuilder.  To read from the
     53   // start of the SpdyFrameBuilder, initialize *iter to NULL.  If successful,
     54   // these methods return true.  Otherwise, false is returned to indicate that
     55   // the result could not be extracted.
     56   bool ReadUInt16(void** iter, uint16* result) const;
     57   bool ReadUInt32(void** iter, uint32* result) const;
     58   bool ReadString(void** iter, std::string* result) const;
     59   bool ReadBytes(void** iter, const char** data, uint16 length) const;
     60   bool ReadData(void** iter, const char** data, uint16* length) const;
     61 
     62   // Methods for adding to the payload.  These values are appended to the end
     63   // of the SpdyFrameBuilder payload.  When reading values, you must read them
     64   // in the order they were added.  Note - binary integers are converted from
     65   // host to network form.
     66   bool WriteUInt16(uint16 value) {
     67     value = htons(value);
     68     return WriteBytes(&value, sizeof(value));
     69   }
     70   bool WriteUInt32(uint32 value) {
     71     value = htonl(value);
     72     return WriteBytes(&value, sizeof(value));
     73   }
     74   bool WriteString(const std::string& value);
     75   bool WriteBytes(const void* data, uint16 data_len);
     76 
     77   // Write an integer to a particular offset in the data buffer.
     78   bool WriteUInt32ToOffset(int offset, uint32 value) {
     79     value = htonl(value);
     80     return WriteBytesToOffset(offset, &value, sizeof(value));
     81   }
     82 
     83   // Write to a particular offset in the data buffer.
     84   bool WriteBytesToOffset(int offset, const void* data, uint32 data_len) {
     85     if (offset + data_len > length_)
     86       return false;
     87     char *ptr = buffer_ + offset;
     88     memcpy(ptr, data, data_len);
     89     return true;
     90   }
     91 
     92   // Allows the caller to write data directly into the SpdyFrameBuilder.
     93   // This saves a copy when the data is not already available in a buffer.
     94   // The caller must not write more than the length it declares it will.
     95   // Use ReadData to get the data.
     96   // Returns NULL on failure.
     97   //
     98   // The returned pointer will only be valid until the next write operation
     99   // on this SpdyFrameBuilder.
    100   char* BeginWriteData(uint16 length);
    101 
    102   // Returns true if the given iterator could point to data with the given
    103   // length. If there is no room for the given data before the end of the
    104   // payload, returns false.
    105   bool IteratorHasRoomFor(const void* iter, int len) const {
    106     const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
    107     if (len < 0 ||
    108         iter < buffer_ ||
    109         iter > end_of_payload() ||
    110         iter > end_of_region ||
    111         end_of_region > end_of_payload())
    112       return false;
    113 
    114     // Watch out for overflow in pointer calculation, which wraps.
    115     return (iter <= end_of_region) && (end_of_region <= end_of_payload());
    116   }
    117 
    118  protected:
    119   size_t capacity() const {
    120     return capacity_;
    121   }
    122 
    123   const char* end_of_payload() const { return buffer_ + length_; }
    124 
    125   // Resizes the buffer for use when writing the specified amount of data. The
    126   // location that the data should be written at is returned, or NULL if there
    127   // was an error. Call EndWrite with the returned offset and the given length
    128   // to pad out for the next write.
    129   char* BeginWrite(size_t length);
    130 
    131   // Completes the write operation by padding the data with NULL bytes until it
    132   // is padded. Should be paired with BeginWrite, but it does not necessarily
    133   // have to be called after the data is written.
    134   void EndWrite(char* dest, int length);
    135 
    136   // Resize the capacity, note that the input value should include the size of
    137   // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
    138   // A new failure will cause a Resize failure... and caller should check
    139   // the return result for true (i.e., successful resizing).
    140   bool Resize(size_t new_capacity);
    141 
    142   // Moves the iterator by the given number of bytes.
    143   static void UpdateIter(void** iter, int bytes) {
    144     *iter = static_cast<char*>(*iter) + bytes;
    145   }
    146 
    147   // Initial size of the payload.
    148   static const int kInitialPayload = 1024;
    149 
    150  private:
    151   char* buffer_;
    152   size_t capacity_;  // Allocation size of payload (or -1 if buffer is const).
    153   size_t length_;    // current length of the buffer
    154   size_t variable_buffer_offset_;  // IF non-zero, then offset to a buffer.
    155 };
    156 
    157 }  // namespace spdy
    158 
    159 #endif  // NET_SPDY_SPDY_FRAME_BUILDER_H_
    160