Files
tubestation/security/manager/ssl/nsSecurityHeaderParser.cpp
Wes Kocher 2a7ed059f1 Backed out 14 changesets (bug 1165515) for b2g mochitest-6 permafail CLOSED TREE
Backed out changeset 9b97e2aa2ed9 (bug 1165515)
Backed out changeset 150606c022a2 (bug 1165515)
Backed out changeset 4e875a488349 (bug 1165515)
Backed out changeset 467e7feeb546 (bug 1165515)
Backed out changeset d6b6cc373197 (bug 1165515)
Backed out changeset 0615265b593c (bug 1165515)
Backed out changeset fafd1dce9f08 (bug 1165515)
Backed out changeset d1df869245f9 (bug 1165515)
Backed out changeset 6876a7c63611 (bug 1165515)
Backed out changeset b7841c94a9a3 (bug 1165515)
Backed out changeset e5e3617f7c73 (bug 1165515)
Backed out changeset 39be3db95978 (bug 1165515)
Backed out changeset 0ec74176f8de (bug 1165515)
Backed out changeset 5b928dd10d71 (bug 1165515)
2015-06-01 17:57:58 -07:00

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'));
}