• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 "net/http/http_response_info.h"
6 
7 #include <optional>
8 
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/pickle.h"
12 #include "base/time/time.h"
13 #include "net/base/net_errors.h"
14 #include "net/cert/sct_status_flags.h"
15 #include "net/cert/signed_certificate_timestamp.h"
16 #include "net/cert/x509_certificate.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/ssl/ssl_cert_request_info.h"
19 #include "net/ssl/ssl_connection_status_flags.h"
20 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
21 #include "third_party/boringssl/src/include/openssl/ssl.h"
22 
23 using base::Time;
24 
25 namespace net {
26 
27 namespace {
28 
KeyExchangeGroupIsValid(int ssl_connection_status)29 bool KeyExchangeGroupIsValid(int ssl_connection_status) {
30   // TLS 1.3 and later always treat the field correctly.
31   if (SSLConnectionStatusToVersion(ssl_connection_status) >=
32       SSL_CONNECTION_VERSION_TLS1_3) {
33     return true;
34   }
35 
36   // Prior to TLS 1.3, only ECDHE ciphers have groups.
37   const SSL_CIPHER* cipher = SSL_get_cipher_by_value(
38       SSLConnectionStatusToCipherSuite(ssl_connection_status));
39   return cipher && SSL_CIPHER_get_kx_nid(cipher) == NID_kx_ecdhe;
40 }
41 
42 }  // namespace
43 
44 // These values can be bit-wise combined to form the flags field of the
45 // serialized HttpResponseInfo.
46 enum {
47   // The version of the response info used when persisting response info.
48   RESPONSE_INFO_VERSION = 3,
49 
50   // The minimum version supported for deserializing response info.
51   RESPONSE_INFO_MINIMUM_VERSION = 3,
52 
53   // We reserve up to 8 bits for the version number.
54   RESPONSE_INFO_VERSION_MASK = 0xFF,
55 
56   // This bit is set if the response info has a cert at the end.
57   // Version 1 serialized only the end-entity certificate, while subsequent
58   // versions include the available certificate chain.
59   RESPONSE_INFO_HAS_CERT = 1 << 8,
60 
61   // This bit was historically set if the response info had a security-bits
62   // field (security strength, in bits, of the SSL connection) at the end.
63   RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9,
64 
65   // This bit is set if the response info has a cert status at the end.
66   RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10,
67 
68   // This bit is set if the response info has vary header data.
69   RESPONSE_INFO_HAS_VARY_DATA = 1 << 11,
70 
71   // This bit is set if the request was cancelled before completion.
72   RESPONSE_INFO_TRUNCATED = 1 << 12,
73 
74   // This bit is set if the response was received via SPDY.
75   RESPONSE_INFO_WAS_SPDY = 1 << 13,
76 
77   // This bit is set if the request has ALPN negotiated.
78   RESPONSE_INFO_WAS_ALPN = 1 << 14,
79 
80   // This bit is set if the request was fetched via an explicit proxy.
81   // This bit is deprecated.
82   RESPONSE_INFO_WAS_PROXY = 1 << 15,
83 
84   // This bit is set if the response info has an SSL connection status field.
85   // This contains the ciphersuite used to fetch the resource as well as the
86   // protocol version, compression method and whether SSLv3 fallback was used.
87   RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16,
88 
89   // This bit is set if the response info has protocol version.
90   RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL = 1 << 17,
91 
92   // This bit is set if the response info has connection info.
93   RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18,
94 
95   // This bit is set if the request has http authentication.
96   RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19,
97 
98   // This bit is set if ssl_info has SCTs.
99   RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS = 1 << 20,
100 
101   RESPONSE_INFO_UNUSED_SINCE_PREFETCH = 1 << 21,
102 
103   // This bit is set if the response has a key exchange group.
104   RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP = 1 << 22,
105 
106   // This bit is set if ssl_info recorded that PKP was bypassed due to a local
107   // trust anchor.
108   RESPONSE_INFO_PKP_BYPASSED = 1 << 23,
109 
110   // This bit is set if stale_revalidate_time is stored.
111   RESPONSE_INFO_HAS_STALENESS = 1 << 24,
112 
113   // This bit is set if the response has a peer signature algorithm.
114   RESPONSE_INFO_HAS_PEER_SIGNATURE_ALGORITHM = 1 << 25,
115 
116   // This bit is set if the response is a prefetch whose reuse should be
117   // restricted in some way.
118   RESPONSE_INFO_RESTRICTED_PREFETCH = 1 << 26,
119 
120   // This bit is set if the response has a nonempty `dns_aliases` entry.
121   RESPONSE_INFO_HAS_DNS_ALIASES = 1 << 27,
122 
123   // This bit is now unused. It may be set on existing entries. Previously it
124   // was set for an entry in the single-keyed cache that had been marked
125   // unusable due to the cache transparency checksum not matching.
126   RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE = 1 << 28,
127 
128   // This bit is set if the response has `encrypted_client_hello` set.
129   RESPONSE_INFO_ENCRYPTED_CLIENT_HELLO = 1 << 29,
130 
131   // This bit is set if the response has `browser_run_id` set.
132   RESPONSE_INFO_BROWSER_RUN_ID = 1 << 30,
133 
134   // This bit is set if the response has extra bit set.
135   RESPONSE_INFO_HAS_EXTRA_FLAGS = 1 << 31,
136 };
137 
138 // These values can be bit-wise combined to form the extra flags field of the
139 // serialized HttpResponseInfo.
140 enum {
141   // This bit is set if the request usd a shared dictionary for decoding its
142   // body.
143   RESPONSE_EXTRA_INFO_DID_USE_SHARED_DICTIONARY = 1,
144 
145   // This bit is set if the response has valid `proxy_chain`.
146   RESPONSE_EXTRA_INFO_HAS_PROXY_CHAIN = 1 << 1,
147 
148   // This bit is set if the response has original_response_time.
149   RESPONSE_EXTRA_INFO_HAS_ORIGINAL_RESPONSE_TIME = 1 << 2
150 };
151 
152 HttpResponseInfo::HttpResponseInfo() = default;
153 
154 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) = default;
155 
156 HttpResponseInfo::~HttpResponseInfo() = default;
157 
158 HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) =
159     default;
160 
InitFromPickle(const base::Pickle & pickle,bool * response_truncated)161 bool HttpResponseInfo::InitFromPickle(const base::Pickle& pickle,
162                                       bool* response_truncated) {
163   base::PickleIterator iter(pickle);
164 
165   // Read flags and verify version
166   int flags;
167   int extra_flags = 0;
168   if (!iter.ReadInt(&flags))
169     return false;
170   if (flags & RESPONSE_INFO_HAS_EXTRA_FLAGS) {
171     if (!iter.ReadInt(&extra_flags)) {
172       return false;
173     }
174   }
175   int version = flags & RESPONSE_INFO_VERSION_MASK;
176   if (version < RESPONSE_INFO_MINIMUM_VERSION ||
177       version > RESPONSE_INFO_VERSION) {
178     DLOG(ERROR) << "unexpected response info version: " << version;
179     return false;
180   }
181 
182   // Read request-time
183   int64_t time_val;
184   if (!iter.ReadInt64(&time_val))
185     return false;
186   request_time = Time::FromInternalValue(time_val);
187   was_cached = true;  // Set status to show cache resurrection.
188 
189   // Read response-time
190   if (!iter.ReadInt64(&time_val))
191     return false;
192   response_time = Time::FromInternalValue(time_val);
193 
194   // Read original-response-time
195   if ((extra_flags & RESPONSE_EXTRA_INFO_HAS_ORIGINAL_RESPONSE_TIME) != 0) {
196     if (!iter.ReadInt64(&time_val)) {
197       return false;
198     }
199     original_response_time = Time::FromInternalValue(time_val);
200   }
201 
202   // Read response-headers
203   headers = base::MakeRefCounted<HttpResponseHeaders>(&iter);
204   if (headers->response_code() == -1)
205     return false;
206 
207   // Read ssl-info
208   if (flags & RESPONSE_INFO_HAS_CERT) {
209     ssl_info.cert = X509Certificate::CreateFromPickle(&iter);
210     if (!ssl_info.cert.get())
211       return false;
212   }
213   if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
214     CertStatus cert_status;
215     if (!iter.ReadUInt32(&cert_status))
216       return false;
217     ssl_info.cert_status = cert_status;
218   }
219   if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
220     // The security_bits field has been removed from ssl_info. For backwards
221     // compatibility, we should still read the value out of iter.
222     int security_bits;
223     if (!iter.ReadInt(&security_bits))
224       return false;
225   }
226 
227   if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) {
228     int connection_status;
229     if (!iter.ReadInt(&connection_status))
230       return false;
231 
232     // SSLv3 is gone, so drop cached entries that were loaded over SSLv3.
233     if (SSLConnectionStatusToVersion(connection_status) ==
234         SSL_CONNECTION_VERSION_SSL3) {
235       return false;
236     }
237     ssl_info.connection_status = connection_status;
238   }
239 
240   // Signed Certificate Timestamps are no longer persisted to the cache, so
241   // ignore them when reading them out.
242   if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) {
243     int num_scts;
244     if (!iter.ReadInt(&num_scts))
245       return false;
246     for (int i = 0; i < num_scts; ++i) {
247       scoped_refptr<ct::SignedCertificateTimestamp> sct(
248           ct::SignedCertificateTimestamp::CreateFromPickle(&iter));
249       uint16_t status;
250       if (!sct.get() || !iter.ReadUInt16(&status))
251         return false;
252     }
253   }
254 
255   // Read vary-data
256   if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
257     if (!vary_data.InitFromPickle(&iter))
258       return false;
259   }
260 
261   // Read socket_address.
262   std::string socket_address_host;
263   if (!iter.ReadString(&socket_address_host))
264     return false;
265   // If the host was written, we always expect the port to follow.
266   uint16_t socket_address_port;
267   if (!iter.ReadUInt16(&socket_address_port))
268     return false;
269 
270   IPAddress ip_address;
271   if (ip_address.AssignFromIPLiteral(socket_address_host)) {
272     remote_endpoint = IPEndPoint(ip_address, socket_address_port);
273   } else if (ParseURLHostnameToAddress(socket_address_host, &ip_address)) {
274     remote_endpoint = IPEndPoint(ip_address, socket_address_port);
275   }
276 
277   // Read protocol-version.
278   if (flags & RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL) {
279     if (!iter.ReadString(&alpn_negotiated_protocol))
280       return false;
281   }
282 
283   // Read connection info.
284   if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) {
285     int value;
286     if (!iter.ReadInt(&value))
287       return false;
288 
289     if (value > static_cast<int>(HttpConnectionInfo::kUNKNOWN) &&
290         value <= static_cast<int>(HttpConnectionInfo::kMaxValue)) {
291       connection_info = static_cast<HttpConnectionInfo>(value);
292     }
293   }
294 
295   // Read key_exchange_group
296   if (flags & RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP) {
297     int key_exchange_group;
298     if (!iter.ReadInt(&key_exchange_group))
299       return false;
300 
301     // Historically, the key_exchange_group field was key_exchange_info which
302     // conflated a number of different values based on the cipher suite, so some
303     // values must be discarded. See https://crbug.com/639421.
304     if (KeyExchangeGroupIsValid(ssl_info.connection_status))
305       ssl_info.key_exchange_group = key_exchange_group;
306   }
307 
308   // Read staleness time.
309   if (flags & RESPONSE_INFO_HAS_STALENESS) {
310     if (!iter.ReadInt64(&time_val))
311       return false;
312     stale_revalidate_timeout = base::Time() + base::Microseconds(time_val);
313   }
314 
315   was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
316 
317   was_alpn_negotiated = (flags & RESPONSE_INFO_WAS_ALPN) != 0;
318 
319   *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0;
320 
321   did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0;
322 
323   unused_since_prefetch = (flags & RESPONSE_INFO_UNUSED_SINCE_PREFETCH) != 0;
324 
325   restricted_prefetch = (flags & RESPONSE_INFO_RESTRICTED_PREFETCH) != 0;
326 
327   // RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE is unused.
328 
329   ssl_info.pkp_bypassed = (flags & RESPONSE_INFO_PKP_BYPASSED) != 0;
330 
331   // Read peer_signature_algorithm.
332   if (flags & RESPONSE_INFO_HAS_PEER_SIGNATURE_ALGORITHM) {
333     int peer_signature_algorithm;
334     if (!iter.ReadInt(&peer_signature_algorithm) ||
335         !base::IsValueInRangeForNumericType<uint16_t>(
336             peer_signature_algorithm)) {
337       return false;
338     }
339     ssl_info.peer_signature_algorithm =
340         base::checked_cast<uint16_t>(peer_signature_algorithm);
341   }
342 
343   // Read DNS aliases.
344   if (flags & RESPONSE_INFO_HAS_DNS_ALIASES) {
345     int num_aliases;
346     if (!iter.ReadInt(&num_aliases))
347       return false;
348 
349     std::string alias;
350     for (int i = 0; i < num_aliases; i++) {
351       if (!iter.ReadString(&alias))
352         return false;
353       dns_aliases.insert(alias);
354     }
355   }
356 
357   ssl_info.encrypted_client_hello =
358       (flags & RESPONSE_INFO_ENCRYPTED_CLIENT_HELLO) != 0;
359 
360   // Read browser_run_id.
361   if (flags & RESPONSE_INFO_BROWSER_RUN_ID) {
362     int64_t id;
363     if (!iter.ReadInt64(&id))
364       return false;
365     browser_run_id = std::make_optional(id);
366   }
367 
368   did_use_shared_dictionary =
369       (extra_flags & RESPONSE_EXTRA_INFO_DID_USE_SHARED_DICTIONARY) != 0;
370 
371   if (extra_flags & RESPONSE_EXTRA_INFO_HAS_PROXY_CHAIN) {
372     if (!proxy_chain.InitFromPickle(&iter)) {
373       return false;
374     }
375   }
376 
377   return true;
378 }
379 
Persist(base::Pickle * pickle,bool skip_transient_headers,bool response_truncated) const380 void HttpResponseInfo::Persist(base::Pickle* pickle,
381                                bool skip_transient_headers,
382                                bool response_truncated) const {
383   int flags = RESPONSE_INFO_VERSION;
384   int extra_flags = 0;
385   if (ssl_info.is_valid()) {
386     flags |= RESPONSE_INFO_HAS_CERT;
387     flags |= RESPONSE_INFO_HAS_CERT_STATUS;
388     if (ssl_info.key_exchange_group != 0)
389       flags |= RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP;
390     if (ssl_info.connection_status != 0)
391       flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS;
392     if (ssl_info.peer_signature_algorithm != 0)
393       flags |= RESPONSE_INFO_HAS_PEER_SIGNATURE_ALGORITHM;
394   }
395   if (vary_data.is_valid())
396     flags |= RESPONSE_INFO_HAS_VARY_DATA;
397   if (response_truncated)
398     flags |= RESPONSE_INFO_TRUNCATED;
399   if (was_fetched_via_spdy)
400     flags |= RESPONSE_INFO_WAS_SPDY;
401   if (was_alpn_negotiated) {
402     flags |= RESPONSE_INFO_WAS_ALPN;
403     flags |= RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL;
404   }
405   if (connection_info != HttpConnectionInfo::kUNKNOWN) {
406     flags |= RESPONSE_INFO_HAS_CONNECTION_INFO;
407   }
408   if (did_use_http_auth)
409     flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION;
410   if (unused_since_prefetch)
411     flags |= RESPONSE_INFO_UNUSED_SINCE_PREFETCH;
412   if (restricted_prefetch)
413     flags |= RESPONSE_INFO_RESTRICTED_PREFETCH;
414   // RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE is not used.
415   if (ssl_info.pkp_bypassed)
416     flags |= RESPONSE_INFO_PKP_BYPASSED;
417   if (!stale_revalidate_timeout.is_null())
418     flags |= RESPONSE_INFO_HAS_STALENESS;
419   if (!dns_aliases.empty())
420     flags |= RESPONSE_INFO_HAS_DNS_ALIASES;
421   if (ssl_info.encrypted_client_hello)
422     flags |= RESPONSE_INFO_ENCRYPTED_CLIENT_HELLO;
423   if (browser_run_id.has_value())
424     flags |= RESPONSE_INFO_BROWSER_RUN_ID;
425 
426   if (did_use_shared_dictionary) {
427     extra_flags |= RESPONSE_EXTRA_INFO_DID_USE_SHARED_DICTIONARY;
428   }
429 
430   if (proxy_chain.IsValid()) {
431     extra_flags |= RESPONSE_EXTRA_INFO_HAS_PROXY_CHAIN;
432   }
433 
434   extra_flags |= RESPONSE_EXTRA_INFO_HAS_ORIGINAL_RESPONSE_TIME;
435   flags |= RESPONSE_INFO_HAS_EXTRA_FLAGS;
436 
437   pickle->WriteInt(flags);
438   pickle->WriteInt(extra_flags);
439   pickle->WriteInt64(request_time.ToInternalValue());
440   pickle->WriteInt64(response_time.ToInternalValue());
441   pickle->WriteInt64(original_response_time.ToInternalValue());
442 
443   HttpResponseHeaders::PersistOptions persist_options =
444       HttpResponseHeaders::PERSIST_RAW;
445 
446   if (skip_transient_headers) {
447     persist_options = HttpResponseHeaders::PERSIST_SANS_COOKIES |
448                       HttpResponseHeaders::PERSIST_SANS_CHALLENGES |
449                       HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP |
450                       HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
451                       HttpResponseHeaders::PERSIST_SANS_RANGES |
452                       HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE;
453   }
454 
455   headers->Persist(pickle, persist_options);
456 
457   if (ssl_info.is_valid()) {
458     ssl_info.cert->Persist(pickle);
459     pickle->WriteUInt32(ssl_info.cert_status);
460     if (ssl_info.connection_status != 0)
461       pickle->WriteInt(ssl_info.connection_status);
462   }
463 
464   if (vary_data.is_valid())
465     vary_data.Persist(pickle);
466 
467   pickle->WriteString(remote_endpoint.ToStringWithoutPort());
468   pickle->WriteUInt16(remote_endpoint.port());
469 
470   if (was_alpn_negotiated)
471     pickle->WriteString(alpn_negotiated_protocol);
472 
473   if (connection_info != HttpConnectionInfo::kUNKNOWN) {
474     pickle->WriteInt(static_cast<int>(connection_info));
475   }
476 
477   if (ssl_info.is_valid() && ssl_info.key_exchange_group != 0)
478     pickle->WriteInt(ssl_info.key_exchange_group);
479 
480   if (flags & RESPONSE_INFO_HAS_STALENESS) {
481     pickle->WriteInt64(
482         (stale_revalidate_timeout - base::Time()).InMicroseconds());
483   }
484 
485   if (ssl_info.is_valid() && ssl_info.peer_signature_algorithm != 0)
486     pickle->WriteInt(ssl_info.peer_signature_algorithm);
487 
488   if (!dns_aliases.empty()) {
489     pickle->WriteInt(dns_aliases.size());
490     for (const auto& alias : dns_aliases)
491       pickle->WriteString(alias);
492   }
493 
494   if (browser_run_id.has_value()) {
495     pickle->WriteInt64(browser_run_id.value());
496   }
497 
498   if (proxy_chain.IsValid()) {
499     proxy_chain.Persist(pickle);
500   }
501 }
502 
DidUseQuic() const503 bool HttpResponseInfo::DidUseQuic() const {
504   switch (connection_info) {
505     case HttpConnectionInfo::kUNKNOWN:
506     case HttpConnectionInfo::kHTTP1_1:
507     case HttpConnectionInfo::kDEPRECATED_SPDY2:
508     case HttpConnectionInfo::kDEPRECATED_SPDY3:
509     case HttpConnectionInfo::kHTTP2:
510     case HttpConnectionInfo::kDEPRECATED_HTTP2_14:
511     case HttpConnectionInfo::kDEPRECATED_HTTP2_15:
512     case HttpConnectionInfo::kHTTP0_9:
513     case HttpConnectionInfo::kHTTP1_0:
514       return false;
515     case HttpConnectionInfo::kQUIC_UNKNOWN_VERSION:
516     case HttpConnectionInfo::kQUIC_32:
517     case HttpConnectionInfo::kQUIC_33:
518     case HttpConnectionInfo::kQUIC_34:
519     case HttpConnectionInfo::kQUIC_35:
520     case HttpConnectionInfo::kQUIC_36:
521     case HttpConnectionInfo::kQUIC_37:
522     case HttpConnectionInfo::kQUIC_38:
523     case HttpConnectionInfo::kQUIC_39:
524     case HttpConnectionInfo::kQUIC_40:
525     case HttpConnectionInfo::kQUIC_41:
526     case HttpConnectionInfo::kQUIC_42:
527     case HttpConnectionInfo::kQUIC_43:
528     case HttpConnectionInfo::kQUIC_44:
529     case HttpConnectionInfo::kQUIC_45:
530     case HttpConnectionInfo::kQUIC_46:
531     case HttpConnectionInfo::kQUIC_47:
532     case HttpConnectionInfo::kQUIC_Q048:
533     case HttpConnectionInfo::kQUIC_T048:
534     case HttpConnectionInfo::kQUIC_Q049:
535     case HttpConnectionInfo::kQUIC_T049:
536     case HttpConnectionInfo::kQUIC_Q050:
537     case HttpConnectionInfo::kQUIC_T050:
538     case HttpConnectionInfo::kQUIC_Q099:
539     case HttpConnectionInfo::kQUIC_T099:
540     case HttpConnectionInfo::kQUIC_999:
541     case HttpConnectionInfo::kQUIC_DRAFT_25:
542     case HttpConnectionInfo::kQUIC_DRAFT_27:
543     case HttpConnectionInfo::kQUIC_DRAFT_28:
544     case HttpConnectionInfo::kQUIC_DRAFT_29:
545     case HttpConnectionInfo::kQUIC_T051:
546     case HttpConnectionInfo::kQUIC_RFC_V1:
547     case HttpConnectionInfo::kDEPRECATED_QUIC_2_DRAFT_1:
548     case HttpConnectionInfo::kQUIC_2_DRAFT_8:
549       return true;
550   }
551 }
552 
WasFetchedViaProxy() const553 bool HttpResponseInfo::WasFetchedViaProxy() const {
554   return proxy_chain.IsValid() && !proxy_chain.is_direct();
555 }
556 
557 }  // namespace net
558