blob: b97f7f796196c3b718f74cd94933adfb4bd0fc7f [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2018 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/quic/core/http/http_encoder.h"
renjietangec095762019-06-19 14:35:02 -07006
QUICHE teama6ef0a62019-03-07 20:34:33 -05007#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05008
9namespace quic {
10
11namespace {
12
13// Set the first byte of a PRIORITY frame according to its fields.
14uint8_t SetPriorityFields(uint8_t num,
15 PriorityElementType type,
16 bool prioritized) {
17 switch (type) {
18 case REQUEST_STREAM:
19 return num;
20 case PUSH_STREAM:
21 if (prioritized) {
22 return num | (1 << 6);
23 }
24 return num | (1 << 4);
25 case PLACEHOLDER:
26 if (prioritized) {
27 return num | (1 << 7);
28 }
29 return num | (1 << 5);
30 case ROOT_OF_TREE:
31 if (prioritized) {
32 num = num | (1 << 6);
33 return num | (1 << 7);
34 }
35 num = num | (1 << 4);
36 return num | (1 << 5);
37 default:
38 QUIC_NOTREACHED();
39 return num;
40 }
41}
42
QUICHE teama6ef0a62019-03-07 20:34:33 -050043} // namespace
44
45HttpEncoder::HttpEncoder() {}
46
47HttpEncoder::~HttpEncoder() {}
48
49QuicByteCount HttpEncoder::SerializeDataFrameHeader(
50 QuicByteCount payload_length,
51 std::unique_ptr<char[]>* output) {
52 DCHECK_NE(0u, payload_length);
renjietang2d475cf2019-04-18 17:03:37 -070053 QuicByteCount header_length = QuicDataWriter::GetVarInt62Len(payload_length) +
54 QuicDataWriter::GetVarInt62Len(
55 static_cast<uint64_t>(HttpFrameType::DATA));
QUICHE teama6ef0a62019-03-07 20:34:33 -050056
57 output->reset(new char[header_length]);
58 QuicDataWriter writer(header_length, output->get());
59
60 if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) {
61 return header_length;
62 }
renjietang3b3e3b32019-04-22 18:01:20 -070063 QUIC_DLOG(ERROR)
64 << "Http encoder failed when attempting to serialize data frame header.";
QUICHE teama6ef0a62019-03-07 20:34:33 -050065 return 0;
66}
67
68QuicByteCount HttpEncoder::SerializeHeadersFrameHeader(
69 QuicByteCount payload_length,
70 std::unique_ptr<char[]>* output) {
71 DCHECK_NE(0u, payload_length);
72 QuicByteCount header_length =
renjietang2d475cf2019-04-18 17:03:37 -070073 QuicDataWriter::GetVarInt62Len(payload_length) +
74 QuicDataWriter::GetVarInt62Len(
75 static_cast<uint64_t>(HttpFrameType::HEADERS));
QUICHE teama6ef0a62019-03-07 20:34:33 -050076
77 output->reset(new char[header_length]);
78 QuicDataWriter writer(header_length, output->get());
79
80 if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) {
81 return header_length;
82 }
renjietang3b3e3b32019-04-22 18:01:20 -070083 QUIC_DLOG(ERROR)
84 << "Http encoder failed when attempting to serialize headers "
85 "frame header.";
QUICHE teama6ef0a62019-03-07 20:34:33 -050086 return 0;
87}
88
89QuicByteCount HttpEncoder::SerializePriorityFrame(
90 const PriorityFrame& priority,
91 std::unique_ptr<char[]>* output) {
92 QuicByteCount payload_length =
93 kPriorityFirstByteLength +
renjietangec095762019-06-19 14:35:02 -070094 (priority.prioritized_type == ROOT_OF_TREE
95 ? 0
96 : QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id)) +
97 (priority.dependency_type == ROOT_OF_TREE
98 ? 0
99 : QuicDataWriter::GetVarInt62Len(priority.element_dependency_id)) +
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100 kPriorityWeightLength;
renjietang2d475cf2019-04-18 17:03:37 -0700101 QuicByteCount total_length =
102 GetTotalLength(payload_length, HttpFrameType::PRIORITY);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500103
104 output->reset(new char[total_length]);
105 QuicDataWriter writer(total_length, output->get());
106
107 if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) {
renjietang3b3e3b32019-04-22 18:01:20 -0700108 QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize "
109 "priority frame header.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500110 return 0;
111 }
112
113 // Set the first byte of the payload.
renjietangec095762019-06-19 14:35:02 -0700114 uint8_t firstByte = 0;
115 firstByte = SetPriorityFields(firstByte, priority.prioritized_type, true);
116 firstByte = SetPriorityFields(firstByte, priority.dependency_type, false);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117 if (priority.exclusive) {
renjietangec095762019-06-19 14:35:02 -0700118 firstByte |= kPriorityExclusiveBit;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500119 }
120
renjietangec095762019-06-19 14:35:02 -0700121 if (writer.WriteUInt8(firstByte) && MaybeWriteIds(priority, &writer) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122 writer.WriteUInt8(priority.weight)) {
123 return total_length;
124 }
renjietang3b3e3b32019-04-22 18:01:20 -0700125 QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize "
126 "priority frame payload.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500127 return 0;
128}
129
130QuicByteCount HttpEncoder::SerializeCancelPushFrame(
131 const CancelPushFrame& cancel_push,
132 std::unique_ptr<char[]>* output) {
133 QuicByteCount payload_length =
134 QuicDataWriter::GetVarInt62Len(cancel_push.push_id);
renjietang2d475cf2019-04-18 17:03:37 -0700135 QuicByteCount total_length =
136 GetTotalLength(payload_length, HttpFrameType::CANCEL_PUSH);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500137
138 output->reset(new char[total_length]);
139 QuicDataWriter writer(total_length, output->get());
140
141 if (WriteFrameHeader(payload_length, HttpFrameType::CANCEL_PUSH, &writer) &&
142 writer.WriteVarInt62(cancel_push.push_id)) {
143 return total_length;
144 }
renjietang3b3e3b32019-04-22 18:01:20 -0700145 QUIC_DLOG(ERROR)
146 << "Http encoder failed when attempting to serialize cancel push frame.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500147 return 0;
148}
149
150QuicByteCount HttpEncoder::SerializeSettingsFrame(
151 const SettingsFrame& settings,
152 std::unique_ptr<char[]>* output) {
renjietang3b3e3b32019-04-22 18:01:20 -0700153 QuicByteCount payload_length = 0;
154 // Calculate the payload length.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500155 for (auto it = settings.values.begin(); it != settings.values.end(); ++it) {
renjietang3b3e3b32019-04-22 18:01:20 -0700156 payload_length += QuicDataWriter::GetVarInt62Len(it->first);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500157 payload_length += QuicDataWriter::GetVarInt62Len(it->second);
158 }
159
renjietang2d475cf2019-04-18 17:03:37 -0700160 QuicByteCount total_length =
161 GetTotalLength(payload_length, HttpFrameType::SETTINGS);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500162
163 output->reset(new char[total_length]);
164 QuicDataWriter writer(total_length, output->get());
165
166 if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) {
renjietang3b3e3b32019-04-22 18:01:20 -0700167 QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize "
168 "settings frame header.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500169 return 0;
170 }
171
172 for (auto it = settings.values.begin(); it != settings.values.end(); ++it) {
renjietang3b3e3b32019-04-22 18:01:20 -0700173 if (!writer.WriteVarInt62(it->first) || !writer.WriteVarInt62(it->second)) {
174 QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize "
175 "settings frame payload.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500176 return 0;
177 }
178 }
179
180 return total_length;
181}
182
183QuicByteCount HttpEncoder::SerializePushPromiseFrameWithOnlyPushId(
184 const PushPromiseFrame& push_promise,
185 std::unique_ptr<char[]>* output) {
186 QuicByteCount payload_length =
187 QuicDataWriter::GetVarInt62Len(push_promise.push_id) +
188 push_promise.headers.length();
189 // GetTotalLength() is not used because headers will not be serialized.
190 QuicByteCount total_length =
renjietang2d475cf2019-04-18 17:03:37 -0700191 QuicDataWriter::GetVarInt62Len(payload_length) +
192 QuicDataWriter::GetVarInt62Len(
193 static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE)) +
QUICHE teama6ef0a62019-03-07 20:34:33 -0500194 QuicDataWriter::GetVarInt62Len(push_promise.push_id);
195
196 output->reset(new char[total_length]);
197 QuicDataWriter writer(total_length, output->get());
198
199 if (WriteFrameHeader(payload_length, HttpFrameType::PUSH_PROMISE, &writer) &&
200 writer.WriteVarInt62(push_promise.push_id)) {
201 return total_length;
202 }
renjietang3b3e3b32019-04-22 18:01:20 -0700203 QUIC_DLOG(ERROR)
204 << "Http encoder failed when attempting to serialize push promise frame.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500205 return 0;
206}
207
208QuicByteCount HttpEncoder::SerializeGoAwayFrame(
209 const GoAwayFrame& goaway,
210 std::unique_ptr<char[]>* output) {
211 QuicByteCount payload_length =
212 QuicDataWriter::GetVarInt62Len(goaway.stream_id);
renjietang2d475cf2019-04-18 17:03:37 -0700213 QuicByteCount total_length =
214 GetTotalLength(payload_length, HttpFrameType::GOAWAY);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500215
216 output->reset(new char[total_length]);
217 QuicDataWriter writer(total_length, output->get());
218
219 if (WriteFrameHeader(payload_length, HttpFrameType::GOAWAY, &writer) &&
220 writer.WriteVarInt62(goaway.stream_id)) {
221 return total_length;
222 }
renjietang3b3e3b32019-04-22 18:01:20 -0700223 QUIC_DLOG(ERROR)
224 << "Http encoder failed when attempting to serialize goaway frame.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500225 return 0;
226}
227
228QuicByteCount HttpEncoder::SerializeMaxPushIdFrame(
229 const MaxPushIdFrame& max_push_id,
230 std::unique_ptr<char[]>* output) {
231 QuicByteCount payload_length =
232 QuicDataWriter::GetVarInt62Len(max_push_id.push_id);
renjietang2d475cf2019-04-18 17:03:37 -0700233 QuicByteCount total_length =
234 GetTotalLength(payload_length, HttpFrameType::MAX_PUSH_ID);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500235
236 output->reset(new char[total_length]);
237 QuicDataWriter writer(total_length, output->get());
238
239 if (WriteFrameHeader(payload_length, HttpFrameType::MAX_PUSH_ID, &writer) &&
240 writer.WriteVarInt62(max_push_id.push_id)) {
241 return total_length;
242 }
renjietang3b3e3b32019-04-22 18:01:20 -0700243 QUIC_DLOG(ERROR)
244 << "Http encoder failed when attempting to serialize max push id frame.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500245 return 0;
246}
247
248QuicByteCount HttpEncoder::SerializeDuplicatePushFrame(
249 const DuplicatePushFrame& duplicate_push,
250 std::unique_ptr<char[]>* output) {
251 QuicByteCount payload_length =
252 QuicDataWriter::GetVarInt62Len(duplicate_push.push_id);
renjietang2d475cf2019-04-18 17:03:37 -0700253 QuicByteCount total_length =
254 GetTotalLength(payload_length, HttpFrameType::DUPLICATE_PUSH);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500255
256 output->reset(new char[total_length]);
257 QuicDataWriter writer(total_length, output->get());
258
259 if (WriteFrameHeader(payload_length, HttpFrameType::DUPLICATE_PUSH,
260 &writer) &&
261 writer.WriteVarInt62(duplicate_push.push_id)) {
262 return total_length;
263 }
renjietang3b3e3b32019-04-22 18:01:20 -0700264 QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize "
265 "duplicate push frame.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500266 return 0;
267}
268
269bool HttpEncoder::WriteFrameHeader(QuicByteCount length,
270 HttpFrameType type,
271 QuicDataWriter* writer) {
renjietangfcd91c02019-04-22 10:40:35 -0700272 return writer->WriteVarInt62(static_cast<uint64_t>(type)) &&
273 writer->WriteVarInt62(length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500274}
275
renjietang2d475cf2019-04-18 17:03:37 -0700276QuicByteCount HttpEncoder::GetTotalLength(QuicByteCount payload_length,
277 HttpFrameType type) {
278 return QuicDataWriter::GetVarInt62Len(payload_length) +
279 QuicDataWriter::GetVarInt62Len(static_cast<uint64_t>(type)) +
QUICHE teama6ef0a62019-03-07 20:34:33 -0500280 payload_length;
281}
282
renjietangec095762019-06-19 14:35:02 -0700283bool HttpEncoder::MaybeWriteIds(const PriorityFrame& priority,
284 QuicDataWriter* writer) {
285 if (priority.prioritized_type != ROOT_OF_TREE) {
286 if (!writer->WriteVarInt62(priority.prioritized_element_id)) {
287 return false;
288 }
289 } else {
290 DCHECK_EQ(0u, priority.prioritized_element_id)
291 << "Prioritized element id should be 0 when prioritized type is "
292 "ROOT_OF_TREE";
293 }
294 if (priority.dependency_type != ROOT_OF_TREE) {
295 if (!writer->WriteVarInt62(priority.element_dependency_id)) {
296 return false;
297 }
298 } else {
299 DCHECK_EQ(0u, priority.element_dependency_id)
300 << "Element dependency id should be 0 when dependency type is "
301 "ROOT_OF_TREE";
302 }
303 return true;
304}
305
QUICHE teama6ef0a62019-03-07 20:34:33 -0500306} // namespace quic