chromium/net/http/http_response_headers.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The rules for header parsing were borrowed from Firefox:
// http://lxr.mozilla.org/seamonkey/source/netwerk/protocol/http/src/nsHttpResponseHead.cpp
// The rules for parsing content-types were also borrowed from Firefox:
// http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834

#include "net/http/http_response_headers.h"

#include <algorithm>
#include <limits>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>

#include "base/format_macros.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/pickle.h"
#include "base/ranges/algorithm.h"
#include "base/strings/escape.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/parse_number.h"
#include "net/base/tracing.h"
#include "net/http/http_byte_range.h"
#include "net/http/http_log_util.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_values.h"

Time;

namespace net {

//-----------------------------------------------------------------------------

namespace {

// These headers are RFC 2616 hop-by-hop headers;
// not to be stored by caches.
const char* const kHopByHopResponseHeaders[] =;

// These headers are challenge response headers;
// not to be stored by caches.
const char* const kChallengeResponseHeaders[] =;

// These headers are cookie setting headers;
// not to be stored by caches or disclosed otherwise.
const char* const kCookieResponseHeaders[] =;

// By default, do not cache Strict-Transport-Security.
// This avoids erroneously re-processing it on page loads from cache ---
// it is defined to be valid only on live and error-free HTTPS connections.
const char* const kSecurityStateHeaders[] =;

// These response headers are not copied from a 304/206 response to the cached
// response headers.  This list is based on Mozilla's nsHttpResponseHead.cpp.
const char* const kNonUpdatedHeaders[] =;

// Some header prefixes mean "Don't copy this header from a 304 response.".
// Rather than listing all the relevant headers, we can consolidate them into
// this list:
const char* const kNonUpdatedHeaderPrefixes[] =;

constexpr char kActivateStorageAccessHeader[] =;

bool ShouldUpdateHeader(std::string_view name) {}

bool HasEmbeddedNulls(std::string_view str) {}

void CheckDoesNotHaveEmbeddedNulls(std::string_view str) {}

void RemoveLeadingSpaces(std::string_view* s) {}

// Parses `status` for response code and status text. Returns the response code,
// and appends the response code and trimmed status text preceded by a space to
// `append_to`. For example, given the input " 404 Not found " would return 404
// and append " 404 Not found" to `append_to`. The odd calling convention is
// necessary to avoid extra copies in the implementation of
// HttpResponseHeaders::ParseStatusLine().
int ParseStatus(std::string_view status, std::string& append_to) {}

}  // namespace

const char HttpResponseHeaders::kContentRange[] =;
const char HttpResponseHeaders::kLastModified[] =;
const char HttpResponseHeaders::kVary[] =;

struct HttpResponseHeaders::ParsedHeader {};

//-----------------------------------------------------------------------------

HttpResponseHeaders::Builder::Builder(HttpVersion version,
                                      std::string_view status)
    :{}

HttpResponseHeaders::Builder::~Builder() = default;

scoped_refptr<HttpResponseHeaders> HttpResponseHeaders::Builder::Build() {}

HttpResponseHeaders::HttpResponseHeaders(const std::string& raw_input)
    :{}

HttpResponseHeaders::HttpResponseHeaders(base::PickleIterator* iter)
    :{}

HttpResponseHeaders::HttpResponseHeaders(
    BuilderPassKey,
    HttpVersion version,
    std::string_view status,
    base::span<const std::pair<std::string_view, std::string_view>> headers)
    :{}

scoped_refptr<HttpResponseHeaders> HttpResponseHeaders::TryToCreate(
    std::string_view headers) {}

scoped_refptr<HttpResponseHeaders> HttpResponseHeaders::TryToCreateForDataURL(
    std::string_view content_type) {}

void HttpResponseHeaders::Persist(base::Pickle* pickle,
                                  PersistOptions options) {}

void HttpResponseHeaders::Update(const HttpResponseHeaders& new_headers) {}

void HttpResponseHeaders::MergeWithHeaders(std::string raw_headers,
                                           const HeaderSet& headers_to_remove) {}

void HttpResponseHeaders::RemoveHeader(std::string_view name) {}

void HttpResponseHeaders::RemoveHeaders(
    const std::unordered_set<std::string>& header_names) {}

void HttpResponseHeaders::RemoveHeaderLine(const std::string& name,
                                           const std::string& value) {}

void HttpResponseHeaders::AddHeader(std::string_view name,
                                    std::string_view value) {}

void HttpResponseHeaders::SetHeader(std::string_view name,
                                    std::string_view value) {}

void HttpResponseHeaders::AddCookie(const std::string& cookie_string) {}

void HttpResponseHeaders::ReplaceStatusLine(const std::string& new_status) {}

void HttpResponseHeaders::UpdateWithNewRange(const HttpByteRange& byte_range,
                                             int64_t resource_size,
                                             bool replace_status_line) {}

void HttpResponseHeaders::Parse(const std::string& raw_input) {}

bool HttpResponseHeaders::GetNormalizedHeader(std::string_view name,
                                              std::string* value) const {}

std::string HttpResponseHeaders::GetStatusLine() const {}

std::string HttpResponseHeaders::GetStatusText() const {}

bool HttpResponseHeaders::EnumerateHeaderLines(size_t* iter,
                                               std::string* name,
                                               std::string* value) const {}

bool HttpResponseHeaders::EnumerateHeader(size_t* iter,
                                          std::string_view name,
                                          std::string* value) const {}

bool HttpResponseHeaders::HasHeaderValue(std::string_view name,
                                         std::string_view value) const {}

bool HttpResponseHeaders::HasHeader(std::string_view name) const {}

HttpResponseHeaders::~HttpResponseHeaders() = default;

// Note: this implementation implicitly assumes that line_end points at a valid
// sentinel character (such as '\0').
// static
HttpVersion HttpResponseHeaders::ParseVersion(
    std::string::const_iterator line_begin,
    std::string::const_iterator line_end) {}

// Note: this implementation implicitly assumes that line_end points at a valid
// sentinel character (such as '\0').
void HttpResponseHeaders::ParseStatusLine(
    std::string::const_iterator line_begin,
    std::string::const_iterator line_end,
    bool has_headers) {}

size_t HttpResponseHeaders::FindHeader(size_t from,
                                       std::string_view search) const {}

std::optional<base::TimeDelta> HttpResponseHeaders::GetCacheControlDirective(
    std::string_view directive) const {}

void HttpResponseHeaders::AddHeader(std::string::const_iterator name_begin,
                                    std::string::const_iterator name_end,
                                    std::string::const_iterator values_begin,
                                    std::string::const_iterator values_end,
                                    ContainsCommas contains_commas) {}

void HttpResponseHeaders::AddToParsed(std::string::const_iterator name_begin,
                                      std::string::const_iterator name_end,
                                      std::string::const_iterator value_begin,
                                      std::string::const_iterator value_end) {}

void HttpResponseHeaders::AddNonCacheableHeaders(HeaderSet* result) const {}

void HttpResponseHeaders::AddHopByHopHeaders(HeaderSet* result) {}

void HttpResponseHeaders::AddCookieHeaders(HeaderSet* result) {}

void HttpResponseHeaders::AddChallengeHeaders(HeaderSet* result) {}

void HttpResponseHeaders::AddHopContentRangeHeaders(HeaderSet* result) {}

void HttpResponseHeaders::AddSecurityStateHeaders(HeaderSet* result) {}

void HttpResponseHeaders::GetMimeTypeAndCharset(std::string* mime_type,
                                                std::string* charset) const {}

bool HttpResponseHeaders::GetMimeType(std::string* mime_type) const {}

bool HttpResponseHeaders::GetCharset(std::string* charset) const {}

bool HttpResponseHeaders::IsRedirect(std::string* location) const {}

bool HttpResponseHeaders::HasStorageAccessRetryHeader() const {}

bool HttpResponseHeaders::HasStorageAccessLoadHeader() const {}

// static
bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) {}

