void DocumentThreadableLoader::handlePreflightResponse(const ResourceResponse& response)
{
    String accessControlErrorDescription;

    if (!passesAccessControlCheck(response, effectiveAllowCredentials(), getSecurityOrigin(), accessControlErrorDescription, m_requestContext)) {
        handlePreflightFailure(response.url().getString(), "Response to preflight request doesn't pass access control check: " + accessControlErrorDescription);
        // |this| may be dead here in async mode.
        return;
    }

    if (!passesPreflightStatusCheck(response, accessControlErrorDescription)) {
        handlePreflightFailure(response.url().getString(), accessControlErrorDescription);
        // |this| may be dead here in async mode.
        return;
    }

    if (m_actualRequest.isExternalRequest() && !passesExternalPreflightCheck(response, accessControlErrorDescription)) {
        handlePreflightFailure(response.url().getString(), accessControlErrorDescription);
        // |this| may be dead here in async mode.
        return;
    }

    std::unique_ptr<CrossOriginPreflightResultCacheItem> preflightResult = wrapUnique(new CrossOriginPreflightResultCacheItem(effectiveAllowCredentials()));
    if (!preflightResult->parse(response, accessControlErrorDescription)
        || !preflightResult->allowsCrossOriginMethod(m_actualRequest.httpMethod(), accessControlErrorDescription)
        || !preflightResult->allowsCrossOriginHeaders(m_actualRequest.httpHeaderFields(), accessControlErrorDescription)) {
        handlePreflightFailure(response.url().getString(), accessControlErrorDescription);
        // |this| may be dead here in async mode.
        return;
    }

    CrossOriginPreflightResultCache::shared().appendEntry(getSecurityOrigin()->toString(), m_actualRequest.url(), std::move(preflightResult));
}
Exemple #2
0
void DocumentThreadableLoader::prepareCrossOriginRequest(
    ResourceRequest& request) {
  if (getSecurityOrigin())
    request.setHTTPOrigin(getSecurityOrigin());
  if (m_overrideReferrer)
    request.setHTTPReferrer(m_referrerAfterRedirect);
}
Exemple #3
0
void SecurityContext::applySandboxFlags(SandboxFlags mask) {
  m_sandboxFlags |= mask;

  if (isSandboxed(SandboxOrigin) && getSecurityOrigin() &&
      !getSecurityOrigin()->isUnique()) {
    setSecurityOrigin(SecurityOrigin::createUnique());
    didUpdateSecurityOrigin();
  }
}
void DocumentThreadableLoader::handleResponse(unsigned long identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle)
{
    ASSERT(m_client);

    if (!m_actualRequest.isNull()) {
        reportResponseReceived(identifier, response);
        handlePreflightResponse(response);
        // |this| may be dead here in async mode.
        return;
    }

    if (response.wasFetchedViaServiceWorker()) {
        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().)
            ASSERT(!m_fallbackRequestForServiceWorker.isNull());
            reportResponseReceived(identifier, response);
            loadFallbackRequestForServiceWorker();
            // |this| may be dead here in async mode.
            return;
        }
        m_fallbackRequestForServiceWorker = ResourceRequest();
        m_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.
    ASSERT(m_fallbackRequestForServiceWorker.isNull() || getSecurityOrigin()->canRequest(m_fallbackRequestForServiceWorker.url()));
    m_fallbackRequestForServiceWorker = ResourceRequest();

    if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessControl) {
        String accessControlErrorDescription;
        if (!passesAccessControlCheck(response, effectiveAllowCredentials(), getSecurityOrigin(), accessControlErrorDescription, m_requestContext)) {
            reportResponseReceived(identifier, response);

            ThreadableLoaderClient* client = m_client;
            clear();
            client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, response.url().getString(), accessControlErrorDescription));
            // |this| may be dead here.
            return;
        }
    }

    m_client->didReceiveResponse(identifier, response, std::move(handle));
}
bool WorkerGlobalScope::isSecureContext(String& errorMessage, const SecureContextCheck privilegeContextCheck) const
{
    // Until there are APIs that are available in workers and that
    // require a privileged context test that checks ancestors, just do
    // a simple check here. Once we have a need for a real
    // |isSecureContext| check here, we can check the responsible
    // document for a privileged context at worker creation time, pass
    // it in via WorkerThreadStartupData, and check it here.
    if (getSecurityOrigin()->isPotentiallyTrustworthy())
        return true;
    errorMessage = getSecurityOrigin()->isPotentiallyTrustworthyErrorMessage();
    return false;
}
KURL DOMFileSystemBase::createFileSystemURL(const String& fullPath) const {
  ASSERT(DOMFilePath::isAbsolute(fullPath));

  if (type() == FileSystemTypeExternal) {
    // For external filesystem originString could be different from what we have
    // in m_filesystemRootURL.
    StringBuilder result;
    result.append("filesystem:");
    result.append(getSecurityOrigin()->toString());
    result.append('/');
    result.append(externalPathPrefix);
    result.append(m_filesystemRootURL.path());
    // Remove the extra leading slash.
    result.append(encodeWithURLEscapeSequences(fullPath.substring(1)));
    return KURL(ParsedURLString, result.toString());
  }

  // For regular types we can just append the entry's fullPath to the
  // m_filesystemRootURL that should look like
  // 'filesystem:<origin>/<typePrefix>'.
  ASSERT(!m_filesystemRootURL.isEmpty());
  KURL url = m_filesystemRootURL;
  // Remove the extra leading slash.
  url.setPath(url.path() + encodeWithURLEscapeSequences(fullPath.substring(1)));
  return url;
}
WorkerGlobalScope::WorkerGlobalScope(
    const KURL& url,
    const String& userAgent,
    WorkerThread* thread,
    double timeOrigin,
    std::unique_ptr<SecurityOrigin::PrivilegeData> starterOriginPrivilageData,
    WorkerClients* workerClients)
    : ActiveScriptWrappable(this),
      m_url(url),
      m_userAgent(userAgent),
      m_v8CacheOptions(V8CacheOptionsDefault),
      m_deprecationWarningBits(UseCounter::NumberOfFeatures),
      m_scriptController(
          WorkerOrWorkletScriptController::create(this, thread->isolate())),
      m_thread(thread),
      m_closing(false),
      m_eventQueue(WorkerEventQueue::create(this)),
      m_workerClients(workerClients),
      m_timers(Platform::current()
                   ->currentThread()
                   ->scheduler()
                   ->timerTaskRunner()
                   ->clone()),
      m_timeOrigin(timeOrigin),
      m_lastPendingErrorEventId(0) {
  InstanceCounters::incrementCounter(
      InstanceCounters::WorkerGlobalScopeCounter);
  setSecurityOrigin(SecurityOrigin::create(url));
  if (starterOriginPrivilageData)
    getSecurityOrigin()->transferPrivilegesFrom(
        std::move(starterOriginPrivilageData));

  if (m_workerClients)
    m_workerClients->reattachThread();
}
bool DocumentThreadableLoader::isAllowedRedirect(const KURL& url) const
{
    if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests)
        return true;

    return m_sameOriginRequest && getSecurityOrigin()->canRequest(url);
}
Exemple #9
0
bool ExecutionContext::shouldSanitizeScriptError(
    const String& sourceURL,
    AccessControlStatus corsStatus) {
  if (corsStatus == OpaqueResource)
    return true;
  return !(getSecurityOrigin()->canRequestNoSuborigin(completeURL(sourceURL)) ||
           corsStatus == SharableCrossOrigin);
}
RemoteSecurityContext::RemoteSecurityContext() : SecurityContext() {
  // RemoteSecurityContext's origin is expected to stay uninitialized until
  // we set it using replicated origin data from the browser process.
  DCHECK(!getSecurityOrigin());

  // Start with a clean slate.
  setContentSecurityPolicy(ContentSecurityPolicy::create());

  // FIXME: Document::initSecurityContext has a few other things we may
  // eventually want here, such as enforcing a setting to
  // grantUniversalAccess().
}
void DocumentThreadableLoader::loadActualRequest()
{
    ResourceRequest actualRequest = m_actualRequest;
    ResourceLoaderOptions actualOptions = m_actualOptions;
    m_actualRequest = ResourceRequest();
    m_actualOptions = ResourceLoaderOptions();

    actualRequest.setHTTPOrigin(getSecurityOrigin());

    clearResource();

    // Explicitly set the SkipServiceWorker flag here. Even if the page was not
    // controlled by a SW when the preflight request was sent, a new SW may be
    // controlling the page now by calling clients.claim(). We should not send
    // the actual request to the SW. https://crbug.com/604583
    actualRequest.setSkipServiceWorker(WebURLRequest::SkipServiceWorker::All);

    loadRequest(actualRequest, actualOptions);
    // |this| may be dead here in async mode.
}
WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilageData, RawPtr<WorkerClients> workerClients)
    : m_url(url)
    , m_userAgent(userAgent)
    , m_v8CacheOptions(V8CacheOptionsDefault)
    , m_scriptController(WorkerOrWorkletScriptController::create(this, thread->isolate()))
    , m_thread(thread)
    , m_workerInspectorController(WorkerInspectorController::create(this))
    , m_closing(false)
    , m_eventQueue(WorkerEventQueue::create(this))
    , m_workerClients(workerClients)
    , m_timers(Platform::current()->currentThread()->scheduler()->timerTaskRunner()->adoptClone())
    , m_timeOrigin(timeOrigin)
    , m_messageStorage(ConsoleMessageStorage::create())
    , m_workerExceptionUniqueIdentifier(0)
{
    setSecurityOrigin(SecurityOrigin::create(url));
    if (starterOriginPrivilageData)
        getSecurityOrigin()->transferPrivilegesFrom(starterOriginPrivilageData);

    if (m_workerClients)
        m_workerClients->reattachThread();
}
Exemple #13
0
// 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::redirectReceived(
    Resource* resource,
    const ResourceRequest& request,
    const ResourceResponse& redirectResponse) {
  DCHECK(m_client);
  DCHECK_EQ(resource, this->resource());
  DCHECK(m_async);

  m_checker.redirectReceived();

  if (!m_actualRequest.isNull()) {
    reportResponseReceived(resource->identifier(), redirectResponse);

    handlePreflightFailure(redirectResponse.url().getString(),
                           "Response for preflight is invalid (redirect)");

    return false;
  }

  if (m_redirectMode == WebURLRequest::FetchRedirectModeManual) {
    // We use |m_redirectMode| to check the original redirect mode. |request| is
    // a new request for redirect. So we don't set the redirect mode of it in
    // WebURLLoaderImpl::Context::OnReceivedRedirect().
    DCHECK(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, redirectResponse,
                     WTF::makeUnique<EmptyDataHandle>());

    if (m_client) {
      DCHECK(m_actualRequest.isNull());
      notifyFinished(resource);
    }

    return false;
  }

  if (m_redirectMode == WebURLRequest::FetchRedirectModeError) {
    ThreadableLoaderClient* client = m_client;
    clear();
    client->didFailRedirectCheck();

    return false;
  }

  // Allow same origin requests to continue after allowing clients to audit the
  // redirect.
  if (isAllowedRedirect(request.url())) {
    m_client->didReceiveRedirectTo(request.url());
    if (m_client->isDocumentThreadableLoaderClient()) {
      return static_cast<DocumentThreadableLoaderClient*>(m_client)
          ->willFollowRedirect(request, redirectResponse);
    }
    return true;
  }

  if (m_corsRedirectLimit <= 0) {
    ThreadableLoaderClient* client = m_client;
    clear();
    client->didFailRedirectCheck();
    return false;
  }

  --m_corsRedirectLimit;

  InspectorInstrumentation::didReceiveCORSRedirectResponse(
      document().frame(), resource->identifier(),
      document().frame()->loader().documentLoader(), redirectResponse,
      resource);

  bool allowRedirect = false;
  String accessControlErrorDescription;

  if (!CrossOriginAccessControl::isLegalRedirectLocation(
          request.url(), accessControlErrorDescription)) {
    accessControlErrorDescription =
        "Redirect from '" + redirectResponse.url().getString() +
        "' has been blocked by CORS policy: " + accessControlErrorDescription;
  } else if (!m_sameOriginRequest &&
             !passesAccessControlCheck(
                 redirectResponse, effectiveAllowCredentials(),
                 getSecurityOrigin(), accessControlErrorDescription,
                 m_requestContext)) {
    // The redirect response must pass the access control check if the original
    // request was not same-origin.
    accessControlErrorDescription =
        "Redirect from '" + redirectResponse.url().getString() + "' to '" +
        request.url().getString() + "' has been blocked by CORS policy: " +
        accessControlErrorDescription;
  } else {
    allowRedirect = true;
  }

  if (!allowRedirect) {
    ThreadableLoaderClient* client = m_client;
    clear();
    client->didFailAccessControlCheck(ResourceError(
        errorDomainBlinkInternal, 0, redirectResponse.url().getString(),
        accessControlErrorDescription));
    return false;
  }

  m_client->didReceiveRedirectTo(request.url());

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

  // If the original request wasn't same-origin, then if the request URL origin
  // is not same origin with the original URL origin, set the source origin to a
  // globally unique identifier. (If the original request was same-origin, the
  // origin of the new request should be the original URL origin.)
  if (!m_sameOriginRequest) {
    RefPtr<SecurityOrigin> originalOrigin =
        SecurityOrigin::create(redirectResponse.url());
    RefPtr<SecurityOrigin> requestOrigin =
        SecurityOrigin::create(request.url());
    if (!originalOrigin->isSameSchemeHostPort(requestOrigin.get()))
      m_securityOrigin = SecurityOrigin::createUnique();
  }
  // Force any subsequent requests to use these checks.
  m_sameOriginRequest = false;

  // Since the request is no longer same-origin, if the user didn't request
  // credentials in the first place, update our state so we neither request them
  // nor expect they must be allowed.
  if (m_resourceLoaderOptions.credentialsRequested ==
      ClientDidNotRequestCredentials)
    m_forceDoNotAllowStoredCredentials = true;

  // Save the referrer to use when following the redirect.
  m_overrideReferrer = true;
  m_referrerAfterRedirect =
      Referrer(request.httpReferrer(), request.getReferrerPolicy());

  ResourceRequest crossOriginRequest(request);

  // Remove any headers that may have been added by the network layer that cause
  // access control to fail.
  crossOriginRequest.clearHTTPReferrer();
  crossOriginRequest.clearHTTPOrigin();
  crossOriginRequest.clearHTTPUserAgent();
  // Add any request headers which we previously saved from the
  // original request.
  for (const auto& header : m_requestHeaders)
    crossOriginRequest.setHTTPHeaderField(header.key, header.value);
  makeCrossOriginAccessRequest(crossOriginRequest);

  return false;
}
Exemple #14
0
void DocumentThreadableLoader::makeCrossOriginAccessRequest(
    const ResourceRequest& request) {
  DCHECK(m_options.crossOriginRequestPolicy == UseAccessControl ||
         request.isExternalRequest());
  DCHECK(m_client);
  DCHECK(!resource());

  // 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())) {
    InspectorInstrumentation::
        documentThreadableLoaderFailedToStartLoadingForClient(m_document,
                                                              m_client);
    ThreadableLoaderClient* client = m_client;
    clear();
    client->didFailAccessControlCheck(ResourceError(
        errorDomainBlinkInternal, 0, request.url().getString(),
        "Cross origin requests are only supported for protocol schemes: " +
            SchemeRegistry::listOfCORSEnabledURLSchemes() + "."));
    return;
  }

  // Non-secure origins may not make "external requests":
  // https://mikewest.github.io/cors-rfc1918/#integration-fetch
  if (!document().isSecureContext() && request.isExternalRequest()) {
    ThreadableLoaderClient* client = m_client;
    clear();
    client->didFailAccessControlCheck(
        ResourceError(errorDomainBlinkInternal, 0, request.url().getString(),
                      "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 crossOriginRequest(request);
  ResourceLoaderOptions crossOriginOptions(m_resourceLoaderOptions);

  crossOriginRequest.removeCredentials();

  crossOriginRequest.setAllowStoredCredentials(effectiveAllowCredentials() ==
                                               AllowStoredCredentials);

  // We update the credentials mode according to effectiveAllowCredentials()
  // here for backward compatibility. But this is not correct.
  // FIXME: We should set it in the caller of DocumentThreadableLoader.
  crossOriginRequest.setFetchCredentialsMode(
      effectiveAllowCredentials() == AllowStoredCredentials
          ? WebURLRequest::FetchCredentialsModeInclude
          : WebURLRequest::FetchCredentialsModeOmit);

  // We use isSimpleOrForbiddenRequest() 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 (!request.isExternalRequest() &&
      ((m_options.preflightPolicy == ConsiderPreflight &&
        FetchUtils::isSimpleOrForbiddenRequest(request.httpMethod(),
                                               request.httpHeaderFields())) ||
       m_options.preflightPolicy == PreventPreflight)) {
    prepareCrossOriginRequest(crossOriginRequest);
    loadRequest(crossOriginRequest, crossOriginOptions);
  } else {
    bool shouldForcePreflight =
        request.isExternalRequest() ||
        InspectorInstrumentation::shouldForceCORSPreflight(m_document);
    bool canSkipPreflight =
        CrossOriginPreflightResultCache::shared().canSkipPreflight(
            getSecurityOrigin()->toString(), crossOriginRequest.url(),
            effectiveAllowCredentials(), crossOriginRequest.httpMethod(),
            crossOriginRequest.httpHeaderFields());
    if (canSkipPreflight && !shouldForcePreflight) {
      if (getSecurityOrigin())
        crossOriginRequest.setHTTPOrigin(getSecurityOrigin());
      if (m_overrideReferrer)
        crossOriginRequest.setHTTPReferrer(m_referrerAfterRedirect);

      prepareCrossOriginRequest(crossOriginRequest);
      loadRequest(crossOriginRequest, crossOriginOptions);
    } else {
      ResourceRequest preflightRequest = createAccessControlPreflightRequest(
          crossOriginRequest, getSecurityOrigin());

      // Create a ResourceLoaderOptions for preflight.
      ResourceLoaderOptions preflightOptions = crossOriginOptions;
      preflightOptions.allowCredentials = DoNotAllowStoredCredentials;

      m_actualRequest = crossOriginRequest;
      m_actualOptions = crossOriginOptions;

      prepareCrossOriginRequest(crossOriginRequest);
      loadRequest(preflightRequest, preflightOptions);
    }
  }
}
void RemoteSecurityContext::setReplicatedOrigin(
    PassRefPtr<SecurityOrigin> origin) {
  DCHECK(origin);
  setSecurityOrigin(std::move(origin));
  contentSecurityPolicy()->setupSelf(*getSecurityOrigin());
}
Exemple #16
0
void DocumentThreadableLoader::start(const ResourceRequest& request) {
  // Setting an outgoing referer is only supported in the async code path.
  DCHECK(m_async || request.httpReferrer().isEmpty());

  m_sameOriginRequest =
      getSecurityOrigin()->canRequestNoSuborigin(request.url());
  m_requestContext = request.requestContext();
  m_redirectMode = request.fetchRedirectMode();

  if (!m_sameOriginRequest &&
      m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) {
    InspectorInstrumentation::
        documentThreadableLoaderFailedToStartLoadingForClient(m_document,
                                                              m_client);
    ThreadableLoaderClient* client = m_client;
    clear();
    client->didFail(ResourceError(errorDomainBlinkInternal, 0,
                                  request.url().getString(),
                                  "Cross origin requests are not supported."));
    return;
  }

  m_requestStartedSeconds = 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.
  m_requestHeaders = request.httpHeaderFields();

  // DocumentThreadableLoader is used by all javascript initiated fetch, so we
  // use this chance to record non-GET fetch script requests. However, this is
  // based on the following assumptions, so please be careful when adding
  // similar logic:
  // - ThreadableLoader is used as backend for all javascript initiated network
  //   fetches.
  // - Note that ThreadableLoader is also used for non-network fetch such as
  //   FileReaderLoader. However it emulates GET method so signal is not
  //   recorded here.
  // - ThreadableLoader w/ non-GET request is only created from javascript
  //   initiated fetch.
  // - Some non-script initiated fetches such as WorkerScriptLoader also use
  //   ThreadableLoader, but they are guaranteed to use GET method.
  if (request.httpMethod() != HTTPNames::GET) {
    if (Page* page = m_document->page())
      page->chromeClient().didObserveNonGetFetchFromScript();
  }

  ResourceRequest newRequest(request);
  if (m_requestContext != WebURLRequest::RequestContextFetch) {
    // When the request context is not "fetch", |crossOriginRequestPolicy|
    // represents the fetch request mode, and |credentialsRequested| represents
    // the fetch credentials mode. So we set those flags here so that we can see
    // the correct request mode and credentials mode in the service worker's
    // fetch event handler.
    switch (m_options.crossOriginRequestPolicy) {
      case DenyCrossOriginRequests:
        newRequest.setFetchRequestMode(
            WebURLRequest::FetchRequestModeSameOrigin);
        break;
      case UseAccessControl:
        if (m_options.preflightPolicy == ForcePreflight) {
          newRequest.setFetchRequestMode(
              WebURLRequest::FetchRequestModeCORSWithForcedPreflight);
        } else {
          newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS);
        }
        break;
      case AllowCrossOriginRequests:
        SECURITY_CHECK(IsNoCORSAllowedContext(m_requestContext,
                                              request.skipServiceWorker()));
        newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeNoCORS);
        break;
    }
    if (m_resourceLoaderOptions.allowCredentials == AllowStoredCredentials) {
      newRequest.setFetchCredentialsMode(
          WebURLRequest::FetchCredentialsModeInclude);
    } else {
      newRequest.setFetchCredentialsMode(
          WebURLRequest::FetchCredentialsModeSameOrigin);
    }
  }

  // We assume that ServiceWorker is skipped for sync requests and unsupported
  // protocol requests by content/ code.
  if (m_async &&
      request.skipServiceWorker() == WebURLRequest::SkipServiceWorker::None &&
      SchemeRegistry::shouldTreatURLSchemeAsAllowingServiceWorkers(
          request.url().protocol()) &&
      m_document->fetcher()->isControlledByServiceWorker()) {
    if (newRequest.fetchRequestMode() == WebURLRequest::FetchRequestModeCORS ||
        newRequest.fetchRequestMode() ==
            WebURLRequest::FetchRequestModeCORSWithForcedPreflight) {
      m_fallbackRequestForServiceWorker = ResourceRequest(request);
      // m_fallbackRequestForServiceWorker is used when a regular controlling
      // service worker doesn't handle a cross origin request. When this happens
      // we still want to give foreign fetch a chance to handle the request, so
      // only skip the controlling service worker for the fallback request. This
      // is currently safe because of http://crbug.com/604084 the
      // wasFallbackRequiredByServiceWorker flag is never set when foreign fetch
      // handled a request.
      m_fallbackRequestForServiceWorker.setSkipServiceWorker(
          WebURLRequest::SkipServiceWorker::Controlling);
    }
    loadRequest(newRequest, m_resourceLoaderOptions);
    return;
  }

  dispatchInitialRequest(newRequest);
}
void RemoteSecurityContext::resetReplicatedContentSecurityPolicy() {
  DCHECK(getSecurityOrigin());
  setContentSecurityPolicy(ContentSecurityPolicy::create());
  contentSecurityPolicy()->setupSelf(*getSecurityOrigin());
}
// 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().
void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
    ASSERT(m_client);
    ASSERT_UNUSED(resource, resource == this->resource());
    ASSERT(m_async);

    if (!m_actualRequest.isNull()) {
        reportResponseReceived(resource->identifier(), redirectResponse);

        handlePreflightFailure(redirectResponse.url().getString(), "Response for preflight is invalid (redirect)");
        // |this| may be dead here.

        request = ResourceRequest();

        return;
    }

    if (m_redirectMode == WebURLRequest::FetchRedirectModeManual) {
        // Keep |this| alive even if the client release a reference in
        // responseReceived().
        WeakPtr<DocumentThreadableLoader> self(m_weakFactory.createWeakPtr());

        // We use |m_redirectMode| to check the original redirect mode.
        // |request| is a new request for redirect. So we don't set the redirect
        // mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
        ASSERT(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, redirectResponse, wrapUnique(new EmptyDataHandle()));

        if (!self) {
            request = ResourceRequest();
            return;
        }

        if (m_client) {
            ASSERT(m_actualRequest.isNull());
            notifyFinished(resource);
        }

        request = ResourceRequest();

        return;
    }

    if (m_redirectMode == WebURLRequest::FetchRedirectModeError) {
        ThreadableLoaderClient* client = m_client;
        clear();
        client->didFailRedirectCheck();
        // |this| may be dead here.

        request = ResourceRequest();

        return;
    }

    // Allow same origin requests to continue after allowing clients to audit the redirect.
    if (isAllowedRedirect(request.url())) {
        if (m_client->isDocumentThreadableLoaderClient())
            static_cast<DocumentThreadableLoaderClient*>(m_client)->willFollowRedirect(request, redirectResponse);
        return;
    }

    if (m_corsRedirectLimit <= 0) {
        ThreadableLoaderClient* client = m_client;
        clear();
        client->didFailRedirectCheck();
        // |this| may be dead here.
    } else if (m_options.crossOriginRequestPolicy == UseAccessControl) {
        --m_corsRedirectLimit;

        InspectorInstrumentation::didReceiveCORSRedirectResponse(document().frame(), resource->identifier(), document().frame()->loader().documentLoader(), redirectResponse, resource);

        bool allowRedirect = false;
        String accessControlErrorDescription;

        // Non-simple cross origin requests (both preflight and actual one) are
        // not allowed to follow redirect.
        if (m_crossOriginNonSimpleRequest) {
            accessControlErrorDescription = "The request was redirected to '"+ request.url().getString() + "', which is disallowed for cross-origin requests that require preflight.";
        } else {
            // The redirect response must pass the access control check if the
            // original request was not same-origin.
            allowRedirect = CrossOriginAccessControl::isLegalRedirectLocation(request.url(), accessControlErrorDescription)
                && (m_sameOriginRequest || passesAccessControlCheck(redirectResponse, effectiveAllowCredentials(), getSecurityOrigin(), accessControlErrorDescription, m_requestContext));
        }

        if (allowRedirect) {
            // FIXME: consider combining this with CORS redirect handling performed by
            // CrossOriginAccessControl::handleRedirect().
            clearResource();

            RefPtr<SecurityOrigin> originalOrigin = SecurityOrigin::create(redirectResponse.url());
            RefPtr<SecurityOrigin> requestOrigin = SecurityOrigin::create(request.url());
            // If the original request wasn't same-origin, then if the request URL origin is not same origin with the original URL origin,
            // set the source origin to a globally unique identifier. (If the original request was same-origin, the origin of the new request
            // should be the original URL origin.)
            if (!m_sameOriginRequest && !originalOrigin->isSameSchemeHostPort(requestOrigin.get()))
                m_securityOrigin = SecurityOrigin::createUnique();
            // Force any subsequent requests to use these checks.
            m_sameOriginRequest = false;

            // Since the request is no longer same-origin, if the user didn't request credentials in
            // the first place, update our state so we neither request them nor expect they must be allowed.
            if (m_resourceLoaderOptions.credentialsRequested == ClientDidNotRequestCredentials)
                m_forceDoNotAllowStoredCredentials = true;

            // Remove any headers that may have been added by the network layer that cause access control to fail.
            request.clearHTTPReferrer();
            request.clearHTTPOrigin();
            request.clearHTTPUserAgent();
            // Add any CORS simple request headers which we previously saved from the original request.
            for (const auto& header : m_simpleRequestHeaders)
                request.setHTTPHeaderField(header.key, header.value);
            makeCrossOriginAccessRequest(request);
            // |this| may be dead here.
            return;
        }

        ThreadableLoaderClient* client = m_client;
        clear();
        client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, redirectResponse.url().getString(), accessControlErrorDescription));
        // |this| may be dead here.
    } else {
        ThreadableLoaderClient* client = m_client;
        clear();
        client->didFailRedirectCheck();
        // |this| may be dead here.
    }

    request = ResourceRequest();
}