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