// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/push_messaging/push_messaging_router.h"

#include <string>

#include "base/check_deref.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_macros.h"
#include "content/browser/devtools/devtools_background_services_context_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom.h"
#include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom.h"

namespace content {

namespace {

using ServiceWorkerStartCallback =
    base::OnceCallback<void(scoped_refptr<ServiceWorkerVersion>,
                            scoped_refptr<ServiceWorkerContextWrapper>,
                            blink::ServiceWorkerStatusCode)>;

DevToolsBackgroundServicesContextImpl* GetDevTools(
    const ServiceWorkerContextWrapper& service_worker_context) {
  auto* storage_partition = service_worker_context.storage_partition();
  // `storage_partition` will be null of the associated profile was deleted,
  // which can happen if the last browser window for that profile was closed.
  return storage_partition
             ? static_cast<DevToolsBackgroundServicesContextImpl*>(
                   storage_partition->GetDevToolsBackgroundServicesContext())
             : nullptr;
}

void RunPushEventCallback(
    PushMessagingRouter::PushEventCallback deliver_message_callback,
    blink::mojom::PushEventStatus push_event_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  // PostTask() to ensure the callback is called asynchronously.
  GetUIThreadTaskRunner({})->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(deliver_message_callback), push_event_status));
}

// Given the |service_worker_registration|, this method finds and finishes the
// |callback| by finding the |service_worker_version|.
void DidFindServiceWorkerRegistration(
    ServiceWorkerMetrics::EventType event_type,
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
    ServiceWorkerStartCallback callback,
    blink::ServiceWorkerStatusCode service_worker_status,
    scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  if (service_worker_status != blink::ServiceWorkerStatusCode::kOk) {
    std::move(callback).Run(nullptr /* service_worker_version */,
                            nullptr /* service_worker_context */,
                            service_worker_status);
    return;
  }
  ServiceWorkerVersion* version = service_worker_registration->active_version();
  DCHECK(version);

  version->RunAfterStartWorker(
      event_type,
      base::BindOnce(std::move(callback), base::WrapRefCounted(version),
                     std::move(service_worker_context)));
}

// Finds the |service_worker_registration|.
void FindServiceWorkerRegistration(
    ServiceWorkerMetrics::EventType event_type,
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
    const url::Origin& origin,
    int64_t service_worker_registration_id,
    ServiceWorkerStartCallback callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  // Try to acquire the registration from storage. If it's already live we'll
  // receive it right away. If not, it will be revived from storage.
  service_worker_context->FindReadyRegistrationForId(
      service_worker_registration_id,
      blink::StorageKey::CreateFirstParty(origin),
      base::BindOnce(&DidFindServiceWorkerRegistration, event_type,
                     service_worker_context, std::move(callback)));
}

// According to the |event_type| this method will start finding the
// |service_worker_version| for the event. Must be called on the UI thread.
void StartServiceWorkerForDispatch(ServiceWorkerMetrics::EventType event_type,
                                   BrowserContext* browser_context,
                                   const GURL& origin,
                                   int64_t service_worker_registration_id,
                                   ServiceWorkerStartCallback callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  StoragePartition* partition =
      browser_context->GetStoragePartitionForUrl(origin);
  scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
      static_cast<ServiceWorkerContextWrapper*>(
          partition->GetServiceWorkerContext());
  FindServiceWorkerRegistration(event_type, std::move(service_worker_context),
                                url::Origin::Create(origin),
                                service_worker_registration_id,
                                std::move(callback));
}

}  // namespace

// static
void PushMessagingRouter::DeliverMessage(
    BrowserContext* browser_context,
    const GURL& origin,
    int64_t service_worker_registration_id,
    const std::string& message_id,
    std::optional<std::string> payload,
    bool record_network_requests,
    PushEventCallback deliver_message_callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  StartServiceWorkerForDispatch(
      ServiceWorkerMetrics::EventType::PUSH, browser_context, origin,
      service_worker_registration_id,
      base::BindOnce(&PushMessagingRouter::DeliverMessageToWorker, message_id,
                     std::move(payload), record_network_requests,
                     std::move(deliver_message_callback)));
}

