diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-22 20:03:01 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-22 20:03:01 +0000 |
commit | eb2ee141e4b40cbc89baaa982c77fe10da6c9f48 (patch) | |
tree | 889fc7e7b89c0483cf97973289d4dff251c6f25b /webkit/appcache | |
parent | f72298c8e0ce1427e8ed682ca5dad0573d6c2763 (diff) | |
download | chromium_src-eb2ee141e4b40cbc89baaa982c77fe10da6c9f48.zip chromium_src-eb2ee141e4b40cbc89baaa982c77fe10da6c9f48.tar.gz chromium_src-eb2ee141e4b40cbc89baaa982c77fe10da6c9f48.tar.bz2 |
Appcache cross-origin HTTPS resources.
BUG=69594
TEST=updated unit tests
Review URL: http://codereview.chromium.org/6526037
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75622 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache')
-rw-r--r-- | webkit/appcache/appcache_update_job.cc | 21 | ||||
-rw-r--r-- | webkit/appcache/appcache_update_job_unittest.cc | 98 | ||||
-rw-r--r-- | webkit/appcache/manifest_parser.cc | 13 | ||||
-rw-r--r-- | webkit/appcache/manifest_parser_unittest.cc | 4 |
4 files changed, 124 insertions, 12 deletions
diff --git a/webkit/appcache/appcache_update_job.cc b/webkit/appcache/appcache_update_job.cc index f2fe26f..d0d4e3b 100644 --- a/webkit/appcache/appcache_update_job.cc +++ b/webkit/appcache/appcache_update_job.cc @@ -123,10 +123,27 @@ void AppCacheUpdateJob::URLFetcher::OnResponseStarted( DCHECK(request == request_); if (request->status().is_success() && (request->GetResponseCode() / 100) == 2) { + + // See http://code.google.com/p/chromium/issues/detail?id=69594 + // We willfully violate the HTML5 spec at this point in order + // to support the appcaching of cross-origin HTTPS resources. + // We've opted for a milder constraint and allow caching unless + // the resource has a "no-store" header. A spec change has been + // requested on the whatwg list. + // TODO(michaeln): Consider doing this for cross-origin HTTP resources too. + if (url_.SchemeIsSecure() && + url_.GetOrigin() != job_->manifest_url_.GetOrigin()) { + if (request->response_headers()-> + HasHeaderValue("cache-control", "no-store")) { + request->Cancel(); + OnResponseCompleted(); + return; + } + } + // Write response info to storage for URL fetches. Wait for async write // completion before reading any response data. - if (fetch_type_ == URL_FETCH || - fetch_type_ == MASTER_ENTRY_FETCH) { + if (fetch_type_ == URL_FETCH || fetch_type_ == MASTER_ENTRY_FETCH) { response_writer_.reset(job_->CreateResponseWriter()); scoped_refptr<HttpResponseInfoIOBuffer> io_buffer( new HttpResponseInfoIOBuffer( diff --git a/webkit/appcache/appcache_update_job_unittest.cc b/webkit/appcache/appcache_update_job_unittest.cc index e91edab..d419fc3 100644 --- a/webkit/appcache/appcache_update_job_unittest.cc +++ b/webkit/appcache/appcache_update_job_unittest.cc @@ -41,9 +41,18 @@ class MockHttpServer { return GURL("http://mockhost/" + path); } + static GURL GetMockHttpsUrl(const std::string& path) { + return GURL("https://mockhost/" + path); + } + + static GURL GetMockCrossOriginHttpsUrl(const std::string& path) { + return GURL("https://cross_origin_host/" + path); + } + static net::URLRequestJob* JobFactory(net::URLRequest* request, const std::string& scheme) { - if (request->url().host() != "mockhost") + if (request->url().host() != "mockhost" && + request->url().host() != "cross_origin_host") return new net::URLRequestErrorJob(request, -1); std::string headers, body; @@ -74,6 +83,10 @@ class MockHttpServer { const char not_found_headers[] = "HTTP/1.1 404 NOT FOUND\0" "\0"; + const char no_store_headers[] = + "HTTP/1.1 200 OK\0" + "Cache-Control: no-store\0" + "\0"; if (path == "/files/wrong-mime-manifest") { (*headers) = std::string(ok_headers, arraysize(ok_headers)); @@ -150,6 +163,17 @@ class MockHttpServer { (*headers) = std::string(error_headers, arraysize(error_headers)); (*body) = "error"; + } else if (path == "/files/valid_cross_origin_https_manifest") { + (*headers) = std::string(manifest_headers, arraysize(manifest_headers)); + (*body) = "CACHE MANIFEST\n" + "https://cross_origin_host/files/explicit1\n"; + } else if (path == "/files/invalid_cross_origin_https_manifest") { + (*headers) = std::string(manifest_headers, arraysize(manifest_headers)); + (*body) = "CACHE MANIFEST\n" + "https://cross_origin_host/files/no-store-headers\n"; + } else if (path == "/files/no-store-headers") { + (*headers) = std::string(no_store_headers, arraysize(no_store_headers)); + (*body) = "no-store"; } else { (*headers) = std::string(not_found_headers, arraysize(not_found_headers)); @@ -465,7 +489,7 @@ namespace { class IOThread : public base::Thread { public: explicit IOThread(const char* name) - : base::Thread(name), old_factory_(NULL) { + : base::Thread(name), old_factory_(NULL), old_factory_https_(NULL) { } ~IOThread() { @@ -481,15 +505,19 @@ class IOThread : public base::Thread { virtual void Init() { old_factory_ = net::URLRequest::RegisterProtocolFactory( "http", MockHttpServer::JobFactory); + old_factory_https_ = net::URLRequest::RegisterProtocolFactory( + "https", MockHttpServer::JobFactory); request_context_ = new TestURLRequestContext(); } virtual void CleanUp() { net::URLRequest::RegisterProtocolFactory("http", old_factory_); + net::URLRequest::RegisterProtocolFactory("https", old_factory_https_); request_context_ = NULL; } net::URLRequest::ProtocolFactory* old_factory_; + net::URLRequest::ProtocolFactory* old_factory_https_; scoped_refptr<net::URLRequestContext> request_context_; }; @@ -2796,6 +2824,64 @@ class AppCacheUpdateJobTest : public testing::Test, UpdateFinished(); } + void CrossOriginHttpsSuccessTest() { + ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()); + + GURL manifest_url = MockHttpServer::GetMockHttpsUrl( + "files/valid_cross_origin_https_manifest"); + + MakeService(); + group_ = new AppCacheGroup( + service_.get(), manifest_url, + service_->storage()->NewGroupId()); + AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_); + group_->update_job_ = update; + + MockFrontend* frontend = MakeMockFrontend(); + AppCacheHost* host = MakeHost(1, frontend); + update->StartUpdate(host, GURL()); + EXPECT_EQ(manifest_url, policy_.requested_manifest_url_); + + // Set up checks for when update job finishes. + do_checks_after_update_finished_ = true; + expect_group_obsolete_ = false; + expect_group_has_cache_ = true; + tested_manifest_ = NONE; + MockFrontend::HostIds host_ids(1, host->host_id()); + frontend->AddExpectedEvent(host_ids, CHECKING_EVENT); + + WaitForUpdateToFinish(); + } + + void CrossOriginHttpsDeniedTest() { + ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()); + + GURL manifest_url = MockHttpServer::GetMockHttpsUrl( + "files/invalid_cross_origin_https_manifest"); + + MakeService(); + group_ = new AppCacheGroup( + service_.get(), manifest_url, + service_->storage()->NewGroupId()); + AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_); + group_->update_job_ = update; + + MockFrontend* frontend = MakeMockFrontend(); + AppCacheHost* host = MakeHost(1, frontend); + update->StartUpdate(host, GURL()); + EXPECT_EQ(manifest_url, policy_.requested_manifest_url_); + + // Set up checks for when update job finishes. + do_checks_after_update_finished_ = true; + expect_group_obsolete_ = false; + expect_group_has_cache_ = false; + tested_manifest_ = NONE; + MockFrontend::HostIds host_ids(1, host->host_id()); + frontend->AddExpectedEvent(host_ids, CHECKING_EVENT); + + WaitForUpdateToFinish(); + } + void WaitForUpdateToFinish() { if (group_->update_status() == AppCacheGroup::IDLE) UpdateFinished(); @@ -3458,6 +3544,14 @@ TEST_F(AppCacheUpdateJobTest, MultipleHeadersRefetch) { RunTestOnIOThread(&AppCacheUpdateJobTest::MultipleHeadersRefetchTest); } +TEST_F(AppCacheUpdateJobTest, CrossOriginHttpsSuccess) { + RunTestOnIOThread(&AppCacheUpdateJobTest::CrossOriginHttpsSuccessTest); +} + +TEST_F(AppCacheUpdateJobTest, CrossOriginHttpsDenied) { + RunTestOnIOThread(&AppCacheUpdateJobTest::CrossOriginHttpsDeniedTest); +} + } // namespace appcache // AppCacheUpdateJobTest is expected to always live longer than the diff --git a/webkit/appcache/manifest_parser.cc b/webkit/appcache/manifest_parser.cc index 49ddd8c..1422bc6 100644 --- a/webkit/appcache/manifest_parser.cc +++ b/webkit/appcache/manifest_parser.cc @@ -165,12 +165,13 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length, continue; } - // If the manifest's scheme is https:, then manifest URL must have same - // origin as resulting absolute URL. - if (mode == EXPLICIT && manifest_url.SchemeIsSecure() && - manifest_url.GetOrigin() != url.GetOrigin()) { - continue; - } + // See http://code.google.com/p/chromium/issues/detail?id=69594 + // We willfully violate the HTML5 spec at this point in order + // to support the appcaching of cross-origin HTTPS resources. + // Per the spec, EXPLICIT cross-origin HTTS resources should be + // ignored here. We've opted for a milder constraint and allow + // caching unless the resource has a "no-store" header. That + // condition is enforced in AppCacheUpdateJob. if (mode == EXPLICIT) { manifest.explicit_urls.insert(url.spec()); diff --git a/webkit/appcache/manifest_parser_unittest.cc b/webkit/appcache/manifest_parser_unittest.cc index dccf84e..2e9c573 100644 --- a/webkit/appcache/manifest_parser_unittest.cc +++ b/webkit/appcache/manifest_parser_unittest.cc @@ -328,7 +328,7 @@ TEST(ManifestParserTest, DifferentOriginUrlWithSecureScheme) { EXPECT_TRUE(manifest.online_whitelist_namespaces.empty()); base::hash_set<std::string> urls = manifest.explicit_urls; - const size_t kExpected = 2; + const size_t kExpected = 3; ASSERT_EQ(kExpected, urls.size()); EXPECT_TRUE(urls.find("https://www.foo.com/relative/secureschemesameorigin") != urls.end()); @@ -336,7 +336,7 @@ TEST(ManifestParserTest, DifferentOriginUrlWithSecureScheme) { urls.end()); EXPECT_FALSE(urls.find("http://www.xyz.com/secureschemedifforigin") != urls.end()); - EXPECT_FALSE(urls.find("https://www.xyz.com/secureschemedifforigin") != + EXPECT_TRUE(urls.find("https://www.xyz.com/secureschemedifforigin") != urls.end()); } |