• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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