OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/quic_headers_stream.h" | 5 #include "net/quic/quic_headers_stream.h" |
6 | 6 |
7 #include "base/strings/stringprintf.h" | 7 #include "base/strings/stringprintf.h" |
8 #include "net/quic/quic_session.h" | 8 #include "net/quic/quic_session.h" |
9 | 9 |
10 using base::StringPiece; | 10 using base::StringPiece; |
11 using std::string; | 11 using std::string; |
12 | 12 |
13 namespace net { | 13 namespace net { |
14 | 14 |
15 namespace { | 15 namespace { |
16 | 16 |
17 const QuicStreamId kInvalidStreamId = 0; | 17 const QuicStreamId kInvalidStreamId = 0; |
18 | 18 |
19 } // namespace | 19 } // namespace |
20 | 20 |
21 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to | 21 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to |
22 // the QuicDataStream, and closes the connection if any unexpected frames | 22 // the QuicDataStream, and closes the connection if any unexpected frames |
23 // are received. | 23 // are received. |
24 class QuicHeadersStream::SpdyFramerVisitor | 24 class QuicHeadersStream::SpdyFramerVisitor |
25 : public SpdyFramerVisitorInterface, | 25 : public SpdyFramerVisitorInterface, |
26 public SpdyFramerDebugVisitorInterface { | 26 public SpdyFramerDebugVisitorInterface { |
27 public: | 27 public: |
28 explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {} | 28 SpdyFramerVisitor(SpdyMajorVersion spdy_version, QuicHeadersStream* stream) |
| 29 : spdy_version_(spdy_version), stream_(stream) {} |
29 | 30 |
30 // SpdyFramerVisitorInterface implementation | 31 // SpdyFramerVisitorInterface implementation |
31 void OnSynStream(SpdyStreamId stream_id, | 32 void OnSynStream(SpdyStreamId stream_id, |
32 SpdyStreamId associated_stream_id, | 33 SpdyStreamId associated_stream_id, |
33 SpdyPriority priority, | 34 SpdyPriority priority, |
34 bool fin, | 35 bool fin, |
35 bool unidirectional) override { | 36 bool unidirectional) override { |
| 37 if (spdy_version_ != SPDY3) { |
| 38 CloseConnection("SPDY SYN_STREAM frame received."); |
| 39 return; |
| 40 } |
| 41 |
36 if (!stream_->IsConnected()) { | 42 if (!stream_->IsConnected()) { |
37 return; | 43 return; |
38 } | 44 } |
39 | 45 |
40 if (associated_stream_id != 0) { | 46 if (associated_stream_id != 0) { |
41 CloseConnection("associated_stream_id != 0"); | 47 CloseConnection("associated_stream_id != 0"); |
42 return; | 48 return; |
43 } | 49 } |
44 | 50 |
45 if (unidirectional != 0) { | 51 if (unidirectional != 0) { |
46 CloseConnection("unidirectional != 0"); | 52 CloseConnection("unidirectional != 0"); |
47 return; | 53 return; |
48 } | 54 } |
49 | 55 |
50 stream_->OnSynStream(stream_id, priority, fin); | 56 stream_->OnSynStream(stream_id, priority, fin); |
51 } | 57 } |
52 | 58 |
53 void OnSynReply(SpdyStreamId stream_id, bool fin) override { | 59 void OnSynReply(SpdyStreamId stream_id, bool fin) override { |
| 60 if (spdy_version_ != SPDY3) { |
| 61 CloseConnection("SPDY SYN_REPLY frame received."); |
| 62 return; |
| 63 } |
| 64 |
54 if (!stream_->IsConnected()) { | 65 if (!stream_->IsConnected()) { |
55 return; | 66 return; |
56 } | 67 } |
57 | 68 |
58 stream_->OnSynReply(stream_id, fin); | 69 stream_->OnSynReply(stream_id, fin); |
59 } | 70 } |
60 | 71 |
61 bool OnControlFrameHeaderData(SpdyStreamId stream_id, | 72 bool OnControlFrameHeaderData(SpdyStreamId stream_id, |
62 const char* header_data, | 73 const char* header_data, |
63 size_t len) override { | 74 size_t len) override { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 void OnGoAway(SpdyStreamId last_accepted_stream_id, | 128 void OnGoAway(SpdyStreamId last_accepted_stream_id, |
118 SpdyGoAwayStatus status) override { | 129 SpdyGoAwayStatus status) override { |
119 CloseConnection("SPDY GOAWAY frame received."); | 130 CloseConnection("SPDY GOAWAY frame received."); |
120 } | 131 } |
121 | 132 |
122 void OnHeaders(SpdyStreamId stream_id, | 133 void OnHeaders(SpdyStreamId stream_id, |
123 bool has_priority, | 134 bool has_priority, |
124 SpdyPriority priority, | 135 SpdyPriority priority, |
125 bool fin, | 136 bool fin, |
126 bool end) override { | 137 bool end) override { |
127 CloseConnection("SPDY HEADERS frame received."); | 138 if (spdy_version_ == SPDY3) { |
| 139 CloseConnection("SPDY HEADERS frame received."); |
| 140 return; |
| 141 } |
| 142 if (!stream_->IsConnected()) { |
| 143 return; |
| 144 } |
| 145 if (has_priority) { |
| 146 stream_->OnSynStream(stream_id, priority, fin); |
| 147 } else { |
| 148 stream_->OnSynReply(stream_id, fin); |
| 149 } |
128 } | 150 } |
129 | 151 |
130 void OnWindowUpdate(SpdyStreamId stream_id, | 152 void OnWindowUpdate(SpdyStreamId stream_id, |
131 uint32 delta_window_size) override { | 153 uint32 delta_window_size) override { |
132 CloseConnection("SPDY WINDOW_UPDATE frame received."); | 154 CloseConnection("SPDY WINDOW_UPDATE frame received."); |
133 } | 155 } |
134 | 156 |
135 void OnPushPromise(SpdyStreamId stream_id, | 157 void OnPushPromise(SpdyStreamId stream_id, |
136 SpdyStreamId promised_stream_id, | 158 SpdyStreamId promised_stream_id, |
137 bool end) override { | 159 bool end) override { |
138 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer"; | 160 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer"; |
139 CloseConnection("SPDY PUSH_PROMISE frame received."); | 161 CloseConnection("SPDY PUSH_PROMISE frame received."); |
140 } | 162 } |
141 | 163 |
142 void OnContinuation(SpdyStreamId stream_id, bool end) override { | 164 void OnContinuation(SpdyStreamId stream_id, bool end) override { |
143 CloseConnection("SPDY CONTINUATION frame received."); | 165 if (spdy_version_ == SPDY3) { |
| 166 LOG(DFATAL) << "CONTINUATION frame received from a SPDY/3 framer"; |
| 167 CloseConnection("SPDY CONTINUATION frame received."); |
| 168 } |
144 } | 169 } |
145 | 170 |
146 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { | 171 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { |
147 CloseConnection("Unknown frame type received."); | 172 CloseConnection("Unknown frame type received."); |
148 return false; | 173 return false; |
149 } | 174 } |
150 | 175 |
151 // SpdyFramerDebugVisitorInterface implementation | 176 // SpdyFramerDebugVisitorInterface implementation |
152 void OnSendCompressedFrame(SpdyStreamId stream_id, | 177 void OnSendCompressedFrame(SpdyStreamId stream_id, |
153 SpdyFrameType type, | 178 SpdyFrameType type, |
(...skipping 10 matching lines...) Expand all Loading... |
164 | 189 |
165 private: | 190 private: |
166 void CloseConnection(const string& details) { | 191 void CloseConnection(const string& details) { |
167 if (stream_->IsConnected()) { | 192 if (stream_->IsConnected()) { |
168 stream_->CloseConnectionWithDetails( | 193 stream_->CloseConnectionWithDetails( |
169 QUIC_INVALID_HEADERS_STREAM_DATA, details); | 194 QUIC_INVALID_HEADERS_STREAM_DATA, details); |
170 } | 195 } |
171 } | 196 } |
172 | 197 |
173 private: | 198 private: |
| 199 SpdyMajorVersion spdy_version_; |
174 QuicHeadersStream* stream_; | 200 QuicHeadersStream* stream_; |
175 | 201 |
176 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); | 202 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); |
177 }; | 203 }; |
178 | 204 |
179 QuicHeadersStream::QuicHeadersStream(QuicSession* session) | 205 QuicHeadersStream::QuicHeadersStream(QuicSession* session) |
180 : ReliableQuicStream(kHeadersStreamId, session), | 206 : ReliableQuicStream(kHeadersStreamId, session), |
181 stream_id_(kInvalidStreamId), | 207 stream_id_(kInvalidStreamId), |
182 fin_(false), | 208 fin_(false), |
183 frame_len_(0), | 209 frame_len_(0) { |
184 spdy_framer_(SPDY3), | 210 InitializeFramer(session->connection()->version()); |
185 spdy_framer_visitor_(new SpdyFramerVisitor(this)) { | |
186 spdy_framer_.set_visitor(spdy_framer_visitor_.get()); | |
187 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); | |
188 // The headers stream is exempt from connection level flow control. | 211 // The headers stream is exempt from connection level flow control. |
189 DisableConnectionFlowControlForThisStream(); | 212 DisableConnectionFlowControlForThisStream(); |
190 } | 213 } |
191 | 214 |
192 QuicHeadersStream::~QuicHeadersStream() {} | 215 QuicHeadersStream::~QuicHeadersStream() {} |
193 | 216 |
194 size_t QuicHeadersStream::WriteHeaders( | 217 size_t QuicHeadersStream::WriteHeaders( |
195 QuicStreamId stream_id, | 218 QuicStreamId stream_id, |
196 const SpdyHeaderBlock& headers, | 219 const SpdyHeaderBlock& headers, |
197 bool fin, | 220 bool fin, |
| 221 QuicPriority priority, |
198 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { | 222 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { |
199 scoped_ptr<SpdySerializedFrame> frame; | 223 scoped_ptr<SpdySerializedFrame> frame; |
200 if (session()->is_server()) { | 224 if (spdy_framer_->protocol_version() == SPDY3) { |
201 SpdySynReplyIR syn_reply(stream_id); | 225 if (session()->is_server()) { |
202 syn_reply.set_name_value_block(headers); | 226 SpdySynReplyIR syn_reply(stream_id); |
203 syn_reply.set_fin(fin); | 227 syn_reply.set_name_value_block(headers); |
204 frame.reset(spdy_framer_.SerializeFrame(syn_reply)); | 228 syn_reply.set_fin(fin); |
| 229 frame.reset(spdy_framer_->SerializeFrame(syn_reply)); |
| 230 } else { |
| 231 SpdySynStreamIR syn_stream(stream_id); |
| 232 syn_stream.set_name_value_block(headers); |
| 233 syn_stream.set_fin(fin); |
| 234 syn_stream.set_priority(priority); |
| 235 frame.reset(spdy_framer_->SerializeFrame(syn_stream)); |
| 236 } |
205 } else { | 237 } else { |
206 SpdySynStreamIR syn_stream(stream_id); | 238 SpdyHeadersIR headers_frame(stream_id); |
207 syn_stream.set_name_value_block(headers); | 239 headers_frame.set_name_value_block(headers); |
208 syn_stream.set_fin(fin); | 240 headers_frame.set_fin(fin); |
209 frame.reset(spdy_framer_.SerializeFrame(syn_stream)); | 241 if (!session()->is_server()) { |
| 242 headers_frame.set_has_priority(true); |
| 243 headers_frame.set_priority(priority); |
| 244 } |
| 245 frame.reset(spdy_framer_->SerializeFrame(headers_frame)); |
210 } | 246 } |
211 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false, | 247 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false, |
212 ack_notifier_delegate); | 248 ack_notifier_delegate); |
213 return frame->size(); | 249 return frame->size(); |
214 } | 250 } |
215 | 251 |
216 uint32 QuicHeadersStream::ProcessRawData(const char* data, | 252 uint32 QuicHeadersStream::ProcessRawData(const char* data, |
217 uint32 data_len) { | 253 uint32 data_len) { |
218 return spdy_framer_.ProcessInput(data, data_len); | 254 return spdy_framer_->ProcessInput(data, data_len); |
219 } | 255 } |
220 | 256 |
221 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; } | 257 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; } |
222 | 258 |
| 259 void QuicHeadersStream::OnSuccessfulVersionNegotiation(QuicVersion version) { |
| 260 InitializeFramer(version); |
| 261 } |
| 262 |
| 263 void QuicHeadersStream::InitializeFramer(QuicVersion version) { |
| 264 SpdyMajorVersion spdy_version = version > QUIC_VERSION_23 ? SPDY4 : SPDY3; |
| 265 if (spdy_framer_.get() != nullptr && |
| 266 spdy_framer_->protocol_version() == spdy_version) { |
| 267 return; |
| 268 } |
| 269 spdy_framer_.reset(new SpdyFramer(spdy_version)); |
| 270 spdy_framer_visitor_.reset(new SpdyFramerVisitor(spdy_version, this)); |
| 271 spdy_framer_->set_visitor(spdy_framer_visitor_.get()); |
| 272 spdy_framer_->set_debug_visitor(spdy_framer_visitor_.get()); |
| 273 } |
| 274 |
223 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id, | 275 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id, |
224 SpdyPriority priority, | 276 SpdyPriority priority, |
225 bool fin) { | 277 bool fin) { |
226 if (!session()->is_server()) { | 278 if (!session()->is_server()) { |
227 CloseConnectionWithDetails( | 279 CloseConnectionWithDetails( |
228 QUIC_INVALID_HEADERS_STREAM_DATA, | 280 QUIC_INVALID_HEADERS_STREAM_DATA, |
229 "SPDY SYN_STREAM frame received at the client"); | 281 "SPDY SYN_STREAM frame received at the client"); |
230 return; | 282 return; |
231 } | 283 } |
232 DCHECK_EQ(kInvalidStreamId, stream_id_); | 284 DCHECK_EQ(kInvalidStreamId, stream_id_); |
(...skipping 25 matching lines...) Expand all Loading... |
258 // Reset state for the next frame. | 310 // Reset state for the next frame. |
259 stream_id_ = kInvalidStreamId; | 311 stream_id_ = kInvalidStreamId; |
260 fin_ = false; | 312 fin_ = false; |
261 frame_len_ = 0; | 313 frame_len_ = 0; |
262 } else { | 314 } else { |
263 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len)); | 315 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len)); |
264 } | 316 } |
265 } | 317 } |
266 | 318 |
267 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { | 319 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { |
268 DCHECK_EQ(kInvalidStreamId, stream_id_); | 320 if (spdy_framer_->protocol_version() == SPDY3) { |
269 DCHECK_EQ(0u, frame_len_); | 321 // SPDY/3 headers always fit into a single frame, so the previous headers |
270 frame_len_ = frame_len; | 322 // should be completely processed when a new frame is received. |
| 323 DCHECK_EQ(kInvalidStreamId, stream_id_); |
| 324 DCHECK_EQ(0u, frame_len_); |
| 325 } |
| 326 frame_len_ += frame_len; |
271 } | 327 } |
272 | 328 |
273 bool QuicHeadersStream::IsConnected() { | 329 bool QuicHeadersStream::IsConnected() { |
274 return session()->connection()->connected(); | 330 return session()->connection()->connected(); |
275 } | 331 } |
276 | 332 |
277 } // namespace net | 333 } // namespace net |
OLD | NEW |