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