// static
void PushMessagingRouter::DeliverMessageToWorker(
    const std::string& message_id,
    std::optional<std::string> payload,
    bool record_network_requests,
    PushEventCallback deliver_message_callback,
    scoped_refptr<ServiceWorkerVersion> service_worker,
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
    blink::ServiceWorkerStatusCode status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  // Service worker registration was not found, run callback immediately
  if (!service_worker) {
    DCHECK_NE(blink::ServiceWorkerStatusCode::kOk, status);
    RunPushEventCallback(
        std::move(deliver_message_callback),
        status == blink::ServiceWorkerStatusCode::kErrorNotFound
            ? blink::mojom::PushEventStatus::NO_SERVICE_WORKER
            : blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR);
    return;
  }

  // RunAfterStartWorker was not successful, end message delivery and log error
  // in devtools_context before running RunPushEventCallback
  if (status != blink::ServiceWorkerStatusCode::kOk) {
    DeliverMessageEnd(std::move(service_worker),
                      std::move(service_worker_context), message_id,
                      std::move(deliver_message_callback), status);
    return;
  }

  int request_id = service_worker->StartRequestWithCustomTimeout(
      ServiceWorkerMetrics::EventType::PUSH,
      base::BindOnce(&PushMessagingRouter::DeliverMessageEnd, service_worker,
                     service_worker_context, message_id,
                     std::move(deliver_message_callback)),
      base::Seconds(blink::mojom::kPushEventTimeoutSeconds),
      ServiceWorkerVersion::KILL_ON_TIMEOUT);

  if (record_network_requests) {
    service_worker->endpoint()->DispatchPushEventRecordingNetworkRequests(
        payload, service_worker->CreatePushEventCallback(request_id));
  } else {
    service_worker->endpoint()->DispatchPushEvent(
        payload, service_worker->CreateSimpleEventCallback(request_id));
  }

  auto* devtools_context =
      GetDevTools(CHECK_DEREF(service_worker_context.get()));
  if (devtools_context && devtools_context->IsRecording(
                              DevToolsBackgroundService::kPushMessaging)) {
    std::map<std::string, std::string> event_metadata;
    if (payload)
      event_metadata["Payload"] = *payload;
    devtools_context->LogBackgroundServiceEvent(
        service_worker->registration_id(), service_worker->key(),
        DevToolsBackgroundService::kPushMessaging, "Push event dispatched",
        message_id, event_metadata);
  }
}

// static
void PushMessagingRouter::DeliverMessageEnd(
    scoped_refptr<ServiceWorkerVersion> service_worker,
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
    const std::string& message_id,
    PushEventCallback deliver_message_callback,
    blink::ServiceWorkerStatusCode service_worker_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  blink::mojom::PushEventStatus push_event_status =
      blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR;
  std::string status_description;
  switch (service_worker_status) {
    case blink::ServiceWorkerStatusCode::kOk:
      push_event_status = blink::mojom::PushEventStatus::SUCCESS;
      status_description = "Success";
      break;
    case blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected:
      push_event_status =
          blink::mojom::PushEventStatus::EVENT_WAITUNTIL_REJECTED;
      status_description = "waitUntil Rejected";
      break;
    case blink::ServiceWorkerStatusCode::kErrorTimeout:
      push_event_status = blink::mojom::PushEventStatus::TIMEOUT;
      status_description = "Timeout";
      break;
    case blink::ServiceWorkerStatusCode::kErrorFailed:
    case blink::ServiceWorkerStatusCode::kErrorAbort:
    case blink::ServiceWorkerStatusCode::kErrorStartWorkerFailed:
    case blink::ServiceWorkerStatusCode::kErrorProcessNotFound:
    case blink::ServiceWorkerStatusCode::kErrorNotFound:
    case blink::ServiceWorkerStatusCode::kErrorIpcFailed:
    case blink::ServiceWorkerStatusCode::kErrorScriptEvaluateFailed:
    case blink::ServiceWorkerStatusCode::kErrorDiskCache:
    case blink::ServiceWorkerStatusCode::kErrorRedundant:
    case blink::ServiceWorkerStatusCode::kErrorDisallowed:
      push_event_status = blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR;
      break;
    case blink::ServiceWorkerStatusCode::kErrorExists:
    case blink::ServiceWorkerStatusCode::kErrorInstallWorkerFailed:
    case blink::ServiceWorkerStatusCode::kErrorActivateWorkerFailed:
    case blink::ServiceWorkerStatusCode::kErrorNetwork:
    case blink::ServiceWorkerStatusCode::kErrorSecurity:
    case blink::ServiceWorkerStatusCode::kErrorState:
    case blink::ServiceWorkerStatusCode::kErrorInvalidArguments:
    case blink::ServiceWorkerStatusCode::kErrorStorageDisconnected:
    case blink::ServiceWorkerStatusCode::kErrorStorageDataCorrupted:
      NOTREACHED() << "Got unexpected error code: "
                   << static_cast<uint32_t>(service_worker_status) << " "
                   << blink::ServiceWorkerStatusToString(service_worker_status);
  }
  RunPushEventCallback(std::move(deliver_message_callback), push_event_status);

  auto* devtools_context =
      GetDevTools(CHECK_DEREF(service_worker_context.get()));
  if (devtools_context &&
      devtools_context->IsRecording(
          DevToolsBackgroundService::kPushMessaging) &&
      push_event_status !=
          blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR) {
    devtools_context->LogBackgroundServiceEvent(
        service_worker->registration_id(), service_worker->key(),
        DevToolsBackgroundService::kPushMessaging, "Push event completed",
        message_id, {{"Status", status_description}});
  }
}

