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