| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 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 "base/logging.h" | |
| 8 #include "base/pickle.h" | |
| 9 #include "base/time/time.h" | |
| 10 #include "net/base/auth.h" | |
| 11 #include "net/base/io_buffer.h" | |
| 12 #include "net/base/net_errors.h" | |
| 13 #include "net/cert/signed_certificate_timestamp.h" | |
| 14 #include "net/cert/x509_certificate.h" | |
| 15 #include "net/http/http_response_headers.h" | |
| 16 #include "net/ssl/ssl_cert_request_info.h" | |
| 17 | |
| 18 using base::Time; | |
| 19 | |
| 20 namespace net { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 X509Certificate::PickleType GetPickleTypeForVersion(int version) { | |
| 25 switch (version) { | |
| 26 case 1: | |
| 27 return X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE; | |
| 28 case 2: | |
| 29 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V2; | |
| 30 case 3: | |
| 31 default: | |
| 32 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V3; | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 } // namespace | |
| 37 | |
| 38 // These values can be bit-wise combined to form the flags field of the | |
| 39 // serialized HttpResponseInfo. | |
| 40 enum { | |
| 41 // The version of the response info used when persisting response info. | |
| 42 RESPONSE_INFO_VERSION = 3, | |
| 43 | |
| 44 // The minimum version supported for deserializing response info. | |
| 45 RESPONSE_INFO_MINIMUM_VERSION = 1, | |
| 46 | |
| 47 // We reserve up to 8 bits for the version number. | |
| 48 RESPONSE_INFO_VERSION_MASK = 0xFF, | |
| 49 | |
| 50 // This bit is set if the response info has a cert at the end. | |
| 51 // Version 1 serialized only the end-entity certificate, while subsequent | |
| 52 // versions include the available certificate chain. | |
| 53 RESPONSE_INFO_HAS_CERT = 1 << 8, | |
| 54 | |
| 55 // This bit is set if the response info has a security-bits field (security | |
| 56 // strength, in bits, of the SSL connection) at the end. | |
| 57 RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9, | |
| 58 | |
| 59 // This bit is set if the response info has a cert status at the end. | |
| 60 RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10, | |
| 61 | |
| 62 // This bit is set if the response info has vary header data. | |
| 63 RESPONSE_INFO_HAS_VARY_DATA = 1 << 11, | |
| 64 | |
| 65 // This bit is set if the request was cancelled before completion. | |
| 66 RESPONSE_INFO_TRUNCATED = 1 << 12, | |
| 67 | |
| 68 // This bit is set if the response was received via SPDY. | |
| 69 RESPONSE_INFO_WAS_SPDY = 1 << 13, | |
| 70 | |
| 71 // This bit is set if the request has NPN negotiated. | |
| 72 RESPONSE_INFO_WAS_NPN = 1 << 14, | |
| 73 | |
| 74 // This bit is set if the request was fetched via an explicit proxy. | |
| 75 RESPONSE_INFO_WAS_PROXY = 1 << 15, | |
| 76 | |
| 77 // This bit is set if the response info has an SSL connection status field. | |
| 78 // This contains the ciphersuite used to fetch the resource as well as the | |
| 79 // protocol version, compression method and whether SSLv3 fallback was used. | |
| 80 RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16, | |
| 81 | |
| 82 // This bit is set if the response info has protocol version. | |
| 83 RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17, | |
| 84 | |
| 85 // This bit is set if the response info has connection info. | |
| 86 RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18, | |
| 87 | |
| 88 // This bit is set if the request has http authentication. | |
| 89 RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19, | |
| 90 | |
| 91 // This bit is set if ssl_info has SCTs. | |
| 92 RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS = 1 << 20, | |
| 93 | |
| 94 RESPONSE_INFO_UNUSED_SINCE_PREFETCH = 1 << 21, | |
| 95 | |
| 96 // TODO(darin): Add other bits to indicate alternate request methods. | |
| 97 // For now, we don't support storing those. | |
| 98 }; | |
| 99 | |
| 100 HttpResponseInfo::HttpResponseInfo() | |
| 101 : was_cached(false), | |
| 102 server_data_unavailable(false), | |
| 103 network_accessed(false), | |
| 104 was_fetched_via_spdy(false), | |
| 105 was_npn_negotiated(false), | |
| 106 was_fetched_via_proxy(false), | |
| 107 did_use_http_auth(false), | |
| 108 unused_since_prefetch(false), | |
| 109 connection_info(CONNECTION_INFO_UNKNOWN) { | |
| 110 } | |
| 111 | |
| 112 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) | |
| 113 : was_cached(rhs.was_cached), | |
| 114 server_data_unavailable(rhs.server_data_unavailable), | |
| 115 network_accessed(rhs.network_accessed), | |
| 116 was_fetched_via_spdy(rhs.was_fetched_via_spdy), | |
| 117 was_npn_negotiated(rhs.was_npn_negotiated), | |
| 118 was_fetched_via_proxy(rhs.was_fetched_via_proxy), | |
| 119 proxy_server(rhs.proxy_server), | |
| 120 did_use_http_auth(rhs.did_use_http_auth), | |
| 121 unused_since_prefetch(rhs.unused_since_prefetch), | |
| 122 socket_address(rhs.socket_address), | |
| 123 npn_negotiated_protocol(rhs.npn_negotiated_protocol), | |
| 124 connection_info(rhs.connection_info), | |
| 125 request_time(rhs.request_time), | |
| 126 response_time(rhs.response_time), | |
| 127 auth_challenge(rhs.auth_challenge), | |
| 128 cert_request_info(rhs.cert_request_info), | |
| 129 ssl_info(rhs.ssl_info), | |
| 130 headers(rhs.headers), | |
| 131 vary_data(rhs.vary_data), | |
| 132 metadata(rhs.metadata) { | |
| 133 } | |
| 134 | |
| 135 HttpResponseInfo::~HttpResponseInfo() { | |
| 136 } | |
| 137 | |
| 138 HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) { | |
| 139 was_cached = rhs.was_cached; | |
| 140 server_data_unavailable = rhs.server_data_unavailable; | |
| 141 network_accessed = rhs.network_accessed; | |
| 142 was_fetched_via_spdy = rhs.was_fetched_via_spdy; | |
| 143 proxy_server = rhs.proxy_server; | |
| 144 was_npn_negotiated = rhs.was_npn_negotiated; | |
| 145 was_fetched_via_proxy = rhs.was_fetched_via_proxy; | |
| 146 did_use_http_auth = rhs.did_use_http_auth; | |
| 147 unused_since_prefetch = rhs.unused_since_prefetch; | |
| 148 socket_address = rhs.socket_address; | |
| 149 npn_negotiated_protocol = rhs.npn_negotiated_protocol; | |
| 150 connection_info = rhs.connection_info; | |
| 151 request_time = rhs.request_time; | |
| 152 response_time = rhs.response_time; | |
| 153 auth_challenge = rhs.auth_challenge; | |
| 154 cert_request_info = rhs.cert_request_info; | |
| 155 ssl_info = rhs.ssl_info; | |
| 156 headers = rhs.headers; | |
| 157 vary_data = rhs.vary_data; | |
| 158 metadata = rhs.metadata; | |
| 159 return *this; | |
| 160 } | |
| 161 | |
| 162 bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, | |
| 163 bool* response_truncated) { | |
| 164 PickleIterator iter(pickle); | |
| 165 | |
| 166 // Read flags and verify version | |
| 167 int flags; | |
| 168 if (!iter.ReadInt(&flags)) | |
| 169 return false; | |
| 170 int version = flags & RESPONSE_INFO_VERSION_MASK; | |
| 171 if (version < RESPONSE_INFO_MINIMUM_VERSION || | |
| 172 version > RESPONSE_INFO_VERSION) { | |
| 173 DLOG(ERROR) << "unexpected response info version: " << version; | |
| 174 return false; | |
| 175 } | |
| 176 | |
| 177 // Read request-time | |
| 178 int64 time_val; | |
| 179 if (!iter.ReadInt64(&time_val)) | |
| 180 return false; | |
| 181 request_time = Time::FromInternalValue(time_val); | |
| 182 was_cached = true; // Set status to show cache resurrection. | |
| 183 | |
| 184 // Read response-time | |
| 185 if (!iter.ReadInt64(&time_val)) | |
| 186 return false; | |
| 187 response_time = Time::FromInternalValue(time_val); | |
| 188 | |
| 189 // Read response-headers | |
| 190 headers = new HttpResponseHeaders(&iter); | |
| 191 if (headers->response_code() == -1) | |
| 192 return false; | |
| 193 | |
| 194 // Read ssl-info | |
| 195 if (flags & RESPONSE_INFO_HAS_CERT) { | |
| 196 X509Certificate::PickleType type = GetPickleTypeForVersion(version); | |
| 197 ssl_info.cert = X509Certificate::CreateFromPickle(&iter, type); | |
| 198 if (!ssl_info.cert.get()) | |
| 199 return false; | |
| 200 } | |
| 201 if (flags & RESPONSE_INFO_HAS_CERT_STATUS) { | |
| 202 CertStatus cert_status; | |
| 203 if (!iter.ReadUInt32(&cert_status)) | |
| 204 return false; | |
| 205 ssl_info.cert_status = cert_status; | |
| 206 } | |
| 207 if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) { | |
| 208 int security_bits; | |
| 209 if (!iter.ReadInt(&security_bits)) | |
| 210 return false; | |
| 211 ssl_info.security_bits = security_bits; | |
| 212 } | |
| 213 | |
| 214 if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) { | |
| 215 int connection_status; | |
| 216 if (!iter.ReadInt(&connection_status)) | |
| 217 return false; | |
| 218 ssl_info.connection_status = connection_status; | |
| 219 } | |
| 220 | |
| 221 if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) { | |
| 222 int num_scts; | |
| 223 if (!iter.ReadInt(&num_scts)) | |
| 224 return false; | |
| 225 for (int i = 0; i < num_scts; ++i) { | |
| 226 scoped_refptr<ct::SignedCertificateTimestamp> sct( | |
| 227 ct::SignedCertificateTimestamp::CreateFromPickle(&iter)); | |
| 228 uint16 status; | |
| 229 if (!sct.get() || !iter.ReadUInt16(&status)) | |
| 230 return false; | |
| 231 ssl_info.signed_certificate_timestamps.push_back( | |
| 232 SignedCertificateTimestampAndStatus( | |
| 233 sct, static_cast<ct::SCTVerifyStatus>(status))); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 // Read vary-data | |
| 238 if (flags & RESPONSE_INFO_HAS_VARY_DATA) { | |
| 239 if (!vary_data.InitFromPickle(&iter)) | |
| 240 return false; | |
| 241 } | |
| 242 | |
| 243 // Read socket_address. | |
| 244 std::string socket_address_host; | |
| 245 if (iter.ReadString(&socket_address_host)) { | |
| 246 // If the host was written, we always expect the port to follow. | |
| 247 uint16 socket_address_port; | |
| 248 if (!iter.ReadUInt16(&socket_address_port)) | |
| 249 return false; | |
| 250 socket_address = HostPortPair(socket_address_host, socket_address_port); | |
| 251 } else if (version > 1) { | |
| 252 // socket_address was not always present in version 1 of the response | |
| 253 // info, so we don't fail if it can't be read. | |
| 254 return false; | |
| 255 } | |
| 256 | |
| 257 // Read protocol-version. | |
| 258 if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) { | |
| 259 if (!iter.ReadString(&npn_negotiated_protocol)) | |
| 260 return false; | |
| 261 } | |
| 262 | |
| 263 // Read connection info. | |
| 264 if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) { | |
| 265 int value; | |
| 266 if (!iter.ReadInt(&value)) | |
| 267 return false; | |
| 268 | |
| 269 if (value > static_cast<int>(CONNECTION_INFO_UNKNOWN) && | |
| 270 value < static_cast<int>(NUM_OF_CONNECTION_INFOS)) { | |
| 271 connection_info = static_cast<ConnectionInfo>(value); | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0; | |
| 276 | |
| 277 was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0; | |
| 278 | |
| 279 was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0; | |
| 280 | |
| 281 *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0; | |
| 282 | |
| 283 did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0; | |
| 284 | |
| 285 unused_since_prefetch = (flags & RESPONSE_INFO_UNUSED_SINCE_PREFETCH) != 0; | |
| 286 | |
| 287 return true; | |
| 288 } | |
| 289 | |
| 290 void HttpResponseInfo::Persist(Pickle* pickle, | |
| 291 bool skip_transient_headers, | |
| 292 bool response_truncated) const { | |
| 293 int flags = RESPONSE_INFO_VERSION; | |
| 294 if (ssl_info.is_valid()) { | |
| 295 flags |= RESPONSE_INFO_HAS_CERT; | |
| 296 flags |= RESPONSE_INFO_HAS_CERT_STATUS; | |
| 297 if (ssl_info.security_bits != -1) | |
| 298 flags |= RESPONSE_INFO_HAS_SECURITY_BITS; | |
| 299 if (ssl_info.connection_status != 0) | |
| 300 flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS; | |
| 301 } | |
| 302 if (vary_data.is_valid()) | |
| 303 flags |= RESPONSE_INFO_HAS_VARY_DATA; | |
| 304 if (response_truncated) | |
| 305 flags |= RESPONSE_INFO_TRUNCATED; | |
| 306 if (was_fetched_via_spdy) | |
| 307 flags |= RESPONSE_INFO_WAS_SPDY; | |
| 308 if (was_npn_negotiated) { | |
| 309 flags |= RESPONSE_INFO_WAS_NPN; | |
| 310 flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL; | |
| 311 } | |
| 312 if (was_fetched_via_proxy) | |
| 313 flags |= RESPONSE_INFO_WAS_PROXY; | |
| 314 if (connection_info != CONNECTION_INFO_UNKNOWN) | |
| 315 flags |= RESPONSE_INFO_HAS_CONNECTION_INFO; | |
| 316 if (did_use_http_auth) | |
| 317 flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION; | |
| 318 if (unused_since_prefetch) | |
| 319 flags |= RESPONSE_INFO_UNUSED_SINCE_PREFETCH; | |
| 320 if (!ssl_info.signed_certificate_timestamps.empty()) | |
| 321 flags |= RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS; | |
| 322 | |
| 323 pickle->WriteInt(flags); | |
| 324 pickle->WriteInt64(request_time.ToInternalValue()); | |
| 325 pickle->WriteInt64(response_time.ToInternalValue()); | |
| 326 | |
| 327 net::HttpResponseHeaders::PersistOptions persist_options = | |
| 328 net::HttpResponseHeaders::PERSIST_RAW; | |
| 329 | |
| 330 if (skip_transient_headers) { | |
| 331 persist_options = | |
| 332 net::HttpResponseHeaders::PERSIST_SANS_COOKIES | | |
| 333 net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES | | |
| 334 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP | | |
| 335 net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE | | |
| 336 net::HttpResponseHeaders::PERSIST_SANS_RANGES | | |
| 337 net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE; | |
| 338 } | |
| 339 | |
| 340 headers->Persist(pickle, persist_options); | |
| 341 | |
| 342 if (ssl_info.is_valid()) { | |
| 343 ssl_info.cert->Persist(pickle); | |
| 344 pickle->WriteUInt32(ssl_info.cert_status); | |
| 345 if (ssl_info.security_bits != -1) | |
| 346 pickle->WriteInt(ssl_info.security_bits); | |
| 347 if (ssl_info.connection_status != 0) | |
| 348 pickle->WriteInt(ssl_info.connection_status); | |
| 349 if (!ssl_info.signed_certificate_timestamps.empty()) { | |
| 350 pickle->WriteInt(ssl_info.signed_certificate_timestamps.size()); | |
| 351 for (SignedCertificateTimestampAndStatusList::const_iterator it = | |
| 352 ssl_info.signed_certificate_timestamps.begin(); it != | |
| 353 ssl_info.signed_certificate_timestamps.end(); ++it) { | |
| 354 it->sct->Persist(pickle); | |
| 355 pickle->WriteUInt16(static_cast<uint16>(it->status)); | |
| 356 } | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 if (vary_data.is_valid()) | |
| 361 vary_data.Persist(pickle); | |
| 362 | |
| 363 pickle->WriteString(socket_address.host()); | |
| 364 pickle->WriteUInt16(socket_address.port()); | |
| 365 | |
| 366 if (was_npn_negotiated) | |
| 367 pickle->WriteString(npn_negotiated_protocol); | |
| 368 | |
| 369 if (connection_info != CONNECTION_INFO_UNKNOWN) | |
| 370 pickle->WriteInt(static_cast<int>(connection_info)); | |
| 371 } | |
| 372 | |
| 373 HttpResponseInfo::ConnectionInfo HttpResponseInfo::ConnectionInfoFromNextProto( | |
| 374 NextProto next_proto) { | |
| 375 switch (next_proto) { | |
| 376 case kProtoDeprecatedSPDY2: | |
| 377 return CONNECTION_INFO_DEPRECATED_SPDY2; | |
| 378 case kProtoSPDY3: | |
| 379 case kProtoSPDY31: | |
| 380 return CONNECTION_INFO_SPDY3; | |
| 381 case kProtoSPDY4_14: | |
| 382 return CONNECTION_INFO_HTTP2_14; | |
| 383 case kProtoSPDY4_15: | |
| 384 return CONNECTION_INFO_HTTP2_15; | |
| 385 case kProtoQUIC1SPDY3: | |
| 386 return CONNECTION_INFO_QUIC1_SPDY3; | |
| 387 | |
| 388 case kProtoUnknown: | |
| 389 case kProtoHTTP11: | |
| 390 break; | |
| 391 } | |
| 392 | |
| 393 NOTREACHED(); | |
| 394 return CONNECTION_INFO_UNKNOWN; | |
| 395 } | |
| 396 | |
| 397 // static | |
| 398 std::string HttpResponseInfo::ConnectionInfoToString( | |
| 399 ConnectionInfo connection_info) { | |
| 400 switch (connection_info) { | |
| 401 case CONNECTION_INFO_UNKNOWN: | |
| 402 return "unknown"; | |
| 403 case CONNECTION_INFO_HTTP1: | |
| 404 return "http/1"; | |
| 405 case CONNECTION_INFO_DEPRECATED_SPDY2: | |
| 406 return "spdy/2"; | |
| 407 case CONNECTION_INFO_SPDY3: | |
| 408 return "spdy/3"; | |
| 409 case CONNECTION_INFO_HTTP2_14: | |
| 410 // For internal consistency, HTTP/2 is named SPDY4 within Chromium. | |
| 411 // This is the HTTP/2 draft-14 identifier. | |
| 412 return "h2-14"; | |
| 413 case CONNECTION_INFO_HTTP2_15: | |
| 414 // This is the HTTP/2 draft-15 identifier. | |
| 415 return "h2-15"; | |
| 416 case CONNECTION_INFO_QUIC1_SPDY3: | |
| 417 return "quic/1+spdy/3"; | |
| 418 case NUM_OF_CONNECTION_INFOS: | |
| 419 break; | |
| 420 } | |
| 421 NOTREACHED(); | |
| 422 return ""; | |
| 423 } | |
| 424 | |
| 425 } // namespace net | |
| OLD | NEW |