123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /* 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 mozilla::LazyLogModule sSHParserLog("nsSecurityHeaderParser");
- #define SHPARSERLOG(args) MOZ_LOG(sSHParserLog, mozilla::LogLevel::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'));
- }
|