blob: 6ee09cbffe470e2b83c0bf819d7601012c35a86e [file] [log] [blame]
// Copyright 2017 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 "platform/network/ParsedContentHeaderFieldParameters.h"
#include "platform/network/HeaderFieldTokenizer.h"
#include "platform/wtf/HashSet.h"
#include "platform/wtf/text/StringBuilder.h"
#include "platform/wtf/text/StringHash.h"
#include "platform/wtf/text/StringView.h"
namespace blink {
// parameters := *(";" parameter)
//
// From http://tools.ietf.org/html/rfc2045#section-5.1:
//
// parameter := attribute "=" value
//
// attribute := token
// ; Matching of attributes
// ; is ALWAYS case-insensitive.
//
// value := token / quoted-string
//
// token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
// or tspecials>
//
// tspecials := "(" / ")" / "<" / ">" / "@" /
// "," / ";" / ":" / "\" / <">
// "/" / "[" / "]" / "?" / "="
// ; Must be in quoted-string,
// ; to use within parameter values
WTF::Optional<ParsedContentHeaderFieldParameters>
ParsedContentHeaderFieldParameters::Parse(HeaderFieldTokenizer tokenizer,
Mode mode) {
NameValuePairs parameters;
while (!tokenizer.IsConsumed()) {
if (!tokenizer.Consume(';')) {
DVLOG(1) << "Failed to find ';'";
return WTF::nullopt;
}
StringView key;
String value;
if (!tokenizer.ConsumeToken(Mode::kNormal, key)) {
DVLOG(1) << "Invalid content parameter name. (at " << tokenizer.Index()
<< ")";
return WTF::nullopt;
}
if (!tokenizer.Consume('=')) {
DVLOG(1) << "Failed to find '='";
return WTF::nullopt;
}
if (!tokenizer.ConsumeTokenOrQuotedString(mode, value)) {
DVLOG(1) << "Invalid content parameter value (at " << tokenizer.Index()
<< ", for '" << key.ToString() << "').";
return WTF::nullopt;
}
parameters.emplace_back(key.ToString(), value);
}
return ParsedContentHeaderFieldParameters(std::move(parameters));
}
String ParsedContentHeaderFieldParameters::ParameterValueForName(
const String& name) const {
if (!name.ContainsOnlyASCII())
return String();
String lower_name = name.LowerASCII();
for (auto i = rbegin(); i != rend(); ++i) {
if (i->name.LowerASCII() == lower_name)
return i->value;
}
return String();
}
size_t ParsedContentHeaderFieldParameters::ParameterCount() const {
return parameters_.size();
}
bool ParsedContentHeaderFieldParameters::HasDuplicatedNames() const {
HashSet<String> names;
for (const auto& parameter : parameters_) {
const String lowered_name = parameter.name.LowerASCII();
if (names.find(lowered_name) != names.end())
return true;
names.insert(lowered_name);
}
return false;
}
} // namespace blink