security/manager/boot/src/nsSecurityHeaderParser.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "nsSecurityHeaderParser.h"
     6 #include "prlog.h"
     8 // The character classes in this file are informed by [RFC2616], Section 2.2.
     9 // signed char is a signed data type one byte (8 bits) wide, so its value can
    10 // never be greater than 127. The following implicitly makes use of this.
    12 // A token is one or more CHAR except CTLs or separators.
    13 // A CHAR is any US-ASCII character (octets 0 - 127).
    14 // A CTL is any US-ASCII control character (octets 0 - 31) and DEL (127).
    15 // A separator is one of ()<>@,;:\"/[]?={} as well as space and
    16 // horizontal-tab (32 and 9, respectively).
    17 // So, this returns true if chr is any octet 33-126 except ()<>@,;:\"/[]?={}
    18 bool
    19 IsTokenSymbol(signed char chr) {
    20   if (chr < 33 || chr == 127 ||
    21       chr == '(' || chr == ')' || chr == '<' || chr == '>' ||
    22       chr == '@' || chr == ',' || chr == ';' || chr == ':' ||
    23       chr == '"' || chr == '/' || chr == '[' || chr == ']' ||
    24       chr == '?' || chr == '=' || chr == '{' || chr == '}' || chr == '\\') {
    25     return false;
    26   }
    27   return true;
    28 }
    30 // A quoted-string consists of a quote (") followed by any amount of
    31 // qdtext or quoted-pair, followed by a quote.
    32 // qdtext is any TEXT except a quote.
    33 // TEXT is any 8-bit octet except CTLs, but including LWS.
    34 // quoted-pair is a backslash (\) followed by a CHAR.
    35 // So, it turns out, \ can't really be a qdtext symbol for our purposes.
    36 // This returns true if chr is any octet 9,10,13,32-126 except <"> or "\"
    37 bool
    38 IsQuotedTextSymbol(signed char chr) {
    39   return ((chr >= 32 && chr != '"' && chr != '\\' && chr != 127) ||
    40           chr == 0x9 || chr == 0xa || chr == 0xd);
    41 }
    43 // The octet following the "\" in a quoted pair can be anything 0-127.
    44 bool
    45 IsQuotedPairSymbol(signed char chr) {
    46   return (chr >= 0);
    47 }
    49 #if defined(PR_LOGGING)
    50 static PRLogModuleInfo *
    51 GetSHParserLog()
    52 {
    53   static PRLogModuleInfo *sSHParserLog;
    54   if (!sSHParserLog) {
    55     sSHParserLog = PR_NewLogModule("nsSecurityHeaderParser");
    56   }
    57   return sSHParserLog;
    58 }
    59 #endif
    61 #define SHPARSERLOG(args) PR_LOG(GetSHParserLog(), PR_LOG_DEBUG, args)
    63 nsSecurityHeaderParser::nsSecurityHeaderParser(const char *aHeader)
    64   : mCursor(aHeader)
    65   , mError(false)
    66 {
    67 }
    69 nsSecurityHeaderParser::~nsSecurityHeaderParser() {
    70   nsSecurityHeaderDirective *directive;
    71   while ((directive = mDirectives.popFirst())) {
    72     delete directive;
    73   }
    74 }
    76 mozilla::LinkedList<nsSecurityHeaderDirective> *
    77 nsSecurityHeaderParser::GetDirectives() {
    78   return &mDirectives;
    79 }
    81 nsresult
    82 nsSecurityHeaderParser::Parse() {
    83   MOZ_ASSERT(mDirectives.isEmpty());
    84   SHPARSERLOG(("trying to parse '%s'", mCursor));
    86   Header();
    88   // if we didn't consume the entire input, we were unable to parse it => error
    89   if (mError || *mCursor) {
    90     return NS_ERROR_FAILURE;
    91   } else {
    92     return NS_OK;
    93   }
    94 }
    96 bool
    97 nsSecurityHeaderParser::Accept(char aChr)
    98 {
    99   if (*mCursor == aChr) {
   100     Advance();
   101     return true;
   102   }
   104   return false;
   105 }
   107 bool
   108 nsSecurityHeaderParser::Accept(bool (*aClassifier) (signed char))
   109 {
   110   if (aClassifier(*mCursor)) {
   111     Advance();
   112     return true;
   113   }
   115   return false;
   116 }
   118 void
   119 nsSecurityHeaderParser::Expect(char aChr)
   120 {
   121   if (*mCursor != aChr) {
   122     mError = true;
   123   } else {
   124     Advance();
   125   }
   126 }
   128 void
   129 nsSecurityHeaderParser::Advance()
   130 {
   131   // Technically, 0 is valid in quoted-pair, but we were handed a
   132   // null-terminated const char *, so this doesn't handle that.
   133   if (*mCursor) {
   134     mOutput.Append(*mCursor);
   135     mCursor++;
   136   } else {
   137     mError = true;
   138   }
   139 }
   141 void
   142 nsSecurityHeaderParser::Header()
   143 {
   144   Directive();
   145   while (Accept(';')) {
   146     Directive();
   147   }
   148 }
   150 void
   151 nsSecurityHeaderParser::Directive()
   152 {
   153   mDirective = new nsSecurityHeaderDirective();
   154   LWSMultiple();
   155   DirectiveName();
   156   LWSMultiple();
   157   if (Accept('=')) {
   158     LWSMultiple();
   159     DirectiveValue();
   160     LWSMultiple();
   161   }
   162   mDirectives.insertBack(mDirective);
   163   SHPARSERLOG(("read directive name '%s', value '%s'",
   164                mDirective->mName.Data(), mDirective->mValue.Data()));
   165 }
   167 void
   168 nsSecurityHeaderParser::DirectiveName()
   169 {
   170   mOutput.Truncate(0);
   171   Token();
   172   mDirective->mName.Assign(mOutput);
   173 }
   175 void
   176 nsSecurityHeaderParser::DirectiveValue()
   177 {
   178   mOutput.Truncate(0);
   179   if (Accept(IsTokenSymbol)) {
   180     Token();
   181     mDirective->mValue.Assign(mOutput);
   182   } else if (Accept('"')) {
   183     // Accept advances the cursor if successful, which appends a character to
   184     // mOutput. The " is not part of what we want to capture, so truncate
   185     // mOutput again.
   186     mOutput.Truncate(0);
   187     QuotedString();
   188     mDirective->mValue.Assign(mOutput);
   189     Expect('"');
   190   }
   191 }
   193 void
   194 nsSecurityHeaderParser::Token()
   195 {
   196   while (Accept(IsTokenSymbol));
   197 }
   199 void
   200 nsSecurityHeaderParser::QuotedString()
   201 {
   202   while (true) {
   203     if (Accept(IsQuotedTextSymbol)) {
   204       QuotedText();
   205     } else if (Accept('\\')) {
   206       QuotedPair();
   207     } else {
   208       break;
   209     }
   210   }
   211 }
   213 void
   214 nsSecurityHeaderParser::QuotedText()
   215 {
   216   while (Accept(IsQuotedTextSymbol));
   217 }
   219 void
   220 nsSecurityHeaderParser::QuotedPair()
   221 {
   222   Accept(IsQuotedPairSymbol);
   223 }
   225 void
   226 nsSecurityHeaderParser::LWSMultiple()
   227 {
   228   while (true) {
   229     if (Accept('\r')) {
   230       LWSCRLF();
   231     } else if (Accept(' ') || Accept('\t')) {
   232       LWS();
   233     } else {
   234       break;
   235     }
   236   }
   237 }
   239 void
   240 nsSecurityHeaderParser::LWSCRLF() {
   241   Expect('\n');
   242   if (!(Accept(' ') || Accept('\t'))) {
   243     mError = true;
   244   }
   245   LWS();
   246 }
   248 void
   249 nsSecurityHeaderParser::LWS()
   250 {
   251   // Note that becaue of how we're called, we don't have to check for
   252   // the mandatory presense of at least one of SP or HT.
   253   while (Accept(' ') || Accept('\t'));
   254 }

mercurial