Remove QUIC server push from QuicSimpleServerSession.
PiperOrigin-RevId: 370658760
Change-Id: I5cec6cd0cc9b0a2a366e11e2dc1e881a88173f10
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index caec403..5aa0c4f 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -3973,312 +3973,6 @@
EXPECT_EQ(trailers, client_->response_trailers());
}
-class EndToEndTestServerPush : public EndToEndTest {
- protected:
- const size_t kNumMaxStreams = 10;
-
- EndToEndTestServerPush() : EndToEndTest() {
- client_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams);
- server_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams);
- client_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams);
- server_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams);
- }
-
- // Add a request with its response and |num_resources| push resources into
- // cache.
- // If |resource_size| == 0, response body of push resources use default string
- // concatenating with resource url. Otherwise, generate a string of
- // |resource_size| as body.
- void AddRequestAndResponseWithServerPush(std::string host,
- std::string path,
- std::string response_body,
- std::string* push_urls,
- const size_t num_resources,
- const size_t resource_size) {
- bool use_large_response = resource_size != 0;
- std::string large_resource;
- if (use_large_response) {
- // Generate a response common body larger than flow control window for
- // push response.
- large_resource = std::string(resource_size, 'a');
- }
- std::list<QuicBackendResponse::ServerPushInfo> push_resources;
- for (size_t i = 0; i < num_resources; ++i) {
- std::string url = push_urls[i];
- QuicUrl resource_url(url);
- std::string body =
- use_large_response
- ? large_resource
- : absl::StrCat("This is server push response body for ", url);
- SpdyHeaderBlock response_headers;
- response_headers[":status"] = "200";
- response_headers["content-length"] = absl::StrCat(body.size());
- push_resources.push_back(QuicBackendResponse::ServerPushInfo(
- resource_url, std::move(response_headers), kV3LowestPriority, body));
- }
-
- memory_cache_backend_.AddSimpleResponseWithServerPushResources(
- host, path, 200, response_body, push_resources);
- }
-};
-
-// Run all server push end to end tests with all supported versions.
-INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush,
- EndToEndTestServerPush,
- ::testing::ValuesIn(GetTestParams()),
- ::testing::PrintToStringParamName());
-
-TEST_P(EndToEndTestServerPush, ServerPush) {
- ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
-
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
- size_t kNumResources = 4;
- std::string push_urls[] = {"https://example.com/font.woff",
- "https://example.com/script.js",
- "https://fonts.example.com/font.woff",
- "https://example.com/logo-hires.jpg"};
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, 0);
-
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- QUIC_DVLOG(1) << "send request for /push_example";
- EXPECT_EQ(kBody, client_->SendSynchronousRequest(
- "https://example.com/push_example"));
- QuicStreamSequencer* sequencer = nullptr;
- if (!version_.UsesHttp3()) {
- QuicSpdyClientSession* client_session = GetClientSession();
- ASSERT_TRUE(client_session);
- QuicHeadersStream* headers_stream =
- QuicSpdySessionPeer::GetHeadersStream(client_session);
- ASSERT_TRUE(headers_stream);
- sequencer = QuicStreamPeer::sequencer(headers_stream);
- ASSERT_TRUE(sequencer);
- // Headers stream's sequencer buffer shouldn't be released because server
- // push hasn't finished yet.
- EXPECT_TRUE(
- QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
- }
-
- for (const std::string& url : push_urls) {
- QUIC_DVLOG(1) << "send request for pushed stream on url " << url;
- std::string expected_body =
- absl::StrCat("This is server push response body for ", url);
- std::string response_body = client_->SendSynchronousRequest(url);
- QUIC_DVLOG(1) << "response body " << response_body;
- EXPECT_EQ(expected_body, response_body);
- }
- if (!version_.UsesHttp3()) {
- ASSERT_TRUE(sequencer);
- EXPECT_FALSE(
- QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
- }
-}
-
-TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
- // Tests that sending a request which has 4 push resources will trigger server
- // to push those 4 resources and client can handle pushed resources and match
- // them with requests later.
- ASSERT_TRUE(Initialize());
-
- if (version_.UsesHttp3()) {
- return;
- }
-
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
- size_t const kNumResources = 4;
- std::string push_urls[] = {
- "https://example.com/font.woff",
- "https://example.com/script.js",
- "https://fonts.example.com/font.woff",
- "https://example.com/logo-hires.jpg",
- };
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, 0);
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- // Send the first request: this will trigger the server to send all the push
- // resources associated with this request, and these will be cached by the
- // client.
- EXPECT_EQ(kBody, client_->SendSynchronousRequest(
- "https://example.com/push_example"));
-
- for (const std::string& url : push_urls) {
- // Sending subsequent requesets will not actually send anything on the wire,
- // as the responses are already in the client's cache.
- QUIC_DVLOG(1) << "send request for pushed stream on url " << url;
- std::string expected_body =
- absl::StrCat("This is server push response body for ", url);
- std::string response_body = client_->SendSynchronousRequest(url);
- QUIC_DVLOG(1) << "response body " << response_body;
- EXPECT_EQ(expected_body, response_body);
- }
- // Expect only original request has been sent and push responses have been
- // received as normal response.
- EXPECT_EQ(1u, client_->num_requests());
- EXPECT_EQ(1u + kNumResources, client_->num_responses());
-}
-
-TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
- if (version_.UsesHttp3()) {
- ASSERT_TRUE(Initialize());
- return;
- }
- // Tests that when streams are not blocked by flow control or congestion
- // control, pushing even more resources than max number of open outgoing
- // streams should still work because all response streams get closed
- // immediately after pushing resources.
- ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
-
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
-
- // One more resource than max number of outgoing stream of this session.
- const size_t kNumResources = 1 + kNumMaxStreams; // 11.
- std::string push_urls[11];
- for (size_t i = 0; i < kNumResources; ++i) {
- push_urls[i] = absl::StrCat("https://example.com/push_resources", i);
- }
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, 0);
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- // Send the first request: this will trigger the server to send all the push
- // resources associated with this request, and these will be cached by the
- // client.
- EXPECT_EQ(kBody, client_->SendSynchronousRequest(
- "https://example.com/push_example"));
-
- for (const std::string& url : push_urls) {
- // Sending subsequent requesets will not actually send anything on the wire,
- // as the responses are already in the client's cache.
- EXPECT_EQ(absl::StrCat("This is server push response body for ", url),
- client_->SendSynchronousRequest(url));
- }
-
- // Only 1 request should have been sent.
- EXPECT_EQ(1u, client_->num_requests());
- // The responses to the original request and all the promised resources
- // should have been received.
- EXPECT_EQ(12u, client_->num_responses());
-}
-
-TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
- if (version_.UsesHttp3()) {
- ASSERT_TRUE(Initialize());
- return;
- }
-
- // Tests that when server tries to send more large resources(large enough to
- // be blocked by flow control window or congestion control window) than max
- // open outgoing streams , server can open upto max number of outgoing
- // streams for them, and the rest will be queued up.
-
- // Reset flow control windows.
- size_t kFlowControlWnd = 20 * 1024; // 20KB.
- // Response body is larger than 1 flow controlblock window.
- size_t kBodySize = kFlowControlWnd * 2;
- set_client_initial_stream_flow_control_receive_window(kFlowControlWnd);
- // Make sure conntection level flow control window is large enough not to
- // block data being sent out though they will be blocked by stream level one.
- set_client_initial_session_flow_control_receive_window(
- kBodySize * kNumMaxStreams + 1024);
-
- ASSERT_TRUE(Initialize());
- EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
-
- // Set reordering to ensure that body arriving before PUSH_PROMISE is ok.
- SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
- SetReorderPercentage(30);
-
- // Add a response with headers, body, and push resources.
- const std::string kBody = "body content";
-
- const size_t kNumResources = kNumMaxStreams + 1;
- std::string push_urls[11];
- for (size_t i = 0; i < kNumResources; ++i) {
- push_urls[i] = absl::StrCat("http://example.com/push_resources", i);
- }
- AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
- push_urls, kNumResources, kBodySize);
-
- client_->client()->set_response_listener(
- std::unique_ptr<QuicSpdyClientBase::ResponseListener>(
- new TestResponseListener));
-
- client_->SendRequest("https://example.com/push_example");
-
- // Pause after the first response arrives.
- while (!client_->response_complete()) {
- // Because of priority, the first response arrived should be to original
- // request.
- client_->WaitForResponse();
- ASSERT_TRUE(client_->connected());
- }
-
- // Check server session to see if it has max number of outgoing streams opened
- // though more resources need to be pushed.
- if (!version_.HasIetfQuicFrames()) {
- server_thread_->Pause();
- QuicSession* server_session = GetServerSession();
- if (server_session != nullptr) {
- EXPECT_EQ(kNumMaxStreams,
- QuicSessionPeer::GetStreamIdManager(server_session)
- ->num_open_outgoing_streams());
- } else {
- ADD_FAILURE() << "Missing server session";
- }
- server_thread_->Resume();
- }
-
- EXPECT_EQ(1u, client_->num_requests());
- EXPECT_EQ(1u, client_->num_responses());
- EXPECT_EQ(kBody, client_->response_body());
-
- // "Send" request for a promised resources will not really send out it because
- // its response is being pushed(but blocked). And the following ack and
- // flow control behavior of SendSynchronousRequests()
- // will unblock the stream to finish receiving response.
- client_->SendSynchronousRequest(push_urls[0]);
- EXPECT_EQ(1u, client_->num_requests());
- EXPECT_EQ(2u, client_->num_responses());
-
- // Do same thing for the rest 10 resources.
- for (size_t i = 1; i < kNumResources; ++i) {
- client_->SendSynchronousRequest(push_urls[i]);
- }
-
- // Because of server push, client gets all pushed resources without actually
- // sending requests for them.
- EXPECT_EQ(1u, client_->num_requests());
- // Including response to original request, 12 responses in total were
- // received.
- EXPECT_EQ(12u, client_->num_responses());
-}
-
// TODO(fayang): this test seems to cause net_unittests timeouts :|
TEST_P(EndToEndTest, DISABLED_TestHugePostWithPacketLoss) {
// This test tests a huge post with introduced packet loss from client to
diff --git a/quic/masque/masque_server_backend.cc b/quic/masque/masque_server_backend.cc
index 112f305..9684ce1 100644
--- a/quic/masque/masque_server_backend.cc
+++ b/quic/masque/masque_server_backend.cc
@@ -90,7 +90,7 @@
QUIC_DLOG(INFO) << "Sending MASQUE response for "
<< request_headers.DebugString();
- request_handler->OnResponseBackendComplete(response.get(), {});
+ request_handler->OnResponseBackendComplete(response.get());
it->second.responses.emplace_back(std::move(response));
return true;
diff --git a/quic/tools/quic_backend_response.h b/quic/tools/quic_backend_response.h
index 1c5cad8..64d7ade 100644
--- a/quic/tools/quic_backend_response.h
+++ b/quic/tools/quic_backend_response.h
@@ -17,6 +17,7 @@
public:
// A ServerPushInfo contains path of the push request and everything needed in
// comprising a response for the push request.
+ // TODO(b/171463363): Remove.
struct ServerPushInfo {
ServerPushInfo(QuicUrl request_url,
spdy::Http2HeaderBlock headers,
diff --git a/quic/tools/quic_memory_cache_backend.cc b/quic/tools/quic_memory_cache_backend.cc
index 967e60f..a5db77f 100644
--- a/quic/tools/quic_memory_cache_backend.cc
+++ b/quic/tools/quic_memory_cache_backend.cc
@@ -341,11 +341,10 @@
if (path != request_headers.end()) {
request_url += std::string(path->second);
}
- std::list<ServerPushInfo> resources = GetServerPushResources(request_url);
QUIC_DVLOG(1)
<< "Fetching QUIC response from backend in-memory cache for url "
<< request_url;
- quic_stream->OnResponseBackendComplete(quic_response, resources);
+ quic_stream->OnResponseBackendComplete(quic_response);
}
// The memory cache does not have a per-stream handler
diff --git a/quic/tools/quic_memory_cache_backend.h b/quic/tools/quic_memory_cache_backend.h
index 1caea5d..b8d2810 100644
--- a/quic/tools/quic_memory_cache_backend.h
+++ b/quic/tools/quic_memory_cache_backend.h
@@ -90,6 +90,7 @@
// some server push resources(resource path, corresponding response status and
// path) associated with it.
// Push resource implicitly come from the same host.
+ // TODO(b/171463363): Remove.
void AddSimpleResponseWithServerPushResources(
absl::string_view host,
absl::string_view path,
@@ -142,6 +143,7 @@
void EnableWebTransport();
// Find all the server push resources associated with |request_url|.
+ // TODO(b/171463363): Remove.
std::list<QuicBackendResponse::ServerPushInfo> GetServerPushResources(
std::string request_url);
@@ -173,6 +175,7 @@
// Add some server push urls with given responses for specified
// request if these push resources are not associated with this request yet.
+ // TODO(b/171463363): Remove.
void MaybeAddServerPushResources(
absl::string_view request_host,
absl::string_view request_path,
@@ -180,6 +183,7 @@
// Check if push resource(push_host/push_path) associated with given request
// url already exists in server push map.
+ // TODO(b/171463363): Remove.
bool PushResourceExistsInCache(std::string original_request_url,
QuicBackendResponse::ServerPushInfo resource);
@@ -196,6 +200,7 @@
QUIC_GUARDED_BY(response_mutex_);
// A map from request URL to associated server push responses (if any).
+ // TODO(b/171463363): Remove.
std::multimap<std::string, QuicBackendResponse::ServerPushInfo>
server_push_resources_ QUIC_GUARDED_BY(response_mutex_);
diff --git a/quic/tools/quic_simple_server_backend.h b/quic/tools/quic_simple_server_backend.h
index 43ced4b..6411567 100644
--- a/quic/tools/quic_simple_server_backend.h
+++ b/quic/tools/quic_simple_server_backend.h
@@ -32,8 +32,7 @@
// Called when the response is ready at the backend and can be send back to
// the QUIC client.
virtual void OnResponseBackendComplete(
- const QuicBackendResponse* response,
- std::list<QuicBackendResponse::ServerPushInfo> resources) = 0;
+ const QuicBackendResponse* response) = 0;
};
struct WebTransportResponse {
diff --git a/quic/tools/quic_simple_server_session.cc b/quic/tools/quic_simple_server_session.cc
index 4075d3f..688ca9f 100644
--- a/quic/tools/quic_simple_server_session.cc
+++ b/quic/tools/quic_simple_server_session.cc
@@ -62,39 +62,6 @@
QuicSpdySession::OnStreamFrame(frame);
}
-void QuicSimpleServerSession::PromisePushResources(
- const std::string& request_url,
- const std::list<QuicBackendResponse::ServerPushInfo>& resources,
- QuicStreamId original_stream_id,
- const spdy::SpdyStreamPrecedence& /* original_precedence */,
- const spdy::Http2HeaderBlock& original_request_headers) {
- if (!server_push_enabled()) {
- return;
- }
-
- for (const QuicBackendResponse::ServerPushInfo& resource : resources) {
- spdy::Http2HeaderBlock headers = SynthesizePushRequestHeaders(
- request_url, resource, original_request_headers);
- // TODO(b/136295430): Use sequential push IDs for IETF QUIC.
- auto new_highest_promised_stream_id =
- highest_promised_stream_id_ +
- QuicUtils::StreamIdDelta(transport_version());
- if (VersionUsesHttp3(transport_version()) &&
- !CanCreatePushStreamWithId(new_highest_promised_stream_id)) {
- return;
- }
- highest_promised_stream_id_ = new_highest_promised_stream_id;
- SendPushPromise(original_stream_id, highest_promised_stream_id_,
- headers.Clone());
- promised_streams_.push_back(
- PromisedStreamInfo(std::move(headers), highest_promised_stream_id_,
- spdy::SpdyStreamPrecedence(resource.priority)));
- }
-
- // Procese promised push request as many as possible.
- HandlePromisedPushRequests();
-}
-
QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(QuicStreamId id) {
if (!ShouldCreateIncomingStream(id)) {
return nullptr;
diff --git a/quic/tools/quic_simple_server_session.h b/quic/tools/quic_simple_server_session.h
index b91966d..636b8e1 100644
--- a/quic/tools/quic_simple_server_session.h
+++ b/quic/tools/quic_simple_server_session.h
@@ -68,17 +68,6 @@
// Override base class to detact client sending data on server push stream.
void OnStreamFrame(const QuicStreamFrame& frame) override;
- // Send out PUSH_PROMISE for all |resources| promised stream id in each frame
- // will increase by 2 for each item in |resources|.
- // And enqueue HEADERS block in those PUSH_PROMISED for sending push response
- // later.
- virtual void PromisePushResources(
- const std::string& request_url,
- const std::list<QuicBackendResponse::ServerPushInfo>& resources,
- QuicStreamId original_stream_id,
- const spdy::SpdyStreamPrecedence& original_precedence,
- const spdy::Http2HeaderBlock& original_request_headers);
-
void OnCanCreateNewOutgoingStream(bool unidirectional) override;
protected:
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc
index 64c486f..d23ba5d 100644
--- a/quic/tools/quic_simple_server_session_test.cc
+++ b/quic/tools/quic_simple_server_session_test.cc
@@ -50,11 +50,6 @@
namespace test {
namespace {
-using PromisedStreamInfo = QuicSimpleServerSession::PromisedStreamInfo;
-
-const QuicByteCount kHeadersFrameHeaderLength = 2;
-const QuicByteCount kHeadersFramePayloadLength = 9;
-
// Data to be sent on a request stream. In Google QUIC, this is interpreted as
// DATA payload (there is no framing on request streams). In IETF QUIC, this is
// interpreted as HEADERS frame (type 0x1) with payload length 122 ('z'). Since
@@ -596,451 +591,6 @@
QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
}
-// In order to test the case where server push stream creation goes beyond
-// limit, server push streams need to be hanging there instead of
-// immediately closing after sending back response.
-// To achieve this goal, this class resets flow control windows so that large
-// responses will not be sent fully in order to prevent push streams from being
-// closed immediately.
-// Also adjust connection-level flow control window to ensure a large response
-// can cause stream-level flow control blocked but not connection-level.
-class QuicSimpleServerSessionServerPushTest
- : public QuicSimpleServerSessionTest {
- protected:
- const size_t kStreamFlowControlWindowSize = 32 * 1024; // 32KB.
-
- QuicSimpleServerSessionServerPushTest() {
- // Reset stream level flow control window to be 32KB.
- if (version().handshake_protocol == PROTOCOL_TLS1_3) {
- if (VersionHasIetfQuicFrames(transport_version())) {
- QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional(
- &config_, kStreamFlowControlWindowSize);
- } else {
- // In this version, push streams are server-initiated bidirectional
- // streams, which are outgoing since we are the server here.
- QuicConfigPeer::
- SetReceivedInitialMaxStreamDataBytesOutgoingBidirectional(
- &config_, kStreamFlowControlWindowSize);
- }
- } else {
- QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
- &config_, kStreamFlowControlWindowSize);
- }
- // Reset connection level flow control window to be 1.5 MB which is large
- // enough that it won't block any stream to write before stream level flow
- // control blocks it.
- QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
- &config_, kInitialSessionFlowControlWindowForTest);
-
- ParsedQuicVersionVector supported_versions = SupportedVersions(version());
- connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
- &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions);
- connection_->SetEncrypter(
- ENCRYPTION_FORWARD_SECURE,
- std::make_unique<NullEncrypter>(connection_->perspective()));
- session_ = std::make_unique<MockQuicSimpleServerSession>(
- config_, connection_, &owner_, &stream_helper_, &crypto_config_,
- &compressed_certs_cache_, &memory_cache_backend_);
- session_->Initialize();
- // Needed to make new session flow control window and server push work.
-
- if (VersionHasIetfQuicFrames(transport_version())) {
- EXPECT_CALL(*session_, WriteControlFrame(_, _))
- .WillRepeatedly(Invoke(&ClearControlFrameWithTransmissionType));
- }
- session_->OnConfigNegotiated();
-
- if (!VersionUsesHttp3(transport_version())) {
- session_->UnregisterStreamPriority(
- QuicUtils::GetHeadersStreamId(transport_version()),
- /*is_static=*/true);
- }
- QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), nullptr);
- // Assume encryption already established.
- QuicCryptoServerStreamBase* crypto_stream =
- CreateMockCryptoServerStream(&crypto_config_, &compressed_certs_cache_,
- session_.get(), &stream_helper_);
-
- QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
- if (!VersionUsesHttp3(transport_version())) {
- session_->RegisterStreamPriority(
- QuicUtils::GetHeadersStreamId(transport_version()),
- /*is_static=*/true,
- spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority));
- }
- if (VersionUsesHttp3(transport_version())) {
- // Ignore writes on the control stream.
- auto send_control_stream =
- QuicSpdySessionPeer::GetSendControlStream(session_.get());
- EXPECT_CALL(*connection_,
- SendStreamData(send_control_stream->id(), _, _, NO_FIN))
- .Times(AnyNumber());
- }
- }
-
- // Given |num_resources|, create this number of fake push resources and push
- // them by sending PUSH_PROMISE for all and sending push responses for as much
- // as possible(limited by kMaxStreamsForTest).
- // If |num_resources| > kMaxStreamsForTest, the left over will be queued.
- // Returns the length of the DATA frame header, or 0 if the version does not
- // use DATA frames.
- QuicByteCount PromisePushResources(size_t num_resources) {
- // testing::InSequence seq;
- // To prevent push streams from being closed the response need to be larger
- // than stream flow control window so stream won't send the full body.
- size_t body_size = 2 * kStreamFlowControlWindowSize; // 64KB.
-
- std::string request_url = "mail.google.com/";
- spdy::Http2HeaderBlock request_headers;
- std::string resource_host = "www.google.com";
- std::string partial_push_resource_path = "/server_push_src";
- std::list<QuicBackendResponse::ServerPushInfo> push_resources;
- std::string scheme = "http";
- QuicByteCount data_frame_header_length = 0;
- for (unsigned int i = 1; i <= num_resources; ++i) {
- QuicStreamId stream_id;
- if (VersionUsesHttp3(transport_version())) {
- stream_id = GetNthServerInitiatedUnidirectionalId(i + 2);
- } else {
- stream_id = GetNthServerInitiatedUnidirectionalId(i - 1);
- }
- std::string path = absl::StrCat(partial_push_resource_path, i);
- std::string url = scheme + "://" + resource_host + path;
- QuicUrl resource_url = QuicUrl(url);
- std::string body(body_size, 'a');
- std::string data;
- data_frame_header_length = 0;
- if (VersionUsesHttp3(transport_version())) {
- std::unique_ptr<char[]> buffer;
- data_frame_header_length =
- HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer);
- std::string header(buffer.get(), data_frame_header_length);
- data = header + body;
- } else {
- data = body;
- }
-
- memory_cache_backend_.AddSimpleResponse(resource_host, path, 200, data);
- push_resources.push_back(QuicBackendResponse::ServerPushInfo(
- resource_url, spdy::Http2HeaderBlock(), QuicStream::kDefaultPriority,
- body));
- // PUSH_PROMISED are sent for all the resources.
- EXPECT_CALL(*session_,
- WritePushPromiseMock(GetNthClientInitiatedBidirectionalId(0),
- stream_id, _));
- if (i <= kMaxStreamsForTest) {
- // |kMaxStreamsForTest| promised responses should be sent.
- // Since flow control window is smaller than response body, not the
- // whole body will be sent.
- QuicStreamOffset offset = 0;
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(stream_id, 1, offset, NO_FIN));
- offset++;
- }
-
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(stream_id, kHeadersFrameHeaderLength,
- offset, NO_FIN));
- offset += kHeadersFrameHeaderLength;
- EXPECT_CALL(*connection_,
- SendStreamData(stream_id, kHeadersFramePayloadLength,
- offset, NO_FIN));
- offset += kHeadersFramePayloadLength;
- }
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(stream_id, data_frame_header_length,
- offset, NO_FIN));
- offset += data_frame_header_length;
- }
- EXPECT_CALL(*connection_, SendStreamData(stream_id, _, offset, NO_FIN))
- .WillOnce(Return(QuicConsumedData(
- kStreamFlowControlWindowSize - offset, false)));
- EXPECT_CALL(*session_, SendBlocked(stream_id));
- }
- }
- session_->PromisePushResources(
- request_url, push_resources, GetNthClientInitiatedBidirectionalId(0),
- spdy::SpdyStreamPrecedence(0, spdy::kHttp2DefaultStreamWeight, false),
- request_headers);
- return data_frame_header_length;
- }
-
- void MaybeConsumeHeadersStreamData() {
- if (!VersionUsesHttp3(transport_version())) {
- QuicStreamId headers_stream_id =
- QuicUtils::GetHeadersStreamId(transport_version());
- EXPECT_CALL(*connection_, SendStreamData(headers_stream_id, _, _, _))
- .Times(AtLeast(1));
- }
- }
-};
-
-ParsedQuicVersionVector SupportedVersionsWithPush() {
- ParsedQuicVersionVector versions;
- for (const ParsedQuicVersion& version : AllSupportedVersions()) {
- if (!version.UsesHttp3()) {
- // Push over HTTP/3 is not supported.
- versions.push_back(version);
- }
- }
- return versions;
-}
-
-INSTANTIATE_TEST_SUITE_P(Tests,
- QuicSimpleServerSessionServerPushTest,
- ::testing::ValuesIn(SupportedVersionsWithPush()));
-
-// Tests that given more than kMaxStreamsForTest resources, all their
-// PUSH_PROMISE's will be sent out and only kMaxStreamsForTest streams will be
-// opened and send push response.
-TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
- MaybeConsumeHeadersStreamData();
- size_t num_resources = kMaxStreamsForTest + 5;
- PromisePushResources(num_resources);
- EXPECT_EQ(kMaxStreamsForTest,
- QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
-}
-
-// Tests that after promised stream queued up, when an opened stream is marked
-// draining, a queued promised stream will become open and send push response.
-TEST_P(QuicSimpleServerSessionServerPushTest,
- HandlePromisedPushRequestsAfterStreamDraining) {
- MaybeConsumeHeadersStreamData();
- size_t num_resources = kMaxStreamsForTest + 1;
- QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
- QuicStreamId next_out_going_stream_id;
- if (VersionUsesHttp3(transport_version())) {
- next_out_going_stream_id =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3);
- } else {
- next_out_going_stream_id =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
- }
-
- // After an open stream is marked draining, a new stream is expected to be
- // created and a response sent on the stream.
- QuicStreamOffset offset = 0;
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(next_out_going_stream_id, 1, offset, NO_FIN));
- offset++;
- }
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(next_out_going_stream_id,
- kHeadersFrameHeaderLength, offset, NO_FIN));
- offset += kHeadersFrameHeaderLength;
- EXPECT_CALL(*connection_,
- SendStreamData(next_out_going_stream_id,
- kHeadersFramePayloadLength, offset, NO_FIN));
- offset += kHeadersFramePayloadLength;
- }
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(next_out_going_stream_id,
- data_frame_header_length, offset, NO_FIN));
- offset += data_frame_header_length;
- }
- EXPECT_CALL(*connection_,
- SendStreamData(next_out_going_stream_id, _, offset, NO_FIN))
- .WillOnce(Return(
- QuicConsumedData(kStreamFlowControlWindowSize - offset, false)));
- EXPECT_CALL(*session_, SendBlocked(next_out_going_stream_id));
-
- if (VersionHasIetfQuicFrames(transport_version())) {
- // The PromisePushedResources call, above, will have used all available
- // stream ids. For version 99, stream ids are not made available until
- // a MAX_STREAMS frame is received. This emulates the reception of one.
- // For pre-v-99, the node monitors its own stream usage and makes streams
- // available as it closes/etc them.
- // Version 99 also has unidirectional static streams, so we need to send
- // MaxStreamFrame of the number of resources + number of static streams.
- session_->OnMaxStreamsFrame(
- QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true));
- }
-
- if (VersionUsesHttp3(transport_version())) {
- session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3),
- /*unidirectional=*/true);
- } else {
- session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(0),
- /*unidirectional=*/true);
- }
- // Number of open outgoing streams should still be the same, because a new
- // stream is opened. And the queue should be empty.
- EXPECT_EQ(kMaxStreamsForTest,
- QuicSessionPeer::GetNumOpenDynamicStreams(session_.get()));
-}
-
-// Tests that after all resources are promised, a RST frame from client can
-// prevent a promised resource to be send out.
-TEST_P(QuicSimpleServerSessionServerPushTest,
- ResetPromisedStreamToCancelServerPush) {
- if (VersionHasIetfQuicFrames(transport_version())) {
- // This test is resetting a stream that is not opened yet. IETF QUIC has no
- // way to handle this. Some similar tests can be added once CANCEL_PUSH is
- // supported.
- return;
- }
- MaybeConsumeHeadersStreamData();
-
- // Having two extra resources to be send later. One of them will be reset, so
- // when opened stream become close, only one will become open.
- size_t num_resources = kMaxStreamsForTest + 2;
- if (VersionHasIetfQuicFrames(transport_version())) {
- // V99 will send out a STREAMS_BLOCKED frame when it tries to exceed the
- // limit. This will clear the frames so that they do not block the later
- // rst-stream frame.
- EXPECT_CALL(*session_, WriteControlFrame(_, _))
- .WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
- }
- QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
-
- // Reset the last stream in the queue. It should be marked cancelled.
- QuicStreamId stream_got_reset;
- if (VersionUsesHttp3(transport_version())) {
- stream_got_reset =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 4);
- } else {
- stream_got_reset =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 1);
- }
- QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset,
- QUIC_STREAM_CANCELLED, 0);
- EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
- EXPECT_CALL(*session_, WriteControlFrame(_, _))
- .WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
- EXPECT_CALL(*connection_,
- OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
- session_->OnRstStream(rst);
-
- // When the first 2 streams becomes draining, the two queued up stream could
- // be created. But since one of them was marked cancelled due to RST frame,
- // only one queued resource will be sent out.
- QuicStreamId stream_not_reset;
- if (VersionUsesHttp3(transport_version())) {
- stream_not_reset =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3);
- } else {
- stream_not_reset =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
- }
- InSequence s;
- QuicStreamOffset offset = 0;
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(stream_not_reset, 1, offset, NO_FIN));
- offset++;
- EXPECT_CALL(*connection_,
- SendStreamData(stream_not_reset, kHeadersFrameHeaderLength,
- offset, NO_FIN));
- offset += kHeadersFrameHeaderLength;
- EXPECT_CALL(*connection_,
- SendStreamData(stream_not_reset, kHeadersFramePayloadLength,
- offset, NO_FIN));
- offset += kHeadersFramePayloadLength;
- EXPECT_CALL(*connection_,
- SendStreamData(stream_not_reset, data_frame_header_length,
- offset, NO_FIN));
- offset += data_frame_header_length;
- }
- EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, _, offset, NO_FIN))
- .WillOnce(Return(
- QuicConsumedData(kStreamFlowControlWindowSize - offset, false)));
- EXPECT_CALL(*session_, SendBlocked(stream_not_reset));
-
- if (VersionHasIetfQuicFrames(transport_version())) {
- // The PromisePushedResources call, above, will have used all available
- // stream ids. For version 99, stream ids are not made available until
- // a MAX_STREAMS frame is received. This emulates the reception of one.
- // For pre-v-99, the node monitors its own stream usage and makes streams
- // available as it closes/etc them.
- session_->OnMaxStreamsFrame(
- QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true));
- }
- session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(3),
- /*unidirectional=*/true);
- session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(4),
- /*unidirectional=*/true);
-}
-
-// Tests that closing a open outgoing stream can trigger a promised resource in
-// the queue to be send out.
-TEST_P(QuicSimpleServerSessionServerPushTest,
- CloseStreamToHandleMorePromisedStream) {
- MaybeConsumeHeadersStreamData();
- size_t num_resources = kMaxStreamsForTest + 1;
- if (VersionHasIetfQuicFrames(transport_version())) {
- // V99 will send out a stream-id-blocked frame when the we desired to exceed
- // the limit. This will clear the frames so that they do not block the later
- // rst-stream frame.
- EXPECT_CALL(*session_, WriteControlFrame(_, _))
- .WillOnce(Invoke(&ClearControlFrameWithTransmissionType));
- }
- QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
- QuicStreamId stream_to_open;
- if (VersionUsesHttp3(transport_version())) {
- stream_to_open =
- GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest + 3);
- } else {
- stream_to_open = GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest);
- }
-
- // Resetting an open stream will close the stream and give space for extra
- // stream to be opened.
- QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(3);
- EXPECT_CALL(*session_, WriteControlFrame(_, _));
- if (!VersionHasIetfQuicFrames(transport_version())) {
- EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
- // For version 99, this is covered in InjectStopSending()
- EXPECT_CALL(*connection_,
- OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
- }
- QuicStreamOffset offset = 0;
- if (VersionUsesHttp3(transport_version())) {
- EXPECT_CALL(*connection_,
- SendStreamData(stream_to_open, 1, offset, NO_FIN));
- offset++;
- EXPECT_CALL(*connection_,
- SendStreamData(stream_to_open, kHeadersFrameHeaderLength,
- offset, NO_FIN));
- offset += kHeadersFrameHeaderLength;
- EXPECT_CALL(*connection_,
- SendStreamData(stream_to_open, kHeadersFramePayloadLength,
- offset, NO_FIN));
- offset += kHeadersFramePayloadLength;
- EXPECT_CALL(*connection_,
- SendStreamData(stream_to_open, data_frame_header_length, offset,
- NO_FIN));
- offset += data_frame_header_length;
- }
- EXPECT_CALL(*connection_, SendStreamData(stream_to_open, _, offset, NO_FIN))
- .WillOnce(Return(
- QuicConsumedData(kStreamFlowControlWindowSize - offset, false)));
-
- EXPECT_CALL(*session_, SendBlocked(stream_to_open));
- QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset,
- QUIC_STREAM_CANCELLED, 0);
- if (VersionHasIetfQuicFrames(transport_version())) {
- // The PromisePushedResources call, above, will have used all available
- // stream ids. For version 99, stream ids are not made available until
- // a MAX_STREAMS frame is received. This emulates the reception of one.
- // For pre-v-99, the node monitors its own stream usage and makes streams
- // available as it closes/etc them.
- session_->OnMaxStreamsFrame(
- QuicMaxStreamsFrame(0, num_resources + 3, /*unidirectional=*/true));
- } else {
- session_->OnRstStream(rst);
- }
- // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
- // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
- // a one-way close.
- InjectStopSending(stream_got_reset, QUIC_STREAM_CANCELLED);
-}
-
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/tools/quic_simple_server_stream.cc b/quic/tools/quic_simple_server_stream.cc
index f4afeb2..ac95e46 100644
--- a/quic/tools/quic_simple_server_stream.cc
+++ b/quic/tools/quic_simple_server_stream.cc
@@ -214,8 +214,7 @@
}
void QuicSimpleServerStream::OnResponseBackendComplete(
- const QuicBackendResponse* response,
- std::list<QuicBackendResponse::ServerPushInfo> resources) {
+ const QuicBackendResponse* response) {
if (response == nullptr) {
QUIC_DVLOG(1) << "Response not found in cache.";
SendNotFoundResponse();
@@ -285,15 +284,6 @@
}
}
- if (!resources.empty()) {
- QUIC_DVLOG(1) << "Stream " << id() << " found " << resources.size()
- << " push resources.";
- QuicSimpleServerSession* session =
- static_cast<QuicSimpleServerSession*>(spdy_session());
- session->PromisePushResources(request_url, resources, id(), precedence(),
- request_headers_);
- }
-
if (response->response_type() == QuicBackendResponse::INCOMPLETE_RESPONSE) {
QUIC_DVLOG(1)
<< "Stream " << id()
diff --git a/quic/tools/quic_simple_server_stream.h b/quic/tools/quic_simple_server_stream.h
index 2dd59f9..6395345 100644
--- a/quic/tools/quic_simple_server_stream.h
+++ b/quic/tools/quic_simple_server_stream.h
@@ -57,9 +57,7 @@
QuicConnectionId connection_id() const override;
QuicStreamId stream_id() const override;
std::string peer_host() const override;
- void OnResponseBackendComplete(
- const QuicBackendResponse* response,
- std::list<QuicBackendResponse::ServerPushInfo> resources) override;
+ void OnResponseBackendComplete(const QuicBackendResponse* response) override;
protected:
// Sends a basic 200 response using SendHeaders for the headers and WriteData
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc
index bf80d47..2542311 100644
--- a/quic/tools/quic_simple_server_stream_test.cc
+++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -187,25 +187,6 @@
MaybeSendStopSendingFrame,
(QuicStreamId stream_id, QuicRstStreamErrorCode error),
(override));
- // Matchers cannot be used on non-copyable types like Http2HeaderBlock.
- void PromisePushResources(
- const std::string& request_url,
- const std::list<QuicBackendResponse::ServerPushInfo>& resources,
- QuicStreamId original_stream_id,
- const spdy::SpdyStreamPrecedence& original_precedence,
- const spdy::Http2HeaderBlock& original_request_headers) override {
- original_request_headers_ = original_request_headers.Clone();
- PromisePushResourcesMock(request_url, resources, original_stream_id,
- original_precedence, original_request_headers);
- }
- MOCK_METHOD(void,
- PromisePushResourcesMock,
- (const std::string&,
- const std::list<QuicBackendResponse::ServerPushInfo>&,
- QuicStreamId,
- const spdy::SpdyStreamPrecedence&,
- const spdy::Http2HeaderBlock&),
- ());
using QuicSession::ActivateStream;
@@ -546,46 +527,6 @@
EXPECT_TRUE(stream_->write_side_closed());
}
-TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) {
- // Tests that if a response has push resources to be send, SendResponse() will
- // call PromisePushResources() to handle these resources.
-
- // Add a request and response with valid headers into cache.
- std::string host = "www.google.com";
- std::string request_path = "/foo";
- std::string body = "Yummm";
- std::unique_ptr<char[]> buffer;
- QuicByteCount header_length =
- HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer);
- QuicBackendResponse::ServerPushInfo push_info(
- QuicUrl(host, "/bar"), spdy::Http2HeaderBlock(),
- QuicStream::kDefaultPriority, "Push body");
- std::list<QuicBackendResponse::ServerPushInfo> push_resources;
- push_resources.push_back(push_info);
- memory_cache_backend_.AddSimpleResponseWithServerPushResources(
- host, request_path, 200, body, push_resources);
-
- spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers();
- (*request_headers)[":path"] = request_path;
- (*request_headers)[":authority"] = host;
- (*request_headers)[":method"] = "GET";
-
- QuicStreamPeer::SetFinReceived(stream_);
- InSequence s;
- EXPECT_CALL(session_, PromisePushResourcesMock(
- host + request_path, _,
- GetNthClientInitiatedBidirectionalStreamId(
- connection_->transport_version(), 0),
- _, _));
- EXPECT_CALL(*stream_, WriteHeadersMock(false));
- if (UsesHttp3()) {
- EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _, _));
- }
- EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _));
- stream_->DoSendResponse();
- EXPECT_EQ(*request_headers, session_.original_request_headers_);
-}
-
TEST_P(QuicSimpleServerStreamTest, SendResponseWithEarlyHints) {
std::string host = "www.google.com";
std::string request_path = "/foo";