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
9using base::StringPiece;
10
11namespace net {
12
13namespace {
14
15const 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.
22class QuicHeadersStream::SpdyFramerVisitor
23    : public SpdyFramerVisitorInterface,
24      public SpdyFramerDebugVisitorInterface {
25 public:
26  explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {}
27
28  // SpdyFramerVisitorInterface implementation
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
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
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
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
82  virtual void OnError(SpdyFramer* framer) OVERRIDE {
83    CloseConnection("SPDY framing error.");
84  }
85
86  virtual void OnDataFrameHeader(SpdyStreamId stream_id,
87                                 size_t length,
88                                 bool fin) OVERRIDE {
89    CloseConnection("SPDY DATA frame received.");
90  }
91
92  virtual void OnRstStream(SpdyStreamId stream_id,
93                           SpdyRstStreamStatus status) OVERRIDE {
94    CloseConnection("SPDY RST_STREAM frame received.");
95  }
96
97  virtual void OnSetting(SpdySettingsIds id,
98                         uint8 flags,
99                         uint32 value) OVERRIDE {
100    CloseConnection("SPDY SETTINGS frame received.");
101  }
102
103  virtual void OnSettingsAck() OVERRIDE {
104    CloseConnection("SPDY SETTINGS frame received.");
105  }
106
107  virtual void OnSettingsEnd() OVERRIDE {
108    CloseConnection("SPDY SETTINGS frame received.");
109  }
110
111  virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE {
112    CloseConnection("SPDY PING frame received.");
113  }
114
115  virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
116                        SpdyGoAwayStatus status) OVERRIDE {
117    CloseConnection("SPDY GOAWAY frame received.");
118  }
119
120  virtual void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) OVERRIDE {
121    CloseConnection("SPDY HEADERS frame received.");
122  }
123
124  virtual void OnWindowUpdate(SpdyStreamId stream_id,
125                              uint32 delta_window_size) OVERRIDE {
126    CloseConnection("SPDY WINDOW_UPDATE frame received.");
127  }
128
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
136  virtual void OnContinuation(SpdyStreamId stream_id, bool end) OVERRIDE {
137    CloseConnection("SPDY CONTINUATION frame received.");
138  }
139
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
146  virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
147                                     SpdyFrameType type,
148                                     size_t payload_len,
149                                     size_t frame_len) OVERRIDE {}
150
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:
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
173QuicHeadersStream::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
191QuicHeadersStream::~QuicHeadersStream() {}
192
193size_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
215uint32 QuicHeadersStream::ProcessRawData(const char* data,
216                                         uint32 data_len) {
217  return spdy_framer_.ProcessInput(data, data_len);
218}
219
220QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; }
221
222void 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
237void 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
249void 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
266void 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
272bool QuicHeadersStream::IsConnected() {
273  return session()->connection()->connected();
274}
275
276}  // namespace net
277