summaryrefslogtreecommitdiff
path: root/chromium/net/http/http_response_info.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/http/http_response_info.cc')
-rw-r--r--chromium/net/http/http_response_info.cc382
1 files changed, 382 insertions, 0 deletions
diff --git a/chromium/net/http/http_response_info.cc b/chromium/net/http/http_response_info.cc
new file mode 100644
index 00000000000..0b57a4e774b
--- /dev/null
+++ b/chromium/net/http/http_response_info.cc
@@ -0,0 +1,382 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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/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;
+ }
+}
+
+} // namespace
+
+// These values can be bit-wise combined to form the flags field of the
+// serialized HttpResponseInfo.
+enum {
+ // The version of the response info used when persisting response info.
+ RESPONSE_INFO_VERSION = 3,
+
+ // The minimum version supported for deserializing response info.
+ RESPONSE_INFO_MINIMUM_VERSION = 1,
+
+ // We reserve up to 8 bits for the version number.
+ RESPONSE_INFO_VERSION_MASK = 0xFF,
+
+ // This bit is set if the response info has a cert at the end.
+ // Version 1 serialized only the end-entity certificate, while subsequent
+ // versions include the available certificate chain.
+ RESPONSE_INFO_HAS_CERT = 1 << 8,
+
+ // This bit is set if the response info has a security-bits field (security
+ // strength, in bits, of the SSL connection) at the end.
+ RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9,
+
+ // This bit is set if the response info has a cert status at the end.
+ RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10,
+
+ // This bit is set if the response info has vary header data.
+ RESPONSE_INFO_HAS_VARY_DATA = 1 << 11,
+
+ // This bit is set if the request was cancelled before completion.
+ RESPONSE_INFO_TRUNCATED = 1 << 12,
+
+ // This bit is set if the response was received via SPDY.
+ RESPONSE_INFO_WAS_SPDY = 1 << 13,
+
+ // This bit is set if the request has NPN negotiated.
+ RESPONSE_INFO_WAS_NPN = 1 << 14,
+
+ // This bit is set if the request was fetched via an explicit proxy.
+ RESPONSE_INFO_WAS_PROXY = 1 << 15,
+
+ // This bit is set if the response info has an SSL connection status field.
+ // This contains the ciphersuite used to fetch the resource as well as the
+ // protocol version, compression method and whether SSLv3 fallback was used.
+ RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16,
+
+ // This bit is set if the response info has protocol version.
+ RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17,
+
+ // This bit is set if the response info has connection info.
+ RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18,
+
+ // This bit is set if the request has http authentication.
+ RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19,
+
+ // TODO(darin): Add other bits to indicate alternate request methods.
+ // For now, we don't support storing those.
+};
+
+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);
+
+ // Read flags and verify version
+ 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;
+ }
+
+ // Read request-time
+ int64 time_val;
+ if (!pickle.ReadInt64(&iter, &time_val))
+ return false;
+ request_time = Time::FromInternalValue(time_val);
+ was_cached = true; // Set status to show cache resurrection.
+
+ // Read response-time
+ if (!pickle.ReadInt64(&iter, &time_val))
+ return false;
+ response_time = Time::FromInternalValue(time_val);
+
+ // Read response-headers
+ headers = new HttpResponseHeaders(pickle, &iter);
+ if (headers->response_code() == -1)
+ return false;
+
+ // Read ssl-info
+ 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;
+ }
+
+ // Read vary-data
+ if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
+ if (!vary_data.InitFromPickle(pickle, &iter))
+ return false;
+ }
+
+ // Read socket_address.
+ std::string socket_address_host;
+ if (pickle.ReadString(&iter, &socket_address_host)) {
+ // If the host was written, we always expect the port to follow.
+ 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) {
+ // socket_address was not always present in version 1 of the response
+ // info, so we don't fail if it can't be read.
+ return false;
+ }
+
+ // Read protocol-version.
+ if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) {
+ if (!pickle.ReadString(&iter, &npn_negotiated_protocol))
+ return false;
+ }
+
+ // Read connection info.
+ 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;
+
+ 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 (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 kProtoSPDY2:
+ return CONNECTION_INFO_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:
+ case kProtoSPDY1:
+ case kProtoSPDY21:
+ break;
+ }
+
+ NOTREACHED();
+ return CONNECTION_INFO_UNKNOWN;
+}
+
+// static
+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_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 "";
+}
+
+} // namespace net