1 // Copyright 2012 The Chromium Authors
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/spdy/buffered_spdy_framer.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/check.h"
11 #include "base/strings/string_util.h"
12 #include "base/trace_event/memory_usage_estimator.h"
13
14 namespace net {
15
16 namespace {
17
18 // GOAWAY frame debug data is only buffered up to this many bytes.
19 size_t kGoAwayDebugDataMaxSize = 1024;
20
21 } // namespace
22
BufferedSpdyFramer(uint32_t max_header_list_size,const NetLogWithSource & net_log,TimeFunc time_func)23 BufferedSpdyFramer::BufferedSpdyFramer(uint32_t max_header_list_size,
24 const NetLogWithSource& net_log,
25 TimeFunc time_func)
26 : spdy_framer_(spdy::SpdyFramer::ENABLE_COMPRESSION),
27 max_header_list_size_(max_header_list_size),
28 net_log_(net_log),
29 time_func_(time_func) {
30 // Do not bother decoding response header payload above the limit.
31 deframer_.GetHpackDecoder()->set_max_decode_buffer_size_bytes(
32 max_header_list_size_);
33 }
34
35 BufferedSpdyFramer::~BufferedSpdyFramer() = default;
36
set_visitor(BufferedSpdyFramerVisitorInterface * visitor)37 void BufferedSpdyFramer::set_visitor(
38 BufferedSpdyFramerVisitorInterface* visitor) {
39 visitor_ = visitor;
40 deframer_.set_visitor(this);
41 }
42
set_debug_visitor(spdy::SpdyFramerDebugVisitorInterface * debug_visitor)43 void BufferedSpdyFramer::set_debug_visitor(
44 spdy::SpdyFramerDebugVisitorInterface* debug_visitor) {
45 spdy_framer_.set_debug_visitor(debug_visitor);
46 deframer_.set_debug_visitor(debug_visitor);
47 }
48
OnError(http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error,std::string)49 void BufferedSpdyFramer::OnError(
50 http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error,
51 std::string /*detailed_error*/) {
52 visitor_->OnError(spdy_framer_error);
53 }
54
OnHeaders(spdy::SpdyStreamId stream_id,size_t payload_length,bool has_priority,int weight,spdy::SpdyStreamId parent_stream_id,bool exclusive,bool fin,bool end)55 void BufferedSpdyFramer::OnHeaders(spdy::SpdyStreamId stream_id,
56 size_t payload_length,
57 bool has_priority,
58 int weight,
59 spdy::SpdyStreamId parent_stream_id,
60 bool exclusive,
61 bool fin,
62 bool end) {
63 frames_received_++;
64 DCHECK(!control_frame_fields_.get());
65 control_frame_fields_ = std::make_unique<ControlFrameFields>();
66 control_frame_fields_->type = spdy::SpdyFrameType::HEADERS;
67 control_frame_fields_->stream_id = stream_id;
68 control_frame_fields_->has_priority = has_priority;
69 if (control_frame_fields_->has_priority) {
70 control_frame_fields_->weight = weight;
71 control_frame_fields_->parent_stream_id = parent_stream_id;
72 control_frame_fields_->exclusive = exclusive;
73 }
74 control_frame_fields_->fin = fin;
75 control_frame_fields_->recv_first_byte_time = time_func_();
76 }
77
OnDataFrameHeader(spdy::SpdyStreamId stream_id,size_t length,bool fin)78 void BufferedSpdyFramer::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
79 size_t length,
80 bool fin) {
81 frames_received_++;
82 visitor_->OnDataFrameHeader(stream_id, length, fin);
83 }
84
OnStreamFrameData(spdy::SpdyStreamId stream_id,const char * data,size_t len)85 void BufferedSpdyFramer::OnStreamFrameData(spdy::SpdyStreamId stream_id,
86 const char* data,
87 size_t len) {
88 visitor_->OnStreamFrameData(stream_id, data, len);
89 }
90
OnStreamEnd(spdy::SpdyStreamId stream_id)91 void BufferedSpdyFramer::OnStreamEnd(spdy::SpdyStreamId stream_id) {
92 visitor_->OnStreamEnd(stream_id);
93 }
94
OnStreamPadLength(spdy::SpdyStreamId stream_id,size_t value)95 void BufferedSpdyFramer::OnStreamPadLength(spdy::SpdyStreamId stream_id,
96 size_t value) {
97 // Deliver the stream pad length byte for flow control handling.
98 visitor_->OnStreamPadding(stream_id, 1);
99 }
100
OnStreamPadding(spdy::SpdyStreamId stream_id,size_t len)101 void BufferedSpdyFramer::OnStreamPadding(spdy::SpdyStreamId stream_id,
102 size_t len) {
103 visitor_->OnStreamPadding(stream_id, len);
104 }
105
OnHeaderFrameStart(spdy::SpdyStreamId stream_id)106 spdy::SpdyHeadersHandlerInterface* BufferedSpdyFramer::OnHeaderFrameStart(
107 spdy::SpdyStreamId stream_id) {
108 coalescer_ =
109 std::make_unique<HeaderCoalescer>(max_header_list_size_, net_log_);
110 return coalescer_.get();
111 }
112
OnHeaderFrameEnd(spdy::SpdyStreamId stream_id)113 void BufferedSpdyFramer::OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) {
114 if (coalescer_->error_seen()) {
115 visitor_->OnStreamError(stream_id,
116 "Could not parse Spdy Control Frame Header.");
117 control_frame_fields_.reset();
118 return;
119 }
120 DCHECK(control_frame_fields_.get());
121 switch (control_frame_fields_->type) {
122 case spdy::SpdyFrameType::HEADERS:
123 visitor_->OnHeaders(
124 control_frame_fields_->stream_id, control_frame_fields_->has_priority,
125 control_frame_fields_->weight,
126 control_frame_fields_->parent_stream_id,
127 control_frame_fields_->exclusive, control_frame_fields_->fin,
128 coalescer_->release_headers(),
129 control_frame_fields_->recv_first_byte_time);
130 break;
131 case spdy::SpdyFrameType::PUSH_PROMISE:
132 visitor_->OnPushPromise(control_frame_fields_->stream_id,
133 control_frame_fields_->promised_stream_id,
134 coalescer_->release_headers());
135 break;
136 default:
137 DCHECK(false) << "Unexpect control frame type: "
138 << control_frame_fields_->type;
139 break;
140 }
141 control_frame_fields_.reset(nullptr);
142 }
143
OnSettings()144 void BufferedSpdyFramer::OnSettings() {
145 visitor_->OnSettings();
146 }
147
OnSetting(spdy::SpdySettingsId id,uint32_t value)148 void BufferedSpdyFramer::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
149 visitor_->OnSetting(id, value);
150 }
151
OnSettingsAck()152 void BufferedSpdyFramer::OnSettingsAck() {
153 visitor_->OnSettingsAck();
154 }
155
OnSettingsEnd()156 void BufferedSpdyFramer::OnSettingsEnd() {
157 visitor_->OnSettingsEnd();
158 }
159
OnPing(spdy::SpdyPingId unique_id,bool is_ack)160 void BufferedSpdyFramer::OnPing(spdy::SpdyPingId unique_id, bool is_ack) {
161 visitor_->OnPing(unique_id, is_ack);
162 }
163
OnRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code)164 void BufferedSpdyFramer::OnRstStream(spdy::SpdyStreamId stream_id,
165 spdy::SpdyErrorCode error_code) {
166 visitor_->OnRstStream(stream_id, error_code);
167 }
OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,spdy::SpdyErrorCode error_code)168 void BufferedSpdyFramer::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
169 spdy::SpdyErrorCode error_code) {
170 DCHECK(!goaway_fields_);
171 goaway_fields_ = std::make_unique<GoAwayFields>();
172 goaway_fields_->last_accepted_stream_id = last_accepted_stream_id;
173 goaway_fields_->error_code = error_code;
174 }
175
OnGoAwayFrameData(const char * goaway_data,size_t len)176 bool BufferedSpdyFramer::OnGoAwayFrameData(const char* goaway_data,
177 size_t len) {
178 if (len > 0) {
179 if (goaway_fields_->debug_data.size() < kGoAwayDebugDataMaxSize) {
180 goaway_fields_->debug_data.append(
181 goaway_data, std::min(len, kGoAwayDebugDataMaxSize -
182 goaway_fields_->debug_data.size()));
183 }
184 return true;
185 }
186 visitor_->OnGoAway(goaway_fields_->last_accepted_stream_id,
187 goaway_fields_->error_code, goaway_fields_->debug_data);
188 goaway_fields_.reset();
189 return true;
190 }
191
OnWindowUpdate(spdy::SpdyStreamId stream_id,int delta_window_size)192 void BufferedSpdyFramer::OnWindowUpdate(spdy::SpdyStreamId stream_id,
193 int delta_window_size) {
194 visitor_->OnWindowUpdate(stream_id, delta_window_size);
195 }
196
OnPushPromise(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId promised_stream_id,bool end)197 void BufferedSpdyFramer::OnPushPromise(spdy::SpdyStreamId stream_id,
198 spdy::SpdyStreamId promised_stream_id,
199 bool end) {
200 frames_received_++;
201 DCHECK(!control_frame_fields_.get());
202 control_frame_fields_ = std::make_unique<ControlFrameFields>();
203 control_frame_fields_->type = spdy::SpdyFrameType::PUSH_PROMISE;
204 control_frame_fields_->stream_id = stream_id;
205 control_frame_fields_->promised_stream_id = promised_stream_id;
206 control_frame_fields_->recv_first_byte_time = time_func_();
207 }
208
OnAltSvc(spdy::SpdyStreamId stream_id,absl::string_view origin,const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector & altsvc_vector)209 void BufferedSpdyFramer::OnAltSvc(
210 spdy::SpdyStreamId stream_id,
211 absl::string_view origin,
212 const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) {
213 visitor_->OnAltSvc(stream_id, origin, altsvc_vector);
214 }
215
OnContinuation(spdy::SpdyStreamId stream_id,size_t payload_length,bool end)216 void BufferedSpdyFramer::OnContinuation(spdy::SpdyStreamId stream_id,
217 size_t payload_length,
218 bool end) {}
219
OnUnknownFrame(spdy::SpdyStreamId stream_id,uint8_t frame_type)220 bool BufferedSpdyFramer::OnUnknownFrame(spdy::SpdyStreamId stream_id,
221 uint8_t frame_type) {
222 return visitor_->OnUnknownFrame(stream_id, frame_type);
223 }
224
ProcessInput(const char * data,size_t len)225 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
226 return deframer_.ProcessInput(data, len);
227 }
228
UpdateHeaderDecoderTableSize(uint32_t value)229 void BufferedSpdyFramer::UpdateHeaderDecoderTableSize(uint32_t value) {
230 deframer_.GetHpackDecoder()->ApplyHeaderTableSizeSetting(value);
231 }
232
233 http2::Http2DecoderAdapter::SpdyFramerError
spdy_framer_error() const234 BufferedSpdyFramer::spdy_framer_error() const {
235 return deframer_.spdy_framer_error();
236 }
237
state() const238 http2::Http2DecoderAdapter::SpdyState BufferedSpdyFramer::state() const {
239 return deframer_.state();
240 }
241
MessageFullyRead()242 bool BufferedSpdyFramer::MessageFullyRead() {
243 return state() == http2::Http2DecoderAdapter::SPDY_FRAME_COMPLETE;
244 }
245
HasError()246 bool BufferedSpdyFramer::HasError() {
247 return deframer_.HasError();
248 }
249
250 // TODO(jgraettinger): Eliminate uses of this method (prefer
251 // spdy::SpdyRstStreamIR).
CreateRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code) const252 std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreateRstStream(
253 spdy::SpdyStreamId stream_id,
254 spdy::SpdyErrorCode error_code) const {
255 spdy::SpdyRstStreamIR rst_ir(stream_id, error_code);
256 return std::make_unique<spdy::SpdySerializedFrame>(
257 spdy_framer_.SerializeRstStream(rst_ir));
258 }
259
260 // TODO(jgraettinger): Eliminate uses of this method (prefer
261 // spdy::SpdySettingsIR).
CreateSettings(const spdy::SettingsMap & values) const262 std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreateSettings(
263 const spdy::SettingsMap& values) const {
264 spdy::SpdySettingsIR settings_ir;
265 for (const auto& it : values) {
266 settings_ir.AddSetting(it.first, it.second);
267 }
268 return std::make_unique<spdy::SpdySerializedFrame>(
269 spdy_framer_.SerializeSettings(settings_ir));
270 }
271
272 // TODO(jgraettinger): Eliminate uses of this method (prefer spdy::SpdyPingIR).
CreatePingFrame(spdy::SpdyPingId unique_id,bool is_ack) const273 std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreatePingFrame(
274 spdy::SpdyPingId unique_id,
275 bool is_ack) const {
276 spdy::SpdyPingIR ping_ir(unique_id);
277 ping_ir.set_is_ack(is_ack);
278 return std::make_unique<spdy::SpdySerializedFrame>(
279 spdy_framer_.SerializePing(ping_ir));
280 }
281
282 // TODO(jgraettinger): Eliminate uses of this method (prefer
283 // spdy::SpdyWindowUpdateIR).
284 std::unique_ptr<spdy::SpdySerializedFrame>
CreateWindowUpdate(spdy::SpdyStreamId stream_id,uint32_t delta_window_size) const285 BufferedSpdyFramer::CreateWindowUpdate(spdy::SpdyStreamId stream_id,
286 uint32_t delta_window_size) const {
287 spdy::SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
288 return std::make_unique<spdy::SpdySerializedFrame>(
289 spdy_framer_.SerializeWindowUpdate(update_ir));
290 }
291
292 // TODO(jgraettinger): Eliminate uses of this method (prefer spdy::SpdyDataIR).
CreateDataFrame(spdy::SpdyStreamId stream_id,const char * data,uint32_t len,spdy::SpdyDataFlags flags)293 std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreateDataFrame(
294 spdy::SpdyStreamId stream_id,
295 const char* data,
296 uint32_t len,
297 spdy::SpdyDataFlags flags) {
298 spdy::SpdyDataIR data_ir(stream_id, std::string_view(data, len));
299 data_ir.set_fin((flags & spdy::DATA_FLAG_FIN) != 0);
300 return std::make_unique<spdy::SpdySerializedFrame>(
301 spdy_framer_.SerializeData(data_ir));
302 }
303
304 // TODO(jgraettinger): Eliminate uses of this method (prefer
305 // spdy::SpdyPriorityIR).
CreatePriority(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId dependency_id,int weight,bool exclusive) const306 std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreatePriority(
307 spdy::SpdyStreamId stream_id,
308 spdy::SpdyStreamId dependency_id,
309 int weight,
310 bool exclusive) const {
311 spdy::SpdyPriorityIR priority_ir(stream_id, dependency_id, weight, exclusive);
312 return std::make_unique<spdy::SpdySerializedFrame>(
313 spdy_framer_.SerializePriority(priority_ir));
314 }
315
UpdateHeaderEncoderTableSize(uint32_t value)316 void BufferedSpdyFramer::UpdateHeaderEncoderTableSize(uint32_t value) {
317 spdy_framer_.UpdateHeaderEncoderTableSize(value);
318 }
319
header_encoder_table_size() const320 uint32_t BufferedSpdyFramer::header_encoder_table_size() const {
321 return spdy_framer_.header_encoder_table_size();
322 }
323
324 BufferedSpdyFramer::ControlFrameFields::ControlFrameFields() = default;
325
326 } // namespace net
327