Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(998)

Unified Diff: net/tools/quic/quic_simple_server_session.cc

Issue 1570343005: relnote: Implement server push methods in QuicSimpleServerSession. Only modify toy Quic server, not… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@0044_CL_111708360
Patch Set: rebase to chain after fix Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/tools/quic/quic_simple_server_session.h ('k') | net/tools/quic/quic_simple_server_session_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/tools/quic/quic_simple_server_session.cc
diff --git a/net/tools/quic/quic_simple_server_session.cc b/net/tools/quic/quic_simple_server_session.cc
index 0c6aeb876852064b61e85d2b06469539df5a6017..9b4257615e401f8e7f16a3462baeb798a5c5a64d 100644
--- a/net/tools/quic/quic_simple_server_session.cc
+++ b/net/tools/quic/quic_simple_server_session.cc
@@ -5,12 +5,14 @@
#include "net/tools/quic/quic_simple_server_session.h"
#include "base/logging.h"
+#include "base/stl_util.h"
#include "net/quic/proto/cached_network_parameters.pb.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_spdy_session.h"
#include "net/quic/reliable_quic_stream.h"
#include "net/tools/quic/quic_simple_server_stream.h"
+#include "url/gurl.h"
namespace net {
namespace tools {
@@ -20,7 +22,8 @@ QuicSimpleServerSession::QuicSimpleServerSession(
QuicConnection* connection,
QuicServerSessionVisitor* visitor,
const QuicCryptoServerConfig* crypto_config)
- : QuicServerSessionBase(config, connection, visitor, crypto_config) {}
+ : QuicServerSessionBase(config, connection, visitor, crypto_config),
+ highest_promised_stream_id_(0) {}
QuicSimpleServerSession::~QuicSimpleServerSession() {}
@@ -30,6 +33,41 @@ QuicSimpleServerSession::CreateQuicCryptoServerStream(
return new QuicCryptoServerStream(crypto_config, this);
}
+void QuicSimpleServerSession::StreamDraining(QuicStreamId id) {
+ QuicSpdySession::StreamDraining(id);
+ if (!IsIncomingStream(id)) {
+ HandlePromisedPushRequests();
+ }
+}
+
+void QuicSimpleServerSession::OnStreamFrame(const QuicStreamFrame& frame) {
+ if (!IsIncomingStream(frame.stream_id)) {
+ LOG(WARNING) << "Client shouldn't send data on server push stream";
+ connection()->SendConnectionCloseWithDetails(
+ QUIC_INVALID_STREAM_ID, "Client sent data on server push stream");
+ return;
+ }
+ QuicSpdySession::OnStreamFrame(frame);
+}
+
+void QuicSimpleServerSession::PromisePushResources(
+ const string& request_url,
+ const list<QuicInMemoryCache::ServerPushInfo>& resources,
+ QuicStreamId original_stream_id,
+ const SpdyHeaderBlock& original_request_headers) {
+ for (QuicInMemoryCache::ServerPushInfo resource : resources) {
+ SpdyHeaderBlock headers = SynthesizePushRequestHeaders(
+ request_url, resource, original_request_headers);
+ highest_promised_stream_id_ += 2;
+ SendPushPromise(original_stream_id, highest_promised_stream_id_, headers);
+ promised_streams_.push_back(PromisedStreamInfo(
+ headers, highest_promised_stream_id_, resource.priority));
+ }
+
+ // Procese promised push request as many as possible.
+ HandlePromisedPushRequests();
+}
+
QuicSpdyStream* QuicSimpleServerSession::CreateIncomingDynamicStream(
QuicStreamId id) {
if (!ShouldCreateIncomingDynamicStream(id)) {
@@ -52,5 +90,98 @@ QuicSimpleServerStream* QuicSimpleServerSession::CreateOutgoingDynamicStream(
return stream;
}
+void QuicSimpleServerSession::CloseStreamInner(QuicStreamId stream_id,
+ bool locally_reset) {
+ QuicSpdySession::CloseStreamInner(stream_id, locally_reset);
+ HandlePromisedPushRequests();
+}
+
+void QuicSimpleServerSession::HandleFrameOnNonexistentOutgoingStream(
+ QuicStreamId stream_id) {
+ // If this stream is a promised but not created stream (stream_id within the
+ // range of next_outgoing_stream_id_ and highes_promised_stream_id_),
+ // connection shouldn't be closed.
+ // Otherwise behave in the same way as base class.
+ if (stream_id > highest_promised_stream_id_) {
+ QuicSession::HandleFrameOnNonexistentOutgoingStream(stream_id);
+ }
+}
+
+void QuicSimpleServerSession::HandleRstOnValidNonexistentStream(
+ const QuicRstStreamFrame& frame) {
+ QuicSession::HandleRstOnValidNonexistentStream(frame);
+ if (!IsClosedStream(frame.stream_id)) {
+ // If a nonexistent stream is not a closed stream and still valid, it must
+ // be a locally preserved stream. Resetting this kind of stream means
+ // cancelling the promised server push.
+ // Since PromisedStreamInfo are queued in sequence, the corresponding
+ // index for it in promised_streams_ can be calculated.
+ DCHECK(frame.stream_id >= next_outgoing_stream_id());
+ size_t index = (frame.stream_id - next_outgoing_stream_id()) / 2;
+ DCHECK(index <= promised_streams_.size());
+ promised_streams_[index].is_cancelled = true;
+ connection()->SendRstStream(frame.stream_id, QUIC_RST_ACKNOWLEDGEMENT, 0);
+ }
+}
+
+SpdyHeaderBlock QuicSimpleServerSession::SynthesizePushRequestHeaders(
+ string request_url,
+ QuicInMemoryCache::ServerPushInfo resource,
+ const SpdyHeaderBlock& original_request_headers) {
+ GURL push_request_url = resource.request_url;
+ string path = push_request_url.path();
+
+ SpdyHeaderBlock spdy_headers = original_request_headers;
+ // :authority could be different from original request.
+ spdy_headers.ReplaceOrAppendHeader(":authority", push_request_url.host());
+ spdy_headers.ReplaceOrAppendHeader(":path", path);
+ // Push request always use GET.
+ spdy_headers.ReplaceOrAppendHeader(":method", "GET");
+ spdy_headers.ReplaceOrAppendHeader("referer", request_url);
+ spdy_headers.ReplaceOrAppendHeader(":scheme", push_request_url.scheme());
+ // It is not possible to push a response to a request that includes a request
+ // body.
+ spdy_headers.ReplaceOrAppendHeader("content-length", "0");
+ // Remove "host" field as push request is a directly generated HTTP2 request
+ // which should use ":authority" instead of "host".
+ spdy_headers.erase("host");
+ return spdy_headers;
+}
+
+void QuicSimpleServerSession::SendPushPromise(
+ QuicStreamId original_stream_id,
+ QuicStreamId promised_stream_id,
+ const SpdyHeaderBlock& headers) {
+ DVLOG(1) << "stream " << original_stream_id
+ << " send PUSH_PROMISE for promised stream " << promised_stream_id;
+ headers_stream()->WritePushPromise(original_stream_id, promised_stream_id,
+ headers, nullptr);
+}
+
+void QuicSimpleServerSession::HandlePromisedPushRequests() {
+ while (!promised_streams_.empty() && ShouldCreateOutgoingDynamicStream()) {
+ const PromisedStreamInfo& promised_info = promised_streams_.front();
+ DCHECK_EQ(next_outgoing_stream_id(), promised_info.stream_id);
+
+ if (promised_info.is_cancelled) {
+ // This stream has been reset by client. Skip this stream id.
+ promised_streams_.pop_front();
+ GetNextOutgoingStreamId();
+ return;
+ }
+
+ QuicSimpleServerStream* promised_stream =
+ static_cast<QuicSimpleServerStream*>(
+ CreateOutgoingDynamicStream(promised_info.priority));
+ DCHECK(promised_stream != nullptr);
+ DCHECK_EQ(promised_info.stream_id, promised_stream->id());
+ DVLOG(1) << "created server push stream " << promised_stream->id();
+
+ promised_stream->PushResponse(promised_info.request_headers);
+
+ promised_streams_.pop_front();
+ }
+}
+
} // namespace tools
} // namespace net
« no previous file with comments | « net/tools/quic/quic_simple_server_session.h ('k') | net/tools/quic/quic_simple_server_session_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698