| Index: content/browser/appcache/appcache_update_job.cc
|
| diff --git a/content/browser/appcache/appcache_update_job.cc b/content/browser/appcache/appcache_update_job.cc
|
| index ec16a5a27f2b93063f5328dc850371a7c1ef7ec5..3f50460147dac43aa01461959fa4cce730c20a44 100644
|
| --- a/content/browser/appcache/appcache_update_job.cc
|
| +++ b/content/browser/appcache/appcache_update_job.cc
|
| @@ -14,15 +14,12 @@
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "content/browser/appcache/appcache_group.h"
|
| #include "content/browser/appcache/appcache_histograms.h"
|
| +#include "content/browser/appcache/appcache_update_url_fetcher.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/base/load_flags.h"
|
| #include "net/base/net_errors.h"
|
| #include "net/base/request_priority.h"
|
| -#include "net/http/http_request_headers.h"
|
| -#include "net/http/http_response_headers.h"
|
| -#include "net/traffic_annotation/network_traffic_annotation.h"
|
| -#include "net/url_request/url_request_context.h"
|
| #include "url/origin.h"
|
|
|
| namespace content {
|
| @@ -31,7 +28,6 @@ namespace {
|
|
|
| const int kBufferSize = 32768;
|
| const size_t kMaxConcurrentUrlFetches = 2;
|
| -const int kMax503Retries = 3;
|
|
|
| std::string FormatUrlErrorMessage(
|
| const char* format, const GURL& url,
|
| @@ -70,36 +66,6 @@ bool IsEvictableError(AppCacheUpdateJob::ResultType result,
|
|
|
| void EmptyCompletionCallback(int result) {}
|
|
|
| -constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
|
| - net::DefineNetworkTrafficAnnotation("appcache_update_job", R"(
|
| - semantics {
|
| - sender: "HTML5 AppCache System"
|
| - description:
|
| - "Web pages can include a link to a manifest file which lists "
|
| - "resources to be cached for offline access. The AppCache system"
|
| - "retrieves those resources in the background."
|
| - trigger:
|
| - "User visits a web page containing a <html manifest=manifestUrl> "
|
| - "tag, or navigates to a document retrieved from an existing appcache "
|
| - "and some resource should be updated."
|
| - data: "None"
|
| - destination: WEBSITE
|
| - }
|
| - policy {
|
| - cookies_allowed: true
|
| - cookies_store: "user"
|
| - setting:
|
| - "Users can control this feature via the 'Cookies' setting under "
|
| - "'Privacy, Content settings'. If cookies are disabled for a single "
|
| - "site, appcaches are disabled for the site only. If they are totally "
|
| - "disabled, all appcache requests will be stopped."
|
| - chrome_policy {
|
| - DefaultCookiesSetting {
|
| - policy_options {mode: MANDATORY}
|
| - DefaultCookiesSetting: 2
|
| - }
|
| - }
|
| - })");
|
| } // namespace
|
|
|
| // Helper class for collecting hosts per frontend when sending notifications
|
| @@ -178,260 +144,6 @@ AppCacheUpdateJob::UrlToFetch::UrlToFetch(const UrlToFetch& other) = default;
|
| AppCacheUpdateJob::UrlToFetch::~UrlToFetch() {
|
| }
|
|
|
| -// Helper class to fetch resources. Depending on the fetch type,
|
| -// can either fetch to an in-memory string or write the response
|
| -// data out to the disk cache.
|
| -AppCacheUpdateJob::URLFetcher::URLFetcher(const GURL& url,
|
| - FetchType fetch_type,
|
| - AppCacheUpdateJob* job)
|
| - : url_(url),
|
| - job_(job),
|
| - fetch_type_(fetch_type),
|
| - retry_503_attempts_(0),
|
| - buffer_(new net::IOBuffer(kBufferSize)),
|
| - request_(
|
| - job->service_->request_context()->CreateRequest(url,
|
| - net::DEFAULT_PRIORITY,
|
| - this,
|
| - kTrafficAnnotation)),
|
| - result_(UPDATE_OK),
|
| - redirect_response_code_(-1) {}
|
| -
|
| -AppCacheUpdateJob::URLFetcher::~URLFetcher() {
|
| - // To defend against URLRequest calling delegate methods during
|
| - // destruction, we test for a !request_ in those methods.
|
| - std::unique_ptr<net::URLRequest> temp = std::move(request_);
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::Start() {
|
| - request_->set_first_party_for_cookies(job_->manifest_url_);
|
| - request_->set_initiator(url::Origin(job_->manifest_url_));
|
| - if (fetch_type_ == MANIFEST_FETCH && job_->doing_full_update_check_)
|
| - request_->SetLoadFlags(request_->load_flags() | net::LOAD_BYPASS_CACHE);
|
| - else if (existing_response_headers_.get())
|
| - AddConditionalHeaders(existing_response_headers_.get());
|
| - request_->Start();
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::OnReceivedRedirect(
|
| - net::URLRequest* request,
|
| - const net::RedirectInfo& redirect_info,
|
| - bool* defer_redirect) {
|
| - if (!request_)
|
| - return;
|
| - DCHECK_EQ(request_.get(), request);
|
| - // Redirect is not allowed by the update process.
|
| - job_->MadeProgress();
|
| - redirect_response_code_ = request->GetResponseCode();
|
| - request->Cancel();
|
| - result_ = REDIRECT_ERROR;
|
| - OnResponseCompleted(net::ERR_ABORTED);
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::OnResponseStarted(net::URLRequest* request,
|
| - int net_error) {
|
| - if (!request_)
|
| - return;
|
| - DCHECK_EQ(request_.get(), request);
|
| - DCHECK_NE(net::ERR_IO_PENDING, net_error);
|
| -
|
| - int response_code = -1;
|
| - if (net_error == net::OK) {
|
| - response_code = request->GetResponseCode();
|
| - job_->MadeProgress();
|
| - }
|
| -
|
| - if ((response_code / 100) != 2) {
|
| - if (response_code > 0)
|
| - result_ = SERVER_ERROR;
|
| - else
|
| - result_ = NETWORK_ERROR;
|
| - OnResponseCompleted(net_error);
|
| - return;
|
| - }
|
| -
|
| - if (url_.SchemeIsCryptographic()) {
|
| - // Do not cache content with cert errors.
|
| - // Also, 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.
|
| - // See http://code.google.com/p/chromium/issues/detail?id=69594
|
| - // TODO(michaeln): Consider doing this for cross-origin HTTP too.
|
| - const net::HttpNetworkSession::Params* session_params =
|
| - request->context()->GetNetworkSessionParams();
|
| - bool ignore_cert_errors = session_params &&
|
| - session_params->ignore_certificate_errors;
|
| - if ((net::IsCertStatusError(request->ssl_info().cert_status) &&
|
| - !ignore_cert_errors) ||
|
| - (url_.GetOrigin() != job_->manifest_url_.GetOrigin() &&
|
| - request->response_headers()->
|
| - HasHeaderValue("cache-control", "no-store"))) {
|
| - DCHECK_EQ(-1, redirect_response_code_);
|
| - request->Cancel();
|
| - result_ = SECURITY_ERROR;
|
| - OnResponseCompleted(net::ERR_ABORTED);
|
| - 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) {
|
| - response_writer_.reset(job_->CreateResponseWriter());
|
| - scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
|
| - new HttpResponseInfoIOBuffer(
|
| - new net::HttpResponseInfo(request->response_info())));
|
| - response_writer_->WriteInfo(
|
| - io_buffer.get(),
|
| - base::Bind(&URLFetcher::OnWriteComplete, base::Unretained(this)));
|
| - } else {
|
| - ReadResponseData();
|
| - }
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::OnReadCompleted(
|
| - net::URLRequest* request, int bytes_read) {
|
| - if (!request_)
|
| - return;
|
| - DCHECK_NE(net::ERR_IO_PENDING, bytes_read);
|
| - DCHECK_EQ(request_.get(), request);
|
| - bool data_consumed = true;
|
| - if (bytes_read > 0) {
|
| - job_->MadeProgress();
|
| - data_consumed = ConsumeResponseData(bytes_read);
|
| - if (data_consumed) {
|
| - while (true) {
|
| - bytes_read = request->Read(buffer_.get(), kBufferSize);
|
| - if (bytes_read <= 0)
|
| - break;
|
| - data_consumed = ConsumeResponseData(bytes_read);
|
| - if (!data_consumed)
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (data_consumed && bytes_read != net::ERR_IO_PENDING) {
|
| - DCHECK_EQ(UPDATE_OK, result_);
|
| - OnResponseCompleted(bytes_read);
|
| - }
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::AddConditionalHeaders(
|
| - const net::HttpResponseHeaders* headers) {
|
| - DCHECK(request_);
|
| - DCHECK(headers);
|
| - net::HttpRequestHeaders extra_headers;
|
| -
|
| - // Add If-Modified-Since header if response info has Last-Modified header.
|
| - const std::string last_modified = "Last-Modified";
|
| - std::string last_modified_value;
|
| - headers->EnumerateHeader(nullptr, last_modified, &last_modified_value);
|
| - if (!last_modified_value.empty()) {
|
| - extra_headers.SetHeader(net::HttpRequestHeaders::kIfModifiedSince,
|
| - last_modified_value);
|
| - }
|
| -
|
| - // Add If-None-Match header if response info has ETag header.
|
| - const std::string etag = "ETag";
|
| - std::string etag_value;
|
| - headers->EnumerateHeader(nullptr, etag, &etag_value);
|
| - if (!etag_value.empty()) {
|
| - extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch,
|
| - etag_value);
|
| - }
|
| - if (!extra_headers.IsEmpty())
|
| - request_->SetExtraRequestHeaders(extra_headers);
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::OnWriteComplete(int result) {
|
| - if (result < 0) {
|
| - request_->Cancel();
|
| - result_ = DISKCACHE_ERROR;
|
| - OnResponseCompleted(net::ERR_ABORTED);
|
| - return;
|
| - }
|
| - ReadResponseData();
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::ReadResponseData() {
|
| - InternalUpdateState state = job_->internal_state_;
|
| - if (state == CACHE_FAILURE || state == CANCELLED || state == COMPLETED)
|
| - return;
|
| - int bytes_read = request_->Read(buffer_.get(), kBufferSize);
|
| - if (bytes_read != net::ERR_IO_PENDING)
|
| - OnReadCompleted(request_.get(), bytes_read);
|
| -}
|
| -
|
| -// Returns false if response data is processed asynchronously, in which
|
| -// case ReadResponseData will be invoked when it is safe to continue
|
| -// reading more response data from the request.
|
| -bool AppCacheUpdateJob::URLFetcher::ConsumeResponseData(int bytes_read) {
|
| - DCHECK_GT(bytes_read, 0);
|
| - switch (fetch_type_) {
|
| - case MANIFEST_FETCH:
|
| - case MANIFEST_REFETCH:
|
| - manifest_data_.append(buffer_->data(), bytes_read);
|
| - break;
|
| - case URL_FETCH:
|
| - case MASTER_ENTRY_FETCH:
|
| - DCHECK(response_writer_.get());
|
| - response_writer_->WriteData(
|
| - buffer_.get(),
|
| - bytes_read,
|
| - base::Bind(&URLFetcher::OnWriteComplete, base::Unretained(this)));
|
| - return false; // wait for async write completion to continue reading
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void AppCacheUpdateJob::URLFetcher::OnResponseCompleted(int net_error) {
|
| - if (net_error == net::OK)
|
| - job_->MadeProgress();
|
| -
|
| - // Retry for 503s where retry-after is 0.
|
| - if (net_error == net::OK && request_->GetResponseCode() == 503 &&
|
| - MaybeRetryRequest()) {
|
| - return;
|
| - }
|
| -
|
| - switch (fetch_type_) {
|
| - case MANIFEST_FETCH:
|
| - job_->HandleManifestFetchCompleted(this, net_error);
|
| - break;
|
| - case URL_FETCH:
|
| - job_->HandleUrlFetchCompleted(this, net_error);
|
| - break;
|
| - case MASTER_ENTRY_FETCH:
|
| - job_->HandleMasterEntryFetchCompleted(this, net_error);
|
| - break;
|
| - case MANIFEST_REFETCH:
|
| - job_->HandleManifestRefetchCompleted(this, net_error);
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| -
|
| - delete this;
|
| -}
|
| -
|
| -bool AppCacheUpdateJob::URLFetcher::MaybeRetryRequest() {
|
| - if (retry_503_attempts_ >= kMax503Retries ||
|
| - !request_->response_headers()->HasHeaderValue("retry-after", "0")) {
|
| - return false;
|
| - }
|
| - ++retry_503_attempts_;
|
| - result_ = UPDATE_OK;
|
| - request_ = job_->service_->request_context()->CreateRequest(
|
| - url_, net::DEFAULT_PRIORITY, this, kTrafficAnnotation);
|
| - Start();
|
| - return true;
|
| -}
|
| -
|
| AppCacheUpdateJob::AppCacheUpdateJob(AppCacheServiceImpl* service,
|
| AppCacheGroup* group)
|
| : service_(service),
|
| @@ -597,11 +309,11 @@ void AppCacheUpdateJob::HandleCacheFailure(
|
|
|
| void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) {
|
| DCHECK(!manifest_fetcher_);
|
| - manifest_fetcher_ = new URLFetcher(
|
| - manifest_url_,
|
| - is_first_fetch ? URLFetcher::MANIFEST_FETCH :
|
| - URLFetcher::MANIFEST_REFETCH,
|
| - this);
|
| + manifest_fetcher_ =
|
| + new URLFetcher(manifest_url_,
|
| + is_first_fetch ? URLFetcher::MANIFEST_FETCH
|
| + : URLFetcher::MANIFEST_REFETCH,
|
| + this, kBufferSize);
|
|
|
| if (is_first_fetch) {
|
| // Maybe load the cached headers to make a condiditional request.
|
| @@ -1304,7 +1016,7 @@ void AppCacheUpdateJob::FetchUrls() {
|
| // Continues asynchronously after data is loaded from newest cache.
|
| } else {
|
| URLFetcher* fetcher = new URLFetcher(
|
| - url_to_fetch.url, URLFetcher::URL_FETCH, this);
|
| + url_to_fetch.url, URLFetcher::URL_FETCH, this, kBufferSize);
|
| if (url_to_fetch.existing_response_info.get() &&
|
| group_->newest_complete_cache()) {
|
| AppCacheEntry* existing_entry =
|
| @@ -1426,8 +1138,8 @@ void AppCacheUpdateJob::FetchMasterEntries() {
|
| }
|
| }
|
| } else {
|
| - URLFetcher* fetcher = new URLFetcher(
|
| - url, URLFetcher::MASTER_ENTRY_FETCH, this);
|
| + URLFetcher* fetcher = new URLFetcher(url, URLFetcher::MASTER_ENTRY_FETCH,
|
| + this, kBufferSize);
|
| fetcher->Start();
|
| master_entry_fetches_.insert(PendingUrlFetches::value_type(url, fetcher));
|
| }
|
|
|