blob: 8a31699e1636ac9feced4f125116e33e28501b66 [file] [log] [blame]
jokulikc971baf92016-01-06 00:36:391// Copyright (c) 2012 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/tools/quic/quic_simple_server_session.h"
6
7#include "base/logging.h"
zhongyi4a9d27b2016-01-12 20:08:318#include "base/stl_util.h"
jokulikc971baf92016-01-06 00:36:399#include "net/quic/proto/cached_network_parameters.pb.h"
10#include "net/quic/quic_connection.h"
11#include "net/quic/quic_flags.h"
12#include "net/quic/quic_spdy_session.h"
13#include "net/quic/reliable_quic_stream.h"
14#include "net/tools/quic/quic_simple_server_stream.h"
zhongyi4a9d27b2016-01-12 20:08:3115#include "url/gurl.h"
jokulikc971baf92016-01-06 00:36:3916
bnc614a92d32016-04-04 13:56:0717using std::string;
18
jokulikc971baf92016-01-06 00:36:3919namespace net {
jokulikc971baf92016-01-06 00:36:3920
21QuicSimpleServerSession::QuicSimpleServerSession(
22 const QuicConfig& config,
23 QuicConnection* connection,
24 QuicServerSessionVisitor* visitor,
rjshaded069aaee2016-03-11 20:42:1725 const QuicCryptoServerConfig* crypto_config,
26 QuicCompressedCertsCache* compressed_certs_cache)
27 : QuicServerSessionBase(config,
28 connection,
29 visitor,
30 crypto_config,
31 compressed_certs_cache),
zhongyi4a9d27b2016-01-12 20:08:3132 highest_promised_stream_id_(0) {}
jokulikc971baf92016-01-06 00:36:3933
34QuicSimpleServerSession::~QuicSimpleServerSession() {}
35
36QuicCryptoServerStreamBase*
37QuicSimpleServerSession::CreateQuicCryptoServerStream(
rjshaded069aaee2016-03-11 20:42:1738 const QuicCryptoServerConfig* crypto_config,
39 QuicCompressedCertsCache* compressed_certs_cache) {
40 return new QuicCryptoServerStream(crypto_config, compressed_certs_cache,
41 FLAGS_enable_quic_stateless_reject_support,
42 this);
jokulikc971baf92016-01-06 00:36:3943}
44
zhongyi4a9d27b2016-01-12 20:08:3145void QuicSimpleServerSession::StreamDraining(QuicStreamId id) {
46 QuicSpdySession::StreamDraining(id);
47 if (!IsIncomingStream(id)) {
48 HandlePromisedPushRequests();
49 }
50}
51
52void QuicSimpleServerSession::OnStreamFrame(const QuicStreamFrame& frame) {
53 if (!IsIncomingStream(frame.stream_id)) {
54 LOG(WARNING) << "Client shouldn't send data on server push stream";
jri78ec06a2016-03-31 18:19:4055 connection()->CloseConnection(
56 QUIC_INVALID_STREAM_ID, "Client sent data on server push stream",
57 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
zhongyi4a9d27b2016-01-12 20:08:3158 return;
59 }
60 QuicSpdySession::OnStreamFrame(frame);
61}
62
63void QuicSimpleServerSession::PromisePushResources(
64 const string& request_url,
jri78ec06a2016-03-31 18:19:4065 const std::list<QuicInMemoryCache::ServerPushInfo>& resources,
zhongyi4a9d27b2016-01-12 20:08:3166 QuicStreamId original_stream_id,
67 const SpdyHeaderBlock& original_request_headers) {
68 for (QuicInMemoryCache::ServerPushInfo resource : resources) {
69 SpdyHeaderBlock headers = SynthesizePushRequestHeaders(
70 request_url, resource, original_request_headers);
71 highest_promised_stream_id_ += 2;
72 SendPushPromise(original_stream_id, highest_promised_stream_id_, headers);
73 promised_streams_.push_back(PromisedStreamInfo(
74 headers, highest_promised_stream_id_, resource.priority));
75 }
76
77 // Procese promised push request as many as possible.
78 HandlePromisedPushRequests();
79}
80
jokulikc971baf92016-01-06 00:36:3981QuicSpdyStream* QuicSimpleServerSession::CreateIncomingDynamicStream(
82 QuicStreamId id) {
83 if (!ShouldCreateIncomingDynamicStream(id)) {
84 return nullptr;
85 }
86
danzh33407f12016-03-04 21:58:1687 QuicSpdyStream* stream = new QuicSimpleServerStream(id, this);
88 ActivateStream(stream);
89 return stream;
jokulikc971baf92016-01-06 00:36:3990}
91
92QuicSimpleServerStream* QuicSimpleServerSession::CreateOutgoingDynamicStream(
93 SpdyPriority priority) {
94 if (!ShouldCreateOutgoingDynamicStream()) {
95 return nullptr;
96 }
97
98 QuicSimpleServerStream* stream =
99 new QuicSimpleServerStream(GetNextOutgoingStreamId(), this);
100 stream->SetPriority(priority);
101 ActivateStream(stream);
102 return stream;
103}
104
zhongyi4a9d27b2016-01-12 20:08:31105void QuicSimpleServerSession::CloseStreamInner(QuicStreamId stream_id,
106 bool locally_reset) {
107 QuicSpdySession::CloseStreamInner(stream_id, locally_reset);
108 HandlePromisedPushRequests();
109}
110
111void QuicSimpleServerSession::HandleFrameOnNonexistentOutgoingStream(
112 QuicStreamId stream_id) {
113 // If this stream is a promised but not created stream (stream_id within the
114 // range of next_outgoing_stream_id_ and highes_promised_stream_id_),
115 // connection shouldn't be closed.
116 // Otherwise behave in the same way as base class.
117 if (stream_id > highest_promised_stream_id_) {
118 QuicSession::HandleFrameOnNonexistentOutgoingStream(stream_id);
119 }
120}
121
122void QuicSimpleServerSession::HandleRstOnValidNonexistentStream(
123 const QuicRstStreamFrame& frame) {
124 QuicSession::HandleRstOnValidNonexistentStream(frame);
125 if (!IsClosedStream(frame.stream_id)) {
126 // If a nonexistent stream is not a closed stream and still valid, it must
127 // be a locally preserved stream. Resetting this kind of stream means
128 // cancelling the promised server push.
129 // Since PromisedStreamInfo are queued in sequence, the corresponding
130 // index for it in promised_streams_ can be calculated.
131 DCHECK(frame.stream_id >= next_outgoing_stream_id());
132 size_t index = (frame.stream_id - next_outgoing_stream_id()) / 2;
133 DCHECK(index <= promised_streams_.size());
134 promised_streams_[index].is_cancelled = true;
135 connection()->SendRstStream(frame.stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
136 }
137}
138
139SpdyHeaderBlock QuicSimpleServerSession::SynthesizePushRequestHeaders(
140 string request_url,
141 QuicInMemoryCache::ServerPushInfo resource,
142 const SpdyHeaderBlock& original_request_headers) {
143 GURL push_request_url = resource.request_url;
144 string path = push_request_url.path();
145
146 SpdyHeaderBlock spdy_headers = original_request_headers;
147 // :authority could be different from original request.
148 spdy_headers.ReplaceOrAppendHeader(":authority", push_request_url.host());
149 spdy_headers.ReplaceOrAppendHeader(":path", path);
150 // Push request always use GET.
151 spdy_headers.ReplaceOrAppendHeader(":method", "GET");
152 spdy_headers.ReplaceOrAppendHeader("referer", request_url);
153 spdy_headers.ReplaceOrAppendHeader(":scheme", push_request_url.scheme());
154 // It is not possible to push a response to a request that includes a request
155 // body.
156 spdy_headers.ReplaceOrAppendHeader("content-length", "0");
157 // Remove "host" field as push request is a directly generated HTTP2 request
158 // which should use ":authority" instead of "host".
159 spdy_headers.erase("host");
160 return spdy_headers;
161}
162
163void QuicSimpleServerSession::SendPushPromise(QuicStreamId original_stream_id,
164 QuicStreamId promised_stream_id,
165 const SpdyHeaderBlock& headers) {
166 DVLOG(1) << "stream " << original_stream_id
167 << " send PUSH_PROMISE for promised stream " << promised_stream_id;
168 headers_stream()->WritePushPromise(original_stream_id, promised_stream_id,
169 headers, nullptr);
170}
171
172void QuicSimpleServerSession::HandlePromisedPushRequests() {
173 while (!promised_streams_.empty() && ShouldCreateOutgoingDynamicStream()) {
174 const PromisedStreamInfo& promised_info = promised_streams_.front();
175 DCHECK_EQ(next_outgoing_stream_id(), promised_info.stream_id);
176
177 if (promised_info.is_cancelled) {
178 // This stream has been reset by client. Skip this stream id.
179 promised_streams_.pop_front();
180 GetNextOutgoingStreamId();
181 return;
182 }
183
184 QuicSimpleServerStream* promised_stream =
185 static_cast<QuicSimpleServerStream*>(
186 CreateOutgoingDynamicStream(promised_info.priority));
187 DCHECK(promised_stream != nullptr);
188 DCHECK_EQ(promised_info.stream_id, promised_stream->id());
189 DVLOG(1) << "created server push stream " << promised_stream->id();
190
ckrasic244375a32016-02-04 21:21:22191 const SpdyHeaderBlock request_headers(promised_info.request_headers);
zhongyi4a9d27b2016-01-12 20:08:31192
193 promised_streams_.pop_front();
ckrasic244375a32016-02-04 21:21:22194 promised_stream->PushResponse(request_headers);
zhongyi4a9d27b2016-01-12 20:08:31195 }
196}
197
jokulikc971baf92016-01-06 00:36:39198} // namespace net