Backed out changeset d68dcf2ef372 (bug 1165515) Backed out changeset 7c3b45a47811 (bug 1165515) Backed out changeset b668b617bef2 (bug 1165515) Backed out changeset d0916e1283a2 (bug 1165515) Backed out changeset ac4dc7489942 (bug 1165515) Backed out changeset e9632ce8bc65 (bug 1165515) Backed out changeset c16d215cc7e4 (bug 1165515) Backed out changeset e4d474f3c51a (bug 1165515) Backed out changeset d87680bf9f7c (bug 1165515) Backed out changeset b3c0a45ba99e (bug 1165515) Backed out changeset 9370fa197674 (bug 1165515) Backed out changeset 50970d668ca1 (bug 1165515) Backed out changeset ffa4eb6d24b9 (bug 1165515) Backed out changeset 5fcf1203cc1d (bug 1165515)
253 lines
5.6 KiB
C++
253 lines
5.6 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "nsSecurityHeaderParser.h"
|
|
#include "mozilla/Logging.h"
|
|
|
|
// The character classes in this file are informed by [RFC2616], Section 2.2.
|
|
// signed char is a signed data type one byte (8 bits) wide, so its value can
|
|
// never be greater than 127. The following implicitly makes use of this.
|
|
|
|
// A token is one or more CHAR except CTLs or separators.
|
|
// A CHAR is any US-ASCII character (octets 0 - 127).
|
|
// A CTL is any US-ASCII control character (octets 0 - 31) and DEL (127).
|
|
// A separator is one of ()<>@,;:\"/[]?={} as well as space and
|
|
// horizontal-tab (32 and 9, respectively).
|
|
// So, this returns true if chr is any octet 33-126 except ()<>@,;:\"/[]?={}
|
|
bool
|
|
IsTokenSymbol(signed char chr) {
|
|
if (chr < 33 || chr == 127 ||
|
|
chr == '(' || chr == ')' || chr == '<' || chr == '>' ||
|
|
chr == '@' || chr == ',' || chr == ';' || chr == ':' ||
|
|
chr == '"' || chr == '/' || chr == '[' || chr == ']' ||
|
|
chr == '?' || chr == '=' || chr == '{' || chr == '}' || chr == '\\') {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// A quoted-string consists of a quote (") followed by any amount of
|
|
// qdtext or quoted-pair, followed by a quote.
|
|
// qdtext is any TEXT except a quote.
|
|
// TEXT is any 8-bit octet except CTLs, but including LWS.
|
|
// quoted-pair is a backslash (\) followed by a CHAR.
|
|
// So, it turns out, \ can't really be a qdtext symbol for our purposes.
|
|
// This returns true if chr is any octet 9,10,13,32-126 except <"> or "\"
|
|
bool
|
|
IsQuotedTextSymbol(signed char chr) {
|
|
return ((chr >= 32 && chr != '"' && chr != '\\' && chr != 127) ||
|
|
chr == 0x9 || chr == 0xa || chr == 0xd);
|
|
}
|
|
|
|
// The octet following the "\" in a quoted pair can be anything 0-127.
|
|
bool
|
|
IsQuotedPairSymbol(signed char chr) {
|
|
return (chr >= 0);
|
|
}
|
|
|
|
static PRLogModuleInfo *
|
|
GetSHParserLog()
|
|
{
|
|
static PRLogModuleInfo *sSHParserLog;
|
|
if (!sSHParserLog) {
|
|
sSHParserLog = PR_NewLogModule("nsSecurityHeaderParser");
|
|
}
|
|
return sSHParserLog;
|
|
}
|
|
|
|
#define SHPARSERLOG(args) MOZ_LOG(GetSHParserLog(), PR_LOG_DEBUG, args)
|
|
|
|
nsSecurityHeaderParser::nsSecurityHeaderParser(const char *aHeader)
|
|
: mCursor(aHeader)
|
|
, mError(false)
|
|
{
|
|
}
|
|
|
|
nsSecurityHeaderParser::~nsSecurityHeaderParser() {
|
|
nsSecurityHeaderDirective *directive;
|
|
while ((directive = mDirectives.popFirst())) {
|
|
delete directive;
|
|
}
|
|
}
|
|
|
|
mozilla::LinkedList<nsSecurityHeaderDirective> *
|
|
nsSecurityHeaderParser::GetDirectives() {
|
|
return &mDirectives;
|
|
}
|
|
|
|
nsresult
|
|
nsSecurityHeaderParser::Parse() {
|
|
MOZ_ASSERT(mDirectives.isEmpty());
|
|
SHPARSERLOG(("trying to parse '%s'", mCursor));
|
|
|
|
Header();
|
|
|
|
// if we didn't consume the entire input, we were unable to parse it => error
|
|
if (mError || *mCursor) {
|
|
return NS_ERROR_FAILURE;
|
|
} else {
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsSecurityHeaderParser::Accept(char aChr)
|
|
{
|
|
if (*mCursor == aChr) {
|
|
Advance();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
nsSecurityHeaderParser::Accept(bool (*aClassifier) (signed char))
|
|
{
|
|
if (aClassifier(*mCursor)) {
|
|
Advance();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::Expect(char aChr)
|
|
{
|
|
if (*mCursor != aChr) {
|
|
mError = true;
|
|
} else {
|
|
Advance();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::Advance()
|
|
{
|
|
// Technically, 0 is valid in quoted-pair, but we were handed a
|
|
// null-terminated const char *, so this doesn't handle that.
|
|
if (*mCursor) {
|
|
mOutput.Append(*mCursor);
|
|
mCursor++;
|
|
} else {
|
|
mError = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::Header()
|
|
{
|
|
Directive();
|
|
while (Accept(';')) {
|
|
Directive();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::Directive()
|
|
{
|
|
mDirective = new nsSecurityHeaderDirective();
|
|
LWSMultiple();
|
|
DirectiveName();
|
|
LWSMultiple();
|
|
if (Accept('=')) {
|
|
LWSMultiple();
|
|
DirectiveValue();
|
|
LWSMultiple();
|
|
}
|
|
mDirectives.insertBack(mDirective);
|
|
SHPARSERLOG(("read directive name '%s', value '%s'",
|
|
mDirective->mName.Data(), mDirective->mValue.Data()));
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::DirectiveName()
|
|
{
|
|
mOutput.Truncate(0);
|
|
Token();
|
|
mDirective->mName.Assign(mOutput);
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::DirectiveValue()
|
|
{
|
|
mOutput.Truncate(0);
|
|
if (Accept(IsTokenSymbol)) {
|
|
Token();
|
|
mDirective->mValue.Assign(mOutput);
|
|
} else if (Accept('"')) {
|
|
// Accept advances the cursor if successful, which appends a character to
|
|
// mOutput. The " is not part of what we want to capture, so truncate
|
|
// mOutput again.
|
|
mOutput.Truncate(0);
|
|
QuotedString();
|
|
mDirective->mValue.Assign(mOutput);
|
|
Expect('"');
|
|
}
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::Token()
|
|
{
|
|
while (Accept(IsTokenSymbol));
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::QuotedString()
|
|
{
|
|
while (true) {
|
|
if (Accept(IsQuotedTextSymbol)) {
|
|
QuotedText();
|
|
} else if (Accept('\\')) {
|
|
QuotedPair();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::QuotedText()
|
|
{
|
|
while (Accept(IsQuotedTextSymbol));
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::QuotedPair()
|
|
{
|
|
Accept(IsQuotedPairSymbol);
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::LWSMultiple()
|
|
{
|
|
while (true) {
|
|
if (Accept('\r')) {
|
|
LWSCRLF();
|
|
} else if (Accept(' ') || Accept('\t')) {
|
|
LWS();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::LWSCRLF() {
|
|
Expect('\n');
|
|
if (!(Accept(' ') || Accept('\t'))) {
|
|
mError = true;
|
|
}
|
|
LWS();
|
|
}
|
|
|
|
void
|
|
nsSecurityHeaderParser::LWS()
|
|
{
|
|
// Note that becaue of how we're called, we don't have to check for
|
|
// the mandatory presense of at least one of SP or HT.
|
|
while (Accept(' ') || Accept('\t'));
|
|
}
|