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