// From RFC 2616 section 13.2.4:
//
// The calculation to determine if a response has expired is quite simple:
//
//   response_is_fresh = (freshness_lifetime > current_age)
//
// Of course, there are other factors that can force a response to always be
// validated or re-fetched.
//
// From RFC 5861 section 3, a stale response may be used while revalidation is
// performed in the background if
//
//   freshness_lifetime + stale_while_revalidate > current_age
//
ValidationType HttpResponseHeaders::RequiresValidation(
    const Time& request_time,
    const Time& response_time,
    const Time& current_time) const {}

// From RFC 2616 section 13.2.4:
//
// The max-age directive takes priority over Expires, so if max-age is present
// in a response, the calculation is simply:
//
//   freshness_lifetime = max_age_value
//
// Otherwise, if Expires is present in the response, the calculation is:
//
//   freshness_lifetime = expires_value - date_value
//
// Note that neither of these calculations is vulnerable to clock skew, since
// all of the information comes from the origin server.
//
// Also, if the response does have a Last-Modified time, the heuristic
// expiration value SHOULD be no more than some fraction of the interval since
// that time. A typical setting of this fraction might be 10%:
//
//   freshness_lifetime = (date_value - last_modified_value) * 0.10
//
// If the stale-while-revalidate directive is present, then it is used to set
// the |staleness| time, unless it overridden by another directive.
//
HttpResponseHeaders::FreshnessLifetimes
HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {}

