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 // TODO(darin): Add other bits to indicate alternate request methods. 95 // For now, we don't support storing those. 96 }; 97 98 HttpResponseInfo::HttpResponseInfo() 99 : was_cached(false), 100 server_data_unavailable(false), 101 network_accessed(false), 102 was_fetched_via_spdy(false), 103 was_npn_negotiated(false), 104 was_fetched_via_proxy(false), 105 did_use_http_auth(false), 106 connection_info(CONNECTION_INFO_UNKNOWN) { 107 } 108 109 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) 110 : was_cached(rhs.was_cached), 111 server_data_unavailable(rhs.server_data_unavailable), 112 network_accessed(rhs.network_accessed), 113 was_fetched_via_spdy(rhs.was_fetched_via_spdy), 114 was_npn_negotiated(rhs.was_npn_negotiated), 115 was_fetched_via_proxy(rhs.was_fetched_via_proxy), 116 did_use_http_auth(rhs.did_use_http_auth), 117 socket_address(rhs.socket_address), 118 npn_negotiated_protocol(rhs.npn_negotiated_protocol), 119 connection_info(rhs.connection_info), 120 request_time(rhs.request_time), 121 response_time(rhs.response_time), 122 auth_challenge(rhs.auth_challenge), 123 cert_request_info(rhs.cert_request_info), 124 ssl_info(rhs.ssl_info), 125 headers(rhs.headers), 126 vary_data(rhs.vary_data), 127 metadata(rhs.metadata) { 128 } 129 130 HttpResponseInfo::~HttpResponseInfo() { 131 } 132 133 HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) { 134 was_cached = rhs.was_cached; 135 server_data_unavailable = rhs.server_data_unavailable; 136 network_accessed = rhs.network_accessed; 137 was_fetched_via_spdy = rhs.was_fetched_via_spdy; 138 was_npn_negotiated = rhs.was_npn_negotiated; 139 was_fetched_via_proxy = rhs.was_fetched_via_proxy; 140 did_use_http_auth = rhs.did_use_http_auth; 141 socket_address = rhs.socket_address; 142 npn_negotiated_protocol = rhs.npn_negotiated_protocol; 143 connection_info = rhs.connection_info; 144 request_time = rhs.request_time; 145 response_time = rhs.response_time; 146 auth_challenge = rhs.auth_challenge; 147 cert_request_info = rhs.cert_request_info; 148 ssl_info = rhs.ssl_info; 149 headers = rhs.headers; 150 vary_data = rhs.vary_data; 151 metadata = rhs.metadata; 152 return *this; 153 } 154 155 bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, 156 bool* response_truncated) { 157 PickleIterator iter(pickle); 158 159 // Read flags and verify version 160 int flags; 161 if (!pickle.ReadInt(&iter, &flags)) 162 return false; 163 int version = flags & RESPONSE_INFO_VERSION_MASK; 164 if (version < RESPONSE_INFO_MINIMUM_VERSION || 165 version > RESPONSE_INFO_VERSION) { 166 DLOG(ERROR) << "unexpected response info version: " << version; 167 return false; 168 } 169 170 // Read request-time 171 int64 time_val; 172 if (!pickle.ReadInt64(&iter, &time_val)) 173 return false; 174 request_time = Time::FromInternalValue(time_val); 175 was_cached = true; // Set status to show cache resurrection. 176 177 // Read response-time 178 if (!pickle.ReadInt64(&iter, &time_val)) 179 return false; 180 response_time = Time::FromInternalValue(time_val); 181 182 // Read response-headers 183 headers = new HttpResponseHeaders(pickle, &iter); 184 if (headers->response_code() == -1) 185 return false; 186 187 // Read ssl-info 188 if (flags & RESPONSE_INFO_HAS_CERT) { 189 X509Certificate::PickleType type = GetPickleTypeForVersion(version); 190 ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type); 191 if (!ssl_info.cert.get()) 192 return false; 193 } 194 if (flags & RESPONSE_INFO_HAS_CERT_STATUS) { 195 CertStatus cert_status; 196 if (!pickle.ReadUInt32(&iter, &cert_status)) 197 return false; 198 ssl_info.cert_status = cert_status; 199 } 200 if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) { 201 int security_bits; 202 if (!pickle.ReadInt(&iter, &security_bits)) 203 return false; 204 ssl_info.security_bits = security_bits; 205 } 206 207 if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) { 208 int connection_status; 209 if (!pickle.ReadInt(&iter, &connection_status)) 210 return false; 211 ssl_info.connection_status = connection_status; 212 } 213 214 if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) { 215 int num_scts; 216 if (!pickle.ReadInt(&iter, &num_scts)) 217 return false; 218 for (int i = 0; i < num_scts; ++i) { 219 scoped_refptr<ct::SignedCertificateTimestamp> sct( 220 ct::SignedCertificateTimestamp::CreateFromPickle(&iter)); 221 uint16 status; 222 if (!sct.get() || !pickle.ReadUInt16(&iter, &status)) 223 return false; 224 ssl_info.signed_certificate_timestamps.push_back( 225 SignedCertificateTimestampAndStatus( 226 sct, static_cast<ct::SCTVerifyStatus>(status))); 227 } 228 } 229 230 // Read vary-data 231 if (flags & RESPONSE_INFO_HAS_VARY_DATA) { 232 if (!vary_data.InitFromPickle(pickle, &iter)) 233 return false; 234 } 235 236 // Read socket_address. 237 std::string socket_address_host; 238 if (pickle.ReadString(&iter, &socket_address_host)) { 239 // If the host was written, we always expect the port to follow. 240 uint16 socket_address_port; 241 if (!pickle.ReadUInt16(&iter, &socket_address_port)) 242 return false; 243 socket_address = HostPortPair(socket_address_host, socket_address_port); 244 } else if (version > 1) { 245 // socket_address was not always present in version 1 of the response 246 // info, so we don't fail if it can't be read. 247 return false; 248 } 249 250 // Read protocol-version. 251 if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) { 252 if (!pickle.ReadString(&iter, &npn_negotiated_protocol)) 253 return false; 254 } 255 256 // Read connection info. 257 if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) { 258 int value; 259 if (!pickle.ReadInt(&iter, &value)) 260 return false; 261 262 if (value > static_cast<int>(CONNECTION_INFO_UNKNOWN) && 263 value < static_cast<int>(NUM_OF_CONNECTION_INFOS)) { 264 connection_info = static_cast<ConnectionInfo>(value); 265 } 266 } 267 268 was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0; 269 270 was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0; 271 272 was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0; 273 274 *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0; 275 276 did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0; 277 278 return true; 279 } 280 281 void HttpResponseInfo::Persist(Pickle* pickle, 282 bool skip_transient_headers, 283 bool response_truncated) const { 284 int flags = RESPONSE_INFO_VERSION; 285 if (ssl_info.is_valid()) { 286 flags |= RESPONSE_INFO_HAS_CERT; 287 flags |= RESPONSE_INFO_HAS_CERT_STATUS; 288 if (ssl_info.security_bits != -1) 289 flags |= RESPONSE_INFO_HAS_SECURITY_BITS; 290 if (ssl_info.connection_status != 0) 291 flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS; 292 } 293 if (vary_data.is_valid()) 294 flags |= RESPONSE_INFO_HAS_VARY_DATA; 295 if (response_truncated) 296 flags |= RESPONSE_INFO_TRUNCATED; 297 if (was_fetched_via_spdy) 298 flags |= RESPONSE_INFO_WAS_SPDY; 299 if (was_npn_negotiated) { 300 flags |= RESPONSE_INFO_WAS_NPN; 301 flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL; 302 } 303 if (was_fetched_via_proxy) 304 flags |= RESPONSE_INFO_WAS_PROXY; 305 if (connection_info != CONNECTION_INFO_UNKNOWN) 306 flags |= RESPONSE_INFO_HAS_CONNECTION_INFO; 307 if (did_use_http_auth) 308 flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION; 309 if (!ssl_info.signed_certificate_timestamps.empty()) 310 flags |= RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS; 311 312 pickle->WriteInt(flags); 313 pickle->WriteInt64(request_time.ToInternalValue()); 314 pickle->WriteInt64(response_time.ToInternalValue()); 315 316 net::HttpResponseHeaders::PersistOptions persist_options = 317 net::HttpResponseHeaders::PERSIST_RAW; 318 319 if (skip_transient_headers) { 320 persist_options = 321 net::HttpResponseHeaders::PERSIST_SANS_COOKIES | 322 net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES | 323 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP | 324 net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE | 325 net::HttpResponseHeaders::PERSIST_SANS_RANGES | 326 net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE; 327 } 328 329 headers->Persist(pickle, persist_options); 330 331 if (ssl_info.is_valid()) { 332 ssl_info.cert->Persist(pickle); 333 pickle->WriteUInt32(ssl_info.cert_status); 334 if (ssl_info.security_bits != -1) 335 pickle->WriteInt(ssl_info.security_bits); 336 if (ssl_info.connection_status != 0) 337 pickle->WriteInt(ssl_info.connection_status); 338 if (!ssl_info.signed_certificate_timestamps.empty()) { 339 pickle->WriteInt(ssl_info.signed_certificate_timestamps.size()); 340 for (SignedCertificateTimestampAndStatusList::const_iterator it = 341 ssl_info.signed_certificate_timestamps.begin(); it != 342 ssl_info.signed_certificate_timestamps.end(); ++it) { 343 it->sct_->Persist(pickle); 344 pickle->WriteUInt16(it->status_); 345 } 346 } 347 } 348 349 if (vary_data.is_valid()) 350 vary_data.Persist(pickle); 351 352 pickle->WriteString(socket_address.host()); 353 pickle->WriteUInt16(socket_address.port()); 354 355 if (was_npn_negotiated) 356 pickle->WriteString(npn_negotiated_protocol); 357 358 if (connection_info != CONNECTION_INFO_UNKNOWN) 359 pickle->WriteInt(static_cast<int>(connection_info)); 360 } 361 362 HttpResponseInfo::ConnectionInfo HttpResponseInfo::ConnectionInfoFromNextProto( 363 NextProto next_proto) { 364 switch (next_proto) { 365 case kProtoDeprecatedSPDY2: 366 return CONNECTION_INFO_DEPRECATED_SPDY2; 367 case kProtoSPDY3: 368 case kProtoSPDY31: 369 return CONNECTION_INFO_SPDY3; 370 case kProtoSPDY4a2: 371 return CONNECTION_INFO_SPDY4A2; 372 case kProtoHTTP2Draft04: 373 return CONNECTION_INFO_HTTP2_DRAFT_04; 374 case kProtoQUIC1SPDY3: 375 return CONNECTION_INFO_QUIC1_SPDY3; 376 377 case kProtoUnknown: 378 case kProtoHTTP11: 379 break; 380 } 381 382 NOTREACHED(); 383 return CONNECTION_INFO_UNKNOWN; 384 } 385 386 // static 387 std::string HttpResponseInfo::ConnectionInfoToString( 388 ConnectionInfo connection_info) { 389 switch (connection_info) { 390 case CONNECTION_INFO_UNKNOWN: 391 return "unknown"; 392 case CONNECTION_INFO_HTTP1: 393 return "http/1"; 394 case CONNECTION_INFO_DEPRECATED_SPDY2: 395 return "spdy/2"; 396 case CONNECTION_INFO_SPDY3: 397 return "spdy/3"; 398 case CONNECTION_INFO_SPDY4A2: 399 return "spdy/4a2"; 400 case CONNECTION_INFO_HTTP2_DRAFT_04: 401 return "HTTP-draft-04/2.0"; 402 case CONNECTION_INFO_QUIC1_SPDY3: 403 return "quic/1+spdy/3"; 404 case NUM_OF_CONNECTION_INFOS: 405 break; 406 } 407 NOTREACHED(); 408 return ""; 409 } 410 411 } // namespace net 412