File: offline_page_request_handler.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (234 lines) | stat: -rw-r--r-- 8,118 bytes parent folder | download | duplicates (4)
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_REQUEST_HANDLER_H_
#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_REQUEST_HANDLER_H_

#include <memory>
#include <string>
#include <vector>

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "components/offline_pages/core/archive_validator.h"
#include "components/offline_pages/core/offline_page_item.h"
#include "components/offline_pages/core/request_header/offline_page_header.h"

namespace base {
class FilePath;
class TaskRunner;
}

namespace content {
class WebContents;
}

namespace net {
class FileStream;
class HttpRequestHeaders;
class HttpResponseHeaders;
class IOBuffer;
}  // namespace net

namespace offline_pages {

// A handler that serves content from a trusted offline file, located either
// in internal directory or in public directory with digest validated, when a
// http/https URL is being navigated on disconnected or poor network. If no
// trusted offline file can be found, fall back to the default network handling
// which will try to load the live version.
//
// The only header handled by this request job is:
// * "X-Chrome-offline" custom header.
class OfflinePageRequestHandler {
 public:
  enum class NetworkState {
    // No network connection.
    DISCONNECTED_NETWORK,
    // Prohibitively slow means that the NetworkQualityEstimator reported a
    // connection slow enough to warrant showing an offline page if available.
    // This requires offline previews to be enabled and the URL of the request
    // to be allowed by previews.
    PROHIBITIVELY_SLOW_NETWORK,
    // Network error received due to bad network, i.e. connected to a hotspot or
    // proxy that does not have a working network.
    FLAKY_NETWORK,
    // Network is in working condition.
    CONNECTED_NETWORK,
    // Force to load the offline page if it is available, though network is in
    // working condition.
    FORCE_OFFLINE_ON_CONNECTED_NETWORK
  };

  // Describes the info about an offline page candidate.
  struct Candidate {
    OfflinePageItem offline_page;
    // Whether the archive file is in internal directory, for which it can be
    // deemed trusted without validation.
    bool archive_is_in_internal_dir;
  };

  // Delegate that allows the consumer to overwrite certain behaviors.
  // All methods are called from IO thread.
  class Delegate {
   public:
    using WebContentsGetter =
        base::RepeatingCallback<content::WebContents*(void)>;
    using TabIdGetter =
        base::RepeatingCallback<bool(content::WebContents*, int*)>;

    // Falls back to the default handling in the case that the offline content
    // can't be found and served.
    virtual void FallbackToDefault() = 0;

    // Notifies that a start error has occurred.
    virtual void NotifyStartError(int error) = 0;

    // Notifies that the headers have been received. |file_size| indicates the
    // total size to be read.
    virtual void NotifyHeadersComplete(int64_t file_size) = 0;

    // Notifies that ReadRawData() is completed. |bytes_read| is either >= 0 to
    // indicate a successful read and count of bytes read, or < 0 to indicate an
    // error.
    virtual void NotifyReadRawDataComplete(int bytes_read) = 0;

    // Sets |is_offline_page| flag in NavigationUIData.
    // Note: this should be called before the response data is being constructed
    // and returned because NavigationUIData may be disposed right after the
    // response data is received.
    virtual void SetOfflinePageNavigationUIData(bool is_offline_page) = 0;

    // Returns the page transition type for this navigation.
    virtual int GetPageTransition() const = 0;

    // Returns the getter to retrieve the web contents associated with this
    // this navigation.
    virtual WebContentsGetter GetWebContentsGetter() const = 0;

    // Returns the getter to retrieve the ID of the tab where this navigation
    // occurs.
    virtual TabIdGetter GetTabIdGetter() const = 0;

   protected:
    virtual ~Delegate() = default;
  };

  class ThreadSafeArchiveValidator final
      : public ArchiveValidator,
        public base::RefCountedThreadSafe<ThreadSafeArchiveValidator> {
   public:
    ThreadSafeArchiveValidator() = default;

   private:
    friend class base::RefCountedThreadSafe<ThreadSafeArchiveValidator>;
    ~ThreadSafeArchiveValidator() override = default;
  };

