a739d6b1e0aecc83184f696653e1bfc1402fb971
[platform/framework/web/crosswalk.git] / src / net / quic / quic_headers_stream.cc
1 // Copyright 2013 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/quic/quic_headers_stream.h"
6
7 #include "net/quic/quic_session.h"
8 #include "net/quic/quic_spdy_decompressor.h"
9
10 using base::StringPiece;
11
12 namespace net {
13
14 namespace {
15
16 const QuicStreamId kInvalidStreamId = 0;
17
18 }  // namespace
19
20 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
21 // the QuicDataStream, and closes the connection if any unexpected frames
22 // are received.
23 class QuicHeadersStream::SpdyFramerVisitor
24     : public SpdyFramerVisitorInterface,
25       public SpdyFramerDebugVisitorInterface {
26  public:
27   explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {}
28
29   // SpdyFramerVisitorInterface implementation
30   virtual void OnSynStream(SpdyStreamId stream_id,
31                            SpdyStreamId associated_stream_id,
32                            SpdyPriority priority,
33                            uint8 credential_slot,
34                            bool fin,
35                            bool unidirectional) OVERRIDE {
36     if (!stream_->IsConnected()) {
37       return;
38     }
39
40     if (associated_stream_id != 0) {
41       CloseConnection("associated_stream_id != 0");
42       return;
43     }
44
45     if (credential_slot != 0) {
46       CloseConnection("credential_slot != 0");
47       return;
48     }
49
50     if (unidirectional != 0) {
51       CloseConnection("unidirectional != 0");
52       return;
53     }
54
55     stream_->OnSynStream(stream_id, priority, fin);
56   }
57
58   virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
59     if (!stream_->IsConnected()) {
60       return;
61     }
62
63     stream_->OnSynReply(stream_id, fin);
64   }
65
66   virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
67                                         const char* header_data,
68                                         size_t len) OVERRIDE {
69     if (!stream_->IsConnected()) {
70       return false;
71     }
72     stream_->OnControlFrameHeaderData(stream_id, header_data, len);
73     return true;
74   }
75
76   virtual void OnStreamFrameData(SpdyStreamId stream_id,
77                                  const char* data,
78                                  size_t len,
79                                  bool fin) OVERRIDE {
80     if (fin && len == 0) {
81       // The framer invokes OnStreamFrameData with zero-length data and
82       // fin = true after processing a SYN_STREAM or SYN_REPLY frame
83       // that had the fin bit set.
84       return;
85     }
86     CloseConnection("SPDY DATA frame recevied.");
87   }
88
89   virtual void OnError(SpdyFramer* framer) OVERRIDE {
90     CloseConnection("SPDY framing error.");
91   }
92
93   virtual void OnDataFrameHeader(SpdyStreamId stream_id,
94                                  size_t length,
95                                  bool fin) OVERRIDE {
96     CloseConnection("SPDY DATA frame recevied.");
97   }
98
99   virtual void OnRstStream(SpdyStreamId stream_id,
100                            SpdyRstStreamStatus status) OVERRIDE {
101     CloseConnection("SPDY RST_STREAM frame recevied.");
102   }
103
104   virtual void OnSetting(SpdySettingsIds id,
105                          uint8 flags,
106                          uint32 value) OVERRIDE {
107     CloseConnection("SPDY SETTINGS frame recevied.");
108   }
109
110   virtual void OnPing(uint32 unique_id) OVERRIDE {
111     CloseConnection("SPDY PING frame recevied.");
112   }
113
114   virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
115                         SpdyGoAwayStatus status) OVERRIDE {
116     CloseConnection("SPDY GOAWAY frame recevied.");
117   }
118
119   virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {
120     CloseConnection("SPDY HEADERS frame recevied.");
121   }
122
123   virtual void OnWindowUpdate(SpdyStreamId stream_id,
124                               uint32 delta_window_size) OVERRIDE {
125     CloseConnection("SPDY WINDOW_UPDATE frame recevied.");
126   }
127
128   virtual void OnPushPromise(SpdyStreamId stream_id,
129                              SpdyStreamId promised_stream_id) OVERRIDE {
130     LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer";
131     CloseConnection("SPDY PUSH_PROMISE frame recevied.");
132   }
133
134   // SpdyFramerDebugVisitorInterface implementation
135   virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
136                                      SpdyFrameType type,
137                                      size_t payload_len,
138                                      size_t frame_len) OVERRIDE {}
139
140   virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id,
141                                         SpdyFrameType type,
142                                         size_t frame_len) OVERRIDE {
143     if (stream_->IsConnected()) {
144       stream_->OnCompressedFrameSize(frame_len);
145     }
146   }
147
148  private:
149   void CloseConnection(const string& details) {
150     if (stream_->IsConnected()) {
151       stream_->CloseConnectionWithDetails(
152           QUIC_INVALID_HEADERS_STREAM_DATA, details);
153     }
154   }
155
156  private:
157   QuicHeadersStream* stream_;
158
159   DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor);
160 };
161
162 QuicHeadersStream::QuicHeadersStream(QuicSession* session)
163     : ReliableQuicStream(kHeadersStreamId, session),
164       stream_id_(kInvalidStreamId),
165       fin_(false),
166       frame_len_(0),
167       spdy_framer_(SPDY3),
168       spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
169   spdy_framer_.set_visitor(spdy_framer_visitor_.get());
170   spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
171 }
172
173 QuicHeadersStream::~QuicHeadersStream() {}
174
175 size_t QuicHeadersStream::WriteHeaders(QuicStreamId stream_id,
176                                        const SpdyHeaderBlock& headers,
177                                        bool fin) {
178   scoped_ptr<SpdySerializedFrame> frame;
179   if (session()->is_server()) {
180     SpdySynReplyIR syn_reply(stream_id);
181     syn_reply.set_name_value_block(headers);
182     syn_reply.set_fin(fin);
183     frame.reset(spdy_framer_.SerializeFrame(syn_reply));
184   } else {
185     SpdySynStreamIR syn_stream(stream_id);
186     syn_stream.set_name_value_block(headers);
187     syn_stream.set_fin(fin);
188     frame.reset(spdy_framer_.SerializeFrame(syn_stream));
189   }
190   WriteOrBufferData(StringPiece(frame->data(), frame->size()), false);
191   return frame->size();
192 }
193
194 uint32 QuicHeadersStream::ProcessRawData(const char* data,
195                                          uint32 data_len) {
196   return spdy_framer_.ProcessInput(data, data_len);
197 }
198
199 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; }
200
201 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id,
202                                     SpdyPriority priority,
203                                     bool fin) {
204   if (!session()->is_server()) {
205     CloseConnectionWithDetails(
206         QUIC_INVALID_HEADERS_STREAM_DATA,
207         "SPDY SYN_STREAM frame recevied at the client");
208     return;
209   }
210   DCHECK_EQ(kInvalidStreamId, stream_id_);
211   stream_id_ = stream_id;
212   fin_ = fin;
213   session()->OnStreamHeadersPriority(stream_id, priority);
214 }
215
216 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id, bool fin) {
217   if (session()->is_server()) {
218     CloseConnectionWithDetails(
219         QUIC_INVALID_HEADERS_STREAM_DATA,
220         "SPDY SYN_REPLY frame recevied at the server");
221     return;
222   }
223   DCHECK_EQ(kInvalidStreamId, stream_id_);
224   stream_id_ = stream_id;
225   fin_ = fin;
226 }
227
228 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id,
229                                                  const char* header_data,
230                                                  size_t len) {
231   DCHECK_EQ(stream_id_, stream_id);
232   if (len == 0) {
233     DCHECK_NE(0u, stream_id_);
234     DCHECK_NE(0u, frame_len_);
235     session()->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
236     // Reset state for the next frame.
237     stream_id_ = kInvalidStreamId;
238     fin_ = false;
239     frame_len_ = 0;
240   } else {
241     session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
242   }
243 }
244
245 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) {
246   DCHECK_EQ(kInvalidStreamId, stream_id_);
247   DCHECK_EQ(0u, frame_len_);
248   frame_len_ = frame_len;
249 }
250
251 bool QuicHeadersStream::IsConnected() {
252   return session()->connection()->connected();
253 }
254
255 }  // namespace net