/*
 * Copyright (C) 2009 Apple Inc. All Rights Reserved.
 * Copyright (C) 2009, 2011 Google Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "third_party/blink/renderer/core/workers/worker_classic_script_loader.h"

#include <memory>
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
#include "third_party/blink/renderer/platform/network/content_security_policy_response_headers.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"

namespace blink {

WorkerClassicScriptLoader::WorkerClassicScriptLoader()
    : response_address_space_(mojom::IPAddressSpace::kPublic),
      mime_type_check_mode_(AllowedByNosniff::MimeTypeCheck::kStrict) {}

void WorkerClassicScriptLoader::LoadSynchronously(
    ExecutionContext& execution_context,
    ResourceFetcher* fetch_client_settings_object_fetcher,
    const KURL& url,
    mojom::RequestContextType request_context,
    mojom::IPAddressSpace creation_address_space) {
  DCHECK(fetch_client_settings_object_fetcher);
  url_ = url;
  execution_context_ = &execution_context;

  // Impose strict MIME-type checks on importScripts(). See
  // https://crbug.com/794548.
  mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kStrict;

  ResourceRequest request(url);
  request.SetHTTPMethod(http_names::kGET);
  request.SetExternalRequestStateFromRequestorAddressSpace(
      creation_address_space);
  request.SetRequestContext(request_context);

  SECURITY_DCHECK(execution_context.IsWorkerGlobalScope());

  ResourceLoaderOptions resource_loader_options;
  resource_loader_options.parser_disposition =
      ParserDisposition::kNotParserInserted;
  resource_loader_options.synchronous_policy = kRequestSynchronously;

  threadable_loader_ = MakeGarbageCollected<ThreadableLoader>(
      execution_context, this, resource_loader_options,
      fetch_client_settings_object_fetcher);
  threadable_loader_->Start(request);
}

void WorkerClassicScriptLoader::LoadTopLevelScriptAsynchronously(
    ExecutionContext& execution_context,
    ResourceFetcher* fetch_client_settings_object_fetcher,
    const KURL& url,
    mojom::RequestContextType request_context,
    network::mojom::FetchRequestMode fetch_request_mode,
    network::mojom::FetchCredentialsMode fetch_credentials_mode,
    mojom::IPAddressSpace creation_address_space,
    bool is_nested_worker,
    base::OnceClosure response_callback,
    base::OnceClosure finished_callback) {
  DCHECK(fetch_client_settings_object_fetcher);
  DCHECK(response_callback || finished_callback);
  response_callback_ = std::move(response_callback);
  finished_callback_ = std::move(finished_callback);
  url_ = url;
  execution_context_ = &execution_context;
  forbid_cross_origin_redirects_ = true;

  if (execution_context.IsDocument()) {
    // For worker creation on a document, don't impose strict MIME-type checks
    // on the top-level worker script for backward compatibility. Note that
    // there is a plan to deprecate legacy mime types for workers. See
    // https://crbug.com/794548.
    mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kLax;
  } else {
    DCHECK(execution_context.IsWorkerGlobalScope());
    if (is_nested_worker) {
      // For nested workers, impose the strict MIME-type checks because the
      // feature is new (enabled by default in M69) and there is no backward
      // compatibility issue.
      mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kStrict;
    } else {
      // For worker creation on a document with off-the-main-thread top-level
      // worker classic script loading, don't impose strict MIME-type checks for
      // backward compatibility.
      // TODO(nhiroki): Always impose strict MIME-type checks on all web
      // workers (https://crbug.com/794548).
      DCHECK(RuntimeEnabledFeatures::OffMainThreadWorkerScriptFetchEnabled());
      mime_type_check_mode_ = AllowedByNosniff::MimeTypeCheck::kLax;
    }
  }

  ResourceRequest request(url);
  request.SetHTTPMethod(http_names::kGET);
  request.SetExternalRequestStateFromRequestorAddressSpace(
      creation_address_space);
  request.SetRequestContext(request_context);
  request.SetFetchRequestMode(fetch_request_mode);
  request.SetFetchCredentialsMode(fetch_credentials_mode);

  need_to_cancel_ = true;
  threadable_loader_ = MakeGarbageCollected<ThreadableLoader>(
      execution_context, this, ResourceLoaderOptions(),
      fetch_client_settings_object_fetcher);
  threadable_loader_->Start(request);
  if (failed_)
    NotifyFinished();
}

const KURL& WorkerClassicScriptLoader::ResponseURL() const {
  DCHECK(!Failed());
  return response_url_;
}

void WorkerClassicScriptLoader::DidReceiveResponse(
    unsigned long identifier,
    const ResourceResponse& response,
    std::unique_ptr<WebDataConsumerHandle> handle) {
  DCHECK(!handle);
  if (response.HttpStatusCode() / 100 != 2 && response.HttpStatusCode()) {
    NotifyError();
    return;
  }
  if (!AllowedByNosniff::MimeTypeAsScript(execution_context_, response,
                                          mime_type_check_mode_)) {
    NotifyError();
    return;
  }

  if (forbid_cross_origin_redirects_ && url_ != response.CurrentRequestUrl() &&
      !SecurityOrigin::AreSameSchemeHostPort(url_,
                                             response.CurrentRequestUrl())) {
    // Forbid cross-origin redirects to ensure the request and response URLs
    // have the same SecurityOrigin.
    execution_context_->AddConsoleMessage(ConsoleMessage::Create(
        kSecurityMessageSource, kErrorMessageLevel,
        "Refused to cross-origin redirects of the top-level worker script."));
    NotifyError();
    return;
  }

  identifier_ = identifier;
  response_url_ = response.ResponseUrl();
  // The response URL may be empty if a service worker did respondWith(new
  // Response()) to generate a response.
  // TODO(falken): Change this to an empty URL if that is indeed spec
  // conformant.
  if (response_url_.IsEmpty())
    response_url_ = response.CurrentRequestUrl();

  response_encoding_ = response.TextEncodingName();
  app_cache_id_ = response.AppCacheID();

  referrer_policy_ = response.HttpHeaderField(http_names::kReferrerPolicy);
  ProcessContentSecurityPolicy(response);
  origin_trial_tokens_ = OriginTrialContext::ParseHeaderValue(
      response.HttpHeaderField(http_names::kOriginTrial));

  if (network_utils::IsReservedIPAddress(response.RemoteIPAddress())) {
    response_address_space_ =
        SecurityOrigin::Create(response_url_)->IsLocalhost()
            ? mojom::IPAddressSpace::kLocal
            : mojom::IPAddressSpace::kPrivate;
  }

  if (response_callback_)
    std::move(response_callback_).Run();
}

void WorkerClassicScriptLoader::DidReceiveData(const char* data, unsigned len) {
  if (failed_)
    return;

  if (!decoder_) {
    decoder_ = TextResourceDecoder::Create(TextResourceDecoderOptions(
        TextResourceDecoderOptions::kPlainTextContent,
        response_encoding_.IsEmpty() ? UTF8Encoding()
                                     : WTF::TextEncoding(response_encoding_)));
  }

  if (!len)
    return;

  source_text_.Append(decoder_->Decode(data, len));
}

void WorkerClassicScriptLoader::DidReceiveCachedMetadata(const char* data,
                                                         int size) {
  cached_metadata_ = std::make_unique<Vector<char>>(size);
  memcpy(cached_metadata_->data(), data, size);
}

void WorkerClassicScriptLoader::DidFinishLoading(unsigned long identifier) {
  need_to_cancel_ = false;
  if (!failed_ && decoder_)
    source_text_.Append(decoder_->Flush());

  NotifyFinished();
}

void WorkerClassicScriptLoader::DidFail(const ResourceError& error) {
  need_to_cancel_ = false;
  canceled_ = error.IsCancellation();
  NotifyError();
}

void WorkerClassicScriptLoader::DidFailRedirectCheck() {
  // When didFailRedirectCheck() is called, the ResourceLoader for the script
  // is not canceled yet. So we don't reset |m_needToCancel| here.
  NotifyError();
}

void WorkerClassicScriptLoader::Trace(Visitor* visitor) {
  visitor->Trace(threadable_loader_);
  visitor->Trace(content_security_policy_);
  visitor->Trace(execution_context_);
  ThreadableLoaderClient::Trace(visitor);
}

void WorkerClassicScriptLoader::Cancel() {
  if (!need_to_cancel_)
    return;
  need_to_cancel_ = false;
  if (threadable_loader_)
    threadable_loader_->Cancel();
}

String WorkerClassicScriptLoader::SourceText() {
  return source_text_.ToString();
}

void WorkerClassicScriptLoader::NotifyError() {
  failed_ = true;
  // NotifyError() could be called before ThreadableLoader::Create() returns
  // e.g. from DidFail(), and in that case threadable_loader_ is not yet set
  // (i.e. still null).
  // Since the callback invocation in NotifyFinished() potentially delete
  // |this| object, the callback invocation should be postponed until the
  // create() call returns. See LoadAsynchronously() for the postponed call.
  if (threadable_loader_)
    NotifyFinished();
}

void WorkerClassicScriptLoader::NotifyFinished() {
  if (!finished_callback_)
    return;

  std::move(finished_callback_).Run();
}

void WorkerClassicScriptLoader::ProcessContentSecurityPolicy(
    const ResourceResponse& response) {
  // Per http://www.w3.org/TR/CSP2/#processing-model-workers, if the Worker's
  // URL is not a GUID, then it grabs its CSP from the response headers
  // directly.  Otherwise, the Worker inherits the policy from the parent
  // document (which is implemented in WorkerMessagingProxy, and
  // m_contentSecurityPolicy should be left as nullptr to inherit the policy).
  if (!response.CurrentRequestUrl().ProtocolIs("blob") &&
      !response.CurrentRequestUrl().ProtocolIs("file") &&
      !response.CurrentRequestUrl().ProtocolIs("filesystem")) {
    content_security_policy_ = ContentSecurityPolicy::Create();
    content_security_policy_->SetOverrideURLForSelf(
        response.CurrentRequestUrl());
    content_security_policy_->DidReceiveHeaders(
        ContentSecurityPolicyResponseHeaders(response));
  }
}

}  // namespace blink
