Registration.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright (c) 2024, Andrew Kaster <andrew@ladybird.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/HashMap.h>
  7. #include <LibWeb/ServiceWorker/Registration.h>
  8. namespace Web::ServiceWorker {
  9. struct RegistrationKey {
  10. StorageAPI::StorageKey key;
  11. ByteString serialized_scope_url;
  12. bool operator==(RegistrationKey const&) const = default;
  13. };
  14. // FIXME: Surely this needs hooks to be cleared and manipulated at the UA level
  15. // Does this need to be serialized to disk as well?
  16. static HashMap<RegistrationKey, Registration> s_registrations;
  17. Registration::Registration(StorageAPI::StorageKey storage_key, URL::URL scope, Bindings::ServiceWorkerUpdateViaCache update_via_cache)
  18. : m_storage_key(move(storage_key))
  19. , m_scope_url(move(scope))
  20. , m_update_via_cache_mode(update_via_cache)
  21. {
  22. }
  23. // https://w3c.github.io/ServiceWorker/#dfn-service-worker-registration-unregistered
  24. bool Registration::is_unregistered()
  25. {
  26. // A service worker registration is said to be unregistered if registration map[this service worker registration's (storage key, serialized scope url)] is not this service worker registration.
  27. // FIXME: Suspect that spec should say to serialize without fragment
  28. auto const key = RegistrationKey { m_storage_key, m_scope_url.serialize(URL::ExcludeFragment::Yes) };
  29. return s_registrations.get(key).map([](auto& registration) { return &registration; }).value_or(nullptr) != this;
  30. }
  31. // https://w3c.github.io/ServiceWorker/#service-worker-registration-stale
  32. bool Registration::is_stale() const
  33. {
  34. using namespace AK::TimeLiterals;
  35. // A service worker registration is said to be stale if the registration’s last update check time is non-null
  36. // and the time difference in seconds calculated by the current time minus the registration’s last update check time is greater than 86400.
  37. if (!m_last_update_check_time.has_value())
  38. return false;
  39. return (MonotonicTime::now() - m_last_update_check_time.value()) > 86400_sec;
  40. }
  41. // https://w3c.github.io/ServiceWorker/#get-registration-algorithm
  42. Optional<Registration&> Registration::get(StorageAPI::StorageKey const& key, Optional<URL::URL> scope)
  43. {
  44. // 1. Run the following steps atomically.
  45. // FIXME: What does this mean? Do we need a mutex? does it need to be 'locked' at the UA level?
  46. // 2. Let scopeString be the empty string.
  47. ByteString scope_string;
  48. // 3. If scope is not null, set scopeString to serialized scope with the exclude fragment flag set.
  49. if (scope.has_value())
  50. scope_string = scope.value().serialize(URL::ExcludeFragment::Yes);
  51. // 4. For each (entry storage key, entry scope) → registration of registration map:
  52. // 1. If storage key equals entry storage key and scopeString matches entry scope, then return registration.
  53. // 5. Return null.
  54. return s_registrations.get({ key, scope_string });
  55. }
  56. // https://w3c.github.io/ServiceWorker/#set-registration-algorithm
  57. Registration& Registration::set(StorageAPI::StorageKey const& storage_key, URL::URL const& scope, Bindings::ServiceWorkerUpdateViaCache update_via_cache)
  58. {
  59. // FIXME: 1. Run the following steps atomically.
  60. // 2. Let scopeString be serialized scope with the exclude fragment flag set.
  61. // 3. Let registration be a new service worker registration whose storage key is set to storage key, scope url is set to scope, and update via cache mode is set to updateViaCache.
  62. // 4. Set registration map[(storage key, scopeString)] to registration.
  63. // 5. Return registration.
  64. // FIXME: Is there a way to "ensure but always replace?"
  65. auto key = RegistrationKey { storage_key, scope.serialize(URL::ExcludeFragment::Yes) };
  66. (void)s_registrations.set(key, Registration(storage_key, scope, update_via_cache));
  67. return s_registrations.get(key).value();
  68. }
  69. void Registration::remove(StorageAPI::StorageKey const& key, URL::URL const& scope)
  70. {
  71. (void)s_registrations.remove({ key, scope.serialize(URL::ExcludeFragment::Yes) });
  72. }
  73. // https://w3c.github.io/ServiceWorker/#get-newest-worker
  74. ServiceWorker* Registration::newest_worker() const
  75. {
  76. // FIXME: 1. Run the following steps atomically.
  77. // 2. Let newestWorker be null.
  78. // 3. If registration’s installing worker is not null, set newestWorker to registration’s installing worker.
  79. // 4. If registration’s waiting worker is not null, set newestWorker to registration’s waiting worker.
  80. // 5. If registration’s active worker is not null, set newestWorker to registration’s active worker.
  81. // 6. Return newestWorker.
  82. return m_installing_worker ? m_installing_worker : m_waiting_worker ? m_waiting_worker
  83. : m_active_worker;
  84. }
  85. }
  86. namespace AK {
  87. template<>
  88. struct Traits<Web::ServiceWorker::RegistrationKey> : public DefaultTraits<Web::ServiceWorker::RegistrationKey> {
  89. static unsigned hash(Web::ServiceWorker::RegistrationKey const& key)
  90. {
  91. return pair_int_hash(Traits<Web::StorageAPI::StorageKey>::hash(key.key), Traits<ByteString>::hash(key.serialized_scope_url));
  92. }
  93. };
  94. }