1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <limits>
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_frame_builder.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_protocol.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace spdy {
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We mark a read only SpdyFrameBuilder with a special capacity_.
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyFrameBuilder::SpdyFrameBuilder()
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : buffer_(NULL),
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      capacity_(0),
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      length_(0),
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      variable_buffer_offset_(0) {
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Resize(kInitialPayload);
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyFrameBuilder::SpdyFrameBuilder(const char* data, int data_len)
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : buffer_(const_cast<char*>(data)),
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      capacity_(kCapacityReadOnly),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      length_(data_len),
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      variable_buffer_offset_(0) {
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyFrameBuilder::~SpdyFrameBuilder() {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (capacity_ != kCapacityReadOnly)
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete[] buffer_;
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFrameBuilder::ReadUInt16(void** iter, uint16* result) const {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(iter);
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!*iter)
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *iter = const_cast<char*>(buffer_);
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IteratorHasRoomFor(*iter, sizeof(*result)))
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *result = ntohs(*(reinterpret_cast<uint16*>(*iter)));
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateIter(iter, sizeof(*result));
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFrameBuilder::ReadUInt32(void** iter, uint32* result) const {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(iter);
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!*iter)
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *iter = const_cast<char*>(buffer_);
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IteratorHasRoomFor(*iter, sizeof(*result)))
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *result = ntohl(*(reinterpret_cast<uint32*>(*iter)));
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateIter(iter, sizeof(*result));
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFrameBuilder::ReadString(void** iter, std::string* result) const {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(iter);
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uint16 len;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ReadUInt16(iter, &len))
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IteratorHasRoomFor(*iter, len))
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char* chars = reinterpret_cast<char*>(*iter);
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->assign(chars, len);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateIter(iter, len);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFrameBuilder::ReadBytes(void** iter, const char** data,
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 uint16 length) const {
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(iter);
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(data);
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IteratorHasRoomFor(*iter, length))
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *data = reinterpret_cast<const char*>(*iter);
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateIter(iter, length);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFrameBuilder::ReadData(void** iter, const char** data,
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                uint16* length) const {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(iter);
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(data);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(length);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ReadUInt16(iter, length))
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ReadBytes(iter, data, *length);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SpdyFrameBuilder::WriteString(const std::string& value) {
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (value.size() > 0xffff)
10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!WriteUInt16(static_cast<int>(value.size())))
11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return WriteBytes(value.data(), static_cast<uint16>(value.size()));
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFrameBuilder::WriteBytes(const void* data, uint16 data_len) {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(capacity_ != kCapacityReadOnly);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char* dest = BeginWrite(data_len);
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!dest)
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(dest, data, data_len);
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EndWrite(dest, data_len);
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  length_ += data_len;
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochchar* SpdyFrameBuilder::BeginWriteData(uint16 length) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(variable_buffer_offset_, 0U) <<
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "There can only be one variable buffer in a SpdyFrameBuilder";
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!WriteUInt16(length))
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char *data_ptr = BeginWrite(length);
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!data_ptr)
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  variable_buffer_offset_ = data_ptr - buffer_ - sizeof(int);
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // EndWrite doesn't necessarily have to be called after the write operation,
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so we call it here to pad out what the caller will eventually write.
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EndWrite(data_ptr, length);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return data_ptr;
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenchar* SpdyFrameBuilder::BeginWrite(size_t length) {
15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t needed_size = length_ + length;
15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return NULL;
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#ifdef ARCH_CPU_64_BITS
15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_LE(length, std::numeric_limits<uint32>::max());
15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif
15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return buffer_ + length_;
15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SpdyFrameBuilder::EndWrite(char* dest, int length) {
16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyFrameBuilder::Resize(size_t new_capacity) {
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (new_capacity <= capacity_)
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char* p = new char[new_capacity];
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!p)
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (buffer_) {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    memcpy(p, buffer_, capacity_);
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete[] buffer_;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  buffer_ = p;
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  capacity_ = new_capacity;
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace spdy
181