1 // Copyright 2016 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 "quiche/http2/test_tools/http2_frame_builder.h"
6
7 #ifdef WIN32
8 #include <winsock2.h> // for htonl() functions
9 #else
10 #include <arpa/inet.h>
11 #include <netinet/in.h> // for htonl, htons
12 #endif
13
14 #include "absl/strings/str_cat.h"
15 #include "quiche/common/platform/api/quiche_test.h"
16
17 namespace http2 {
18 namespace test {
19
Http2FrameBuilder(Http2FrameType type,uint8_t flags,uint32_t stream_id)20 Http2FrameBuilder::Http2FrameBuilder(Http2FrameType type, uint8_t flags,
21 uint32_t stream_id) {
22 AppendUInt24(0); // Frame payload length, unknown so far.
23 Append(type);
24 AppendUInt8(flags);
25 AppendUInt31(stream_id);
26 }
27
Http2FrameBuilder(const Http2FrameHeader & v)28 Http2FrameBuilder::Http2FrameBuilder(const Http2FrameHeader& v) { Append(v); }
29
Append(absl::string_view s)30 void Http2FrameBuilder::Append(absl::string_view s) {
31 absl::StrAppend(&buffer_, s);
32 }
33
AppendBytes(const void * data,uint32_t num_bytes)34 void Http2FrameBuilder::AppendBytes(const void* data, uint32_t num_bytes) {
35 Append(absl::string_view(static_cast<const char*>(data), num_bytes));
36 }
37
AppendZeroes(size_t num_zero_bytes)38 void Http2FrameBuilder::AppendZeroes(size_t num_zero_bytes) {
39 char zero = 0;
40 buffer_.append(num_zero_bytes, zero);
41 }
42
AppendUInt8(uint8_t value)43 void Http2FrameBuilder::AppendUInt8(uint8_t value) { AppendBytes(&value, 1); }
44
AppendUInt16(uint16_t value)45 void Http2FrameBuilder::AppendUInt16(uint16_t value) {
46 value = htons(value);
47 AppendBytes(&value, 2);
48 }
49
AppendUInt24(uint32_t value)50 void Http2FrameBuilder::AppendUInt24(uint32_t value) {
51 // Doesn't make sense to try to append a larger value, as that doesn't
52 // simulate something an encoder could do (i.e. the other 8 bits simply aren't
53 // there to be occupied).
54 EXPECT_EQ(value, value & 0xffffff);
55 value = htonl(value);
56 AppendBytes(reinterpret_cast<char*>(&value) + 1, 3);
57 }
58
AppendUInt31(uint32_t value)59 void Http2FrameBuilder::AppendUInt31(uint32_t value) {
60 // If you want to test the high-bit being set, call AppendUInt32 instead.
61 uint32_t tmp = value & StreamIdMask();
62 EXPECT_EQ(value, value & StreamIdMask())
63 << "High-bit of uint32_t should be clear.";
64 value = htonl(tmp);
65 AppendBytes(&value, 4);
66 }
67
AppendUInt32(uint32_t value)68 void Http2FrameBuilder::AppendUInt32(uint32_t value) {
69 value = htonl(value);
70 AppendBytes(&value, sizeof(value));
71 }
72
Append(Http2ErrorCode error_code)73 void Http2FrameBuilder::Append(Http2ErrorCode error_code) {
74 AppendUInt32(static_cast<uint32_t>(error_code));
75 }
76
Append(Http2FrameType type)77 void Http2FrameBuilder::Append(Http2FrameType type) {
78 AppendUInt8(static_cast<uint8_t>(type));
79 }
80
Append(Http2SettingsParameter parameter)81 void Http2FrameBuilder::Append(Http2SettingsParameter parameter) {
82 AppendUInt16(static_cast<uint16_t>(parameter));
83 }
84
Append(const Http2FrameHeader & v)85 void Http2FrameBuilder::Append(const Http2FrameHeader& v) {
86 AppendUInt24(v.payload_length);
87 Append(v.type);
88 AppendUInt8(v.flags);
89 AppendUInt31(v.stream_id);
90 }
91
Append(const Http2PriorityFields & v)92 void Http2FrameBuilder::Append(const Http2PriorityFields& v) {
93 // The EXCLUSIVE flag is the high-bit of the 32-bit stream dependency field.
94 uint32_t tmp = v.stream_dependency & StreamIdMask();
95 EXPECT_EQ(tmp, v.stream_dependency);
96 if (v.is_exclusive) {
97 tmp |= 0x80000000;
98 }
99 AppendUInt32(tmp);
100
101 // The PRIORITY frame's weight field is logically in the range [1, 256],
102 // but is encoded as a byte in the range [0, 255].
103 ASSERT_LE(1u, v.weight);
104 ASSERT_LE(v.weight, 256u);
105 AppendUInt8(v.weight - 1);
106 }
107
Append(const Http2RstStreamFields & v)108 void Http2FrameBuilder::Append(const Http2RstStreamFields& v) {
109 Append(v.error_code);
110 }
111
Append(const Http2SettingFields & v)112 void Http2FrameBuilder::Append(const Http2SettingFields& v) {
113 Append(v.parameter);
114 AppendUInt32(v.value);
115 }
116
Append(const Http2PushPromiseFields & v)117 void Http2FrameBuilder::Append(const Http2PushPromiseFields& v) {
118 AppendUInt31(v.promised_stream_id);
119 }
120
Append(const Http2PingFields & v)121 void Http2FrameBuilder::Append(const Http2PingFields& v) {
122 AppendBytes(v.opaque_bytes, sizeof Http2PingFields::opaque_bytes);
123 }
124
Append(const Http2GoAwayFields & v)125 void Http2FrameBuilder::Append(const Http2GoAwayFields& v) {
126 AppendUInt31(v.last_stream_id);
127 Append(v.error_code);
128 }
129
Append(const Http2WindowUpdateFields & v)130 void Http2FrameBuilder::Append(const Http2WindowUpdateFields& v) {
131 EXPECT_NE(0u, v.window_size_increment) << "Increment must be non-zero.";
132 AppendUInt31(v.window_size_increment);
133 }
134
Append(const Http2AltSvcFields & v)135 void Http2FrameBuilder::Append(const Http2AltSvcFields& v) {
136 AppendUInt16(v.origin_length);
137 }
138
Append(const Http2PriorityUpdateFields & v)139 void Http2FrameBuilder::Append(const Http2PriorityUpdateFields& v) {
140 AppendUInt31(v.prioritized_stream_id);
141 }
142
143 // Methods for changing existing buffer contents.
144
WriteAt(absl::string_view s,size_t offset)145 void Http2FrameBuilder::WriteAt(absl::string_view s, size_t offset) {
146 ASSERT_LE(offset, buffer_.size());
147 size_t len = offset + s.size();
148 if (len > buffer_.size()) {
149 buffer_.resize(len);
150 }
151 for (size_t ndx = 0; ndx < s.size(); ++ndx) {
152 buffer_[offset + ndx] = s[ndx];
153 }
154 }
155
WriteBytesAt(const void * data,uint32_t num_bytes,size_t offset)156 void Http2FrameBuilder::WriteBytesAt(const void* data, uint32_t num_bytes,
157 size_t offset) {
158 WriteAt(absl::string_view(static_cast<const char*>(data), num_bytes), offset);
159 }
160
WriteUInt24At(uint32_t value,size_t offset)161 void Http2FrameBuilder::WriteUInt24At(uint32_t value, size_t offset) {
162 ASSERT_LT(value, static_cast<uint32_t>(1 << 24));
163 value = htonl(value);
164 WriteBytesAt(reinterpret_cast<char*>(&value) + 1, sizeof(value) - 1, offset);
165 }
166
SetPayloadLength(uint32_t payload_length)167 void Http2FrameBuilder::SetPayloadLength(uint32_t payload_length) {
168 WriteUInt24At(payload_length, 0);
169 }
170
SetPayloadLength()171 size_t Http2FrameBuilder::SetPayloadLength() {
172 EXPECT_GE(size(), Http2FrameHeader::EncodedSize());
173 uint32_t payload_length = size() - Http2FrameHeader::EncodedSize();
174 SetPayloadLength(payload_length);
175 return payload_length;
176 }
177
178 } // namespace test
179 } // namespace http2
180