1 // Copyright (c) 2011 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/ssl_cert_request_info.h" 14 #include "net/base/x509_certificate.h" 15 #include "net/http/http_response_headers.h" 16 17 using base::Time; 18 19 namespace net { 20 21 // These values can be bit-wise combined to form the flags field of the 22 // serialized HttpResponseInfo. 23 enum { 24 // The version of the response info used when persisting response info. 25 RESPONSE_INFO_VERSION = 2, 26 27 // The minimum version supported for deserializing response info. 28 RESPONSE_INFO_MINIMUM_VERSION = 1, 29 30 // We reserve up to 8 bits for the version number. 31 RESPONSE_INFO_VERSION_MASK = 0xFF, 32 33 // This bit is set if the response info has a cert at the end. 34 RESPONSE_INFO_HAS_CERT = 1 << 8, 35 36 // This bit is set if the response info has a security-bits field (security 37 // strength, in bits, of the SSL connection) at the end. 38 RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9, 39 40 // This bit is set if the response info has a cert status at the end. 41 RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10, 42 43 // This bit is set if the response info has vary header data. 44 RESPONSE_INFO_HAS_VARY_DATA = 1 << 11, 45 46 // This bit is set if the request was cancelled before completion. 47 RESPONSE_INFO_TRUNCATED = 1 << 12, 48 49 // This bit is set if the response was received via SPDY. 50 RESPONSE_INFO_WAS_SPDY = 1 << 13, 51 52 // This bit is set if the request has NPN negotiated. 53 RESPONSE_INFO_WAS_NPN = 1 << 14, 54 55 // This bit is set if the request was fetched via an explicit proxy. 56 RESPONSE_INFO_WAS_PROXY = 1 << 15, 57 58 // TODO(darin): Add other bits to indicate alternate request methods. 59 // For now, we don't support storing those. 60 }; 61 62 HttpResponseInfo::HttpResponseInfo() 63 : was_cached(false), 64 was_fetched_via_spdy(false), 65 was_npn_negotiated(false), 66 was_fetched_via_proxy(false) { 67 } 68 69 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) 70 : was_cached(rhs.was_cached), 71 was_fetched_via_spdy(rhs.was_fetched_via_spdy), 72 was_npn_negotiated(rhs.was_npn_negotiated), 73 was_fetched_via_proxy(rhs.was_fetched_via_proxy), 74 socket_address(rhs.socket_address), 75 request_time(rhs.request_time), 76 response_time(rhs.response_time), 77 auth_challenge(rhs.auth_challenge), 78 cert_request_info(rhs.cert_request_info), 79 ssl_info(rhs.ssl_info), 80 headers(rhs.headers), 81 vary_data(rhs.vary_data), 82 metadata(rhs.metadata) { 83 } 84 85 HttpResponseInfo::~HttpResponseInfo() { 86 } 87 88 HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) { 89 was_cached = rhs.was_cached; 90 was_fetched_via_spdy = rhs.was_fetched_via_spdy; 91 was_npn_negotiated = rhs.was_npn_negotiated; 92 was_fetched_via_proxy = rhs.was_fetched_via_proxy; 93 socket_address = rhs.socket_address; 94 request_time = rhs.request_time; 95 response_time = rhs.response_time; 96 auth_challenge = rhs.auth_challenge; 97 cert_request_info = rhs.cert_request_info; 98 ssl_info = rhs.ssl_info; 99 headers = rhs.headers; 100 vary_data = rhs.vary_data; 101 metadata = rhs.metadata; 102 return *this; 103 } 104 105 bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, 106 bool* response_truncated) { 107 void* iter = NULL; 108 109 // read flags and verify version 110 int flags; 111 if (!pickle.ReadInt(&iter, &flags)) 112 return false; 113 int version = flags & RESPONSE_INFO_VERSION_MASK; 114 if (version < RESPONSE_INFO_MINIMUM_VERSION || 115 version > RESPONSE_INFO_VERSION) { 116 DLOG(ERROR) << "unexpected response info version: " << version; 117 return false; 118 } 119 120 // read request-time 121 int64 time_val; 122 if (!pickle.ReadInt64(&iter, &time_val)) 123 return false; 124 request_time = Time::FromInternalValue(time_val); 125 was_cached = true; // Set status to show cache resurrection. 126 127 // read response-time 128 if (!pickle.ReadInt64(&iter, &time_val)) 129 return false; 130 response_time = Time::FromInternalValue(time_val); 131 132 // read response-headers 133 headers = new HttpResponseHeaders(pickle, &iter); 134 DCHECK_NE(headers->response_code(), -1); 135 136 // read ssl-info 137 if (flags & RESPONSE_INFO_HAS_CERT) { 138 // Version 1 only serialized only the end-entity certificate, 139 // while subsequent versions include the entire chain. 140 X509Certificate::PickleType type = (version == 1) ? 141 X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE : 142 X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN; 143 ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type); 144 } 145 if (flags & RESPONSE_INFO_HAS_CERT_STATUS) { 146 int cert_status; 147 if (!pickle.ReadInt(&iter, &cert_status)) 148 return false; 149 ssl_info.cert_status = cert_status; 150 } 151 if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) { 152 int security_bits; 153 if (!pickle.ReadInt(&iter, &security_bits)) 154 return false; 155 ssl_info.security_bits = security_bits; 156 } 157 158 // read vary-data 159 if (flags & RESPONSE_INFO_HAS_VARY_DATA) { 160 if (!vary_data.InitFromPickle(pickle, &iter)) 161 return false; 162 } 163 164 // Read socket_address. This was not always present in the response info, 165 // so we don't fail if it can't be read. If additional fields are added in 166 // a future version, then they must only be read if this operation succeeds. 167 std::string socket_address_host; 168 if (pickle.ReadString(&iter, &socket_address_host)) { 169 // If the host was written, we always expect the port to follow. 170 uint16 socket_address_port; 171 if (!pickle.ReadUInt16(&iter, &socket_address_port)) 172 return false; 173 socket_address = HostPortPair(socket_address_host, socket_address_port); 174 } 175 176 was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0; 177 178 was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0; 179 180 was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0; 181 182 *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) ? true : false; 183 184 return true; 185 } 186 187 void HttpResponseInfo::Persist(Pickle* pickle, 188 bool skip_transient_headers, 189 bool response_truncated) const { 190 int flags = RESPONSE_INFO_VERSION; 191 if (ssl_info.is_valid()) { 192 flags |= RESPONSE_INFO_HAS_CERT; 193 flags |= RESPONSE_INFO_HAS_CERT_STATUS; 194 if (ssl_info.security_bits != -1) 195 flags |= RESPONSE_INFO_HAS_SECURITY_BITS; 196 // TODO(wtc): we should persist ssl_info.connection_status. 197 } 198 if (vary_data.is_valid()) 199 flags |= RESPONSE_INFO_HAS_VARY_DATA; 200 if (response_truncated) 201 flags |= RESPONSE_INFO_TRUNCATED; 202 if (was_fetched_via_spdy) 203 flags |= RESPONSE_INFO_WAS_SPDY; 204 if (was_npn_negotiated) 205 flags |= RESPONSE_INFO_WAS_NPN; 206 if (was_fetched_via_proxy) 207 flags |= RESPONSE_INFO_WAS_PROXY; 208 209 pickle->WriteInt(flags); 210 pickle->WriteInt64(request_time.ToInternalValue()); 211 pickle->WriteInt64(response_time.ToInternalValue()); 212 213 net::HttpResponseHeaders::PersistOptions persist_options = 214 net::HttpResponseHeaders::PERSIST_RAW; 215 216 if (skip_transient_headers) { 217 persist_options = 218 net::HttpResponseHeaders::PERSIST_SANS_COOKIES | 219 net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES | 220 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP | 221 net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE | 222 net::HttpResponseHeaders::PERSIST_SANS_RANGES; 223 } 224 225 headers->Persist(pickle, persist_options); 226 227 if (ssl_info.is_valid()) { 228 ssl_info.cert->Persist(pickle); 229 pickle->WriteInt(ssl_info.cert_status); 230 if (ssl_info.security_bits != -1) 231 pickle->WriteInt(ssl_info.security_bits); 232 } 233 234 if (vary_data.is_valid()) 235 vary_data.Persist(pickle); 236 237 pickle->WriteString(socket_address.host()); 238 pickle->WriteUInt16(socket_address.port()); 239 } 240 241 } // namespace net 242