// Copyright (c) 2009 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.h"
#include "net/http/http_response_headers.h"
using base::Time;
namespace net {
// 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 = 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.
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,
// TODO(darin): Add other bits to indicate alternate request methods.
// For now, we don't support storing those.
};
HttpResponseInfo::HttpResponseInfo()
: was_cached(false),
was_fetched_via_spdy(false) {
}
HttpResponseInfo::~HttpResponseInfo() {
}
bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
bool* response_truncated) {
void* iter = NULL;
// 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_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);
DCHECK_NE(headers->response_code(), -1);
// read ssl-info
if (flags & RESPONSE_INFO_HAS_CERT) {
ssl_info.cert =
X509Certificate::CreateFromPickle(pickle, &iter);
}
if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
int cert_status;
if (!pickle.ReadInt(&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;
}
// read vary-data
if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
if (!vary_data.InitFromPickle(pickle, &iter))
return false;
}
was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
*response_truncated = (flags & RESPONSE_INFO_TRUNCATED) ? true : false;
return true;
}
void HttpResponseInfo::Persist(Pickle* pickle,
bool skip_transient_headers,
bool response_truncated) const {
int flags = RESPONSE_INFO_VERSION;
if (ssl_info.cert) {
flags |= RESPONSE_INFO_HAS_CERT;
flags |= RESPONSE_INFO_HAS_CERT_STATUS;
}
if (ssl_info.security_bits != -1)
flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
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;
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;
}
headers->Persist(pickle, persist_options);
if (ssl_info.cert) {
ssl_info.cert->Persist(pickle);
pickle->WriteInt(ssl_info.cert_status);
}
if (ssl_info.security_bits != -1)
pickle->WriteInt(ssl_info.security_bits);
if (vary_data.is_valid())
vary_data.Persist(pickle);
}
} // namespace net