// static
void PushMessagingRouter::FireSubscriptionChangeEvent(
    BrowserContext* browser_context,
    const GURL& origin,
    int64_t service_worker_registration_id,
    blink::mojom::PushSubscriptionPtr new_subscription,
    blink::mojom::PushSubscriptionPtr old_subscription,
    PushEventCallback subscription_change_callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  CHECK(features::IsPushSubscriptionChangeEventEnabled());

  StartServiceWorkerForDispatch(
      ServiceWorkerMetrics::EventType::PUSH_SUBSCRIPTION_CHANGE,
      browser_context, origin, service_worker_registration_id,
      base::BindOnce(&PushMessagingRouter::FireSubscriptionChangeEventToWorker,
                     std::move(new_subscription), std::move(old_subscription),
                     std::move(subscription_change_callback)));
}

// static
void PushMessagingRouter::FireSubscriptionChangeEventToWorker(
    blink::mojom::PushSubscriptionPtr new_subscription,
    blink::mojom::PushSubscriptionPtr old_subscription,
    PushEventCallback subscription_change_callback,
    scoped_refptr<ServiceWorkerVersion> service_worker,
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
    blink::ServiceWorkerStatusCode status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  CHECK(features::IsPushSubscriptionChangeEventEnabled());

  if (!service_worker) {
    DCHECK_NE(blink::ServiceWorkerStatusCode::kOk, status);
    RunPushEventCallback(
        std::move(subscription_change_callback),
        status == blink::ServiceWorkerStatusCode::kErrorNotFound
            ? blink::mojom::PushEventStatus::NO_SERVICE_WORKER
            : blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR);
    return;
  }

  if (status != blink::ServiceWorkerStatusCode::kOk) {
    FireSubscriptionChangeEventEnd(std::move(service_worker),
                                   std::move(subscription_change_callback),
                                   status);
    return;
  }

  int request_id = service_worker->StartRequestWithCustomTimeout(
      ServiceWorkerMetrics::EventType::PUSH_SUBSCRIPTION_CHANGE,
      base::BindOnce(&PushMessagingRouter::FireSubscriptionChangeEventEnd,
                     service_worker, std::move(subscription_change_callback)),
      base::Seconds(blink::mojom::kPushEventTimeoutSeconds),
      ServiceWorkerVersion::KILL_ON_TIMEOUT);

  service_worker->endpoint()->DispatchPushSubscriptionChangeEvent(
      std::move(old_subscription), std::move(new_subscription),
      service_worker->CreateSimpleEventCallback(request_id));
}

// static
void PushMessagingRouter::FireSubscriptionChangeEventEnd(
    scoped_refptr<ServiceWorkerVersion> service_worker,
    PushEventCallback subscription_change_callback,
    blink::ServiceWorkerStatusCode service_worker_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  blink::mojom::PushEventStatus push_event_status =
      blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR;
  switch (service_worker_status) {
    case blink::ServiceWorkerStatusCode::kOk:
      push_event_status = blink::mojom::PushEventStatus::SUCCESS;
      break;
    case blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected:
      push_event_status =
          blink::mojom::PushEventStatus::EVENT_WAITUNTIL_REJECTED;
      break;
    case blink::ServiceWorkerStatusCode::kErrorTimeout:
      push_event_status = blink::mojom::PushEventStatus::TIMEOUT;
      break;
    default:
      break;
  }
  RunPushEventCallback(std::move(subscription_change_callback),
                       push_event_status);
}

}  // namespace content
