javascript_browsertest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // Copyright 2021 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. #include "base/fuchsia/mem_buffer_util.h"
  5. #include "content/public/test/browser_test.h"
  6. #include "fuchsia_web/common/test/frame_test_util.h"
  7. #include "fuchsia_web/common/test/test_navigation_listener.h"
  8. #include "fuchsia_web/webengine/browser/frame_impl_browser_test_base.h"
  9. #include "fuchsia_web/webengine/test/frame_for_test.h"
  10. namespace {
  11. constexpr char kPage1Path[] = "/title1.html";
  12. constexpr char kPage1Title[] = "title 1";
  13. constexpr char kDynamicTitlePath[] = "/dynamic_title.html";
  14. constexpr int64_t kOnLoadScriptId = 0;
  15. using JavaScriptTest = FrameImplTestBase;
  16. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScript) {
  17. constexpr int64_t kBindingsId = 1234;
  18. net::test_server::EmbeddedTestServerHandle test_server_handle;
  19. ASSERT_TRUE(test_server_handle =
  20. embedded_test_server()->StartAndReturnHandle());
  21. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  22. auto frame = FrameForTest::Create(context(), {});
  23. frame->AddBeforeLoadJavaScript(
  24. kBindingsId, {embedded_test_server()->GetOrigin().Serialize()},
  25. base::MemBufferFromString("stashed_title = 'hello';", "test"),
  26. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  27. EXPECT_TRUE(result.is_response());
  28. });
  29. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  30. fuchsia::web::LoadUrlParams(),
  31. url.spec()));
  32. frame.navigation_listener().RunUntilUrlEquals(url);
  33. }
  34. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScriptUpdated) {
  35. constexpr int64_t kBindingsId = 1234;
  36. net::test_server::EmbeddedTestServerHandle test_server_handle;
  37. ASSERT_TRUE(test_server_handle =
  38. embedded_test_server()->StartAndReturnHandle());
  39. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  40. auto frame = FrameForTest::Create(context(), {});
  41. frame->AddBeforeLoadJavaScript(
  42. kBindingsId, {embedded_test_server()->GetOrigin().Serialize()},
  43. base::MemBufferFromString("stashed_title = 'hello';", "test"),
  44. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  45. EXPECT_TRUE(result.is_response());
  46. });
  47. // Verify that this script clobbers the previous script, as opposed to being
  48. // injected alongside it. (The latter would result in the title being
  49. // "helloclobber").
  50. frame->AddBeforeLoadJavaScript(
  51. kBindingsId, {embedded_test_server()->GetOrigin().Serialize()},
  52. base::MemBufferFromString("stashed_title = document.title + 'clobber';",
  53. "test"),
  54. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  55. EXPECT_TRUE(result.is_response());
  56. });
  57. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  58. fuchsia::web::LoadUrlParams(),
  59. url.spec()));
  60. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, "clobber");
  61. }
  62. // Verifies that bindings are injected in order by producing a cumulative,
  63. // non-commutative result.
  64. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScriptOrdered) {
  65. constexpr int64_t kBindingsId1 = 1234;
  66. constexpr int64_t kBindingsId2 = 5678;
  67. net::test_server::EmbeddedTestServerHandle test_server_handle;
  68. ASSERT_TRUE(test_server_handle =
  69. embedded_test_server()->StartAndReturnHandle());
  70. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  71. auto frame = FrameForTest::Create(context(), {});
  72. frame->AddBeforeLoadJavaScript(
  73. kBindingsId1, {embedded_test_server()->GetOrigin().Serialize()},
  74. base::MemBufferFromString("stashed_title = 'hello';", "test"),
  75. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  76. EXPECT_TRUE(result.is_response());
  77. });
  78. frame->AddBeforeLoadJavaScript(
  79. kBindingsId2, {embedded_test_server()->GetOrigin().Serialize()},
  80. base::MemBufferFromString("stashed_title += ' there';", "test"),
  81. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  82. EXPECT_TRUE(result.is_response());
  83. });
  84. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  85. fuchsia::web::LoadUrlParams(),
  86. url.spec()));
  87. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, "hello there");
  88. }
  89. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScriptRemoved) {
  90. constexpr int64_t kBindingsId1 = 1234;
  91. constexpr int64_t kBindingsId2 = 5678;
  92. net::test_server::EmbeddedTestServerHandle test_server_handle;
  93. ASSERT_TRUE(test_server_handle =
  94. embedded_test_server()->StartAndReturnHandle());
  95. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  96. auto frame = FrameForTest::Create(context(), {});
  97. frame->AddBeforeLoadJavaScript(
  98. kBindingsId1, {embedded_test_server()->GetOrigin().Serialize()},
  99. base::MemBufferFromString("stashed_title = 'foo';", "test"),
  100. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  101. EXPECT_TRUE(result.is_response());
  102. });
  103. // Add a script which clobbers "foo".
  104. frame->AddBeforeLoadJavaScript(
  105. kBindingsId2, {embedded_test_server()->GetOrigin().Serialize()},
  106. base::MemBufferFromString("stashed_title = 'bar';", "test"),
  107. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  108. EXPECT_TRUE(result.is_response());
  109. });
  110. // Deletes the clobbering script.
  111. frame->RemoveBeforeLoadJavaScript(kBindingsId2);
  112. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  113. fuchsia::web::LoadUrlParams(),
  114. url.spec()));
  115. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, "foo");
  116. }
  117. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScriptRemoveInvalidId) {
  118. net::test_server::EmbeddedTestServerHandle test_server_handle;
  119. ASSERT_TRUE(test_server_handle =
  120. embedded_test_server()->StartAndReturnHandle());
  121. GURL url(embedded_test_server()->GetURL(kPage1Path));
  122. auto frame = FrameForTest::Create(context(), {});
  123. frame->RemoveBeforeLoadJavaScript(kOnLoadScriptId);
  124. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  125. fuchsia::web::LoadUrlParams(),
  126. url.spec()));
  127. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, kPage1Title);
  128. }
  129. // Test JS injection using ExecuteJavaScriptNoResult() to set a value, and
  130. // ExecuteJavaScript() to retrieve that value.
  131. IN_PROC_BROWSER_TEST_F(JavaScriptTest, ExecuteJavaScript) {
  132. constexpr char kJsonStringLiteral[] = "\"I am a literal, literally\"";
  133. auto frame = FrameForTest::Create(context(), {});
  134. net::test_server::EmbeddedTestServerHandle test_server_handle;
  135. ASSERT_TRUE(test_server_handle =
  136. embedded_test_server()->StartAndReturnHandle());
  137. const GURL kUrl(embedded_test_server()->GetURL(kPage1Path));
  138. // Navigate to a page and wait for it to finish loading.
  139. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  140. fuchsia::web::LoadUrlParams(),
  141. kUrl.spec()));
  142. frame.navigation_listener().RunUntilUrlAndTitleEquals(kUrl, kPage1Title);
  143. // Execute with no result to set the variable.
  144. frame->ExecuteJavaScriptNoResult(
  145. {kUrl.DeprecatedGetOriginAsURL().spec()},
  146. base::MemBufferFromString(
  147. base::StringPrintf("my_variable = %s;", kJsonStringLiteral), "test"),
  148. [](fuchsia::web::Frame_ExecuteJavaScriptNoResult_Result result) {
  149. EXPECT_TRUE(result.is_response());
  150. });
  151. // Execute a script snippet to return the variable's value.
  152. base::RunLoop loop;
  153. frame->ExecuteJavaScript(
  154. {kUrl.DeprecatedGetOriginAsURL().spec()},
  155. base::MemBufferFromString("my_variable;", "test"),
  156. [&](fuchsia::web::Frame_ExecuteJavaScript_Result result) {
  157. ASSERT_TRUE(result.is_response());
  158. std::string result_json =
  159. *base::StringFromMemBuffer(result.response().result);
  160. EXPECT_EQ(result_json, kJsonStringLiteral);
  161. loop.Quit();
  162. });
  163. loop.Run();
  164. }
  165. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScriptVmoDestroyed) {
  166. net::test_server::EmbeddedTestServerHandle test_server_handle;
  167. ASSERT_TRUE(test_server_handle =
  168. embedded_test_server()->StartAndReturnHandle());
  169. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  170. auto frame = FrameForTest::Create(context(), {});
  171. frame->AddBeforeLoadJavaScript(
  172. kOnLoadScriptId, {embedded_test_server()->GetOrigin().Serialize()},
  173. base::MemBufferFromString("stashed_title = 'hello';", "test"),
  174. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  175. EXPECT_TRUE(result.is_response());
  176. });
  177. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  178. fuchsia::web::LoadUrlParams(),
  179. url.spec()));
  180. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, "hello");
  181. }
  182. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScriptWrongOrigin) {
  183. net::test_server::EmbeddedTestServerHandle test_server_handle;
  184. ASSERT_TRUE(test_server_handle =
  185. embedded_test_server()->StartAndReturnHandle());
  186. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  187. auto frame = FrameForTest::Create(context(), {});
  188. frame->AddBeforeLoadJavaScript(
  189. kOnLoadScriptId, {"http://example.com"},
  190. base::MemBufferFromString("stashed_title = 'hello';", "test"),
  191. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  192. EXPECT_TRUE(result.is_response());
  193. });
  194. // Expect that the original HTML title is used, because we didn't inject a
  195. // script with a replacement title.
  196. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  197. fuchsia::web::LoadUrlParams(),
  198. url.spec()));
  199. frame.navigation_listener().RunUntilUrlAndTitleEquals(
  200. url, "Welcome to Stan the Offline Dino's Homepage");
  201. }
  202. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BeforeLoadScriptWildcardOrigin) {
  203. net::test_server::EmbeddedTestServerHandle test_server_handle;
  204. ASSERT_TRUE(test_server_handle =
  205. embedded_test_server()->StartAndReturnHandle());
  206. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  207. auto frame = FrameForTest::Create(context(), {});
  208. frame->AddBeforeLoadJavaScript(
  209. kOnLoadScriptId, {"*"},
  210. base::MemBufferFromString("stashed_title = 'hello';", "test"),
  211. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  212. EXPECT_TRUE(result.is_response());
  213. });
  214. // Test script injection for the origin 127.0.0.1.
  215. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  216. fuchsia::web::LoadUrlParams(),
  217. url.spec()));
  218. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, "hello");
  219. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  220. fuchsia::web::LoadUrlParams(),
  221. url::kAboutBlankURL));
  222. frame.navigation_listener().RunUntilUrlEquals(GURL(url::kAboutBlankURL));
  223. // Test script injection using a different origin ("localhost"), which should
  224. // still be picked up by the wildcard.
  225. GURL alt_url = embedded_test_server()->GetURL("localhost", kDynamicTitlePath);
  226. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  227. fuchsia::web::LoadUrlParams(),
  228. alt_url.spec()));
  229. frame.navigation_listener().RunUntilUrlAndTitleEquals(alt_url, "hello");
  230. }
  231. // Test that we can inject scripts before and after RenderFrame creation.
  232. IN_PROC_BROWSER_TEST_F(JavaScriptTest,
  233. BeforeLoadScriptEarlyAndLateRegistrations) {
  234. constexpr int64_t kOnLoadScriptId2 = kOnLoadScriptId + 1;
  235. net::test_server::EmbeddedTestServerHandle test_server_handle;
  236. ASSERT_TRUE(test_server_handle =
  237. embedded_test_server()->StartAndReturnHandle());
  238. GURL url(embedded_test_server()->GetURL(kDynamicTitlePath));
  239. auto frame = FrameForTest::Create(context(), {});
  240. frame->AddBeforeLoadJavaScript(
  241. kOnLoadScriptId, {embedded_test_server()->GetOrigin().Serialize()},
  242. base::MemBufferFromString("stashed_title = 'hello';", "test"),
  243. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  244. EXPECT_TRUE(result.is_response());
  245. });
  246. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  247. fuchsia::web::LoadUrlParams(),
  248. url.spec()));
  249. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, "hello");
  250. frame->AddBeforeLoadJavaScript(
  251. kOnLoadScriptId2, {embedded_test_server()->GetOrigin().Serialize()},
  252. base::MemBufferFromString("stashed_title += ' there';", "test"),
  253. [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
  254. EXPECT_TRUE(result.is_response());
  255. });
  256. // Navigate away to clean the slate.
  257. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  258. fuchsia::web::LoadUrlParams(),
  259. url::kAboutBlankURL));
  260. frame.navigation_listener().RunUntilUrlEquals(GURL(url::kAboutBlankURL));
  261. // Navigate back and see if both scripts are working.
  262. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  263. fuchsia::web::LoadUrlParams(),
  264. url.spec()));
  265. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, "hello there");
  266. }
  267. IN_PROC_BROWSER_TEST_F(JavaScriptTest, BadEncoding) {
  268. auto frame = FrameForTest::Create(context(), {});
  269. net::test_server::EmbeddedTestServerHandle test_server_handle;
  270. ASSERT_TRUE(test_server_handle =
  271. embedded_test_server()->StartAndReturnHandle());
  272. GURL url(embedded_test_server()->GetURL(kPage1Path));
  273. EXPECT_TRUE(LoadUrlAndExpectResponse(frame.GetNavigationController(),
  274. fuchsia::web::LoadUrlParams(),
  275. url.spec()));
  276. frame.navigation_listener().RunUntilUrlAndTitleEquals(url, kPage1Title);
  277. base::RunLoop run_loop;
  278. // 0xFE is an illegal UTF-8 byte; it should cause UTF-8 conversion to fail.
  279. frame->ExecuteJavaScriptNoResult(
  280. {embedded_test_server()->GetOrigin().Serialize()},
  281. base::MemBufferFromString("true;\xfe", "test"),
  282. [&run_loop](fuchsia::web::Frame_ExecuteJavaScriptNoResult_Result result) {
  283. EXPECT_TRUE(result.is_err());
  284. EXPECT_EQ(result.err(), fuchsia::web::FrameError::BUFFER_NOT_UTF8);
  285. run_loop.Quit();
  286. });
  287. run_loop.Run();
  288. }
  289. } // namespace