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 "net/quic/quic_session.h"
9 using base::StringPiece;
15 const QuicStreamId kInvalidStreamId = 0;
19 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
20 // the QuicDataStream, and closes the connection if any unexpected frames
22 class QuicHeadersStream::SpdyFramerVisitor
23 : public SpdyFramerVisitorInterface,
24 public SpdyFramerDebugVisitorInterface {
26 explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {}
28 // SpdyFramerVisitorInterface implementation
29 void OnSynStream(SpdyStreamId stream_id,
30 SpdyStreamId associated_stream_id,
31 SpdyPriority priority,
33 bool unidirectional) override {
34 if (!stream_->IsConnected()) {
38 if (associated_stream_id != 0) {
39 CloseConnection("associated_stream_id != 0");
43 if (unidirectional != 0) {
44 CloseConnection("unidirectional != 0");
48 stream_->OnSynStream(stream_id, priority, fin);
51 void OnSynReply(SpdyStreamId stream_id, bool fin) override {
52 if (!stream_->IsConnected()) {
56 stream_->OnSynReply(stream_id, fin);
59 bool OnControlFrameHeaderData(SpdyStreamId stream_id,
60 const char* header_data,
61 size_t len) override {
62 if (!stream_->IsConnected()) {
65 stream_->OnControlFrameHeaderData(stream_id, header_data, len);
69 void OnStreamFrameData(SpdyStreamId stream_id,
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.
79 CloseConnection("SPDY DATA frame received.");
82 void OnError(SpdyFramer* framer) override {
83 CloseConnection("SPDY framing error.");
86 void OnDataFrameHeader(SpdyStreamId stream_id,
89 CloseConnection("SPDY DATA frame received.");
92 void OnRstStream(SpdyStreamId stream_id,
93 SpdyRstStreamStatus status) override {
94 CloseConnection("SPDY RST_STREAM frame received.");
97 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override {
98 CloseConnection("SPDY SETTINGS frame received.");
101 void OnSettingsAck() override {
102 CloseConnection("SPDY SETTINGS frame received.");
105 void OnSettingsEnd() override {
106 CloseConnection("SPDY SETTINGS frame received.");
109 void OnPing(SpdyPingId unique_id, bool is_ack) override {
110 CloseConnection("SPDY PING frame received.");
113 void OnGoAway(SpdyStreamId last_accepted_stream_id,
114 SpdyGoAwayStatus status) override {
115 CloseConnection("SPDY GOAWAY frame received.");
118 void OnHeaders(SpdyStreamId stream_id,
120 SpdyPriority priority,
123 CloseConnection("SPDY HEADERS frame received.");
126 void OnWindowUpdate(SpdyStreamId stream_id,
127 uint32 delta_window_size) override {
128 CloseConnection("SPDY WINDOW_UPDATE frame received.");
131 void OnPushPromise(SpdyStreamId stream_id,
132 SpdyStreamId promised_stream_id,
134 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer";
135 CloseConnection("SPDY PUSH_PROMISE frame received.");
138 void OnContinuation(SpdyStreamId stream_id, bool end) override {
139 CloseConnection("SPDY CONTINUATION frame received.");
142 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
143 CloseConnection("SPDY unknown frame received.");
147 // SpdyFramerDebugVisitorInterface implementation
148 void OnSendCompressedFrame(SpdyStreamId stream_id,
151 size_t frame_len) override {}
153 void OnReceiveCompressedFrame(SpdyStreamId stream_id,
155 size_t frame_len) override {
156 if (stream_->IsConnected()) {
157 stream_->OnCompressedFrameSize(frame_len);
162 void CloseConnection(const string& details) {
163 if (stream_->IsConnected()) {
164 stream_->CloseConnectionWithDetails(
165 QUIC_INVALID_HEADERS_STREAM_DATA, details);
170 QuicHeadersStream* stream_;
172 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor);
175 QuicHeadersStream::QuicHeadersStream(QuicSession* session)
176 : ReliableQuicStream(kHeadersStreamId, session),
177 stream_id_(kInvalidStreamId),
181 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
182 spdy_framer_.set_visitor(spdy_framer_visitor_.get());
183 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
184 if (version() < QUIC_VERSION_21) {
185 // Prior to QUIC_VERSION_21 the headers stream is not subject to any flow
187 DisableFlowControl();
189 // The headers stream is exempt from connection level flow control.
190 DisableConnectionFlowControlForThisStream();
193 QuicHeadersStream::~QuicHeadersStream() {}
195 size_t QuicHeadersStream::WriteHeaders(
196 QuicStreamId stream_id,
197 const SpdyHeaderBlock& headers,
199 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
200 scoped_ptr<SpdySerializedFrame> frame;
201 if (session()->is_server()) {
202 SpdySynReplyIR syn_reply(stream_id);
203 syn_reply.set_name_value_block(headers);
204 syn_reply.set_fin(fin);
205 frame.reset(spdy_framer_.SerializeFrame(syn_reply));
207 SpdySynStreamIR syn_stream(stream_id);
208 syn_stream.set_name_value_block(headers);
209 syn_stream.set_fin(fin);
210 frame.reset(spdy_framer_.SerializeFrame(syn_stream));
212 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false,
213 ack_notifier_delegate);
214 return frame->size();
217 uint32 QuicHeadersStream::ProcessRawData(const char* data,
219 return spdy_framer_.ProcessInput(data, data_len);
222 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; }
224 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id,
225 SpdyPriority priority,
227 if (!session()->is_server()) {
228 CloseConnectionWithDetails(
229 QUIC_INVALID_HEADERS_STREAM_DATA,
230 "SPDY SYN_STREAM frame received at the client");
233 DCHECK_EQ(kInvalidStreamId, stream_id_);
234 stream_id_ = stream_id;
236 session()->OnStreamHeadersPriority(stream_id, priority);
239 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id, bool fin) {
240 if (session()->is_server()) {
241 CloseConnectionWithDetails(
242 QUIC_INVALID_HEADERS_STREAM_DATA,
243 "SPDY SYN_REPLY frame received at the server");
246 DCHECK_EQ(kInvalidStreamId, stream_id_);
247 stream_id_ = stream_id;
251 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id,
252 const char* header_data,
254 DCHECK_EQ(stream_id_, stream_id);
256 DCHECK_NE(0u, stream_id_);
257 DCHECK_NE(0u, frame_len_);
258 session()->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
259 // Reset state for the next frame.
260 stream_id_ = kInvalidStreamId;
264 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
268 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) {
269 DCHECK_EQ(kInvalidStreamId, stream_id_);
270 DCHECK_EQ(0u, frame_len_);
271 frame_len_ = frame_len;
274 bool QuicHeadersStream::IsConnected() {
275 return session()->connection()->connected();