Roll src/third_party/skia 5cc0f6c:01d3319
[chromium-blink-merge.git] / net / quic / quic_headers_stream.cc
blobb40142db16605874f568b555e1d94f0dfe3643b9
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.
5 #include "net/quic/quic_headers_stream.h"
7 #include "base/strings/stringprintf.h"
8 #include "net/quic/quic_session.h"
10 using base::StringPiece;
11 using std::string;
13 namespace net {
15 namespace {
17 const QuicStreamId kInvalidStreamId = 0;
19 } // namespace
21 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
22 // the QuicDataStream, and closes the connection if any unexpected frames
23 // are received.
24 class QuicHeadersStream::SpdyFramerVisitor
25 : public SpdyFramerVisitorInterface,
26 public SpdyFramerDebugVisitorInterface {
27 public:
28 SpdyFramerVisitor(SpdyMajorVersion spdy_version, QuicHeadersStream* stream)
29 : spdy_version_(spdy_version), stream_(stream) {}
31 // SpdyFramerVisitorInterface implementation
32 void OnSynStream(SpdyStreamId stream_id,
33 SpdyStreamId associated_stream_id,
34 SpdyPriority priority,
35 bool fin,
36 bool unidirectional) override {
37 if (spdy_version_ != SPDY3) {
38 CloseConnection("SPDY SYN_STREAM frame received.");
39 return;
42 if (!stream_->IsConnected()) {
43 return;
46 if (associated_stream_id != 0) {
47 CloseConnection("associated_stream_id != 0");
48 return;
51 if (unidirectional != 0) {
52 CloseConnection("unidirectional != 0");
53 return;
56 stream_->OnSynStream(stream_id, priority, fin);
59 void OnSynReply(SpdyStreamId stream_id, bool fin) override {
60 if (spdy_version_ != SPDY3) {
61 CloseConnection("SPDY SYN_REPLY frame received.");
62 return;
65 if (!stream_->IsConnected()) {
66 return;
69 stream_->OnSynReply(stream_id, fin);
72 bool OnControlFrameHeaderData(SpdyStreamId stream_id,
73 const char* header_data,
74 size_t len) override {
75 if (!stream_->IsConnected()) {
76 return false;
78 stream_->OnControlFrameHeaderData(stream_id, header_data, len);
79 return true;
82 void OnStreamFrameData(SpdyStreamId stream_id,
83 const char* data,
84 size_t len,
85 bool fin) override {
86 if (fin && len == 0) {
87 // The framer invokes OnStreamFrameData with zero-length data and
88 // fin = true after processing a SYN_STREAM or SYN_REPLY frame
89 // that had the fin bit set.
90 return;
92 CloseConnection("SPDY DATA frame received.");
95 void OnError(SpdyFramer* framer) override {
96 CloseConnection(base::StringPrintf(
97 "SPDY framing error: %s",
98 SpdyFramer::ErrorCodeToString(framer->error_code())));
101 void OnDataFrameHeader(SpdyStreamId stream_id,
102 size_t length,
103 bool fin) override {
104 CloseConnection("SPDY DATA frame received.");
107 void OnRstStream(SpdyStreamId stream_id,
108 SpdyRstStreamStatus status) override {
109 CloseConnection("SPDY RST_STREAM frame received.");
112 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override {
113 CloseConnection("SPDY SETTINGS frame received.");
116 void OnSettingsAck() override {
117 CloseConnection("SPDY SETTINGS frame received.");
120 void OnSettingsEnd() override {
121 CloseConnection("SPDY SETTINGS frame received.");
124 void OnPing(SpdyPingId unique_id, bool is_ack) override {
125 CloseConnection("SPDY PING frame received.");
128 void OnGoAway(SpdyStreamId last_accepted_stream_id,
129 SpdyGoAwayStatus status) override {
130 CloseConnection("SPDY GOAWAY frame received.");
133 void OnHeaders(SpdyStreamId stream_id,
134 bool has_priority,
135 SpdyPriority priority,
136 bool fin,
137 bool end) override {
138 if (spdy_version_ == SPDY3) {
139 CloseConnection("SPDY HEADERS frame received.");
140 return;
142 if (!stream_->IsConnected()) {
143 return;
145 if (has_priority) {
146 stream_->OnSynStream(stream_id, priority, fin);
147 } else {
148 stream_->OnSynReply(stream_id, fin);
152 void OnWindowUpdate(SpdyStreamId stream_id,
153 uint32 delta_window_size) override {
154 CloseConnection("SPDY WINDOW_UPDATE frame received.");
157 void OnPushPromise(SpdyStreamId stream_id,
158 SpdyStreamId promised_stream_id,
159 bool end) override {
160 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer";
161 CloseConnection("SPDY PUSH_PROMISE frame received.");
164 void OnContinuation(SpdyStreamId stream_id, bool end) override {
165 if (spdy_version_ == SPDY3) {
166 LOG(DFATAL) << "CONTINUATION frame received from a SPDY/3 framer";
167 CloseConnection("SPDY CONTINUATION frame received.");
171 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
172 CloseConnection("Unknown frame type received.");
173 return false;
176 // SpdyFramerDebugVisitorInterface implementation
177 void OnSendCompressedFrame(SpdyStreamId stream_id,
178 SpdyFrameType type,
179 size_t payload_len,
180 size_t frame_len) override {}
182 void OnReceiveCompressedFrame(SpdyStreamId stream_id,
183 SpdyFrameType type,
184 size_t frame_len) override {
185 if (stream_->IsConnected()) {
186 stream_->OnCompressedFrameSize(frame_len);
190 private:
191 void CloseConnection(const string& details) {
192 if (stream_->IsConnected()) {
193 stream_->CloseConnectionWithDetails(
194 QUIC_INVALID_HEADERS_STREAM_DATA, details);
198 private:
199 SpdyMajorVersion spdy_version_;
200 QuicHeadersStream* stream_;
202 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor);
205 QuicHeadersStream::QuicHeadersStream(QuicSession* session)
206 : ReliableQuicStream(kHeadersStreamId, session),
207 stream_id_(kInvalidStreamId),
208 fin_(false),
209 frame_len_(0) {
210 InitializeFramer(session->connection()->version());
211 // The headers stream is exempt from connection level flow control.
212 DisableConnectionFlowControlForThisStream();
215 QuicHeadersStream::~QuicHeadersStream() {}
217 size_t QuicHeadersStream::WriteHeaders(
218 QuicStreamId stream_id,
219 const SpdyHeaderBlock& headers,
220 bool fin,
221 QuicPriority priority,
222 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
223 scoped_ptr<SpdySerializedFrame> frame;
224 if (spdy_framer_->protocol_version() == SPDY3) {
225 if (session()->is_server()) {
226 SpdySynReplyIR syn_reply(stream_id);
227 syn_reply.set_name_value_block(headers);
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));
237 } else {
238 SpdyHeadersIR headers_frame(stream_id);
239 headers_frame.set_name_value_block(headers);
240 headers_frame.set_fin(fin);
241 if (!session()->is_server()) {
242 headers_frame.set_has_priority(true);
243 headers_frame.set_priority(priority);
245 frame.reset(spdy_framer_->SerializeFrame(headers_frame));
247 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false,
248 ack_notifier_delegate);
249 return frame->size();
252 uint32 QuicHeadersStream::ProcessRawData(const char* data,
253 uint32 data_len) {
254 return spdy_framer_->ProcessInput(data, data_len);
257 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; }
259 void QuicHeadersStream::OnSuccessfulVersionNegotiation(QuicVersion version) {
260 InitializeFramer(version);
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;
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());
275 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id,
276 SpdyPriority priority,
277 bool fin) {
278 if (!session()->is_server()) {
279 CloseConnectionWithDetails(
280 QUIC_INVALID_HEADERS_STREAM_DATA,
281 "SPDY SYN_STREAM frame received at the client");
282 return;
284 DCHECK_EQ(kInvalidStreamId, stream_id_);
285 stream_id_ = stream_id;
286 fin_ = fin;
287 session()->OnStreamHeadersPriority(stream_id, priority);
290 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id, bool fin) {
291 if (session()->is_server()) {
292 CloseConnectionWithDetails(
293 QUIC_INVALID_HEADERS_STREAM_DATA,
294 "SPDY SYN_REPLY frame received at the server");
295 return;
297 DCHECK_EQ(kInvalidStreamId, stream_id_);
298 stream_id_ = stream_id;
299 fin_ = fin;
302 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id,
303 const char* header_data,
304 size_t len) {
305 DCHECK_EQ(stream_id_, stream_id);
306 if (len == 0) {
307 DCHECK_NE(0u, stream_id_);
308 DCHECK_NE(0u, frame_len_);
309 session()->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
310 // Reset state for the next frame.
311 stream_id_ = kInvalidStreamId;
312 fin_ = false;
313 frame_len_ = 0;
314 } else {
315 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
319 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) {
320 if (spdy_framer_->protocol_version() == SPDY3) {
321 // SPDY/3 headers always fit into a single frame, so the previous headers
322 // should be completely processed when a new frame is received.
323 DCHECK_EQ(kInvalidStreamId, stream_id_);
324 DCHECK_EQ(0u, frame_len_);
326 frame_len_ += frame_len;
329 bool QuicHeadersStream::IsConnected() {
330 return session()->connection()->connected();
333 } // namespace net