Chromium Code Reviews| Index: content/browser/service_worker/service_worker_browsertest.cc |
| diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc |
| index af3770edc21448435fe0778badf3872deb1f88de..0bf0226cc9c3aed0141f33fa8fda9627d39c3a58 100644 |
| --- a/content/browser/service_worker/service_worker_browsertest.cc |
| +++ b/content/browser/service_worker/service_worker_browsertest.cc |
| @@ -388,6 +388,22 @@ bool CheckHeader(const base::DictionaryValue& dict, |
| return false; |
| } |
| +bool HasHeader(const base::DictionaryValue& dict, |
| + base::StringPiece header_name) { |
| + const base::ListValue* headers = nullptr; |
| + EXPECT_TRUE(dict.GetList("headers", &headers)); |
| + for (size_t i = 0; i < headers->GetSize(); ++i) { |
| + const base::ListValue* name_value_pair = nullptr; |
| + EXPECT_TRUE(headers->GetList(i, &name_value_pair)); |
| + EXPECT_EQ(2u, name_value_pair->GetSize()); |
| + std::string name; |
| + EXPECT_TRUE(name_value_pair->GetString(0, &name)); |
| + if (name == header_name) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| net::HttpResponseInfo CreateHttpResponseInfo() { |
| net::HttpResponseInfo info; |
| const char data[] = |
| @@ -1498,6 +1514,24 @@ class ServiceWorkerNavigationPreloadTest : public ServiceWorkerBrowserTest { |
| observer->Wait(); |
| } |
| + std::string LoadNavigationPreloadTestPage(const GURL& page_url, |
| + const GURL& worker_url, |
| + const char* expected_result) { |
| + RegisterMonitorRequestHandler(); |
| + StartServerAndNavigateToSetup(); |
| + SetupForNavigationPreloadTest(page_url, worker_url); |
| + |
| + const base::string16 title = base::ASCIIToUTF16("PASS"); |
| + TitleWatcher title_watcher(shell()->web_contents(), title); |
| + title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("ERROR")); |
| + title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("REJECTED")); |
| + title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("RESOLVED")); |
| + NavigateToURL(shell(), page_url); |
| + EXPECT_EQ(base::ASCIIToUTF16(expected_result), |
| + title_watcher.WaitAndGetTitle()); |
| + return GetTextContent(); |
| + } |
| + |
| void RegisterMonitorRequestHandler() { |
| embedded_test_server()->RegisterRequestMonitor( |
| base::Bind(&self::MonitorRequestHandler, base::Unretained(this))); |
| @@ -1542,6 +1576,21 @@ class ServiceWorkerNavigationPreloadTest : public ServiceWorkerBrowserTest { |
| return text_content; |
| } |
| + void OpaqueRedirectResponseCheck(const std::string& text_content, |
| + const GURL& page_url) const { |
| + std::unique_ptr<base::Value> result = base::JSONReader::Read(text_content); |
| + base::DictionaryValue* dict = nullptr; |
| + ASSERT_TRUE(result->GetAsDictionary(&dict)); |
| + EXPECT_EQ("opaqueredirect", GetString(*dict, "type")); |
| + EXPECT_EQ(page_url, GURL(GetString(*dict, "url"))); |
| + EXPECT_EQ(0, GetInt(*dict, "status")); |
| + EXPECT_FALSE(GetBoolean(*dict, "ok")); |
| + EXPECT_EQ("", GetString(*dict, "statusText")); |
| + const base::ListValue* headers = nullptr; |
| + ASSERT_TRUE(dict->GetList("headers", &headers)); |
| + EXPECT_EQ(0u, headers->GetSize()); |
| + } |
| + |
| std::map<std::string, std::vector<net::test_server::HttpRequest>> |
| request_log_; |
| @@ -1682,15 +1731,8 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, NetworkFallback) { |
| RegisterStaticFile(kPageUrl, kPage, "text/html"); |
| RegisterStaticFile(kWorkerUrl, kScript, "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("PASS"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| - EXPECT_EQ("Hello world.", GetTextContent()); |
| + EXPECT_EQ("Hello world.", |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "PASS")); |
| // The page request must be sent once or twice: |
| // - A navigation preload request may be sent. But it is possible that the |
| @@ -1816,16 +1858,8 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| RegisterStaticFile(kPageUrl, kPage, "text/html"); |
| RegisterStaticFile(kWorkerUrl, kScript, "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("PASS"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("ERROR")); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| - EXPECT_EQ("Hello world.", GetTextContent()); |
| + EXPECT_EQ("Hello world.", |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "PASS")); |
| // The page request must be sent only once, since the worker responded with |
| // the navigation preload response |
| @@ -1854,15 +1888,8 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, GetResponseText) { |
| RegisterStaticFile(kPageUrl, kPage, "text/html"); |
| RegisterStaticFile(kWorkerUrl, kScript, "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("PASS"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| - EXPECT_EQ("Hello world.", GetTextContent()); |
| + EXPECT_EQ("Hello world.", |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "PASS")); |
| // The page request must be sent only once, since the worker responded with |
| // "Hello world". |
| @@ -1889,15 +1916,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, EmptyBody) { |
| RegisterStaticFile(kPageUrl, kPage, "text/html"); |
| RegisterStaticFile(kWorkerUrl, kScript, "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("PASS"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| - EXPECT_EQ("[]", GetTextContent()); |
| + EXPECT_EQ("[]", LoadNavigationPreloadTestPage(page_url, worker_url, "PASS")); |
| EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| } |
| @@ -1940,17 +1959,8 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript, |
| "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("REJECTED"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("RESOLVED")); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| EXPECT_EQ("NetworkError: Service Worker navigation preload network error.", |
| - GetTextContent()); |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "REJECTED")); |
| } |
| IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| @@ -1965,28 +1975,18 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript, |
| "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("RESOLVED"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("REJECTED")); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("ERROR")); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| + std::unique_ptr<base::Value> result = base::JSONReader::Read( |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED")); |
| // The page request must be sent only once, since the worker responded with |
| // a generated Response. |
| EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| - std::unique_ptr<base::Value> result = |
| - base::JSONReader::Read(GetTextContent()); |
| base::DictionaryValue* dict = nullptr; |
| ASSERT_TRUE(result->GetAsDictionary(&dict)); |
| EXPECT_EQ("basic", GetString(*dict, "type")); |
| EXPECT_EQ(page_url, GURL(GetString(*dict, "url"))); |
| EXPECT_EQ(200, GetInt(*dict, "status")); |
| - EXPECT_EQ(true, GetBoolean(*dict, "ok")); |
| + EXPECT_TRUE(GetBoolean(*dict, "ok")); |
| EXPECT_EQ("OK", GetString(*dict, "statusText")); |
| EXPECT_TRUE(CheckHeader(*dict, "content-type", "text/html")); |
| EXPECT_TRUE(CheckHeader(*dict, "content-length", |
| @@ -2002,21 +2002,12 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, NotEnabled) { |
| RegisterStaticFile(kPageUrl, kPage, "text/html"); |
| RegisterStaticFile(kWorkerUrl, kPreloadResponseTestScript, "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("RESOLVED"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("REJECTED")); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("ERROR")); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| + EXPECT_EQ("Resolved with undefined.", |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED")); |
| // The page request must not be sent, since the worker responded with a |
| // generated Response and the navigation preload isn't enabled. |
| EXPECT_EQ(0, GetRequestCount(kPageUrl)); |
| - EXPECT_EQ("Resolved with undefined.", GetTextContent()); |
| } |
| IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| @@ -2041,38 +2032,28 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript, |
| "text/javascript"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("RESOLVED"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("REJECTED")); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("ERROR")); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| + std::unique_ptr<base::Value> result = base::JSONReader::Read( |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED")); |
| // The page request must be sent only once, since the worker responded with |
| // a generated Response. |
| EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| - std::unique_ptr<base::Value> result = |
| - base::JSONReader::Read(GetTextContent()); |
| base::DictionaryValue* dict = nullptr; |
| ASSERT_TRUE(result->GetAsDictionary(&dict)); |
| EXPECT_EQ("basic", GetString(*dict, "type")); |
| EXPECT_EQ(page_url, GURL(GetString(*dict, "url"))); |
| EXPECT_EQ(201, GetInt(*dict, "status")); |
| - EXPECT_EQ(true, GetBoolean(*dict, "ok")); |
| + EXPECT_TRUE(GetBoolean(*dict, "ok")); |
| EXPECT_EQ("HELLOWORLD", GetString(*dict, "statusText")); |
| EXPECT_TRUE(CheckHeader(*dict, "content-type", "text/html")); |
| EXPECT_TRUE(CheckHeader(*dict, "content-length", "32")); |
| EXPECT_TRUE(CheckHeader(*dict, "custom-header", "pen pineapple, apple pen")); |
| // The forbidden response headers (Set-Cookie, Set-Cookie2) must be removed. |
| - EXPECT_FALSE(dict->HasKey("set-cookie")); |
| - EXPECT_FALSE(dict->HasKey("set-cookie2")); |
| + EXPECT_FALSE(HasHeader(*dict, "set-cookie")); |
| + EXPECT_FALSE(HasHeader(*dict, "set-cookie2")); |
| } |
| -IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, RejectRedirects) { |
| +IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, NormalRedirect) { |
| const char kPageUrl[] = "/service_worker/navigation_preload.html"; |
| const char kWorkerUrl[] = "/service_worker/navigation_preload.js"; |
| const char kRedirectedPageUrl[] = |
| @@ -2083,8 +2064,6 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, RejectRedirects) { |
| "Location: /service_worker/navigation_preload_redirected.html\r\n" |
| "\r\n"; |
| const char kRedirectedPage[] = "<title>ERROR</title>Redirected page."; |
| - const GURL redirecred_page_url = |
| - embedded_test_server()->GetURL(kRedirectedPageUrl); |
| const GURL page_url = embedded_test_server()->GetURL(kPageUrl); |
| const GURL worker_url = embedded_test_server()->GetURL(kWorkerUrl); |
| RegisterCustomResponse(kPageUrl, kPageResponse); |
| @@ -2093,25 +2072,131 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, RejectRedirects) { |
| "text/javascript"); |
| RegisterStaticFile(kRedirectedPageUrl, kRedirectedPage, "text/html"); |
| - RegisterMonitorRequestHandler(); |
| - StartServerAndNavigateToSetup(); |
| - SetupForNavigationPreloadTest(page_url, worker_url); |
| - |
| - const base::string16 title = base::ASCIIToUTF16("REJECTED"); |
| - TitleWatcher title_watcher(shell()->web_contents(), title); |
| - title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("RESOLVED")); |
| - NavigateToURL(shell(), page_url); |
| - EXPECT_EQ(title, title_watcher.WaitAndGetTitle()); |
| + OpaqueRedirectResponseCheck( |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED"), |
| + page_url); |
| // The page request must be sent only once, since the worker responded with |
| // a generated Response. |
| EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| // The redirected request must not be sent. |
| EXPECT_EQ(0, GetRequestCount(kRedirectedPageUrl)); |
| - EXPECT_EQ( |
| - "NetworkError: Service Worker navigation preload doesn't support " |
| - "redirects.", |
| - GetTextContent()); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| + InvalidRedirect_MultiLocation) { |
| + const char kPageUrl[] = "/service_worker/navigation_preload.html"; |
| + const char kWorkerUrl[] = "/service_worker/navigation_preload.js"; |
| + const char kRedirectedPageUrl1[] = |
| + "/service_worker/navigation_preload_redirected1.html"; |
| + const char kRedirectedPageUrl2[] = |
| + "/service_worker/navigation_preload_redirected2.html"; |
| + const char kPageResponse[] = |
| + "HTTP/1.1 302 Found\r\n" |
| + "Connection: close\r\n" |
| + "Location: /service_worker/navigation_preload_redirected1.html\r\n" |
| + "Location: /service_worker/navigation_preload_redirected2.html\r\n" |
| + "\r\n"; |
| + const char kRedirectedPage[] = "<title>ERROR</title>Redirected page."; |
| + const GURL page_url = embedded_test_server()->GetURL(kPageUrl); |
| + const GURL worker_url = embedded_test_server()->GetURL(kWorkerUrl); |
| + RegisterCustomResponse(kPageUrl, kPageResponse); |
| + RegisterStaticFile( |
| + kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript, |
| + "text/javascript"); |
| + RegisterStaticFile(kRedirectedPageUrl1, kRedirectedPage, "text/html"); |
| + |
| + // According to the spec, multiple Location headers is not an error. So the |
| + // preloadResponse must be resolved with an opaque redirect response. |
| + // But Chrome treats multiple Location headers as an error (crbug.com/98895). |
| + EXPECT_EQ("NetworkError: Service Worker navigation preload network error.", |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "REJECTED")); |
| + |
| + // The page request must be sent only once, since the worker responded with |
| + // a generated Response. |
| + EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| + // The redirected request must not be sent. |
| + EXPECT_EQ(0, GetRequestCount(kRedirectedPageUrl1)); |
| + EXPECT_EQ(0, GetRequestCount(kRedirectedPageUrl2)); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| + InvalidRedirect_InvalidLocation) { |
| + const char kPageUrl[] = "/service_worker/navigation_preload.html"; |
| + const char kWorkerUrl[] = "/service_worker/navigation_preload.js"; |
| + const char kPageResponse[] = |
| + "HTTP/1.1 302 Found\r\n" |
| + "Connection: close\r\n" |
| + "Location: http://\r\n" |
| + "\r\n"; |
| + const GURL page_url = embedded_test_server()->GetURL(kPageUrl); |
| + const GURL worker_url = embedded_test_server()->GetURL(kWorkerUrl); |
| + RegisterCustomResponse(kPageUrl, kPageResponse); |
| + RegisterStaticFile( |
| + kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript, |
| + "text/javascript"); |
| + |
| + // According to the spec, even if the location URL is invalid, the |
| + // preloadResponse must be resolve with an opaque redirect response. But |
| + // currently Chrome handles the invalid location URL in the browser process as |
| + // an error. |
|
falken
2017/03/31 07:36:03
Make this a TODO with bug?
horo
2017/03/31 09:56:30
Done.
|
| + EXPECT_EQ("NetworkError: Service Worker navigation preload network error.", |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "REJECTED")); |
| + |
| + // The page request must be sent only once, since the worker responded with |
| + // a generated Response. |
| + EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| + InvalidRedirect_NoLocation) { |
| + const char kPageUrl[] = "/service_worker/navigation_preload.html"; |
| + const char kWorkerUrl[] = "/service_worker/navigation_preload.js"; |
| + const char kPageResponse[] = |
| + "HTTP/1.1 302 Found\r\n" |
| + "Connection: close\r\n" |
| + "Custom-Header: hello\r\n" |
| + "\r\n"; |
| + const GURL page_url = embedded_test_server()->GetURL(kPageUrl); |
| + const GURL worker_url = embedded_test_server()->GetURL(kWorkerUrl); |
| + RegisterCustomResponse(kPageUrl, kPageResponse); |
| + RegisterStaticFile( |
| + kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript, |
| + "text/javascript"); |
| + |
| + OpaqueRedirectResponseCheck( |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED"), |
| + page_url); |
| + |
| + // The page request must be sent only once, since the worker responded with |
| + // a generated Response. |
| + EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, |
| + InvalidRedirect_NoLocationWithBody) { |
| + const char kPageUrl[] = "/service_worker/navigation_preload.html"; |
| + const char kWorkerUrl[] = "/service_worker/navigation_preload.js"; |
| + const char kPageResponse[] = |
| + "HTTP/1.1 302 Found\r\n" |
| + "Connection: close\r\n" |
| + "Custom-Header: hello\r\n" |
| + "\r\n" |
| + "Body\r\n"; |
| + const GURL page_url = embedded_test_server()->GetURL(kPageUrl); |
| + const GURL worker_url = embedded_test_server()->GetURL(kWorkerUrl); |
| + RegisterCustomResponse(kPageUrl, kPageResponse); |
| + RegisterStaticFile( |
| + kWorkerUrl, kEnableNavigationPreloadScript + kPreloadResponseTestScript, |
| + "text/javascript"); |
| + |
| + OpaqueRedirectResponseCheck( |
| + LoadNavigationPreloadTestPage(page_url, worker_url, "RESOLVED"), |
| + page_url); |
| + |
| + // The page request must be sent only once, since the worker responded with |
| + // a generated Response. |
| + EXPECT_EQ(1, GetRequestCount(kPageUrl)); |
| } |
| // Tests responding with the navigation preload response when the navigation |