Bug 1928997: Update tabs icon in Unified Search popup r=desktop-theme-reviewers,daleh...
[gecko.git] / security / manager / ssl / nsSecurityHeaderParser.cpp
blob5edec4c859dcf393a0b48184b311e5a5817b7ce1
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 "mozilla/Logging.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 IsTokenSymbol(signed char chr) {
19 if (chr < 33 || chr == 127 || chr == '(' || chr == ')' || chr == '<' ||
20 chr == '>' || chr == '@' || chr == ',' || chr == ';' || chr == ':' ||
21 chr == '"' || chr == '/' || chr == '[' || chr == ']' || chr == '?' ||
22 chr == '=' || chr == '{' || chr == '}' || chr == '\\') {
23 return false;
25 return true;
28 // A quoted-string consists of a quote (") followed by any amount of
29 // qdtext or quoted-pair, followed by a quote.
30 // qdtext is any TEXT except a quote.
31 // TEXT is any 8-bit octet except CTLs, but including LWS.
32 // quoted-pair is a backslash (\) followed by a CHAR.
33 // So, it turns out, \ can't really be a qdtext symbol for our purposes.
34 // This returns true if chr is any octet 9,10,13,32-126 except <"> or "\"
35 bool IsQuotedTextSymbol(signed char chr) {
36 return ((chr >= 32 && chr != '"' && chr != '\\' && chr != 127) ||
37 chr == 0x9 || chr == 0xa || chr == 0xd);
40 // The octet following the "\" in a quoted pair can be anything 0-127.
41 bool IsQuotedPairSymbol(signed char chr) { return (chr >= 0); }
43 static mozilla::LazyLogModule sSHParserLog("nsSecurityHeaderParser");
45 #define SHPARSERLOG(args) MOZ_LOG(sSHParserLog, mozilla::LogLevel::Debug, args)
47 nsSecurityHeaderParser::nsSecurityHeaderParser(const nsCString& aHeader)
48 : mCursor(aHeader.get()), mDirective(nullptr), mError(false) {}
50 nsSecurityHeaderParser::~nsSecurityHeaderParser() {
51 nsSecurityHeaderDirective* directive;
52 while ((directive = mDirectives.popFirst())) {
53 delete directive;
57 mozilla::LinkedList<nsSecurityHeaderDirective>*
58 nsSecurityHeaderParser::GetDirectives() {
59 return &mDirectives;
62 nsresult nsSecurityHeaderParser::Parse() {
63 MOZ_ASSERT(mDirectives.isEmpty());
64 SHPARSERLOG(("trying to parse '%s'", mCursor));
66 Header();
68 // if we didn't consume the entire input, we were unable to parse it => error
69 if (mError || *mCursor) {
70 return NS_ERROR_FAILURE;
71 } else {
72 return NS_OK;
76 bool nsSecurityHeaderParser::Accept(char aChr) {
77 if (*mCursor == aChr) {
78 Advance();
79 return true;
82 return false;
85 bool nsSecurityHeaderParser::Accept(bool (*aClassifier)(signed char)) {
86 if (aClassifier(*mCursor)) {
87 Advance();
88 return true;
91 return false;
94 void nsSecurityHeaderParser::Expect(char aChr) {
95 if (*mCursor != aChr) {
96 mError = true;
97 } else {
98 Advance();
102 void nsSecurityHeaderParser::Advance() {
103 // Technically, 0 is valid in quoted-pair, but we were handed a
104 // null-terminated const char *, so this doesn't handle that.
105 if (*mCursor) {
106 mOutput.Append(*mCursor);
107 mCursor++;
108 } else {
109 mError = true;
113 void nsSecurityHeaderParser::Header() {
114 Directive();
115 while (Accept(';')) {
116 Directive();
120 void nsSecurityHeaderParser::Directive() {
121 mDirective = new nsSecurityHeaderDirective();
122 LWSMultiple();
123 DirectiveName();
124 LWSMultiple();
125 if (Accept('=')) {
126 LWSMultiple();
127 DirectiveValue();
128 LWSMultiple();
130 mDirectives.insertBack(mDirective);
131 if (mDirective->mValue.isSome()) {
132 SHPARSERLOG(("read directive name '%s', value '%s'",
133 mDirective->mName.Data(), mDirective->mValue->Data()));
134 } else {
135 SHPARSERLOG(
136 ("read valueless directive name '%s'", mDirective->mName.Data()));
140 void nsSecurityHeaderParser::DirectiveName() {
141 mOutput.Truncate(0);
142 Token();
143 mDirective->mName.Assign(mOutput);
146 void nsSecurityHeaderParser::DirectiveValue() {
147 mOutput.Truncate(0);
148 mDirective->mValue.emplace();
149 if (Accept(IsTokenSymbol)) {
150 Token();
151 mDirective->mValue->Assign(mOutput);
152 } else if (Accept('"')) {
153 // Accept advances the cursor if successful, which appends a character to
154 // mOutput. The " is not part of what we want to capture, so truncate
155 // mOutput again.
156 mOutput.Truncate(0);
157 QuotedString();
158 mDirective->mValue->Assign(mOutput);
159 Expect('"');
163 void nsSecurityHeaderParser::Token() { while (Accept(IsTokenSymbol)); }
165 void nsSecurityHeaderParser::QuotedString() {
166 while (true) {
167 if (Accept(IsQuotedTextSymbol)) {
168 QuotedText();
169 } else if (Accept('\\')) {
170 QuotedPair();
171 } else {
172 break;
177 void nsSecurityHeaderParser::QuotedText() {
178 while (Accept(IsQuotedTextSymbol));
181 void nsSecurityHeaderParser::QuotedPair() { Accept(IsQuotedPairSymbol); }
183 void nsSecurityHeaderParser::LWSMultiple() {
184 while (true) {
185 if (Accept('\r')) {
186 LWSCRLF();
187 } else if (Accept(' ') || Accept('\t')) {
188 LWS();
189 } else {
190 break;
195 void nsSecurityHeaderParser::LWSCRLF() {
196 Expect('\n');
197 if (!(Accept(' ') || Accept('\t'))) {
198 mError = true;
200 LWS();
203 void nsSecurityHeaderParser::LWS() {
204 // Note that becaue of how we're called, we don't have to check for
205 // the mandatory presense of at least one of SP or HT.
206 while (Accept(' ') || Accept('\t'));