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_
|