• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
length()41   int length() const { return length_; }
42 
43   // Takes the buffer from the SpdyFrameBuilder.
take()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.
WriteUInt16(uint16 value)66   bool WriteUInt16(uint16 value) {
67     value = htons(value);
68     return WriteBytes(&value, sizeof(value));
69   }
WriteUInt32(uint32 value)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.
WriteUInt32ToOffset(int offset,uint32 value)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.
WriteBytesToOffset(int offset,const void * data,uint32 data_len)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.
IteratorHasRoomFor(const void * iter,int len)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:
capacity()119   size_t capacity() const {
120     return capacity_;
121   }
122 
end_of_payload()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.
UpdateIter(void ** iter,int 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