File: shared_dictionary_storage.h

package info (click to toggle)
chromium 145.0.7632.159-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 5,976,224 kB
  • sloc: cpp: 36,198,469; ansic: 7,634,080; javascript: 3,564,060; python: 1,649,622; xml: 838,470; asm: 717,087; pascal: 185,708; sh: 88,786; perl: 88,718; objc: 79,984; sql: 59,811; cs: 42,452; fortran: 24,101; makefile: 21,144; tcl: 15,277; php: 14,022; yacc: 9,066; ruby: 7,553; awk: 3,720; lisp: 3,233; lex: 1,328; ada: 727; jsp: 228; sed: 36
file content (205 lines) | stat: -rw-r--r-- 7,591 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_STORAGE_H_
#define SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_STORAGE_H_

#include <list>
#include <map>
#include <set>
#include <string>

#include "base/component_export.h"
#include "base/containers/contains.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/strings/pattern.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"

class GURL;

namespace net {
class HttpResponseHeaders;
class SharedDictionary;
}  // namespace net

namespace url_pattern {
class SimpleUrlPatternMatcher;
}

namespace network {
namespace mojom {
enum class FetchResponseType : int32_t;
enum class RequestDestination : int32_t;
enum class RequestMode : int32_t;
enum class SharedDictionaryError : int32_t;
}  // namespace mojom

class SharedDictionaryWriter;

// Shared Dictionary Storage manages dictionaries for a particular
// net::SharedDictionaryIsolationKey.
class COMPONENT_EXPORT(NETWORK_SERVICE) SharedDictionaryStorage
    : public base::RefCounted<SharedDictionaryStorage> {
 public:
  SharedDictionaryStorage(const SharedDictionaryStorage&) = delete;
  SharedDictionaryStorage& operator=(const SharedDictionaryStorage&) = delete;

  // Returns a SharedDictionaryWriter if `headers` has a valid
  // `use-as-dictionary` header, and `access_allowed_check_callback`
  // returns true,
  static base::expected<scoped_refptr<SharedDictionaryWriter>,
                        mojom::SharedDictionaryError>
  MaybeCreateWriter(const std::string& use_as_dictionary_header,
                    bool shared_dictionary_writer_enabled,
                    SharedDictionaryStorage* storage,
                    mojom::RequestMode request_mode,
                    mojom::FetchResponseType response_tainting,
                    const GURL& url,
                    const base::Time request_time,
                    const base::Time response_time,
                    const net::HttpResponseHeaders& headers,
                    bool was_fetched_via_cache,
                    base::OnceCallback<bool()> access_allowed_check_callback);

  // Returns a matching SharedDictionary for `url`. If the metadata has not been
  // read from the database, this method returns nullptr.
  virtual scoped_refptr<net::SharedDictionary> GetDictionarySync(
      const GURL& url,
      mojom::RequestDestination destination) = 0;

  // If the metadata has already been read from the database, this method calls
  // `callback` synchronously with a matching `SharedDictionary`. Otherwise,
  // this method waits until the metadata is available, and then calls
  // `callback` with a matching `SharedDictionary`.
  virtual void GetDictionary(
      const GURL& url,
      mojom::RequestDestination destination,
      base::OnceCallback<void(scoped_refptr<net::SharedDictionary>)>
          callback) = 0;

 protected:
  friend class base::RefCounted<SharedDictionaryStorage>;

  SharedDictionaryStorage();
  virtual ~SharedDictionaryStorage();

  // Called to create a SharedDictionaryWriter.
  virtual base::expected<scoped_refptr<SharedDictionaryWriter>,
                         mojom::SharedDictionaryError>
  CreateWriter(
      const GURL& url,
      base::Time last_fetch_time,
      base::Time response_time,
      base::TimeDelta expiration,
      const std::string& match,
      const std::set<mojom::RequestDestination>& match_dest,
      const std::string& id,
      std::unique_ptr<url_pattern::SimpleUrlPatternMatcher> matcher) = 0;

  // If the matching dictionary is already registered, this method updates the
  // `last_fetch_time` of the registered dictionary, and returns true.
  // Otherwise, this method returns false.
  virtual bool UpdateLastFetchTimeIfAlreadyRegistered(
      const GURL& url,
      base::Time response_time,
      base::TimeDelta expiration,
      const std::string& match,
      const std::set<mojom::RequestDestination>& match_dest,
      const std::string& id,
      const std::optional<base::TimeDelta>& ttl,
      base::Time last_fetch_time) = 0;
};

// Returns a matching dictionary for `url` from `dictionary_info_map`.
// This is a template method because SharedDictionaryStorageInMemory and
// SharedDictionaryStorageOnDisk are using different class for
// DictionaryInfoType.
template <class DictionaryInfoType>
DictionaryInfoType* GetMatchingDictionaryFromDictionaryInfoMap(
    std::map<
        url::SchemeHostPort,
        std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
                 DictionaryInfoType>>& dictionary_info_map,
    const GURL& url,
    mojom::RequestDestination destination,
    std::list<DictionaryInfoType*>& expired_entries) {
  auto it = dictionary_info_map.find(url::SchemeHostPort(url));
  if (it == dictionary_info_map.end()) {
    return nullptr;
  }
  base::Time now = base::Time::Now();
  DictionaryInfoType* matched_info = nullptr;
  for (auto& item : it->second) {
    DictionaryInfoType& info = item.second;
    CHECK(std::make_tuple(info.match(), info.match_dest()) == item.first);

    // Keep track of (but don't match) expired entries.
    if (info.response_time() + info.expiration() <= now) {
      expired_entries.push_back(&info);
      continue;
    }

    if (matched_info &&
        ((matched_info->match().size() > info.match().size()) ||
         (matched_info->match().size() == info.match().size() &&
          matched_info->last_fetch_time() > info.last_fetch_time()))) {
      continue;
    }
    // When `match_dest` is empty, we don't check the `destination`.
    if (!info.match_dest().empty() &&
        !base::Contains(info.match_dest(), destination)) {
      continue;
    }
    CHECK(info.matcher());
    if (info.matcher()->Match(url)) {
      matched_info = &info;
    }
  }
  return matched_info;
}

// Returns the matching registered dictionary in `dictionary_info_map`. This is
// used to avoid registering the same dictionary from the disk cache.
// This is a template method because SharedDictionaryStorageInMemory and
// SharedDictionaryStorageOnDisk are using different class for
// DictionaryInfoType.
template <class DictionaryInfoType>
DictionaryInfoType* FindRegisteredInDictionaryInfoMap(
    std::map<
        url::SchemeHostPort,
        std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
                 DictionaryInfoType>>& dictionary_info_map,
    const GURL& url,
    base::Time response_time,
    base::TimeDelta expiration,
    const std::string& match,
    const std::set<mojom::RequestDestination>& match_dest,
    const std::string& id,
    const std::optional<base::TimeDelta>& ttl) {
  auto it1 = dictionary_info_map.find(url::SchemeHostPort(url));
  if (it1 == dictionary_info_map.end()) {
    return nullptr;
  }
  auto it2 = it1->second.find(std::make_tuple(match, match_dest));
  if (it2 == it1->second.end()) {
    return nullptr;
  }
  // The response_time can update on every fetch if "ttl" is used so only
  // check for the exact match of response_time if a ttl isn't present.
  if (it2->second.url() == url &&
      (ttl || it2->second.response_time() == response_time) &&
      it2->second.expiration() == expiration && it2->second.id() == id) {
    return &it2->second;
  } else {
    return nullptr;
  }
}

}  // namespace network

#endif  // SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_STORAGE_H_