Commit 74a9f080 authored by Chase Phillips's avatar Chase Phillips Committed by Commit Bot

AppCache: Add X-AppCache-Allowed scope override header

This CL extends the manifest scope behavior so a server can override
the default scope.  The default scope for a new AppCache instance
is the manifest URL with an empty path.  An upcoming change will
update the default to be the manifest URL without the manifest
filename.

If a server wants to support the behavior that a manifest can specify
resources outside of that scope, the server can pass a response header
in their 200 or 304 response named X-AppCache-Allowed.  The value of
this header must be a URL path and have a last character equal to a
forward slash.

Bug: 999001
Change-Id: I0277c5ab0645346c4a7c6d5eec5ea67c9cbeeda2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1935035
Commit-Queue: Victor Costan <pwnall@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#721895}
parent 3b862e33
......@@ -29,11 +29,10 @@ bool AppCache::CheckValidManifestScope(const GURL& manifest_url,
}
// static
std::string AppCache::GetManifestScope(
base::Optional<std::string> optional_scope,
const GURL& manifest_url) {
if (optional_scope.has_value()) {
std::string scope = manifest_url.Resolve(optional_scope.value()).path();
std::string AppCache::GetManifestScope(const GURL& manifest_url,
std::string optional_scope) {
if (!optional_scope.empty()) {
std::string scope = manifest_url.Resolve(optional_scope).path();
if (CheckValidManifestScope(manifest_url, scope)) {
return scope;
}
......
......@@ -50,9 +50,8 @@ class CONTENT_EXPORT AppCache
static bool CheckValidManifestScope(const GURL& manifest_url,
const std::string& manifest_scope);
static std::string GetManifestScope(
base::Optional<std::string> optional_scope,
const GURL& manifest_url);
static std::string GetManifestScope(const GURL& manifest_url,
std::string optional_scope);
AppCache(AppCacheStorage* storage, int64_t cache_id);
......
......@@ -441,15 +441,18 @@ void AppCacheUpdateJob::HandleManifestFetchCompleted(URLFetcher* url_fetcher,
UpdateURLLoaderRequest* request = manifest_fetcher->request();
int response_code = -1;
bool is_valid_response_code = false;
fetched_manifest_scope_ =
AppCache::GetManifestScope(base::Optional<std::string>(), manifest_url_);
std::string optional_manifest_scope;
if (net_error == net::OK) {
response_code = request->GetResponseCode();
is_valid_response_code = (response_code / 100 == 2);
std::string mime_type = request->GetMimeType();
manifest_has_valid_mime_type_ = (mime_type == "text/cache-manifest");
optional_manifest_scope = request->GetAppCacheAllowedHeader();
}
fetched_manifest_scope_ =
AppCache::GetManifestScope(manifest_url_, optional_manifest_scope);
if (is_valid_response_code) {
manifest_data_ = manifest_fetcher->manifest_data();
......@@ -460,6 +463,9 @@ void AppCacheUpdateJob::HandleManifestFetchCompleted(URLFetcher* url_fetcher,
else
ContinueHandleManifestFetchCompleted(true);
} else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) {
// Note: Scope changes aren't considered if the server sends a 304 response.
// The response cannot contain a body (per HTTP spec), so we treat these
// cases as implying that the scope also hasn't changed.
ContinueHandleManifestFetchCompleted(false);
} else if ((response_code == 404 || response_code == 410) &&
update_type_ == UPGRADE_ATTEMPT) {
......@@ -1069,6 +1075,11 @@ void AppCacheUpdateJob::CheckIfManifestChanged() {
return;
}
if (fetched_manifest_scope_ != cached_manifest_scope_) {
ContinueHandleManifestFetchCompleted(true);
return;
}
// Load manifest data from storage to compare against fetched manifest.
manifest_response_reader_ =
storage_->CreateResponseReader(manifest_url_, entry->response_id());
......@@ -1081,6 +1092,7 @@ void AppCacheUpdateJob::CheckIfManifestChanged() {
}
void AppCacheUpdateJob::OnManifestDataReadComplete(int result) {
DCHECK_EQ(fetched_manifest_scope_, cached_manifest_scope_);
if (result > 0) {
loaded_manifest_data_.append(read_manifest_buffer_->data(), result);
manifest_response_reader_->ReadData(
......
......@@ -15,6 +15,7 @@
namespace content {
namespace {
constexpr net::NetworkTrafficAnnotationTag kAppCacheTrafficAnnotation =
net::DefineNetworkTrafficAnnotation("appcache_update_job", R"(
semantics {
......@@ -44,6 +45,8 @@ constexpr net::NetworkTrafficAnnotationTag kAppCacheTrafficAnnotation =
}
}
})");
const char kAppCacheAllowed[] = "X-AppCache-Allowed";
}
AppCacheUpdateJob::UpdateURLLoaderRequest::~UpdateURLLoaderRequest() {}
......@@ -106,6 +109,16 @@ int AppCacheUpdateJob::UpdateURLLoaderRequest::GetResponseCode() const {
return 0;
}
std::string
AppCacheUpdateJob::UpdateURLLoaderRequest::GetAppCacheAllowedHeader() const {
std::string string_value;
if (!response_->headers || !response_->headers->EnumerateHeader(
nullptr, kAppCacheAllowed, &string_value)) {
return "";
}
return string_value;
}
const net::HttpResponseInfo&
AppCacheUpdateJob::UpdateURLLoaderRequest::GetResponseInfo() const {
return *http_response_info_;
......
......@@ -76,6 +76,10 @@ class AppCacheUpdateJob::UpdateURLLoaderRequest
// called. For non-HTTP requests, this method returns -1.
int GetResponseCode() const;
// Fetch the X-AppCache-Allowed response header and return the scope based
// on the header.
std::string GetAppCacheAllowedHeader() const;
// Get the HTTP response info in its entirety.
const net::HttpResponseInfo& GetResponseInfo() const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment