http_response_info.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.h" 10#include "net/base/auth.h" 11#include "net/base/io_buffer.h" 12#include "net/base/net_errors.h" 13#include "net/base/x509_certificate.h" 14#include "net/http/http_response_headers.h" 15#include "net/ssl/ssl_cert_request_info.h" 16 17using base::Time; 18 19namespace net { 20 21namespace { 22 23X509Certificate::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. 39enum { 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 // TODO(darin): Add other bits to indicate alternate request methods. 88 // For now, we don't support storing those. 89}; 90 91HttpResponseInfo::HttpResponseInfo() 92 : was_cached(false), 93 server_data_unavailable(false), 94 was_fetched_via_spdy(false), 95 was_npn_negotiated(false), 96 was_fetched_via_proxy(false), 97 connection_info(CONNECTION_INFO_UNKNOWN) { 98} 99 100HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) 101 : was_cached(rhs.was_cached), 102 server_data_unavailable(rhs.server_data_unavailable), 103 was_fetched_via_spdy(rhs.was_fetched_via_spdy), 104 was_npn_negotiated(rhs.was_npn_negotiated), 105 was_fetched_via_proxy(rhs.was_fetched_via_proxy), 106 socket_address(rhs.socket_address), 107 npn_negotiated_protocol(rhs.npn_negotiated_protocol), 108 connection_info(rhs.connection_info), 109 request_time(rhs.request_time), 110 response_time(rhs.response_time), 111 auth_challenge(rhs.auth_challenge), 112 cert_request_info(rhs.cert_request_info), 113 ssl_info(rhs.ssl_info), 114 headers(rhs.headers), 115 vary_data(rhs.vary_data), 116 metadata(rhs.metadata) { 117} 118 119HttpResponseInfo::~HttpResponseInfo() { 120} 121 122HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) { 123 was_cached = rhs.was_cached; 124 server_data_unavailable = rhs.server_data_unavailable; 125 was_fetched_via_spdy = rhs.was_fetched_via_spdy; 126 was_npn_negotiated = rhs.was_npn_negotiated; 127 was_fetched_via_proxy = rhs.was_fetched_via_proxy; 128 socket_address = rhs.socket_address; 129 npn_negotiated_protocol = rhs.npn_negotiated_protocol; 130 request_time = rhs.request_time; 131 response_time = rhs.response_time; 132 auth_challenge = rhs.auth_challenge; 133 cert_request_info = rhs.cert_request_info; 134 ssl_info = rhs.ssl_info; 135 headers = rhs.headers; 136 vary_data = rhs.vary_data; 137 metadata = rhs.metadata; 138 return *this; 139} 140 141bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, 142 bool* response_truncated) { 143 PickleIterator iter(pickle); 144 145 // Read flags and verify version 146 int flags; 147 if (!pickle.ReadInt(&iter, &flags)) 148 return false; 149 int version = flags & RESPONSE_INFO_VERSION_MASK; 150 if (version < RESPONSE_INFO_MINIMUM_VERSION || 151 version > RESPONSE_INFO_VERSION) { 152 DLOG(ERROR) << "unexpected response info version: " << version; 153 return false; 154 } 155 156 // Read request-time 157 int64 time_val; 158 if (!pickle.ReadInt64(&iter, &time_val)) 159 return false; 160 request_time = Time::FromInternalValue(time_val); 161 was_cached = true; // Set status to show cache resurrection. 162 163 // Read response-time 164 if (!pickle.ReadInt64(&iter, &time_val)) 165 return false; 166 response_time = Time::FromInternalValue(time_val); 167 168 // Read response-headers 169 headers = new HttpResponseHeaders(pickle, &iter); 170 if (headers->response_code() == -1) 171 return false; 172 173 // Read ssl-info 174 if (flags & RESPONSE_INFO_HAS_CERT) { 175 X509Certificate::PickleType type = GetPickleTypeForVersion(version); 176 ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type); 177 if (!ssl_info.cert) 178 return false; 179 } 180 if (flags & RESPONSE_INFO_HAS_CERT_STATUS) { 181 CertStatus cert_status; 182 if (!pickle.ReadUInt32(&iter, &cert_status)) 183 return false; 184 ssl_info.cert_status = cert_status; 185 } 186 if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) { 187 int security_bits; 188 if (!pickle.ReadInt(&iter, &security_bits)) 189 return false; 190 ssl_info.security_bits = security_bits; 191 } 192 193 if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) { 194 int connection_status; 195 if (!pickle.ReadInt(&iter, &connection_status)) 196 return false; 197 ssl_info.connection_status = connection_status; 198 } 199 200 // Read vary-data 201 if (flags & RESPONSE_INFO_HAS_VARY_DATA) { 202 if (!vary_data.InitFromPickle(pickle, &iter)) 203 return false; 204 } 205 206 // Read socket_address. 207 std::string socket_address_host; 208 if (pickle.ReadString(&iter, &socket_address_host)) { 209 // If the host was written, we always expect the port to follow. 210 uint16 socket_address_port; 211 if (!pickle.ReadUInt16(&iter, &socket_address_port)) 212 return false; 213 socket_address = HostPortPair(socket_address_host, socket_address_port); 214 } else if (version > 1) { 215 // socket_address was not always present in version 1 of the response 216 // info, so we don't fail if it can't be read. 217 return false; 218 } 219 220 // Read protocol-version. 221 if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) { 222 if (!pickle.ReadString(&iter, &npn_negotiated_protocol)) 223 return false; 224 } 225 226 // Read connection info. 227 if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) { 228 int value; 229 if (!pickle.ReadInt(&iter, &value)) 230 return false; 231 232 if (value > static_cast<int>(CONNECTION_INFO_UNKNOWN) && 233 value < static_cast<int>(NUM_OF_CONNECTION_INFOS)) { 234 connection_info = static_cast<ConnectionInfo>(value); 235 } 236 } 237 238 was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0; 239 240 was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0; 241 242 was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0; 243 244 *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0; 245 246 return true; 247} 248 249void HttpResponseInfo::Persist(Pickle* pickle, 250 bool skip_transient_headers, 251 bool response_truncated) const { 252 int flags = RESPONSE_INFO_VERSION; 253 if (ssl_info.is_valid()) { 254 flags |= RESPONSE_INFO_HAS_CERT; 255 flags |= RESPONSE_INFO_HAS_CERT_STATUS; 256 if (ssl_info.security_bits != -1) 257 flags |= RESPONSE_INFO_HAS_SECURITY_BITS; 258 if (ssl_info.connection_status != 0) 259 flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS; 260 } 261 if (vary_data.is_valid()) 262 flags |= RESPONSE_INFO_HAS_VARY_DATA; 263 if (response_truncated) 264 flags |= RESPONSE_INFO_TRUNCATED; 265 if (was_fetched_via_spdy) 266 flags |= RESPONSE_INFO_WAS_SPDY; 267 if (was_npn_negotiated) { 268 flags |= RESPONSE_INFO_WAS_NPN; 269 flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL; 270 } 271 if (was_fetched_via_proxy) 272 flags |= RESPONSE_INFO_WAS_PROXY; 273 if (connection_info != CONNECTION_INFO_UNKNOWN) 274 flags |= RESPONSE_INFO_HAS_CONNECTION_INFO; 275 276 pickle->WriteInt(flags); 277 pickle->WriteInt64(request_time.ToInternalValue()); 278 pickle->WriteInt64(response_time.ToInternalValue()); 279 280 net::HttpResponseHeaders::PersistOptions persist_options = 281 net::HttpResponseHeaders::PERSIST_RAW; 282 283 if (skip_transient_headers) { 284 persist_options = 285 net::HttpResponseHeaders::PERSIST_SANS_COOKIES | 286 net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES | 287 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP | 288 net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE | 289 net::HttpResponseHeaders::PERSIST_SANS_RANGES | 290 net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE; 291 } 292 293 headers->Persist(pickle, persist_options); 294 295 if (ssl_info.is_valid()) { 296 ssl_info.cert->Persist(pickle); 297 pickle->WriteUInt32(ssl_info.cert_status); 298 if (ssl_info.security_bits != -1) 299 pickle->WriteInt(ssl_info.security_bits); 300 if (ssl_info.connection_status != 0) 301 pickle->WriteInt(ssl_info.connection_status); 302 } 303 304 if (vary_data.is_valid()) 305 vary_data.Persist(pickle); 306 307 pickle->WriteString(socket_address.host()); 308 pickle->WriteUInt16(socket_address.port()); 309 310 if (was_npn_negotiated) 311 pickle->WriteString(npn_negotiated_protocol); 312 313 if (connection_info != CONNECTION_INFO_UNKNOWN) 314 pickle->WriteInt(static_cast<int>(connection_info)); 315} 316 317} // namespace net 318