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
15namespace 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.
28class 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