  OfflinePageRequestHandler(
      const GURL& url,
      const net::HttpRequestHeaders& extra_request_headers,
      Delegate* delegate);

  OfflinePageRequestHandler(const OfflinePageRequestHandler&) = delete;
  OfflinePageRequestHandler& operator=(const OfflinePageRequestHandler&) =
      delete;

  ~OfflinePageRequestHandler();

  void Start();
  void Kill();
  bool IsServingOfflinePage() const;

  // Returns the http response headers to trigger a redirect.
  scoped_refptr<net::HttpResponseHeaders> GetRedirectHeaders();

  // Reads at most |dest_size| bytes of the raw data into |dest| buffer.
  int ReadRawData(net::IOBuffer* dest, int dest_size);

  // Called when offline pages matching the request URL are found. The list is
  // sorted based on creation date in descending order.
  void OnOfflinePagesAvailable(const std::vector<Candidate>& candidates);

 private:
  enum class FileValidationResult {
    // The file passes the digest validation and thus can be trusted.
    FILE_VALIDATION_SUCCEEDED,
    // The file does not exist.
    FILE_NOT_FOUND,
    // The digest validation fails.
    FILE_VALIDATION_FAILED,
  };

  void StartAsync();

  NetworkState GetNetworkState() const;

  const OfflinePageItem& GetCurrentOfflinePage() const;

  bool IsProcessingFileUrlIntent() const;
  bool IsProcessingContentUrlIntent() const;
  bool IsProcessingFileOrContentUrlIntent() const;

  void OnTrustedOfflinePageFound();
  void VisitTrustedOfflinePage();
  void Redirect(const GURL& redirected_url);

  void OpenFile(const base::FilePath& file_path,
                const base::RepeatingCallback<void(int)>& callback);
  void UpdateDigestOnBackground(
      scoped_refptr<net::IOBuffer> buffer,
      size_t len,
      base::OnceCallback<void(void)> digest_updated_callback);
  void FinalizeDigestOnBackground(
      base::OnceCallback<void(const std::string&)> digest_finalized_callback);

  // All the work related to validations.
  void ValidateFile();
  void GetFileSizeForValidation();
  void DidGetFileSizeForValidation(std::optional<int64_t> file_size);
  void DidOpenForValidation(int result);
  void ReadForValidation();
  void DidReadForValidation(int result);
  void DidComputeActualDigestForValidation(const std::string& actual_digest);
  void OnFileValidationDone(FileValidationResult result);

  // All the work related to serving from the archive file.
  void DidOpenForServing(int result);
  void DidSeekForServing(int64_t result);
  void DidReadForServing(scoped_refptr<net::IOBuffer> buf, int result);
  void NotifyReadRawDataComplete(int result);
  void DidComputeActualDigestForServing(int result,
                                        const std::string& actual_digest);

  GURL url_;
  raw_ptr<Delegate> delegate_;

  OfflinePageHeader offline_header_;
  NetworkState network_state_;

  // For redirect simulation.
  scoped_refptr<net::HttpResponseHeaders> fake_headers_for_redirect_;

  // To run any file related operations.
  scoped_refptr<base::TaskRunner> file_task_runner_;

  // For file validaton purpose.
  std::vector<Candidate> candidates_;
  size_t candidate_index_;
  scoped_refptr<net::IOBuffer> buffer_;
  scoped_refptr<ThreadSafeArchiveValidator> archive_validator_;

  // For the purpose of serving from the archive file.
  base::FilePath file_path_;
  std::unique_ptr<net::FileStream> stream_;

  base::WeakPtrFactory<OfflinePageRequestHandler> weak_ptr_factory_{this};
};

}  // namespace offline_pages

#endif  // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_REQUEST_HANDLER_H_