| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_SPDY_SPDY_FRAME_BUILDER_H_ |
| #define NET_SPDY_SPDY_FRAME_BUILDER_H_ |
| #pragma once |
| |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "net/base/sys_byteorder.h" |
| #include "net/spdy/spdy_protocol.h" |
| |
| namespace spdy { |
| |
| // This class provides facilities for basic binary value packing and unpacking |
| // into Spdy frames. |
| // |
| // The SpdyFrameBuilder supports appending primitive values (int, string, etc) |
| // to a frame instance. The SpdyFrameBuilder grows its internal memory buffer |
| // dynamically to hold the sequence of primitive values. The internal memory |
| // buffer is exposed as the "data" of the SpdyFrameBuilder. |
| // |
| // When reading from a SpdyFrameBuilder the consumer must know what value types |
| // to read and in what order to read them as the SpdyFrameBuilder does not keep |
| // track of the type of data written to it. |
| class SpdyFrameBuilder { |
| public: |
| SpdyFrameBuilder(); |
| |
| // Initializes a SpdyFrameBuilder from a const block of data. The data is |
| // not copied; instead the data is merely referenced by this |
| // SpdyFrameBuilder. Only const methods should be used when initialized |
| // this way. |
| SpdyFrameBuilder(const char* data, int data_len); |
| |
| ~SpdyFrameBuilder(); |
| |
| // Returns the size of the SpdyFrameBuilder's data. |
| int length() const { return length_; } |
| |
| // Takes the buffer from the SpdyFrameBuilder. |
| SpdyFrame* take() { |
| SpdyFrame* rv = new SpdyFrame(buffer_, true); |
| buffer_ = NULL; |
| capacity_ = 0; |
| length_ = 0; |
| return rv; |
| } |
| |
| // Methods for reading the payload of the SpdyFrameBuilder. To read from the |
| // start of the SpdyFrameBuilder, initialize *iter to NULL. If successful, |
| // these methods return true. Otherwise, false is returned to indicate that |
| // the result could not be extracted. |
| bool ReadUInt16(void** iter, uint16* result) const; |
| bool ReadUInt32(void** iter, uint32* result) const; |
| bool ReadString(void** iter, std::string* result) const; |
| bool ReadBytes(void** iter, const char** data, uint16 length) const; |
| bool ReadData(void** iter, const char** data, uint16* length) const; |
| |
| // Methods for adding to the payload. These values are appended to the end |
| // of the SpdyFrameBuilder payload. When reading values, you must read them |
| // in the order they were added. Note - binary integers are converted from |
| // host to network form. |
| bool WriteUInt16(uint16 value) { |
| value = htons(value); |
| return WriteBytes(&value, sizeof(value)); |
| } |
| bool WriteUInt32(uint32 value) { |
| value = htonl(value); |
| return WriteBytes(&value, sizeof(value)); |
| } |
| bool WriteString(const std::string& value); |
| bool WriteBytes(const void* data, uint16 data_len); |
| |
| // Write an integer to a particular offset in the data buffer. |
| bool WriteUInt32ToOffset(int offset, uint32 value) { |
| value = htonl(value); |
| return WriteBytesToOffset(offset, &value, sizeof(value)); |
| } |
| |
| // Write to a particular offset in the data buffer. |
| bool WriteBytesToOffset(int offset, const void* data, uint32 data_len) { |
| if (offset + data_len > length_) |
| return false; |
| char *ptr = buffer_ + offset; |
| memcpy(ptr, data, data_len); |
| return true; |
| } |
| |
| // Allows the caller to write data directly into the SpdyFrameBuilder. |
| // This saves a copy when the data is not already available in a buffer. |
| // The caller must not write more than the length it declares it will. |
| // Use ReadData to get the data. |
| // Returns NULL on failure. |
| // |
| // The returned pointer will only be valid until the next write operation |
| // on this SpdyFrameBuilder. |
| char* BeginWriteData(uint16 length); |
| |
| // Returns true if the given iterator could point to data with the given |
| // length. If there is no room for the given data before the end of the |
| // payload, returns false. |
| bool IteratorHasRoomFor(const void* iter, int len) const { |
| const char* end_of_region = reinterpret_cast<const char*>(iter) + len; |
| if (len < 0 || |
| iter < buffer_ || |
| iter > end_of_payload() || |
| iter > end_of_region || |
| end_of_region > end_of_payload()) |
| return false; |
| |
| // Watch out for overflow in pointer calculation, which wraps. |
| return (iter <= end_of_region) && (end_of_region <= end_of_payload()); |
| } |
| |
| protected: |
| size_t capacity() const { |
| return capacity_; |
| } |
| |
| const char* end_of_payload() const { return buffer_ + length_; } |
| |
| // Resizes the buffer for use when writing the specified amount of data. The |
| // location that the data should be written at is returned, or NULL if there |
| // was an error. Call EndWrite with the returned offset and the given length |
| // to pad out for the next write. |
| char* BeginWrite(size_t length); |
| |
| // Completes the write operation by padding the data with NULL bytes until it |
| // is padded. Should be paired with BeginWrite, but it does not necessarily |
| // have to be called after the data is written. |
| void EndWrite(char* dest, int length); |
| |
| // Resize the capacity, note that the input value should include the size of |
| // the header: new_capacity = sizeof(Header) + desired_payload_capacity. |
| // A new failure will cause a Resize failure... and caller should check |
| // the return result for true (i.e., successful resizing). |
| bool Resize(size_t new_capacity); |
| |
| // Moves the iterator by the given number of bytes. |
| static void UpdateIter(void** iter, int bytes) { |
| *iter = static_cast<char*>(*iter) + bytes; |
| } |
| |
| // Initial size of the payload. |
| static const int kInitialPayload = 1024; |
| |
| private: |
| char* buffer_; |
| size_t capacity_; // Allocation size of payload (or -1 if buffer is const). |
| size_t length_; // current length of the buffer |
| size_t variable_buffer_offset_; // IF non-zero, then offset to a buffer. |
| }; |
| |
| } // namespace spdy |
| |
| #endif // NET_SPDY_SPDY_FRAME_BUILDER_H_ |