1// Copyright (c) 2012 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/spdy/buffered_spdy_framer.h"
6
7#include "base/logging.h"
8
9namespace net {
10
11SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) {
12  switch (next_proto) {
13    case kProtoSPDY2:
14    case kProtoSPDY21:
15      return SPDY2;
16    case kProtoSPDY3:
17    case kProtoSPDY31:
18      return SPDY3;
19    // SPDY/4 and HTTP/2 share the same framing for now.
20    case kProtoSPDY4a2:
21    case kProtoHTTP2Draft04:
22      return SPDY4;
23    case kProtoUnknown:
24    case kProtoHTTP11:
25    case kProtoSPDY1:
26    case kProtoQUIC1SPDY3:
27      break;
28  }
29  NOTREACHED();
30  return SPDY2;
31}
32
33BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version,
34                                       bool enable_compression)
35    : spdy_framer_(version),
36      visitor_(NULL),
37      header_buffer_used_(0),
38      header_buffer_valid_(false),
39      header_stream_id_(SpdyFramer::kInvalidStream),
40      frames_received_(0) {
41  spdy_framer_.set_enable_compression(enable_compression);
42  memset(header_buffer_, 0, sizeof(header_buffer_));
43}
44
45BufferedSpdyFramer::~BufferedSpdyFramer() {
46}
47
48void BufferedSpdyFramer::set_visitor(
49    BufferedSpdyFramerVisitorInterface* visitor) {
50  visitor_ = visitor;
51  spdy_framer_.set_visitor(this);
52}
53
54void BufferedSpdyFramer::set_debug_visitor(
55    SpdyFramerDebugVisitorInterface* debug_visitor) {
56  spdy_framer_.set_debug_visitor(debug_visitor);
57}
58
59void BufferedSpdyFramer::OnError(SpdyFramer* spdy_framer) {
60  DCHECK(spdy_framer);
61  visitor_->OnError(spdy_framer->error_code());
62}
63
64void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id,
65                                     SpdyStreamId associated_stream_id,
66                                     SpdyPriority priority,
67                                     uint8 credential_slot,
68                                     bool fin,
69                                     bool unidirectional) {
70  frames_received_++;
71  DCHECK(!control_frame_fields_.get());
72  control_frame_fields_.reset(new ControlFrameFields());
73  control_frame_fields_->type = SYN_STREAM;
74  control_frame_fields_->stream_id = stream_id;
75  control_frame_fields_->associated_stream_id = associated_stream_id;
76  control_frame_fields_->priority = priority;
77  control_frame_fields_->credential_slot = credential_slot;
78  control_frame_fields_->fin = fin;
79  control_frame_fields_->unidirectional = unidirectional;
80
81  InitHeaderStreaming(stream_id);
82}
83
84void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
85                                   bool fin) {
86  frames_received_++;
87  DCHECK(!control_frame_fields_.get());
88  control_frame_fields_.reset(new ControlFrameFields());
89  control_frame_fields_->type = HEADERS;
90  control_frame_fields_->stream_id = stream_id;
91  control_frame_fields_->fin = fin;
92
93  InitHeaderStreaming(stream_id);
94}
95
96void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
97                                    bool fin) {
98  frames_received_++;
99  DCHECK(!control_frame_fields_.get());
100  control_frame_fields_.reset(new ControlFrameFields());
101  control_frame_fields_->type = SYN_REPLY;
102  control_frame_fields_->stream_id = stream_id;
103  control_frame_fields_->fin = fin;
104
105  InitHeaderStreaming(stream_id);
106}
107
108bool BufferedSpdyFramer::OnCredentialFrameData(const char* frame_data,
109                                               size_t len) {
110  DCHECK(false);
111  return false;
112}
113
114bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
115                                                  const char* header_data,
116                                                  size_t len) {
117  CHECK_EQ(header_stream_id_, stream_id);
118
119  if (len == 0) {
120    // Indicates end-of-header-block.
121    CHECK(header_buffer_valid_);
122
123    SpdyHeaderBlock headers;
124    size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
125        header_buffer_, header_buffer_used_, &headers);
126    // TODO(rch): this really should be checking parsed_len != len,
127    // but a bunch of tests fail.  Need to figure out why.
128    if (parsed_len == 0) {
129      visitor_->OnStreamError(
130          stream_id, "Could not parse Spdy Control Frame Header.");
131      return false;
132    }
133    DCHECK(control_frame_fields_.get());
134    switch (control_frame_fields_->type) {
135      case SYN_STREAM:
136        visitor_->OnSynStream(control_frame_fields_->stream_id,
137                              control_frame_fields_->associated_stream_id,
138                              control_frame_fields_->priority,
139                              control_frame_fields_->credential_slot,
140                              control_frame_fields_->fin,
141                              control_frame_fields_->unidirectional,
142                              headers);
143        break;
144      case SYN_REPLY:
145        visitor_->OnSynReply(control_frame_fields_->stream_id,
146                             control_frame_fields_->fin,
147                             headers);
148        break;
149      case HEADERS:
150        visitor_->OnHeaders(control_frame_fields_->stream_id,
151                            control_frame_fields_->fin,
152                            headers);
153        break;
154      default:
155        DCHECK(false) << "Unexpect control frame type: "
156                      << control_frame_fields_->type;
157        break;
158    }
159    control_frame_fields_.reset(NULL);
160    return true;
161  }
162
163  const size_t available = kHeaderBufferSize - header_buffer_used_;
164  if (len > available) {
165    header_buffer_valid_ = false;
166    visitor_->OnStreamError(
167        stream_id, "Received more data than the allocated size.");
168    return false;
169  }
170  memcpy(header_buffer_ + header_buffer_used_, header_data, len);
171  header_buffer_used_ += len;
172  return true;
173}
174
175void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
176                                           size_t length,
177                                           bool fin) {
178  frames_received_++;
179  header_stream_id_ = stream_id;
180}
181
182void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
183                                           const char* data,
184                                           size_t len,
185                                           bool fin) {
186  visitor_->OnStreamFrameData(stream_id, data, len, fin);
187}
188
189void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
190  visitor_->OnSettings(clear_persisted);
191}
192
193void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
194                                   uint8 flags,
195                                   uint32 value) {
196  visitor_->OnSetting(id, flags, value);
197}
198
199void BufferedSpdyFramer::OnPing(uint32 unique_id) {
200  visitor_->OnPing(unique_id);
201}
202
203void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
204                                     SpdyRstStreamStatus status) {
205  visitor_->OnRstStream(stream_id, status);
206}
207void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
208                                  SpdyGoAwayStatus status) {
209  visitor_->OnGoAway(last_accepted_stream_id, status);
210}
211
212void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
213                                        uint32 delta_window_size) {
214  visitor_->OnWindowUpdate(stream_id, delta_window_size);
215}
216
217void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
218                                       SpdyStreamId promised_stream_id) {
219  visitor_->OnPushPromise(stream_id, promised_stream_id);
220}
221
222int BufferedSpdyFramer::protocol_version() {
223  return spdy_framer_.protocol_version();
224}
225
226size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
227  return spdy_framer_.ProcessInput(data, len);
228}
229
230void BufferedSpdyFramer::Reset() {
231  spdy_framer_.Reset();
232}
233
234SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
235  return spdy_framer_.error_code();
236}
237
238SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
239  return spdy_framer_.state();
240}
241
242bool BufferedSpdyFramer::MessageFullyRead() {
243  return state() == SpdyFramer::SPDY_AUTO_RESET;
244}
245
246bool BufferedSpdyFramer::HasError() {
247  return spdy_framer_.HasError();
248}
249
250SpdyFrame* BufferedSpdyFramer::CreateSynStream(
251    SpdyStreamId stream_id,
252    SpdyStreamId associated_stream_id,
253    SpdyPriority priority,
254    uint8 credential_slot,
255    SpdyControlFlags flags,
256    bool compressed,
257    const SpdyHeaderBlock* headers) {
258  return spdy_framer_.CreateSynStream(stream_id, associated_stream_id, priority,
259                                      credential_slot, flags, compressed,
260                                      headers);
261}
262
263SpdyFrame* BufferedSpdyFramer::CreateSynReply(
264    SpdyStreamId stream_id,
265    SpdyControlFlags flags,
266    bool compressed,
267    const SpdyHeaderBlock* headers) {
268  return spdy_framer_.CreateSynReply(stream_id, flags, compressed, headers);
269}
270
271SpdyFrame* BufferedSpdyFramer::CreateRstStream(
272    SpdyStreamId stream_id,
273    SpdyRstStreamStatus status) const {
274  return spdy_framer_.CreateRstStream(stream_id, status);
275}
276
277SpdyFrame* BufferedSpdyFramer::CreateSettings(
278    const SettingsMap& values) const {
279  return spdy_framer_.CreateSettings(values);
280}
281
282SpdyFrame* BufferedSpdyFramer::CreatePingFrame(
283    uint32 unique_id) const {
284  return spdy_framer_.CreatePingFrame(unique_id);
285}
286
287SpdyFrame* BufferedSpdyFramer::CreateGoAway(
288    SpdyStreamId last_accepted_stream_id,
289    SpdyGoAwayStatus status) const {
290  return spdy_framer_.CreateGoAway(last_accepted_stream_id, status);
291}
292
293SpdyFrame* BufferedSpdyFramer::CreateHeaders(
294    SpdyStreamId stream_id,
295    SpdyControlFlags flags,
296    bool compressed,
297    const SpdyHeaderBlock* headers) {
298  return spdy_framer_.CreateHeaders(stream_id, flags, compressed, headers);
299}
300
301SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
302    SpdyStreamId stream_id,
303    uint32 delta_window_size) const {
304  return spdy_framer_.CreateWindowUpdate(stream_id, delta_window_size);
305}
306
307SpdyFrame* BufferedSpdyFramer::CreateCredentialFrame(
308    const SpdyCredential& credential) const {
309  return spdy_framer_.CreateCredentialFrame(credential);
310}
311
312SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
313                                               const char* data,
314                                               uint32 len,
315                                               SpdyDataFlags flags) {
316  return spdy_framer_.CreateDataFrame(stream_id, data, len, flags);
317}
318
319SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
320  return spdy_framer_.GetHighestPriority();
321}
322
323void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
324  memset(header_buffer_, 0, kHeaderBufferSize);
325  header_buffer_used_ = 0;
326  header_buffer_valid_ = true;
327  header_stream_id_ = stream_id;
328  DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
329}
330
331}  // namespace net
332