blob: faeccdf4ff3b3198d10c5d75332e4ec509671885 [file] [log] [blame]
// Copyright (c) 2019 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 "quiche/quic/core/qpack/value_splitting_header_list.h"
#include "absl/strings/string_view.h"
#include "quiche/quic/platform/api/quic_logging.h"
namespace quic {
namespace {
const char kCookieKey[] = "cookie";
const char kCookieSeparator = ';';
const char kOptionalSpaceAfterCookieSeparator = ' ';
const char kNonCookieSeparator = '\0';
} // namespace
ValueSplittingHeaderList::const_iterator::const_iterator(
const spdy::Http2HeaderBlock* header_list,
spdy::Http2HeaderBlock::const_iterator header_list_iterator)
: header_list_(header_list),
header_list_iterator_(header_list_iterator),
value_start_(0) {
UpdateHeaderField();
}
bool ValueSplittingHeaderList::const_iterator::operator==(
const const_iterator& other) const {
return header_list_iterator_ == other.header_list_iterator_ &&
value_start_ == other.value_start_;
}
bool ValueSplittingHeaderList::const_iterator::operator!=(
const const_iterator& other) const {
return !(*this == other);
}
const ValueSplittingHeaderList::const_iterator&
ValueSplittingHeaderList::const_iterator::operator++() {
if (value_end_ == absl::string_view::npos) {
// This was the last frament within |*header_list_iterator_|,
// move on to the next header element of |header_list_|.
++header_list_iterator_;
value_start_ = 0;
} else {
// Find the next fragment within |*header_list_iterator_|.
value_start_ = value_end_ + 1;
}
UpdateHeaderField();
return *this;
}
const ValueSplittingHeaderList::value_type&
ValueSplittingHeaderList::const_iterator::operator*() const {
return header_field_;
}
const ValueSplittingHeaderList::value_type*
ValueSplittingHeaderList::const_iterator::operator->() const {
return &header_field_;
}
void ValueSplittingHeaderList::const_iterator::UpdateHeaderField() {
QUICHE_DCHECK(value_start_ != absl::string_view::npos);
if (header_list_iterator_ == header_list_->end()) {
return;
}
const absl::string_view name = header_list_iterator_->first;
const absl::string_view original_value = header_list_iterator_->second;
if (name == kCookieKey) {
value_end_ = original_value.find(kCookieSeparator, value_start_);
} else {
value_end_ = original_value.find(kNonCookieSeparator, value_start_);
}
const absl::string_view value =
original_value.substr(value_start_, value_end_ - value_start_);
header_field_ = std::make_pair(name, value);
// Skip character after ';' separator if it is a space.
if (name == kCookieKey && value_end_ != absl::string_view::npos &&
value_end_ + 1 < original_value.size() &&
original_value[value_end_ + 1] == kOptionalSpaceAfterCookieSeparator) {
++value_end_;
}
}
ValueSplittingHeaderList::ValueSplittingHeaderList(
const spdy::Http2HeaderBlock* header_list)
: header_list_(header_list) {
QUICHE_DCHECK(header_list_);
}
ValueSplittingHeaderList::const_iterator ValueSplittingHeaderList::begin()
const {
return const_iterator(header_list_, header_list_->begin());
}
ValueSplittingHeaderList::const_iterator ValueSplittingHeaderList::end() const {
return const_iterator(header_list_, header_list_->end());
}
} // namespace quic