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