// From RFC 7234 section 4.2.3:
//
// The following data is used for the age calculation:
//
//    age_value
//
//       The term "age_value" denotes the value of the Age header field
//       (Section 5.1), in a form appropriate for arithmetic operation; or
//       0, if not available.
//
//    date_value
//
//       The term "date_value" denotes the value of the Date header field,
//       in a form appropriate for arithmetic operations.  See Section
//       7.1.1.2 of [RFC7231] for the definition of the Date header field,
//       and for requirements regarding responses without it.
//
//    now
//
//       The term "now" means "the current value of the clock at the host
//       performing the calculation".  A host ought to use NTP ([RFC5905])
//       or some similar protocol to synchronize its clocks to Coordinated
//       Universal Time.
//
//    request_time
//
//       The current value of the clock at the host at the time the request
//       resulting in the stored response was made.
//
//    response_time
//
//       The current value of the clock at the host at the time the
//       response was received.
//
//    The age is then calculated as
//
//     apparent_age = max(0, response_time - date_value);
//     response_delay = response_time - request_time;
//     corrected_age_value = age_value + response_delay;
//     corrected_initial_age = max(apparent_age, corrected_age_value);
//     resident_time = now - response_time;
//     current_age = corrected_initial_age + resident_time;
//
base::TimeDelta HttpResponseHeaders::GetCurrentAge(
    const Time& request_time,
    const Time& response_time,
    const Time& current_time) const {}

std::optional<base::TimeDelta> HttpResponseHeaders::GetMaxAgeValue() const {}

std::optional<base::TimeDelta> HttpResponseHeaders::GetAgeValue() const {}

std::optional<Time> HttpResponseHeaders::GetDateValue() const {}

std::optional<Time> HttpResponseHeaders::GetLastModifiedValue() const {}

std::optional<Time> HttpResponseHeaders::GetExpiresValue() const {}

std::optional<base::TimeDelta>
HttpResponseHeaders::GetStaleWhileRevalidateValue() const {}

std::optional<Time> HttpResponseHeaders::GetTimeValuedHeader(
    const std::string& name) const {}

// We accept the first value of "close" or "keep-alive" in a Connection or
// Proxy-Connection header, in that order. Obeying "keep-alive" in HTTP/1.1 or
// "close" in 1.0 is not strictly standards-compliant, but we'd like to
// avoid looking at the Proxy-Connection header whenever it is reasonable to do
// so.
// TODO(ricea): Measure real-world usage of the "Proxy-Connection" header,
// with a view to reducing support for it in order to make our Connection header
// handling more RFC 7230 compliant.
bool HttpResponseHeaders::IsKeepAlive() const {}

bool HttpResponseHeaders::HasStrongValidators() const {}

bool HttpResponseHeaders::HasValidators() const {}

// From RFC 2616:
// Content-Length = "Content-Length" ":" 1*DIGIT
int64_t HttpResponseHeaders::GetContentLength() const {}

int64_t HttpResponseHeaders::GetInt64HeaderValue(
    const std::string& header) const {}

bool HttpResponseHeaders::GetContentRangeFor206(
    int64_t* first_byte_position,
    int64_t* last_byte_position,
    int64_t* instance_length) const {}

base::Value::Dict HttpResponseHeaders::NetLogParams(
    NetLogCaptureMode capture_mode) const {}

bool HttpResponseHeaders::IsChunkEncoded() const {}

bool HttpResponseHeaders::IsCookieResponseHeader(std::string_view name) {}

void HttpResponseHeaders::WriteIntoTrace(perfetto::TracedValue context) const {}

bool HttpResponseHeaders::StrictlyEquals(
    const HttpResponseHeaders& other) const {}

}  // namespace net