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