/*
 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
 * Copyright (C) 2013, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "core/loader/DocumentThreadableLoader.h"

#include <memory>
#include "core/dom/Document.h"
#include "core/dom/TaskRunnerHelper.h"
#include "core/frame/FrameConsole.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/LocalFrameClient.h"
#include "core/frame/WebFeature.h"
#include "core/inspector/ConsoleMessage.h"
#include "core/inspector/InspectorNetworkAgent.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "core/loader/BaseFetchContext.h"
#include "core/loader/DocumentThreadableLoaderClient.h"
#include "core/loader/FrameLoader.h"
#include "core/loader/ThreadableLoaderClient.h"
#include "core/loader/ThreadableLoadingContext.h"
#include "core/probe/CoreProbes.h"
#include "platform/SharedBuffer.h"
#include "platform/exported/WrappedResourceRequest.h"
#include "platform/loader/fetch/FetchParameters.h"
#include "platform/loader/fetch/FetchUtils.h"
#include "platform/loader/fetch/Resource.h"
#include "platform/loader/fetch/ResourceFetcher.h"
#include "platform/loader/fetch/ResourceLoaderOptions.h"
#include "platform/loader/fetch/ResourceRequest.h"
#include "platform/weborigin/SchemeRegistry.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "platform/weborigin/SecurityPolicy.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/PtrUtil.h"
#include "platform/wtf/WeakPtr.h"
#include "public/platform/Platform.h"
#include "public/platform/WebCORS.h"
#include "public/platform/WebCORSPreflightResultCache.h"
#include "public/platform/WebSecurityOrigin.h"
#include "public/platform/WebURLRequest.h"
#include "services/network/public/interfaces/fetch_api.mojom-blink.h"

namespace blink {

namespace {

class EmptyDataHandle final : public WebDataConsumerHandle {
 private:
  class EmptyDataReader final : public WebDataConsumerHandle::Reader {
   public:
    explicit EmptyDataReader(WebDataConsumerHandle::Client* client)
        : factory_(this) {
      Platform::Current()->CurrentThread()->GetWebTaskRunner()->PostTask(
          BLINK_FROM_HERE,
          WTF::Bind(&EmptyDataReader::Notify, factory_.CreateWeakPtr(),
                    WTF::Unretained(client)));
    }

   private:
    Result BeginRead(const void** buffer,
                     WebDataConsumerHandle::Flags,
                     size_t* available) override {
      *available = 0;
      *buffer = nullptr;
      return kDone;
    }
    Result EndRead(size_t) override {
      return WebDataConsumerHandle::kUnexpectedError;
    }
    void Notify(WebDataConsumerHandle::Client* client) {
      client->DidGetReadable();
    }
    WeakPtrFactory<EmptyDataReader> factory_;
  };

  std::unique_ptr<Reader> ObtainReader(Client* client) override {
    return WTF::MakeUnique<EmptyDataReader>(client);
  }
  const char* DebugName() const override { return "EmptyDataHandle"; }
};

}  // namespace

// Max number of CORS redirects handled in DocumentThreadableLoader. Same number
// as net/url_request/url_request.cc, and same number as
// https://fetch.spec.whatwg.org/#concept-http-fetch, Step 4.
// FIXME: currently the number of redirects is counted and limited here and in
// net/url_request/url_request.cc separately.
static const int kMaxCORSRedirects = 20;

void DocumentThreadableLoader::LoadResourceSynchronously(
    Document& document,
    const ResourceRequest& request,
    ThreadableLoaderClient& client,
    const ThreadableLoaderOptions& options,
    const ResourceLoaderOptions& resource_loader_options) {
  (new DocumentThreadableLoader(*ThreadableLoadingContext::Create(document),
                                &client, kLoadSynchronously, options,
                                resource_loader_options))
      ->Start(request);
}

DocumentThreadableLoader* DocumentThreadableLoader::Create(
    ThreadableLoadingContext& loading_context,
    ThreadableLoaderClient* client,
    const ThreadableLoaderOptions& options,
    const ResourceLoaderOptions& resource_loader_options) {
  return new DocumentThreadableLoader(loading_context, client,
                                      kLoadAsynchronously, options,
                                      resource_loader_options);
}

DocumentThreadableLoader::DocumentThreadableLoader(
    ThreadableLoadingContext& loading_context,
    ThreadableLoaderClient* client,
    BlockingBehavior blocking_behavior,
    const ThreadableLoaderOptions& options,
    const ResourceLoaderOptions& resource_loader_options)
    : client_(client),
      loading_context_(&loading_context),
      options_(options),
      resource_loader_options_(resource_loader_options),
      out_of_blink_cors_(RuntimeEnabledFeatures::OutOfBlinkCORSEnabled()),
      cors_flag_(false),
      suborigin_force_credentials_(false),
      security_origin_(resource_loader_options_.security_origin),
      is_using_data_consumer_handle_(false),
      async_(blocking_behavior == kLoadAsynchronously),
      request_context_(WebURLRequest::kRequestContextUnspecified),
      fetch_request_mode_(WebURLRequest::kFetchRequestModeSameOrigin),
      fetch_credentials_mode_(WebURLRequest::kFetchCredentialsModeOmit),
      timeout_timer_(
          TaskRunnerHelper::Get(TaskType::kNetworking, GetExecutionContext()),
          this,
          &DocumentThreadableLoader::DidTimeout),
      request_started_seconds_(0.0),
      cors_redirect_limit_(0),
      redirect_mode_(WebURLRequest::kFetchRedirectModeFollow),
      override_referrer_(false) {
  DCHECK(client);
}

void DocumentThreadableLoader::Start(const ResourceRequest& request) {
  if (out_of_blink_cors_)
    StartOutOfBlinkCORS(request);
  else
    StartBlinkCORS(request);
}

void DocumentThreadableLoader::StartOutOfBlinkCORS(
    const ResourceRequest& request) {
  DCHECK(out_of_blink_cors_);

  // TODO(hintzed) replace this delegation with an implementation that does not
  // perform CORS checks but relies on CORSURLLoader for CORS
  // (https://crbug.com/736308).
  StartBlinkCORS(request);
}

void DocumentThreadableLoader::DispatchInitialRequestOutOfBlinkCORS(
    ResourceRequest& request) {
  DCHECK(out_of_blink_cors_);

  // TODO(hintzed) replace this delegation with an implementation that does not
  // perform CORS checks but relies on CORSURLLoader for CORS
  // (https://crbug.com/736308).
  DispatchInitialRequestBlinkCORS(request);
}

void DocumentThreadableLoader::HandleResponseOutOfBlinkCORS(
    unsigned long identifier,
    WebURLRequest::FetchRequestMode request_mode,
    WebURLRequest::FetchCredentialsMode credentials_mode,
    const ResourceResponse& response,
    std::unique_ptr<WebDataConsumerHandle> handle) {
  // TODO(hintzed) replace this delegation with an implementation that does not
  // perform CORS checks but relies on CORSURLLoader for CORS
  // (https://crbug.com/736308).
  HandleResponseBlinkCORS(identifier, request_mode, credentials_mode, response,
                          std::move(handle));
}

bool DocumentThreadableLoader::RedirectReceivedOutOfBlinkCORS(
    Resource* resource,
    const ResourceRequest& new_request,
    const ResourceResponse& redirect_response) {
  DCHECK(out_of_blink_cors_);

  // TODO(hintzed) replace this delegation with an implementation that does not
  // perform CORS checks but relies on CORSURLLoader for CORS
  // (https://crbug.com/736308).
  return RedirectReceivedBlinkCORS(resource, new_request, redirect_response);
}

void DocumentThreadableLoader::MakeCrossOriginAccessRequestOutOfBlinkCORS(
    const ResourceRequest& request) {
  DCHECK(out_of_blink_cors_);

  // TODO(hintzed) replace this delegation with an implementation that does not
  // perform CORS checks but relies on CORSURLLoader for CORS
  // (https://crbug.com/736308).
  MakeCrossOriginAccessRequestBlinkCORS(request);
}

void DocumentThreadableLoader::StartBlinkCORS(const ResourceRequest& request) {
  // Setting an outgoing referer is only supported in the async code path.
  DCHECK(async_ || request.HttpReferrer().IsEmpty());

  bool cors_enabled =
      WebCORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode());

  // kPreventPreflight can be used only when the CORS is enabled.
  DCHECK(options_.preflight_policy == kConsiderPreflight || cors_enabled);

  if (cors_enabled) {
    cors_redirect_limit_ = kMaxCORSRedirects;
  }

  request_context_ = request.GetRequestContext();
  fetch_request_mode_ = request.GetFetchRequestMode();
  fetch_credentials_mode_ = request.GetFetchCredentialsMode();
  redirect_mode_ = request.GetFetchRedirectMode();

  if (request.GetFetchRequestMode() == WebURLRequest::kFetchRequestModeNoCORS) {
    SECURITY_CHECK(WebCORS::IsNoCORSAllowedContext(
        request_context_, request.GetServiceWorkerMode()));
  } else {
    cors_flag_ = !GetSecurityOrigin()->CanRequestNoSuborigin(request.Url());
  }

  // Per https://w3c.github.io/webappsec-suborigins/#security-model-opt-outs,
  // credentials are forced when credentials mode is "same-origin", the
  // 'unsafe-credentials' option is set, and the request's physical origin is
  // the same as the URL's.

  suborigin_force_credentials_ =
      GetSecurityOrigin()->HasSuboriginAndShouldAllowCredentialsFor(
          request.Url());

  // The CORS flag variable is not yet used at the step in the spec that
  // corresponds to this line, but divert |cors_flag_| here for convenience.
  if (cors_flag_ && request.GetFetchRequestMode() ==
                        WebURLRequest::kFetchRequestModeSameOrigin) {
    probe::documentThreadableLoaderFailedToStartLoadingForClient(
        GetExecutionContext(), client_);
    ThreadableLoaderClient* client = client_;
    Clear();
    ResourceError error = ResourceError::CancelledDueToAccessCheckError(
        request.Url(), ResourceRequestBlockedReason::kOther,
        "Cross origin requests are not supported.");
    const String message = "Failed to load " + error.FailingURL() + ": " +
                           error.LocalizedDescription();
    GetExecutionContext()->AddConsoleMessage(
        ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message));
    client->DidFail(error);
    return;
  }

  request_started_seconds_ = MonotonicallyIncreasingTime();

  // Save any headers on the request here. If this request redirects
  // cross-origin, we cancel the old request create a new one, and copy these
  // headers.
  request_headers_ = request.HttpHeaderFields();

  ResourceRequest new_request(request);

  // Set the service worker mode to none if "bypass for network" in DevTools is
  // enabled.
  bool should_bypass_service_worker = false;
  probe::shouldBypassServiceWorker(GetExecutionContext(),
                                   &should_bypass_service_worker);
  if (should_bypass_service_worker)
    new_request.SetServiceWorkerMode(WebURLRequest::ServiceWorkerMode::kNone);

  // Process the CORS protocol inside the DocumentThreadableLoader for the
  // following cases:
  //
  // - When the request is sync or the protocol is unsupported since we can
  //   assume that any SW is skipped for such requests by content/ code.
  // - When the ServiceWorkerMode is not kAll, the local SW will be skipped.
  //   The request can still be intercepted by a foreign SW, but we cannot know
  //   whether such a foreign fetch interception happens or not at this point.
  // - If we're not yet controlled by a local SW, then we're sure that this
  //   request won't be intercepted by a local SW. In case we end up with
  //   sending a CORS preflight request, the actual request to be sent later
  //   may be intercepted. This is taken care of in LoadPreflightRequest() by
  //   setting the ServiceWorkerMode to kNone.
  //
  // From the above analysis, you can see that the request can never be
  // intercepted by a local SW inside this if-block. It's because:
  // - the ServiceWorkerMode needs to be kAll, and
  // - we're controlled by a SW at this point
  // to allow a local SW to intercept the request. Even when the request gets
  // issued asnychronously after performing the CORS preflight, it doesn'g get
  // intercepted since LoadPreflightRequest() sets the flag to kNone in
  // advance.
  if (!async_ ||
      new_request.GetServiceWorkerMode() !=
          WebURLRequest::ServiceWorkerMode::kAll ||
      !SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers(
          new_request.Url().Protocol()) ||
      !loading_context_->GetResourceFetcher()->IsControlledByServiceWorker()) {
    DispatchInitialRequestBlinkCORS(new_request);
    return;
  }

  if (WebCORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode())) {
    // Save the request to fallback_request_for_service_worker to use when the
    // local SW doesn't handle (call respondWith()) a CORS enabled request.
    fallback_request_for_service_worker_ = ResourceRequest(request);

    // We still want to give a foreign SW if any a chance to handle the
    // request. So, only skip the controlling local SW for the fallback
    // request. This is currently safe because of http://crbug.com/604084. The
    // WasFallbackRequiredByServiceWorker() flag is never set when a foreign SW
    // handled a request.
    fallback_request_for_service_worker_.SetServiceWorkerMode(
        WebURLRequest::ServiceWorkerMode::kForeign);
  }

  LoadRequest(new_request, resource_loader_options_);
}

void DocumentThreadableLoader::DispatchInitialRequest(
    ResourceRequest& request) {
  if (out_of_blink_cors_)
    DispatchInitialRequestOutOfBlinkCORS(request);
  else
    DispatchInitialRequestBlinkCORS(request);
}

void DocumentThreadableLoader::DispatchInitialRequestBlinkCORS(
    ResourceRequest& request) {
  if (!request.IsExternalRequest() && !cors_flag_) {
    LoadRequest(request, resource_loader_options_);
    return;
  }

  DCHECK(WebCORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) ||
         request.IsExternalRequest());

  MakeCrossOriginAccessRequest(request);
}

void DocumentThreadableLoader::PrepareCrossOriginRequest(
    ResourceRequest& request) const {
  if (GetSecurityOrigin())
    request.SetHTTPOrigin(GetSecurityOrigin());
  if (override_referrer_)
    request.SetHTTPReferrer(referrer_after_redirect_);
}

void DocumentThreadableLoader::LoadPreflightRequest(
    const ResourceRequest& actual_request,
    const ResourceLoaderOptions& actual_options) {
  WebURLRequest web_url_request = WebCORS::CreateAccessControlPreflightRequest(
      WrappedResourceRequest(actual_request));

  ResourceRequest& preflight_request =
      web_url_request.ToMutableResourceRequest();

  // TODO(tyoshino): Call prepareCrossOriginRequest(preflightRequest) to
  // also set the referrer header.
  if (GetSecurityOrigin())
    preflight_request.SetHTTPOrigin(GetSecurityOrigin());

  actual_request_ = actual_request;
  actual_options_ = actual_options;

  // Explicitly set the ServiceWorkerMode to None here. Although the page is
  // not controlled by a SW at this point, a new SW may be controlling the
  // page when this actual request gets sent later. We should not send the
  // actual request to the SW. See https://crbug.com/604583.
  actual_request_.SetServiceWorkerMode(WebURLRequest::ServiceWorkerMode::kNone);

  // Create a ResourceLoaderOptions for preflight.
  ResourceLoaderOptions preflight_options = actual_options;

  LoadRequest(preflight_request, preflight_options);
}

void DocumentThreadableLoader::MakeCrossOriginAccessRequest(
    const ResourceRequest& request) {
  if (out_of_blink_cors_)
    MakeCrossOriginAccessRequestOutOfBlinkCORS(request);
  else
    MakeCrossOriginAccessRequestBlinkCORS(request);
}

void DocumentThreadableLoader::MakeCrossOriginAccessRequestBlinkCORS(
    const ResourceRequest& request) {
  DCHECK(WebCORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) ||
         request.IsExternalRequest());
  DCHECK(client_);
  DCHECK(!GetResource());

  // Cross-origin requests are only allowed certain registered schemes. We would
  // catch this when checking response headers later, but there is no reason to
  // send a request, preflighted or not, that's guaranteed to be denied.
  if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled(
          request.Url().Protocol())) {
    probe::documentThreadableLoaderFailedToStartLoadingForClient(
        GetExecutionContext(), client_);
    DispatchDidFailAccessControlCheck(
        ResourceError::CancelledDueToAccessCheckError(
            request.Url(), ResourceRequestBlockedReason::kOther,
            String::Format(
                "Cross origin requests are only supported for "
                "protocol schemes: %s.",
                WebCORS::ListOfCORSEnabledURLSchemes().Ascii().c_str())));
    return;
  }

  // Non-secure origins may not make "external requests":
  // https://wicg.github.io/cors-rfc1918/#integration-fetch
  String error_message;
  if (!GetExecutionContext()->IsSecureContext(error_message) &&
      request.IsExternalRequest()) {
    DispatchDidFailAccessControlCheck(
        ResourceError::CancelledDueToAccessCheckError(
            request.Url(), ResourceRequestBlockedReason::kOrigin,
            "Requests to internal network resources are not allowed "
            "from non-secure contexts (see https://goo.gl/Y0ZkNV). "
            "This is an experimental restriction which is part of "
            "'https://mikewest.github.io/cors-rfc1918/'."));
    return;
  }

  ResourceRequest cross_origin_request(request);
  ResourceLoaderOptions cross_origin_options(resource_loader_options_);

  cross_origin_request.RemoveUserAndPassFromURL();

  // Enforce the CORS preflight for checking the Access-Control-Allow-External
  // header. The CORS preflight cache doesn't help for this purpose.
  if (request.IsExternalRequest()) {
    LoadPreflightRequest(cross_origin_request, cross_origin_options);
    return;
  }

  if (request.GetFetchRequestMode() !=
      WebURLRequest::kFetchRequestModeCORSWithForcedPreflight) {
    if (options_.preflight_policy == kPreventPreflight) {
      PrepareCrossOriginRequest(cross_origin_request);
      LoadRequest(cross_origin_request, cross_origin_options);
      return;
    }

    DCHECK_EQ(options_.preflight_policy, kConsiderPreflight);

    // We use ContainsOnlyCORSSafelistedOrForbiddenHeaders() here since
    // |request| may have been modified in the process of loading (not from
    // the user's input). For example, referrer. We need to accept them. For
    // security, we must reject forbidden headers/methods at the point we
    // accept user's input. Not here.
    if (WebCORS::IsCORSSafelistedMethod(request.HttpMethod()) &&
        WebCORS::ContainsOnlyCORSSafelistedOrForbiddenHeaders(
            request.HttpHeaderFields())) {
      PrepareCrossOriginRequest(cross_origin_request);
      LoadRequest(cross_origin_request, cross_origin_options);
      return;
    }
  }

  // Now, we need to check that the request passes the CORS preflight either by
  // issuing a CORS preflight or based on an entry in the CORS preflight cache.

  bool should_ignore_preflight_cache = false;
  // Prevent use of the CORS preflight cache when instructed by the DevTools
  // not to use caches.
  probe::shouldForceCORSPreflight(GetExecutionContext(),
                                  &should_ignore_preflight_cache);
  if (should_ignore_preflight_cache ||
      !WebCORSPreflightResultCache::Shared().CanSkipPreflight(
          GetSecurityOrigin()->ToString(), cross_origin_request.Url(),
          cross_origin_request.GetFetchCredentialsMode(),
          cross_origin_request.HttpMethod(),
          cross_origin_request.HttpHeaderFields())) {
    LoadPreflightRequest(cross_origin_request, cross_origin_options);
    return;
  }

  // We don't want any requests that could involve a CORS preflight to get
  // intercepted by a foreign SW, even if we have the result of the preflight
  // cached already. See https://crbug.com/674370.
  cross_origin_request.SetServiceWorkerMode(
      WebURLRequest::ServiceWorkerMode::kNone);

  PrepareCrossOriginRequest(cross_origin_request);
  LoadRequest(cross_origin_request, cross_origin_options);
}

DocumentThreadableLoader::~DocumentThreadableLoader() {
  CHECK(!client_);
  DCHECK(!resource_);
}

void DocumentThreadableLoader::OverrideTimeout(
    unsigned long timeout_milliseconds) {
  DCHECK(async_);

  // |m_requestStartedSeconds| == 0.0 indicates loading is already finished and
  // |m_timeoutTimer| is already stopped, and thus we do nothing for such cases.
  // See https://crbug.com/551663 for details.
  if (request_started_seconds_ <= 0.0)
    return;

  timeout_timer_.Stop();
  // At the time of this method's implementation, it is only ever called by
  // XMLHttpRequest, when the timeout attribute is set after sending the
  // request.
  //
  // The XHR request says to resolve the time relative to when the request
  // was initially sent, however other uses of this method may need to
  // behave differently, in which case this should be re-arranged somehow.
  if (timeout_milliseconds) {
    double elapsed_time =
        MonotonicallyIncreasingTime() - request_started_seconds_;
    double next_fire = timeout_milliseconds / 1000.0;
    double resolved_time = std::max(next_fire - elapsed_time, 0.0);
    timeout_timer_.StartOneShot(resolved_time, BLINK_FROM_HERE);
  }
}

void DocumentThreadableLoader::Cancel() {
  // Cancel can re-enter, and therefore |resource()| might be null here as a
  // result.
  if (!client_ || !GetResource()) {
    Clear();
    return;
  }

  DispatchDidFail(ResourceError::CancelledError(GetResource()->Url()));
}

void DocumentThreadableLoader::Detach() {
  Resource* resource = GetResource();
  if (resource)
    resource->SetDetachable();
  Clear();
}

void DocumentThreadableLoader::SetDefersLoading(bool value) {
  if (GetResource())
    GetResource()->SetDefersLoading(value);
}

void DocumentThreadableLoader::Clear() {
  client_ = nullptr;
  timeout_timer_.Stop();
  request_started_seconds_ = 0.0;
  ClearResource();
}

bool DocumentThreadableLoader::RedirectReceived(
    Resource* resource,
    const ResourceRequest& new_request,
    const ResourceResponse& redirect_response) {
  if (out_of_blink_cors_) {
    return RedirectReceivedOutOfBlinkCORS(resource, new_request,
                                          redirect_response);
  } else {
    return RedirectReceivedBlinkCORS(resource, new_request, redirect_response);
  }
}

// In this method, we can clear |request| to tell content::WebURLLoaderImpl of
// Chromium not to follow the redirect. This works only when this method is
// called by RawResource::willSendRequest(). If called by
// RawResource::didAddClient(), clearing |request| won't be propagated to
// content::WebURLLoaderImpl. So, this loader must also get detached from the
// resource by calling clearResource().
bool DocumentThreadableLoader::RedirectReceivedBlinkCORS(
    Resource* resource,
    const ResourceRequest& new_request,
    const ResourceResponse& redirect_response) {
  DCHECK(client_);
  DCHECK_EQ(resource, this->GetResource());
  DCHECK(async_);

  suborigin_force_credentials_ = false;

  checker_.RedirectReceived();

  const KURL& new_url = new_request.Url();
  const KURL& original_url = redirect_response.Url();

  if (!actual_request_.IsNull()) {
    ReportResponseReceived(resource->Identifier(), redirect_response);

    HandlePreflightFailure(original_url,
                           "Response for preflight is invalid (redirect)");

    return false;
  }

  if (redirect_mode_ == WebURLRequest::kFetchRedirectModeManual) {
    // We use |redirect_mode_| to check the original redirect mode.
    // |new_request| is a new request for redirect. So we don't set the
    // redirect mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
    DCHECK(new_request.UseStreamOnResponse());
    // There is no need to read the body of redirect response because there is
    // no way to read the body of opaque-redirect filtered response's internal
    // response.
    // TODO(horo): If we support any API which expose the internal body, we will
    // have to read the body. And also HTTPCache changes will be needed because
    // it doesn't store the body of redirect responses.
    ResponseReceived(resource, redirect_response,
                     WTF::MakeUnique<EmptyDataHandle>());

    if (client_) {
      DCHECK(actual_request_.IsNull());
      NotifyFinished(resource);
    }

    return false;
  }

  if (redirect_mode_ == WebURLRequest::kFetchRedirectModeError) {
    ThreadableLoaderClient* client = client_;
    Clear();
    client->DidFailRedirectCheck();

    return false;
  }

  // Allow same origin requests to continue after allowing clients to audit the
  // redirect.
  if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) {
    client_->DidReceiveRedirectTo(new_url);
    if (client_->IsDocumentThreadableLoaderClient()) {
      return static_cast<DocumentThreadableLoaderClient*>(client_)
          ->WillFollowRedirect(new_url, redirect_response);
    }
    return true;
  }

  if (cors_redirect_limit_ <= 0) {
    ThreadableLoaderClient* client = client_;
    Clear();
    client->DidFailRedirectCheck();
    return false;
  }

  --cors_redirect_limit_;

  probe::didReceiveCORSRedirectResponse(
      GetExecutionContext(), resource->Identifier(),
      GetDocument() && GetDocument()->GetFrame()
          ? GetDocument()->GetFrame()->Loader().GetDocumentLoader()
          : nullptr,
      redirect_response, resource);

  WebCORS::RedirectStatus redirect_status =
      WebCORS::CheckRedirectLocation(new_url);
  if (redirect_status != WebCORS::RedirectStatus::kRedirectSuccess) {
    StringBuilder builder;
    builder.Append("Redirect from '");
    builder.Append(original_url.GetString());
    builder.Append("' has been blocked by CORS policy: ");
    builder.Append(WebCORS::RedirectErrorString(redirect_status, new_url));
    DispatchDidFailAccessControlCheck(
        ResourceError::CancelledDueToAccessCheckError(
            original_url, ResourceRequestBlockedReason::kOther,
            builder.ToString()));
    return false;
  }

  if (cors_flag_) {
    // The redirect response must pass the access control check if the CORS
    // flag is set.
    WebCORS::AccessStatus cors_status = WebCORS::CheckAccess(
        redirect_response.Url(), redirect_response.HttpStatusCode(),
        redirect_response.HttpHeaderFields(),
        new_request.GetFetchCredentialsMode(),
        WebSecurityOrigin(GetSecurityOrigin()));
    if (cors_status != WebCORS::AccessStatus::kAccessAllowed) {
      StringBuilder builder;
      builder.Append("Redirect from '");
      builder.Append(original_url.GetString());
      builder.Append("' to '");
      builder.Append(new_url.GetString());
      builder.Append("' has been blocked by CORS policy: ");
      builder.Append(WebCORS::AccessControlErrorString(
          cors_status, redirect_response.HttpStatusCode(),
          redirect_response.HttpHeaderFields(),
          WebSecurityOrigin(GetSecurityOrigin()), request_context_));
      DispatchDidFailAccessControlCheck(
          ResourceError::CancelledDueToAccessCheckError(
              original_url, ResourceRequestBlockedReason::kOther,
              builder.ToString()));
      return false;
    }
  }

  client_->DidReceiveRedirectTo(new_url);

  // FIXME: consider combining this with CORS redirect handling performed by
  // CrossOriginAccessControl::handleRedirect().
  ClearResource();

  // If
  // - CORS flag is set, and
  // - the origin of the redirect target URL is not same origin with the origin
  //   of the current request's URL
  // set the source origin to a unique opaque origin.
  //
  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
  if (cors_flag_) {
    scoped_refptr<SecurityOrigin> original_origin =
        SecurityOrigin::Create(original_url);
    scoped_refptr<SecurityOrigin> new_origin = SecurityOrigin::Create(new_url);
    if (!original_origin->IsSameSchemeHostPort(new_origin.get()))
      security_origin_ = SecurityOrigin::CreateUnique();
  }

  // Set |cors_flag_| so that further logic (corresponds to the main fetch in
  // the spec) will be performed with CORS flag set.
  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
  cors_flag_ = true;

  // Save the referrer to use when following the redirect.
  override_referrer_ = true;
  referrer_after_redirect_ =
      Referrer(new_request.HttpReferrer(), new_request.GetReferrerPolicy());

  ResourceRequest cross_origin_request(new_request);

  // Remove any headers that may have been added by the network layer that cause
  // access control to fail.
  cross_origin_request.ClearHTTPReferrer();
  cross_origin_request.ClearHTTPOrigin();
  cross_origin_request.ClearHTTPUserAgent();
  // Add any request headers which we previously saved from the
  // original request.
  for (const auto& header : request_headers_)
    cross_origin_request.SetHTTPHeaderField(header.key, header.value);
  MakeCrossOriginAccessRequest(cross_origin_request);

  return false;
}

void DocumentThreadableLoader::RedirectBlocked() {
  checker_.RedirectBlocked();

  // Tells the client that a redirect was received but not followed (for an
  // unknown reason).
  ThreadableLoaderClient* client = client_;
  Clear();
  client->DidFailRedirectCheck();
}

void DocumentThreadableLoader::DataSent(
    Resource* resource,
    unsigned long long bytes_sent,
    unsigned long long total_bytes_to_be_sent) {
  DCHECK(client_);
  DCHECK_EQ(resource, this->GetResource());
  DCHECK(async_);

  checker_.DataSent();
  client_->DidSendData(bytes_sent, total_bytes_to_be_sent);
}

void DocumentThreadableLoader::DataDownloaded(Resource* resource,
                                              int data_length) {
  DCHECK(client_);
  DCHECK_EQ(resource, this->GetResource());
  DCHECK(actual_request_.IsNull());
  DCHECK(async_);

  checker_.DataDownloaded();
  client_->DidDownloadData(data_length);
}

void DocumentThreadableLoader::DidReceiveResourceTiming(
    Resource* resource,
    const ResourceTimingInfo& info) {
  DCHECK(client_);
  DCHECK_EQ(resource, this->GetResource());
  DCHECK(async_);

  client_->DidReceiveResourceTiming(info);
}

void DocumentThreadableLoader::ResponseReceived(
    Resource* resource,
    const ResourceResponse& response,
    std::unique_ptr<WebDataConsumerHandle> handle) {
  DCHECK_EQ(resource, this->GetResource());
  DCHECK(async_);

  checker_.ResponseReceived();

  if (handle)
    is_using_data_consumer_handle_ = true;

  HandleResponse(resource->Identifier(), fetch_request_mode_,
                 fetch_credentials_mode_, response, std::move(handle));
}

void DocumentThreadableLoader::HandlePreflightResponse(
    const ResourceResponse& response) {

  WebCORS::AccessStatus cors_status = WebCORS::CheckAccess(
      response.Url(), response.HttpStatusCode(), response.HttpHeaderFields(),
      actual_request_.GetFetchCredentialsMode(),
      WebSecurityOrigin(GetSecurityOrigin()));
  if (cors_status != WebCORS::AccessStatus::kAccessAllowed) {
    StringBuilder builder;
    builder.Append(
        "Response to preflight request doesn't pass access "
        "control check: ");
    builder.Append(WebCORS::AccessControlErrorString(
        cors_status, response.HttpStatusCode(), response.HttpHeaderFields(),
        WebSecurityOrigin(GetSecurityOrigin()), request_context_));
    HandlePreflightFailure(response.Url(), builder.ToString());
    return;
  }

  WebCORS::PreflightStatus preflight_status =
      WebCORS::CheckPreflight(response.HttpStatusCode());
  if (preflight_status != WebCORS::PreflightStatus::kPreflightSuccess) {
    HandlePreflightFailure(response.Url(),
                           WebCORS::PreflightErrorString(
                               preflight_status, response.HttpHeaderFields(),
                               response.HttpStatusCode()));
    return;
  }

  if (actual_request_.IsExternalRequest()) {
    WebCORS::PreflightStatus external_preflight_status =
        WebCORS::CheckExternalPreflight(response.HttpHeaderFields());
    if (external_preflight_status !=
        WebCORS::PreflightStatus::kPreflightSuccess) {
      HandlePreflightFailure(response.Url(), WebCORS::PreflightErrorString(
                                                 external_preflight_status,
                                                 response.HttpHeaderFields(),
                                                 response.HttpStatusCode()));
      return;
    }
  }

  WebString access_control_error_description;
  std::unique_ptr<WebCORSPreflightResultCacheItem> preflight_result =
      WebCORSPreflightResultCacheItem::Create(
          actual_request_.GetFetchCredentialsMode(),
          response.HttpHeaderFields(), access_control_error_description);

  if (!preflight_result ||
      !preflight_result->AllowsCrossOriginMethod(
          actual_request_.HttpMethod(), access_control_error_description) ||
      !preflight_result->AllowsCrossOriginHeaders(
          actual_request_.HttpHeaderFields(),
          access_control_error_description)) {
    HandlePreflightFailure(response.Url(), access_control_error_description);
    return;
  }

  WebCORSPreflightResultCache::Shared().AppendEntry(
      GetSecurityOrigin()->ToString(), actual_request_.Url(),
      std::move(preflight_result));
}

void DocumentThreadableLoader::ReportResponseReceived(
    unsigned long identifier,
    const ResourceResponse& response) {
  LocalFrame* frame = GetDocument() ? GetDocument()->GetFrame() : nullptr;
  if (!frame)
    return;
  DocumentLoader* loader = frame->Loader().GetDocumentLoader();
  probe::didReceiveResourceResponse(GetExecutionContext(), identifier, loader,
                                    response, GetResource());
  frame->Console().ReportResourceResponseReceived(loader, identifier, response);
}

void DocumentThreadableLoader::HandleResponse(
    unsigned long identifier,
    WebURLRequest::FetchRequestMode request_mode,
    WebURLRequest::FetchCredentialsMode credentials_mode,
    const ResourceResponse& response,
    std::unique_ptr<WebDataConsumerHandle> handle) {
  if (out_of_blink_cors_) {
    HandleResponseOutOfBlinkCORS(identifier, request_mode, credentials_mode,
                                 response, std::move(handle));
  } else {
    HandleResponseBlinkCORS(identifier, request_mode, credentials_mode,
                            response, std::move(handle));
  }
}

void DocumentThreadableLoader::HandleResponseBlinkCORS(
    unsigned long identifier,
    WebURLRequest::FetchRequestMode request_mode,
    WebURLRequest::FetchCredentialsMode credentials_mode,
    const ResourceResponse& response,
    std::unique_ptr<WebDataConsumerHandle> handle) {
  DCHECK(client_);

  if (!actual_request_.IsNull()) {
    ReportResponseReceived(identifier, response);
    HandlePreflightResponse(response);
    return;
  }

  if (response.WasFetchedViaServiceWorker()) {
    if (response.WasFetchedViaForeignFetch()) {
      loading_context_->GetFetchContext()->CountUsage(
          WebFeature::kForeignFetchInterception);
    }
    if (response.WasFallbackRequiredByServiceWorker()) {
      // At this point we must have m_fallbackRequestForServiceWorker. (For
      // SharedWorker the request won't be CORS or CORS-with-preflight,
      // therefore fallback-to-network is handled in the browser process when
      // the ServiceWorker does not call respondWith().)
      DCHECK(!fallback_request_for_service_worker_.IsNull());
      ReportResponseReceived(identifier, response);
      LoadFallbackRequestForServiceWorker();
      return;
    }

    // It's possible that we issue a fetch with request with non "no-cors"
    // mode but get an opaque filtered response if a service worker is involved.
    // We dispatch a CORS failure for the case.
    // TODO(yhirano): This is probably not spec conformant. Fix it after
    // https://github.com/w3c/preload/issues/100 is addressed.
    if (request_mode != WebURLRequest::kFetchRequestModeNoCORS &&
        response.ResponseTypeViaServiceWorker() ==
            network::mojom::FetchResponseType::kOpaque) {
      StringBuilder builder;
      builder.Append(WebCORS::AccessControlErrorString(
          WebCORS::AccessStatus::kInvalidResponse, response.HttpStatusCode(),
          response.HttpHeaderFields(), WebSecurityOrigin(GetSecurityOrigin()),
          request_context_));
      DispatchDidFailAccessControlCheck(
          ResourceError::CancelledDueToAccessCheckError(
              response.Url(), ResourceRequestBlockedReason::kOther,
              builder.ToString()));
      return;
    }

    fallback_request_for_service_worker_ = ResourceRequest();
    client_->DidReceiveResponse(identifier, response, std::move(handle));
    return;
  }

  // Even if the request met the conditions to get handled by a Service Worker
  // in the constructor of this class (and therefore
  // |m_fallbackRequestForServiceWorker| is set), the Service Worker may skip
  // processing the request. Only if the request is same origin, the skipped
  // response may come here (wasFetchedViaServiceWorker() returns false) since
  // such a request doesn't have to go through the CORS algorithm by calling
  // loadFallbackRequestForServiceWorker().
  // FIXME: We should use |m_sameOriginRequest| when we will support Suborigins
  // (crbug.com/336894) for Service Worker.
  DCHECK(fallback_request_for_service_worker_.IsNull() ||
         GetSecurityOrigin()->CanRequest(
             fallback_request_for_service_worker_.Url()));
  fallback_request_for_service_worker_ = ResourceRequest();

  if (WebCORS::IsCORSEnabledRequestMode(request_mode) && cors_flag_) {
    WebCORS::AccessStatus cors_status = WebCORS::CheckAccess(
        response.Url(), response.HttpStatusCode(), response.HttpHeaderFields(),
        credentials_mode, WebSecurityOrigin(GetSecurityOrigin()));
    if (cors_status != WebCORS::AccessStatus::kAccessAllowed) {
      ReportResponseReceived(identifier, response);
      DispatchDidFailAccessControlCheck(
          ResourceError::CancelledDueToAccessCheckError(
              response.Url(), ResourceRequestBlockedReason::kOther,
              WebCORS::AccessControlErrorString(
                  cors_status, response.HttpStatusCode(),
                  response.HttpHeaderFields(),
                  WebSecurityOrigin(GetSecurityOrigin()), request_context_)));
      return;
    }
  }

  client_->DidReceiveResponse(identifier, response, std::move(handle));
}

void DocumentThreadableLoader::SetSerializedCachedMetadata(Resource*,
                                                           const char* data,
                                                           size_t size) {
  checker_.SetSerializedCachedMetadata();

  if (!actual_request_.IsNull())
    return;
  client_->DidReceiveCachedMetadata(data, size);
}

void DocumentThreadableLoader::DataReceived(Resource* resource,
                                            const char* data,
                                            size_t data_length) {
  DCHECK_EQ(resource, this->GetResource());
  DCHECK(async_);

  checker_.DataReceived();

  if (is_using_data_consumer_handle_)
    return;

  // TODO(junov): Fix the ThreadableLoader ecosystem to use size_t. Until then,
  // we use safeCast to trap potential overflows.
  HandleReceivedData(data, SafeCast<unsigned>(data_length));
}

void DocumentThreadableLoader::HandleReceivedData(const char* data,
                                                  size_t data_length) {
  DCHECK(client_);

  // Preflight data should be invisible to clients.
  if (!actual_request_.IsNull())
    return;

  DCHECK(fallback_request_for_service_worker_.IsNull());

  client_->DidReceiveData(data, data_length);
}

void DocumentThreadableLoader::NotifyFinished(Resource* resource) {
  DCHECK(client_);
  DCHECK_EQ(resource, this->GetResource());
  DCHECK(async_);

  checker_.NotifyFinished(resource);

  if (resource->ErrorOccurred()) {
    DispatchDidFail(resource->GetResourceError());
  } else {
    HandleSuccessfulFinish(resource->Identifier(), resource->LoadFinishTime());
  }
}

void DocumentThreadableLoader::HandleSuccessfulFinish(unsigned long identifier,
                                                      double finish_time) {
  DCHECK(fallback_request_for_service_worker_.IsNull());

  if (!actual_request_.IsNull()) {
    DCHECK(actual_request_.IsExternalRequest() || cors_flag_);
    LoadActualRequest();
    return;
  }

  ThreadableLoaderClient* client = client_;
  // Protect the resource in |didFinishLoading| in order not to release the
  // downloaded file.
  Persistent<Resource> protect = GetResource();
  Clear();
  client->DidFinishLoading(identifier, finish_time);
}

void DocumentThreadableLoader::DidTimeout(TimerBase* timer) {
  DCHECK(async_);
  DCHECK_EQ(timer, &timeout_timer_);
  // clearResource() may be called in clear() and some other places. clear()
  // calls stop() on |m_timeoutTimer|. In the other places, the resource is set
  // again. If the creation fails, clear() is called. So, here, resource() is
  // always non-nullptr.
  DCHECK(GetResource());
  // When |m_client| is set to nullptr only in clear() where |m_timeoutTimer|
  // is stopped. So, |m_client| is always non-nullptr here.
  DCHECK(client_);

  DispatchDidFail(ResourceError::TimeoutError(GetResource()->Url()));
}

void DocumentThreadableLoader::LoadFallbackRequestForServiceWorker() {
  ClearResource();
  ResourceRequest fallback_request(fallback_request_for_service_worker_);
  fallback_request_for_service_worker_ = ResourceRequest();
  if (out_of_blink_cors_)
    DispatchInitialRequestOutOfBlinkCORS(fallback_request);
  else
    DispatchInitialRequestBlinkCORS(fallback_request);
}

void DocumentThreadableLoader::LoadActualRequest() {
  ResourceRequest actual_request = actual_request_;
  ResourceLoaderOptions actual_options = actual_options_;
  actual_request_ = ResourceRequest();
  actual_options_ = ResourceLoaderOptions();

  ClearResource();

  PrepareCrossOriginRequest(actual_request);
  LoadRequest(actual_request, actual_options);
}

void DocumentThreadableLoader::HandlePreflightFailure(
    const KURL& url,
    const String& error_description) {
  // Prevent handleSuccessfulFinish() from bypassing access check.
  actual_request_ = ResourceRequest();

  DispatchDidFailAccessControlCheck(
      ResourceError::CancelledDueToAccessCheckError(
          url, ResourceRequestBlockedReason::kOther, error_description));
}

void DocumentThreadableLoader::DispatchDidFailAccessControlCheck(
    const ResourceError& error) {
  const String message = "Failed to load " + error.FailingURL() + ": " +
                         error.LocalizedDescription();
  GetExecutionContext()->AddConsoleMessage(
      ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message));

  ThreadableLoaderClient* client = client_;
  Clear();
  client->DidFail(error);
}

void DocumentThreadableLoader::DispatchDidFail(const ResourceError& error) {
  ThreadableLoaderClient* client = client_;
  Clear();
  client->DidFail(error);
}

void DocumentThreadableLoader::LoadRequestAsync(
    const ResourceRequest& request,
    ResourceLoaderOptions resource_loader_options) {
  if (!actual_request_.IsNull())
    resource_loader_options.data_buffering_policy = kBufferData;

  // The timer can be active if this is the actual request of a
  // CORS-with-preflight request.
  if (options_.timeout_milliseconds > 0 && !timeout_timer_.IsActive()) {
    timeout_timer_.StartOneShot(options_.timeout_milliseconds / 1000.0,
                                BLINK_FROM_HERE);
  }

  FetchParameters new_params(request, resource_loader_options);
  if (request.GetFetchRequestMode() == WebURLRequest::kFetchRequestModeNoCORS)
    new_params.SetOriginRestriction(FetchParameters::kNoOriginRestriction);
  DCHECK(!GetResource());

  ResourceFetcher* fetcher = loading_context_->GetResourceFetcher();
  if (request.GetRequestContext() == WebURLRequest::kRequestContextVideo ||
      request.GetRequestContext() == WebURLRequest::kRequestContextAudio)
    SetResource(RawResource::FetchMedia(new_params, fetcher));
  else if (request.GetRequestContext() ==
           WebURLRequest::kRequestContextManifest)
    SetResource(RawResource::FetchManifest(new_params, fetcher));
  else
    SetResource(RawResource::Fetch(new_params, fetcher));

  if (!GetResource()) {
    probe::documentThreadableLoaderFailedToStartLoadingForClient(
        GetExecutionContext(), client_);
    ThreadableLoaderClient* client = client_;
    Clear();
    // setResource() might call notifyFinished() and thus clear()
    // synchronously, and in such cases ThreadableLoaderClient is already
    // notified and |client| is null.
    if (!client)
      return;
    String message =
        String("Failed to start loading ") + request.Url().GetString();
    GetExecutionContext()->AddConsoleMessage(
        ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message));
    client->DidFail(ResourceError::CancelledError(request.Url()));
    return;
  }

  if (GetResource()->IsLoading()) {
    unsigned long identifier = GetResource()->Identifier();
    probe::documentThreadableLoaderStartedLoadingForClient(
        GetExecutionContext(), identifier, client_);
  } else {
    probe::documentThreadableLoaderFailedToStartLoadingForClient(
        GetExecutionContext(), client_);
  }
}

void DocumentThreadableLoader::LoadRequestSync(
    const ResourceRequest& request,
    ResourceLoaderOptions resource_loader_options) {
  FetchParameters fetch_params(request, resource_loader_options);
  if (request.GetFetchRequestMode() == WebURLRequest::kFetchRequestModeNoCORS)
    fetch_params.SetOriginRestriction(FetchParameters::kNoOriginRestriction);
  Resource* resource = RawResource::FetchSynchronously(
      fetch_params, loading_context_->GetResourceFetcher());
  ResourceResponse response =
      resource ? resource->GetResponse() : ResourceResponse();
  unsigned long identifier = resource
                                 ? resource->Identifier()
                                 : std::numeric_limits<unsigned long>::max();
  ResourceError error =
      resource ? resource->GetResourceError() : ResourceError();

  probe::documentThreadableLoaderStartedLoadingForClient(GetExecutionContext(),
                                                         identifier, client_);
  ThreadableLoaderClient* client = client_;

  if (!resource) {
    client_ = nullptr;
    client->DidFail(error);
    return;
  }

  const KURL& request_url = request.Url();

  // No exception for file:/// resources, see <rdar://problem/4962298>. Also, if
  // we have an HTTP response, then it wasn't a network error in fact.
  if (!error.IsNull() && !request_url.IsLocalFile() &&
      response.HttpStatusCode() <= 0) {
    client_ = nullptr;
    client->DidFail(error);
    return;
  }

  // FIXME: A synchronous request does not tell us whether a redirect happened
  // or not, so we guess by comparing the request and response URLs. This isn't
  // a perfect test though, since a server can serve a redirect to the same URL
  // that was requested. Also comparing the request and response URLs as strings
  // will fail if the requestURL still has its credentials.
  if (request_url != response.Url() &&
      !IsAllowedRedirect(request.GetFetchRequestMode(), response.Url())) {
    client_ = nullptr;
    client->DidFailRedirectCheck();
    return;
  }

  HandleResponse(identifier, request.GetFetchRequestMode(),
                 request.GetFetchCredentialsMode(), response, nullptr);

  // HandleResponse() may detect an error. In such a case (check |m_client| as
  // it gets reset by clear() call), skip the rest.
  //
  // |this| is alive here since loadResourceSynchronously() keeps it alive until
  // the end of the function.
  if (!client_)
    return;

  if (scoped_refptr<const SharedBuffer> data = resource->ResourceBuffer()) {
    data->ForEachSegment([this](const char* segment, size_t segment_size,
                                size_t segment_offset) -> bool {
      HandleReceivedData(segment, segment_size);
      // The client may cancel this loader in handleReceivedData().
      return client_;
    });
  }

  // The client may cancel this loader in handleReceivedData(). In such a case,
  // skip the rest.
  if (!client_)
    return;

  HandleSuccessfulFinish(identifier, 0.0);
}

void DocumentThreadableLoader::LoadRequest(
    ResourceRequest& request,
    ResourceLoaderOptions resource_loader_options) {
  resource_loader_options.cors_handling_by_resource_fetcher =
      kDisableCORSHandlingByResourceFetcher;

  bool allow_stored_credentials = false;
  switch (request.GetFetchCredentialsMode()) {
    case WebURLRequest::kFetchCredentialsModeOmit:
      break;
    case WebURLRequest::kFetchCredentialsModeSameOrigin:
      // TODO(tyoshino): It's wrong to use |cors_flag| here. Fix it to use the
      // response tainting.
      //
      // TODO(tyoshino): The credentials mode must work even when the "no-cors"
      // mode is in use. See the following issues:
      // - https://github.com/whatwg/fetch/issues/130
      // - https://github.com/whatwg/fetch/issues/169
      allow_stored_credentials = !cors_flag_ || suborigin_force_credentials_;
      break;
    case WebURLRequest::kFetchCredentialsModeInclude:
    case WebURLRequest::kFetchCredentialsModePassword:
      allow_stored_credentials = true;
      break;
  }
  request.SetAllowStoredCredentials(allow_stored_credentials);

  resource_loader_options.security_origin = security_origin_;
  if (async_)
    LoadRequestAsync(request, resource_loader_options);
  else
    LoadRequestSync(request, resource_loader_options);
}

bool DocumentThreadableLoader::IsAllowedRedirect(
    WebURLRequest::FetchRequestMode fetch_request_mode,
    const KURL& url) const {
  if (fetch_request_mode == WebURLRequest::kFetchRequestModeNoCORS)
    return true;

  return !cors_flag_ && GetSecurityOrigin()->CanRequest(url);
}

SecurityOrigin* DocumentThreadableLoader::GetSecurityOrigin() const {
  return security_origin_
             ? security_origin_.get()
             : loading_context_->GetFetchContext()->GetSecurityOrigin();
}

Document* DocumentThreadableLoader::GetDocument() const {
  ExecutionContext* context = GetExecutionContext();
  if (context->IsDocument())
    return ToDocument(context);
  return nullptr;
}

ExecutionContext* DocumentThreadableLoader::GetExecutionContext() const {
  DCHECK(loading_context_);
  return loading_context_->GetExecutionContext();
}

void DocumentThreadableLoader::Trace(blink::Visitor* visitor) {
  visitor->Trace(resource_);
  visitor->Trace(loading_context_);
  ThreadableLoader::Trace(visitor);
  RawResourceClient::Trace(visitor);
}

}  // namespace blink
