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