Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2018 The Chromium Authors |
Tsuyoshi Horo | cdbb490 | 2018-04-12 06:09:14 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "content/browser/web_package/signed_exchange_utils.h" |
| 6 | |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 7 | #include <string_view> |
| 8 | |
Kunihiko Sakamoto | 0cc9371 | 2019-01-11 06:26:53 | [diff] [blame] | 9 | #include "base/command_line.h" |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 10 | #include "base/feature_list.h" |
Kunihiko Sakamoto | 6405d0af | 2021-11-18 00:46:37 | [diff] [blame] | 11 | #include "base/metrics/histogram_functions.h" |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 12 | #include "base/strings/string_util.h" |
Hans Wennborg | 5ffd139 | 2019-10-16 11:00:02 | [diff] [blame] | 13 | #include "base/strings/stringprintf.h" |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 14 | #include "base/time/time.h" |
Tsuyoshi Horo | cdbb490 | 2018-04-12 06:09:14 | [diff] [blame] | 15 | #include "base/trace_event/trace_event.h" |
Tsuyoshi Horo | 154dafc | 2018-11-06 09:32:28 | [diff] [blame] | 16 | #include "content/browser/loader/download_utils_impl.h" |
Tsuyoshi Horo | 4801e76 | 2018-04-25 07:36:57 | [diff] [blame] | 17 | #include "content/browser/web_package/signed_exchange_devtools_proxy.h" |
Tsuyoshi Horo | b40c7c3 | 2018-05-31 07:32:45 | [diff] [blame] | 18 | #include "content/browser/web_package/signed_exchange_error.h" |
Kunihiko Sakamoto | e6aa22e | 2018-06-15 03:26:55 | [diff] [blame] | 19 | #include "content/browser/web_package/signed_exchange_request_handler.h" |
Arthur Sonzogni | bdeca8e | 2023-09-11 08:32:12 | [diff] [blame] | 20 | #include "content/common/features.h" |
Kunihiko Sakamoto | f586da6 | 2019-03-28 03:03:04 | [diff] [blame] | 21 | #include "content/public/browser/content_browser_client.h" |
| 22 | #include "content/public/common/content_client.h" |
Kunihiko Sakamoto | 0cc9371 | 2019-01-11 06:26:53 | [diff] [blame] | 23 | #include "content/public/common/content_switches.h" |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 24 | #include "net/http/http_util.h" |
Matt Menke | 930e44d | 2020-07-16 02:26:44 | [diff] [blame] | 25 | #include "net/url_request/redirect_info.h" |
Tsuyoshi Horo | 4f5ce901 | 2019-02-27 01:04:45 | [diff] [blame] | 26 | #include "services/network/public/cpp/features.h" |
Sigurd Schneider | e3d43c6b | 2021-07-27 13:35:01 | [diff] [blame] | 27 | #include "services/network/public/cpp/resource_request.h" |
Lucas Furukawa Gadani | d661c0d | 2019-12-02 19:58:16 | [diff] [blame] | 28 | #include "services/network/public/mojom/url_response_head.mojom.h" |
Tsuyoshi Horo | cdbb490 | 2018-04-12 06:09:14 | [diff] [blame] | 29 | |
| 30 | namespace content { |
| 31 | namespace signed_exchange_utils { |
| 32 | |
Tsuyoshi Horo | af905953 | 2019-08-29 15:27:02 | [diff] [blame] | 33 | namespace { |
Kunihiko Sakamoto | 6405d0af | 2021-11-18 00:46:37 | [diff] [blame] | 34 | constexpr char kLoadResultHistogram[] = "SignedExchange.LoadResult2"; |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 35 | std::optional<base::Time> g_verification_time_for_testing; |
Tsuyoshi Horo | af905953 | 2019-08-29 15:27:02 | [diff] [blame] | 36 | } // namespace |
| 37 | |
Kunihiko Sakamoto | 6405d0af | 2021-11-18 00:46:37 | [diff] [blame] | 38 | void RecordLoadResultHistogram(SignedExchangeLoadResult result) { |
| 39 | base::UmaHistogramEnumeration(kLoadResultHistogram, result); |
| 40 | } |
| 41 | |
Tsuyoshi Horo | 6361cb0 | 2018-06-04 04:36:02 | [diff] [blame] | 42 | void ReportErrorAndTraceEvent( |
Tsuyoshi Horo | b40c7c3 | 2018-05-31 07:32:45 | [diff] [blame] | 43 | SignedExchangeDevToolsProxy* devtools_proxy, |
Tsuyoshi Horo | b40c7c3 | 2018-05-31 07:32:45 | [diff] [blame] | 44 | const std::string& error_message, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 45 | std::optional<SignedExchangeError::FieldIndexPair> error_field) { |
Tsuyoshi Horo | 6361cb0 | 2018-06-04 04:36:02 | [diff] [blame] | 46 | TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("loading"), |
| 47 | "SignedExchangeError", TRACE_EVENT_SCOPE_THREAD, "error", |
| 48 | error_message); |
Tsuyoshi Horo | 4801e76 | 2018-04-25 07:36:57 | [diff] [blame] | 49 | if (devtools_proxy) |
Tsuyoshi Horo | b40c7c3 | 2018-05-31 07:32:45 | [diff] [blame] | 50 | devtools_proxy->ReportError(error_message, std::move(error_field)); |
Tsuyoshi Horo | cdbb490 | 2018-04-12 06:09:14 | [diff] [blame] | 51 | } |
| 52 | |
Clark DuVall | ab63d14 | 2019-07-23 04:24:36 | [diff] [blame] | 53 | bool IsSignedExchangeHandlingEnabled(BrowserContext* context) { |
Andrew Williams | 3835147 | 2024-07-24 16:47:30 | [diff] [blame] | 54 | return GetContentClient()->browser()->AllowSignedExchange(context); |
Kunihiko Sakamoto | 0cc9371 | 2019-01-11 06:26:53 | [diff] [blame] | 55 | } |
| 56 | |
Tsuyoshi Horo | 4f5ce901 | 2019-02-27 01:04:45 | [diff] [blame] | 57 | bool IsSignedExchangeReportingForDistributorsEnabled() { |
Dave Tapuska | b325d75 | 2024-04-23 01:34:14 | [diff] [blame] | 58 | return base::FeatureList::IsEnabled(network::features::kReporting); |
Tsuyoshi Horo | 4f5ce901 | 2019-02-27 01:04:45 | [diff] [blame] | 59 | } |
| 60 | |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 61 | bool ShouldHandleAsSignedHTTPExchange( |
| 62 | const GURL& request_url, |
Lucas Furukawa Gadani | d661c0d | 2019-12-02 19:58:16 | [diff] [blame] | 63 | const network::mojom::URLResponseHead& head) { |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 64 | // Currently we don't support the signed exchange which is returned from a |
| 65 | // service worker. |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 66 | // TODO(crbug.com/40558902): Decide whether we should support it or not. |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 67 | if (head.was_fetched_via_service_worker) |
| 68 | return false; |
Kunihiko Sakamoto | e6aa22e | 2018-06-15 03:26:55 | [diff] [blame] | 69 | if (!SignedExchangeRequestHandler::IsSupportedMimeType(head.mime_type)) |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 70 | return false; |
Tsuyoshi Horo | 73af162 | 2019-02-28 05:34:04 | [diff] [blame] | 71 | // Do not handle responses without HttpResponseHeaders. |
| 72 | // (Example: data:application/signed-exchange,) |
| 73 | if (!head.headers.get()) |
| 74 | return false; |
Josh Simmons | 05aa52f | 2023-08-30 22:45:18 | [diff] [blame] | 75 | if (download_utils::MustDownload(/*browser_context=*/nullptr, request_url, |
| 76 | head.headers.get(), head.mime_type)) { |
Tsuyoshi Horo | 154dafc | 2018-11-06 09:32:28 | [diff] [blame] | 77 | return false; |
| 78 | } |
Kunihiko Sakamoto | f586da6 | 2019-03-28 03:03:04 | [diff] [blame] | 79 | return true; |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 80 | } |
| 81 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 82 | std::optional<SignedExchangeVersion> GetSignedExchangeVersion( |
Matt Menke | 16ba457 | 2024-10-04 04:24:18 | [diff] [blame] | 83 | std::string_view content_type) { |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 84 | // https://wicg.github.io/webpackage/loading.html#signed-exchange-version |
| 85 | // Step 1. Let mimeType be the supplied MIME type of response. [spec text] |
| 86 | // |content_type| is the supplied MIME type. |
| 87 | // Step 2. If mimeType is undefined, return undefined. [spec text] |
| 88 | // Step 3. If mimeType's essence is not "application/signed-exchange", return |
| 89 | // undefined. [spec text] |
| 90 | const std::string::size_type semicolon = content_type.find(';'); |
| 91 | const std::string essence = base::ToLowerASCII(base::TrimWhitespaceASCII( |
| 92 | content_type.substr(0, semicolon), base::TRIM_ALL)); |
| 93 | if (essence != "application/signed-exchange") |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 94 | return std::nullopt; |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 95 | |
| 96 | // Step 4.Let params be mimeType's parameters. [spec text] |
| 97 | std::map<std::string, std::string> params; |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 98 | if (semicolon != std::string_view::npos) { |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 99 | net::HttpUtil::NameValuePairsIterator parser( |
Matt Menke | 16ba457 | 2024-10-04 04:24:18 | [diff] [blame] | 100 | content_type.substr(semicolon + 1), ';'); |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 101 | while (parser.GetNext()) { |
Matt Menke | 300c5516 | 2024-10-02 15:09:47 | [diff] [blame] | 102 | params[base::ToLowerASCII(parser.name())] = parser.value(); |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 103 | } |
| 104 | if (!parser.valid()) |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 105 | return std::nullopt; |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 106 | } |
| 107 | // Step 5. If params["v"] exists, return it. Otherwise, return undefined. |
| 108 | // [spec text] |
| 109 | auto iter = params.find("v"); |
| 110 | if (iter != params.end()) { |
Kouhei Ueno | 9007cf2 | 2019-01-09 08:23:24 | [diff] [blame] | 111 | if (iter->second == "b3") |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 112 | return std::make_optional(SignedExchangeVersion::kB3); |
| 113 | return std::make_optional(SignedExchangeVersion::kUnknown); |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 114 | } |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 115 | return std::nullopt; |
Kunihiko Sakamoto | b5c94d90 | 2018-09-04 04:09:02 | [diff] [blame] | 116 | } |
| 117 | |
Tsuyoshi Horo | 06eb28f | 2019-02-21 13:52:24 | [diff] [blame] | 118 | SignedExchangeLoadResult GetLoadResultFromSignatureVerifierResult( |
| 119 | SignedExchangeSignatureVerifier::Result verify_result) { |
| 120 | switch (verify_result) { |
| 121 | case SignedExchangeSignatureVerifier::Result::kSuccess: |
| 122 | return SignedExchangeLoadResult::kSuccess; |
| 123 | case SignedExchangeSignatureVerifier::Result::kErrCertificateSHA256Mismatch: |
| 124 | // "Handling the certificate reference |
| 125 | // ... |
| 126 | // - If the SHA-256 hash of chain’s leaf's certificate is not equal to |
| 127 | // certSha256, return "signature_verification_error"." [spec text] |
| 128 | return SignedExchangeLoadResult::kSignatureVerificationError; |
| 129 | case SignedExchangeSignatureVerifier::Result:: |
| 130 | kErrSignatureVerificationFailed: |
| 131 | // "Validating a signature |
| 132 | // ... |
| 133 | // - If parsedSignature’s signature is not a valid signature of message |
| 134 | // by publicKey using the ecdsa_secp256r1_sha256 algorithm, return |
| 135 | // invalid." [spec text] |
| 136 | // |
| 137 | // "Parsing signed exchanges |
| 138 | // - ... |
| 139 | // - If parsedSignature is not valid for headerBytes and |
| 140 | // requestUrlBytes, and signed exchange version version, return |
| 141 | // "signature_verification_error"." [spec text] |
| 142 | return SignedExchangeLoadResult::kSignatureVerificationError; |
Tsuyoshi Horo | 06eb28f | 2019-02-21 13:52:24 | [diff] [blame] | 143 | case SignedExchangeSignatureVerifier::Result::kErrUnsupportedCertType: |
| 144 | // "Validating a signature |
| 145 | // ... |
| 146 | // - If parsedSignature’s signature is not a valid signature of message |
| 147 | // by publicKey using the ecdsa_secp256r1_sha256 algorithm, return |
| 148 | // invalid." [spec text] |
| 149 | // |
| 150 | // "Parsing signed exchanges |
| 151 | // - ... |
| 152 | // - If parsedSignature is not valid for headerBytes and |
| 153 | // requestUrlBytes, and signed exchange version version, return |
| 154 | // "signature_verification_error"." [spec text] |
| 155 | return SignedExchangeLoadResult::kSignatureVerificationError; |
| 156 | case SignedExchangeSignatureVerifier::Result::kErrValidityPeriodTooLong: |
| 157 | // "Cross-origin trust |
| 158 | // ... |
| 159 | // - If signature’s expiration time is more than 604800 seconds (7 days) |
| 160 | // after signature’s date, return "untrusted"." [spec text] |
| 161 | // |
| 162 | // "Parsing signed exchanges |
| 163 | // - ... |
| 164 | // - If parsedSignature does not establish cross-origin trust for |
| 165 | // parsedExchange, return "cert_verification_error"." [spec text] |
| 166 | return SignedExchangeLoadResult::kCertVerificationError; |
| 167 | case SignedExchangeSignatureVerifier::Result::kErrFutureDate: |
| 168 | case SignedExchangeSignatureVerifier::Result::kErrExpired: |
| 169 | // "Validating a signature |
| 170 | // ... |
| 171 | // - If the UA’s estimate of the current time is more than clockSkew |
| 172 | // before signature’s date, return "untrusted". |
| 173 | // - If the UA’s estimate of the current time is after signature’s |
| 174 | // expiration time, return "untrusted"." [spec text] |
| 175 | // |
| 176 | // "Parsing signed exchanges |
| 177 | // - ... |
| 178 | // - If parsedSignature is not valid for headerBytes and |
| 179 | // requestUrlBytes, and signed exchange version version, return |
| 180 | // "signature_verification_error"." [spec text] |
| 181 | return SignedExchangeLoadResult::kSignatureVerificationError; |
| 182 | |
| 183 | // Deprecated error results. |
| 184 | case SignedExchangeSignatureVerifier::Result::kErrNoCertificate_deprecated: |
| 185 | case SignedExchangeSignatureVerifier::Result:: |
| 186 | kErrNoCertificateSHA256_deprecated: |
| 187 | case SignedExchangeSignatureVerifier::Result:: |
| 188 | kErrInvalidSignatureFormat_deprecated: |
| 189 | case SignedExchangeSignatureVerifier::Result:: |
Kunihiko Sakamoto | 44cd9a8 | 2019-02-26 05:47:06 | [diff] [blame] | 190 | kErrInvalidSignatureIntegrity_deprecated: |
| 191 | case SignedExchangeSignatureVerifier::Result:: |
Tsuyoshi Horo | 06eb28f | 2019-02-21 13:52:24 | [diff] [blame] | 192 | kErrInvalidTimestamp_deprecated: |
Peter Boström | fc7ddc18 | 2024-10-31 19:37:21 | [diff] [blame] | 193 | NOTREACHED(); |
Tsuyoshi Horo | 06eb28f | 2019-02-21 13:52:24 | [diff] [blame] | 194 | } |
| 195 | |
Peter Boström | fc7ddc18 | 2024-10-31 19:37:21 | [diff] [blame] | 196 | NOTREACHED(); |
Tsuyoshi Horo | 06eb28f | 2019-02-21 13:52:24 | [diff] [blame] | 197 | } |
| 198 | |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 199 | net::RedirectInfo CreateRedirectInfo( |
| 200 | const GURL& new_url, |
| 201 | const network::ResourceRequest& outer_request, |
Lucas Furukawa Gadani | 62fcfa9 | 2019-12-05 15:38:41 | [diff] [blame] | 202 | const network::mojom::URLResponseHead& outer_response, |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 203 | bool is_fallback_redirect) { |
| 204 | // https://wicg.github.io/webpackage/loading.html#mp-http-fetch |
| 205 | // Step 3. Set actualResponse's status to 303. [spec text] |
| 206 | return net::RedirectInfo::ComputeRedirectInfo( |
Dominic Farolino | 28e2121 | 2019-12-03 17:38:07 | [diff] [blame] | 207 | "GET", outer_request.url, outer_request.site_for_cookies, |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 208 | outer_request.update_first_party_url_on_redirect |
Matt Menke | 930e44d | 2020-07-16 02:26:44 | [diff] [blame] | 209 | ? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT |
| 210 | : net::RedirectInfo::FirstPartyURLPolicy::NEVER_CHANGE_URL, |
Kelvin Jiang | badc704 | 2025-06-27 01:34:27 | [diff] [blame] | 211 | outer_request.referrer_policy, outer_request.referrer.spec(), |
| 212 | outer_request.request_initiator, 303, new_url, |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 213 | net::RedirectUtil::GetReferrerPolicyHeader(outer_response.headers.get()), |
| 214 | false /* insecure_scheme_was_upgraded */, true /* copy_fragment */, |
| 215 | is_fallback_redirect); |
| 216 | } |
| 217 | |
Lucas Furukawa Gadani | 62fcfa9 | 2019-12-05 15:38:41 | [diff] [blame] | 218 | network::mojom::URLResponseHeadPtr CreateRedirectResponseHead( |
| 219 | const network::mojom::URLResponseHead& outer_response, |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 220 | bool is_fallback_redirect) { |
Lucas Furukawa Gadani | 62fcfa9 | 2019-12-05 15:38:41 | [diff] [blame] | 221 | auto response_head = network::mojom::URLResponseHead::New(); |
| 222 | response_head->encoded_data_length = 0; |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 223 | std::string buf; |
| 224 | std::string link_header; |
| 225 | if (!is_fallback_redirect && |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 226 | outer_response.headers) { |
Chris Fredrickson | c0314cc | 2024-10-18 14:48:51 | [diff] [blame] | 227 | link_header = outer_response.headers->GetNormalizedHeader("link").value_or( |
| 228 | std::string()); |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 229 | } |
| 230 | if (link_header.empty()) { |
| 231 | buf = base::StringPrintf("HTTP/1.1 %d %s\r\n", 303, "See Other"); |
| 232 | } else { |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 233 | buf = base::StringPrintf( |
| 234 | "HTTP/1.1 %d %s\r\n" |
| 235 | "link: %s\r\n", |
| 236 | 303, "See Other", link_header.c_str()); |
| 237 | } |
Lucas Furukawa Gadani | 62fcfa9 | 2019-12-05 15:38:41 | [diff] [blame] | 238 | response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>( |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 239 | net::HttpUtil::AssembleRawHeaders(buf)); |
Lucas Furukawa Gadani | 62fcfa9 | 2019-12-05 15:38:41 | [diff] [blame] | 240 | response_head->encoded_data_length = 0; |
| 241 | response_head->request_start = outer_response.request_start; |
| 242 | response_head->response_start = outer_response.response_start; |
| 243 | response_head->request_time = outer_response.request_time; |
| 244 | response_head->response_time = outer_response.response_time; |
| 245 | response_head->load_timing = outer_response.load_timing; |
Tsuyoshi Horo | d5eb761 | 2019-05-09 08:59:46 | [diff] [blame] | 246 | return response_head; |
| 247 | } |
| 248 | |
John Abd-El-Malek | d96edf3 | 2019-07-29 22:04:52 | [diff] [blame] | 249 | int MakeRequestID() { |
| 250 | // Request ID for browser initiated requests. request_ids generated by |
| 251 | // child processes are counted up from 0, while browser created requests |
| 252 | // start at -2 and go down from there. (We need to start at -2 because -1 is |
| 253 | // used as a special value all over the resource_dispatcher_host for |
| 254 | // uninitialized variables.) This way, we no longer have the unlikely (but |
| 255 | // observed in the real world!) event where we have two requests with the same |
| 256 | // request_id_. |
Avi Drissman | ded7717 | 2021-07-02 18:23:00 | [diff] [blame] | 257 | static std::atomic_int request_id(-1); |
John Abd-El-Malek | d96edf3 | 2019-07-29 22:04:52 | [diff] [blame] | 258 | |
Avi Drissman | ded7717 | 2021-07-02 18:23:00 | [diff] [blame] | 259 | return --request_id; |
John Abd-El-Malek | d96edf3 | 2019-07-29 22:04:52 | [diff] [blame] | 260 | } |
| 261 | |
Tsuyoshi Horo | af905953 | 2019-08-29 15:27:02 | [diff] [blame] | 262 | base::Time GetVerificationTime() { |
| 263 | if (g_verification_time_for_testing) |
| 264 | return *g_verification_time_for_testing; |
| 265 | return base::Time::Now(); |
| 266 | } |
| 267 | |
| 268 | void SetVerificationTimeForTesting( |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 269 | std::optional<base::Time> verification_time_for_testing) { |
Tsuyoshi Horo | af905953 | 2019-08-29 15:27:02 | [diff] [blame] | 270 | g_verification_time_for_testing = verification_time_for_testing; |
| 271 | } |
| 272 | |
Kunihiko Sakamoto | 6405d0af | 2021-11-18 00:46:37 | [diff] [blame] | 273 | bool IsCookielessOnlyExchange(const net::HttpResponseHeaders& inner_headers) { |
Matt Menke | 16ba457 | 2024-10-04 04:24:18 | [diff] [blame] | 274 | std::optional<std::string_view> value; |
Kunihiko Sakamoto | 6405d0af | 2021-11-18 00:46:37 | [diff] [blame] | 275 | size_t iter = 0; |
Matt Menke | 16ba457 | 2024-10-04 04:24:18 | [diff] [blame] | 276 | while ((value = inner_headers.EnumerateHeader(&iter, "Vary"))) { |
| 277 | if (base::EqualsCaseInsensitiveASCII(*value, "cookie")) { |
Kunihiko Sakamoto | 6405d0af | 2021-11-18 00:46:37 | [diff] [blame] | 278 | return true; |
Matt Menke | 16ba457 | 2024-10-04 04:24:18 | [diff] [blame] | 279 | } |
Kunihiko Sakamoto | 6405d0af | 2021-11-18 00:46:37 | [diff] [blame] | 280 | } |
| 281 | return false; |
| 282 | } |
| 283 | |
Tsuyoshi Horo | cdbb490 | 2018-04-12 06:09:14 | [diff] [blame] | 284 | } // namespace signed_exchange_utils |
| 285 | } // namespace content |