This source file includes following definitions.
- GetPickleTypeForVersion
- connection_info
- metadata
- InitFromPickle
- Persist
- ConnectionInfoFromNextProto
- ConnectionInfoToString
#include "net/http/http_response_info.h"
#include "base/logging.h"
#include "base/pickle.h"
#include "base/time/time.h"
#include "net/base/auth.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/x509_certificate.h"
#include "net/http/http_response_headers.h"
#include "net/ssl/ssl_cert_request_info.h"
using base::Time;
namespace net {
namespace {
X509Certificate::PickleType GetPickleTypeForVersion(int version) {
switch (version) {
case 1:
return X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE;
case 2:
return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V2;
case 3:
default:
return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V3;
}
}
}
enum {
RESPONSE_INFO_VERSION = 3,
RESPONSE_INFO_MINIMUM_VERSION = 1,
RESPONSE_INFO_VERSION_MASK = 0xFF,
RESPONSE_INFO_HAS_CERT = 1 << 8,
RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9,
RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10,
RESPONSE_INFO_HAS_VARY_DATA = 1 << 11,
RESPONSE_INFO_TRUNCATED = 1 << 12,
RESPONSE_INFO_WAS_SPDY = 1 << 13,
RESPONSE_INFO_WAS_NPN = 1 << 14,
RESPONSE_INFO_WAS_PROXY = 1 << 15,
RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16,
RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17,
RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18,
RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19,
RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS = 1 << 20,
};
HttpResponseInfo::HttpResponseInfo()
: was_cached(false),
server_data_unavailable(false),
network_accessed(false),
was_fetched_via_spdy(false),
was_npn_negotiated(false),
was_fetched_via_proxy(false),
did_use_http_auth(false),
connection_info(CONNECTION_INFO_UNKNOWN) {
}
HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
: was_cached(rhs.was_cached),
server_data_unavailable(rhs.server_data_unavailable),
network_accessed(rhs.network_accessed),
was_fetched_via_spdy(rhs.was_fetched_via_spdy),
was_npn_negotiated(rhs.was_npn_negotiated),
was_fetched_via_proxy(rhs.was_fetched_via_proxy),
did_use_http_auth(rhs.did_use_http_auth),
socket_address(rhs.socket_address),
npn_negotiated_protocol(rhs.npn_negotiated_protocol),
connection_info(rhs.connection_info),
request_time(rhs.request_time),
response_time(rhs.response_time),
auth_challenge(rhs.auth_challenge),
cert_request_info(rhs.cert_request_info),
ssl_info(rhs.ssl_info),
headers(rhs.headers),
vary_data(rhs.vary_data),
metadata(rhs.metadata) {
}
HttpResponseInfo::~HttpResponseInfo() {
}
HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
was_cached = rhs.was_cached;
server_data_unavailable = rhs.server_data_unavailable;
network_accessed = rhs.network_accessed;
was_fetched_via_spdy = rhs.was_fetched_via_spdy;
was_npn_negotiated = rhs.was_npn_negotiated;
was_fetched_via_proxy = rhs.was_fetched_via_proxy;
did_use_http_auth = rhs.did_use_http_auth;
socket_address = rhs.socket_address;
npn_negotiated_protocol = rhs.npn_negotiated_protocol;
connection_info = rhs.connection_info;
request_time = rhs.request_time;
response_time = rhs.response_time;
auth_challenge = rhs.auth_challenge;
cert_request_info = rhs.cert_request_info;
ssl_info = rhs.ssl_info;
headers = rhs.headers;
vary_data = rhs.vary_data;
metadata = rhs.metadata;
return *this;
}
bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
bool* response_truncated) {
PickleIterator iter(pickle);
int flags;
if (!pickle.ReadInt(&iter, &flags))
return false;
int version = flags & RESPONSE_INFO_VERSION_MASK;
if (version < RESPONSE_INFO_MINIMUM_VERSION ||
version > RESPONSE_INFO_VERSION) {
DLOG(ERROR) << "unexpected response info version: " << version;
return false;
}
int64 time_val;
if (!pickle.ReadInt64(&iter, &time_val))
return false;
request_time = Time::FromInternalValue(time_val);
was_cached = true;
if (!pickle.ReadInt64(&iter, &time_val))
return false;
response_time = Time::FromInternalValue(time_val);
headers = new HttpResponseHeaders(pickle, &iter);
if (headers->response_code() == -1)
return false;
if (flags & RESPONSE_INFO_HAS_CERT) {
X509Certificate::PickleType type = GetPickleTypeForVersion(version);
ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type);
if (!ssl_info.cert.get())
return false;
}
if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
CertStatus cert_status;
if (!pickle.ReadUInt32(&iter, &cert_status))
return false;
ssl_info.cert_status = cert_status;
}
if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
int security_bits;
if (!pickle.ReadInt(&iter, &security_bits))
return false;
ssl_info.security_bits = security_bits;
}
if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) {
int connection_status;
if (!pickle.ReadInt(&iter, &connection_status))
return false;
ssl_info.connection_status = connection_status;
}
if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) {
int num_scts;
if (!pickle.ReadInt(&iter, &num_scts))
return false;
for (int i = 0; i < num_scts; ++i) {
scoped_refptr<ct::SignedCertificateTimestamp> sct(
ct::SignedCertificateTimestamp::CreateFromPickle(&iter));
uint16 status;
if (!sct.get() || !pickle.ReadUInt16(&iter, &status))
return false;
ssl_info.signed_certificate_timestamps.push_back(
SignedCertificateTimestampAndStatus(
sct, static_cast<ct::SCTVerifyStatus>(status)));
}
}
if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
if (!vary_data.InitFromPickle(pickle, &iter))
return false;
}
std::string socket_address_host;
if (pickle.ReadString(&iter, &socket_address_host)) {
uint16 socket_address_port;
if (!pickle.ReadUInt16(&iter, &socket_address_port))
return false;
socket_address = HostPortPair(socket_address_host, socket_address_port);
} else if (version > 1) {
return false;
}
if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) {
if (!pickle.ReadString(&iter, &npn_negotiated_protocol))
return false;
}
if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) {
int value;
if (!pickle.ReadInt(&iter, &value))
return false;
if (value > static_cast<int>(CONNECTION_INFO_UNKNOWN) &&
value < static_cast<int>(NUM_OF_CONNECTION_INFOS)) {
connection_info = static_cast<ConnectionInfo>(value);
}
}
was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0;
was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
*response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0;
did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0;
return true;
}
void HttpResponseInfo::Persist(Pickle* pickle,
bool skip_transient_headers,
bool response_truncated) const {
int flags = RESPONSE_INFO_VERSION;
if (ssl_info.is_valid()) {
flags |= RESPONSE_INFO_HAS_CERT;
flags |= RESPONSE_INFO_HAS_CERT_STATUS;
if (ssl_info.security_bits != -1)
flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
if (ssl_info.connection_status != 0)
flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS;
}
if (vary_data.is_valid())
flags |= RESPONSE_INFO_HAS_VARY_DATA;
if (response_truncated)
flags |= RESPONSE_INFO_TRUNCATED;
if (was_fetched_via_spdy)
flags |= RESPONSE_INFO_WAS_SPDY;
if (was_npn_negotiated) {
flags |= RESPONSE_INFO_WAS_NPN;
flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL;
}
if (was_fetched_via_proxy)
flags |= RESPONSE_INFO_WAS_PROXY;
if (connection_info != CONNECTION_INFO_UNKNOWN)
flags |= RESPONSE_INFO_HAS_CONNECTION_INFO;
if (did_use_http_auth)
flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION;
if (!ssl_info.signed_certificate_timestamps.empty())
flags |= RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS;
pickle->WriteInt(flags);
pickle->WriteInt64(request_time.ToInternalValue());
pickle->WriteInt64(response_time.ToInternalValue());
net::HttpResponseHeaders::PersistOptions persist_options =
net::HttpResponseHeaders::PERSIST_RAW;
if (skip_transient_headers) {
persist_options =
net::HttpResponseHeaders::PERSIST_SANS_COOKIES |
net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES |
net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP |
net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
net::HttpResponseHeaders::PERSIST_SANS_RANGES |
net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE;
}
headers->Persist(pickle, persist_options);
if (ssl_info.is_valid()) {
ssl_info.cert->Persist(pickle);
pickle->WriteUInt32(ssl_info.cert_status);
if (ssl_info.security_bits != -1)
pickle->WriteInt(ssl_info.security_bits);
if (ssl_info.connection_status != 0)
pickle->WriteInt(ssl_info.connection_status);
if (!ssl_info.signed_certificate_timestamps.empty()) {
pickle->WriteInt(ssl_info.signed_certificate_timestamps.size());
for (SignedCertificateTimestampAndStatusList::const_iterator it =
ssl_info.signed_certificate_timestamps.begin(); it !=
ssl_info.signed_certificate_timestamps.end(); ++it) {
it->sct->Persist(pickle);
pickle->WriteUInt16(it->status);
}
}
}
if (vary_data.is_valid())
vary_data.Persist(pickle);
pickle->WriteString(socket_address.host());
pickle->WriteUInt16(socket_address.port());
if (was_npn_negotiated)
pickle->WriteString(npn_negotiated_protocol);
if (connection_info != CONNECTION_INFO_UNKNOWN)
pickle->WriteInt(static_cast<int>(connection_info));
}
HttpResponseInfo::ConnectionInfo HttpResponseInfo::ConnectionInfoFromNextProto(
NextProto next_proto) {
switch (next_proto) {
case kProtoDeprecatedSPDY2:
return CONNECTION_INFO_DEPRECATED_SPDY2;
case kProtoSPDY3:
case kProtoSPDY31:
return CONNECTION_INFO_SPDY3;
case kProtoSPDY4a2:
return CONNECTION_INFO_SPDY4A2;
case kProtoHTTP2Draft04:
return CONNECTION_INFO_HTTP2_DRAFT_04;
case kProtoQUIC1SPDY3:
return CONNECTION_INFO_QUIC1_SPDY3;
case kProtoUnknown:
case kProtoHTTP11:
break;
}
NOTREACHED();
return CONNECTION_INFO_UNKNOWN;
}
std::string HttpResponseInfo::ConnectionInfoToString(
ConnectionInfo connection_info) {
switch (connection_info) {
case CONNECTION_INFO_UNKNOWN:
return "unknown";
case CONNECTION_INFO_HTTP1:
return "http/1";
case CONNECTION_INFO_DEPRECATED_SPDY2:
return "spdy/2";
case CONNECTION_INFO_SPDY3:
return "spdy/3";
case CONNECTION_INFO_SPDY4A2:
return "spdy/4a2";
case CONNECTION_INFO_HTTP2_DRAFT_04:
return "HTTP-draft-04/2.0";
case CONNECTION_INFO_QUIC1_SPDY3:
return "quic/1+spdy/3";
case NUM_OF_CONNECTION_INFOS:
break;
}
NOTREACHED();
return "";
}
}