123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "weblayer/public/js_communication/web_message.h"
- #include "base/callback.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/test/scoped_feature_list.h"
- #include "content/public/common/content_features.h"
- #include "net/dns/mock_host_resolver.h"
- #include "weblayer/public/js_communication/web_message.h"
- #include "weblayer/public/js_communication/web_message_host.h"
- #include "weblayer/public/js_communication/web_message_host_factory.h"
- #include "weblayer/public/js_communication/web_message_reply_proxy.h"
- #include "weblayer/public/navigation.h"
- #include "weblayer/public/navigation_controller.h"
- #include "weblayer/public/tab.h"
- #include "weblayer/shell/browser/shell.h"
- #include "weblayer/test/weblayer_browser_test.h"
- #include "weblayer/test/weblayer_browser_test_utils.h"
- namespace weblayer {
- namespace {
- class WebMessageHostImpl;
- WebMessageHostImpl* current_connection = nullptr;
- // WebMessageHost implementation that records contents of OnPostMessage().
- class WebMessageHostImpl : public WebMessageHost {
- public:
- WebMessageHostImpl(base::RepeatingClosure quit_closure,
- const std::string& origin_string,
- bool is_main_frame,
- WebMessageReplyProxy* proxy)
- : quit_closure_(quit_closure), proxy_(proxy) {
- current_connection = this;
- }
- ~WebMessageHostImpl() override {
- if (current_connection == this)
- current_connection = nullptr;
- }
- int back_forward_cache_state_changed_call_count() const {
- return back_forward_cache_state_changed_call_count_;
- }
- void WaitForBackForwardStateToBe(bool value) {
- if (value == proxy_->IsInBackForwardCache())
- return;
- expected_back_forward_value_ = value;
- state_changed_run_loop_ = std::make_unique<base::RunLoop>();
- state_changed_run_loop_->Run();
- state_changed_run_loop_.reset();
- }
- WebMessageReplyProxy* proxy() { return proxy_; }
- std::vector<std::u16string>& messages() { return messages_; }
- // WebMessageHost:
- void OnPostMessage(std::unique_ptr<WebMessage> message) override {
- messages_.push_back(std::move(message->message));
- if (++call_count_ == 1) {
- // First time called, send a message to the page.
- std::unique_ptr<WebMessage> m2 = std::make_unique<WebMessage>();
- m2->message = u"from c++";
- proxy_->PostWebMessage(std::move(m2));
- } else {
- // On subsequent calls quit.
- quit_closure_.Run();
- }
- }
- void OnBackForwardCacheStateChanged() override {
- ++back_forward_cache_state_changed_call_count_;
- if (state_changed_run_loop_ &&
- expected_back_forward_value_ == proxy_->IsInBackForwardCache()) {
- state_changed_run_loop_->Quit();
- }
- }
- private:
- int call_count_ = 0;
- int back_forward_cache_state_changed_call_count_ = 0;
- base::RepeatingClosure quit_closure_;
- raw_ptr<WebMessageReplyProxy> proxy_;
- std::vector<std::u16string> messages_;
- bool expected_back_forward_value_ = false;
- std::unique_ptr<base::RunLoop> state_changed_run_loop_;
- };
- // WebMessageHostFactory implementation that creates WebMessageHostImpl.
- class WebMessageHostFactoryImpl : public WebMessageHostFactory {
- public:
- explicit WebMessageHostFactoryImpl(base::RepeatingClosure quit_closure)
- : quit_closure_(quit_closure) {}
- ~WebMessageHostFactoryImpl() override = default;
- // WebMessageHostFactory:
- std::unique_ptr<WebMessageHost> CreateHost(
- const std::string& origin_string,
- bool is_main_frame,
- WebMessageReplyProxy* proxy) override {
- return std::make_unique<WebMessageHostImpl>(quit_closure_, origin_string,
- is_main_frame, proxy);
- }
- private:
- base::RepeatingClosure quit_closure_;
- };
- } // namespace
- using WebMessageTest = WebLayerBrowserTest;
- IN_PROC_BROWSER_TEST_F(WebMessageTest, SendAndReceive) {
- EXPECT_TRUE(embedded_test_server()->Start());
- base::RunLoop run_loop;
- shell()->tab()->AddWebMessageHostFactory(
- std::make_unique<WebMessageHostFactoryImpl>(run_loop.QuitClosure()), u"x",
- {"*"});
- // web_message_test.html posts a message immediately.
- shell()->tab()->GetNavigationController()->Navigate(
- embedded_test_server()->GetURL("/web_message_test.html"));
- run_loop.Run();
- // There should be two messages. The one from the page, and the ack triggered
- // when WebMessageHostImpl calls PostMessage().
- ASSERT_TRUE(current_connection);
- ASSERT_EQ(2u, current_connection->messages().size());
- EXPECT_EQ(u"from page", current_connection->messages()[0]);
- EXPECT_EQ(u"bouncing from c++", current_connection->messages()[1]);
- // WebLayer's Page has no functions, verify it can be requested.
- current_connection->proxy()->GetPage();
- }
- // Ensures that a listener removed from a post message works.
- IN_PROC_BROWSER_TEST_F(WebMessageTest, RemoveFromReceive) {
- EXPECT_TRUE(embedded_test_server()->Start());
- base::RunLoop run_loop;
- shell()->tab()->AddWebMessageHostFactory(
- std::make_unique<WebMessageHostFactoryImpl>(run_loop.QuitClosure()), u"x",
- {"*"});
- // web_message_test.html posts a message immediately.
- shell()->tab()->GetNavigationController()->Navigate(
- embedded_test_server()->GetURL("/web_message_test2.html"));
- run_loop.Run();
- // There should be two messages. The one from the page, and the ack triggered
- // when WebMessageHostImpl calls PostMessage().
- ASSERT_TRUE(current_connection);
- ASSERT_EQ(2u, current_connection->messages().size());
- EXPECT_EQ(u"from page", current_connection->messages()[0]);
- EXPECT_EQ(u"bouncing from c++", current_connection->messages()[1]);
- // WebLayer's Page has no functions, verify it can be requested.
- current_connection->proxy()->GetPage();
- }
- class WebMessageTestWithBfCache : public WebLayerBrowserTest {
- public:
- // WebLayerBrowserTest:
- void SetUp() override {
- scoped_feature_list_.InitWithFeaturesAndParameters(
- {{features::kBackForwardCache,
- {// Set a very long TTL before expiration (longer than the test
- // timeout) so tests that are expecting deletion don't pass when
- // they shouldn't.
- {"TimeToLiveInBackForwardCacheInSeconds", "3600"}}}},
- // Allow BackForwardCache for all devices regardless of their memory.
- {features::kBackForwardCacheMemoryControls});
- WebLayerBrowserTest::SetUp();
- }
- void SetUpOnMainThread() override {
- WebLayerBrowserTest::SetUpOnMainThread();
- host_resolver()->AddRule("*", "127.0.0.1");
- }
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
- };
- IN_PROC_BROWSER_TEST_F(WebMessageTestWithBfCache, Basic) {
- ASSERT_TRUE(embedded_test_server()->Start());
- GURL url1(embedded_test_server()->GetURL("a.com", "/web_message_test.html"));
- base::RunLoop run_loop;
- shell()->tab()->AddWebMessageHostFactory(
- std::make_unique<WebMessageHostFactoryImpl>(run_loop.QuitClosure()), u"x",
- {"http://a.com:" + url1.port()});
- auto* navigation_controller = shell()->tab()->GetNavigationController();
- navigation_controller->Navigate(url1);
- run_loop.Run();
- // A WebMessageHostImpl should be created, and it should not be in the cache.
- WebMessageHostImpl* web_message_host = current_connection;
- ASSERT_TRUE(web_message_host);
- EXPECT_FALSE(web_message_host->proxy()->IsInBackForwardCache());
- EXPECT_EQ(0, web_message_host->back_forward_cache_state_changed_call_count());
- Page* original_page = &(web_message_host->proxy()->GetPage());
- // Navigate to a new host. The old page should go into the cache.
- OneShotNavigationObserver observer1(shell());
- navigation_controller->Navigate(
- embedded_test_server()->GetURL("b.com", "/simple_page.html"));
- observer1.WaitForNavigation();
- EXPECT_TRUE(observer1.completed());
- ASSERT_EQ(current_connection, web_message_host);
- web_message_host->WaitForBackForwardStateToBe(true);
- EXPECT_EQ(1, web_message_host->back_forward_cache_state_changed_call_count());
- // Navigate back.
- OneShotNavigationObserver observer2(shell());
- navigation_controller->GoBack();
- observer2.WaitForNavigation();
- web_message_host->WaitForBackForwardStateToBe(false);
- EXPECT_EQ(2, web_message_host->back_forward_cache_state_changed_call_count());
- EXPECT_EQ(original_page, &(web_message_host->proxy()->GetPage()));
- }
- } // namespace weblayer
|