summaryrefslogtreecommitdiffstats
path: root/webkit/appcache
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-22 20:03:01 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-22 20:03:01 +0000
commiteb2ee141e4b40cbc89baaa982c77fe10da6c9f48 (patch)
tree889fc7e7b89c0483cf97973289d4dff251c6f25b /webkit/appcache
parentf72298c8e0ce1427e8ed682ca5dad0573d6c2763 (diff)
downloadchromium_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.cc21
-rw-r--r--webkit/appcache/appcache_update_job_unittest.cc98
-rw-r--r--webkit/appcache/manifest_parser.cc13
-rw-r--r--webkit/appcache/manifest_parser_unittest.cc4
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());
}