1// Copyright (c) 2009 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#include <limits>
6
7#include "net/spdy/spdy_frame_builder.h"
8#include "net/spdy/spdy_protocol.h"
9
10namespace spdy {
11
12// We mark a read only SpdyFrameBuilder with a special capacity_.
13static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
14
15SpdyFrameBuilder::SpdyFrameBuilder()
16    : buffer_(NULL),
17      capacity_(0),
18      length_(0),
19      variable_buffer_offset_(0) {
20  Resize(kInitialPayload);
21}
22
23SpdyFrameBuilder::SpdyFrameBuilder(const char* data, int data_len)
24    : buffer_(const_cast<char*>(data)),
25      capacity_(kCapacityReadOnly),
26      length_(data_len),
27      variable_buffer_offset_(0) {
28}
29
30SpdyFrameBuilder::~SpdyFrameBuilder() {
31  if (capacity_ != kCapacityReadOnly)
32    delete[] buffer_;
33}
34
35bool SpdyFrameBuilder::ReadUInt16(void** iter, uint16* result) const {
36  DCHECK(iter);
37  if (!*iter)
38    *iter = const_cast<char*>(buffer_);
39
40  if (!IteratorHasRoomFor(*iter, sizeof(*result)))
41    return false;
42
43  *result = ntohs(*(reinterpret_cast<uint16*>(*iter)));
44
45  UpdateIter(iter, sizeof(*result));
46  return true;
47}
48
49bool SpdyFrameBuilder::ReadUInt32(void** iter, uint32* result) const {
50  DCHECK(iter);
51  if (!*iter)
52    *iter = const_cast<char*>(buffer_);
53
54  if (!IteratorHasRoomFor(*iter, sizeof(*result)))
55    return false;
56
57  *result = ntohl(*(reinterpret_cast<uint32*>(*iter)));
58
59  UpdateIter(iter, sizeof(*result));
60  return true;
61}
62
63bool SpdyFrameBuilder::ReadString(void** iter, std::string* result) const {
64  DCHECK(iter);
65
66  uint16 len;
67  if (!ReadUInt16(iter, &len))
68    return false;
69
70  if (!IteratorHasRoomFor(*iter, len))
71    return false;
72
73  char* chars = reinterpret_cast<char*>(*iter);
74  result->assign(chars, len);
75
76  UpdateIter(iter, len);
77  return true;
78}
79
80bool SpdyFrameBuilder::ReadBytes(void** iter, const char** data,
81                                 uint16 length) const {
82  DCHECK(iter);
83  DCHECK(data);
84
85  if (!IteratorHasRoomFor(*iter, length))
86    return false;
87
88  *data = reinterpret_cast<const char*>(*iter);
89
90  UpdateIter(iter, length);
91  return true;
92}
93
94bool SpdyFrameBuilder::ReadData(void** iter, const char** data,
95                                uint16* length) const {
96  DCHECK(iter);
97  DCHECK(data);
98  DCHECK(length);
99
100  if (!ReadUInt16(iter, length))
101    return false;
102
103  return ReadBytes(iter, data, *length);
104}
105
106bool SpdyFrameBuilder::WriteString(const std::string& value) {
107  if (value.size() > 0xffff)
108    return false;
109
110  if (!WriteUInt16(static_cast<int>(value.size())))
111    return false;
112
113  return WriteBytes(value.data(), static_cast<uint16>(value.size()));
114}
115
116bool SpdyFrameBuilder::WriteBytes(const void* data, uint16 data_len) {
117  DCHECK(capacity_ != kCapacityReadOnly);
118
119  char* dest = BeginWrite(data_len);
120  if (!dest)
121    return false;
122
123  memcpy(dest, data, data_len);
124
125  EndWrite(dest, data_len);
126  length_ += data_len;
127  return true;
128}
129
130char* SpdyFrameBuilder::BeginWriteData(uint16 length) {
131  DCHECK_EQ(variable_buffer_offset_, 0U) <<
132    "There can only be one variable buffer in a SpdyFrameBuilder";
133
134  if (!WriteUInt16(length))
135    return NULL;
136
137  char *data_ptr = BeginWrite(length);
138  if (!data_ptr)
139    return NULL;
140
141  variable_buffer_offset_ = data_ptr - buffer_ - sizeof(int);
142
143  // EndWrite doesn't necessarily have to be called after the write operation,
144  // so we call it here to pad out what the caller will eventually write.
145  EndWrite(data_ptr, length);
146  return data_ptr;
147}
148
149char* SpdyFrameBuilder::BeginWrite(size_t length) {
150  size_t needed_size = length_ + length;
151  if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
152    return NULL;
153
154#ifdef ARCH_CPU_64_BITS
155  DCHECK_LE(length, std::numeric_limits<uint32>::max());
156#endif
157
158  return buffer_ + length_;
159}
160
161void SpdyFrameBuilder::EndWrite(char* dest, int length) {
162}
163
164bool SpdyFrameBuilder::Resize(size_t new_capacity) {
165  if (new_capacity <= capacity_)
166    return true;
167
168  char* p = new char[new_capacity];
169  if (!p)
170    return false;
171  if (buffer_) {
172    memcpy(p, buffer_, capacity_);
173    delete[] buffer_;
174  }
175  buffer_ = p;
176  capacity_ = new_capacity;
177  return true;
178}
179
180}  // namespace spdy
181