Bug 1835710 - Cancel off-thread JIT compilation before changing nursery allocation...
[gecko.git] / dom / base / MimeType.cpp
blobd9defe3b57eee39c05b83bb9a1bc95838e4cda9b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MimeType.h"
8 #include "nsUnicharUtils.h"
10 namespace {
11 template <typename Char>
12 constexpr bool IsHTTPTokenPoint(Char aChar) {
13 using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
14 auto c = static_cast<UnsignedChar>(aChar);
15 return c == '!' || c == '#' || c == '$' || c == '%' || c == '&' ||
16 c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' ||
17 c == '^' || c == '_' || c == '`' || c == '|' || c == '~' ||
18 mozilla::IsAsciiAlphanumeric(c);
21 template <typename Char>
22 constexpr bool IsHTTPQuotedStringTokenPoint(Char aChar) {
23 using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
24 auto c = static_cast<UnsignedChar>(aChar);
25 return c == 0x9 || (c >= ' ' && c <= '~') || mozilla::IsNonAsciiLatin1(c);
28 template <typename Char>
29 constexpr bool IsHTTPWhitespace(Char aChar) {
30 using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
31 auto c = static_cast<UnsignedChar>(aChar);
32 return c == 0x9 || c == 0xA || c == 0xD || c == 0x20;
34 } // namespace
36 template <typename char_type>
37 /* static */ mozilla::UniquePtr<TMimeType<char_type>>
38 TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
39 // See https://mimesniff.spec.whatwg.org/#parsing-a-mime-type
41 // Steps 1-2
42 const char_type* pos = aMimeType.BeginReading();
43 const char_type* end = aMimeType.EndReading();
44 while (pos < end && IsHTTPWhitespace(*pos)) {
45 ++pos;
47 if (pos == end) {
48 return nullptr;
50 while (end > pos && IsHTTPWhitespace(*(end - 1))) {
51 --end;
54 // Steps 3-4
55 const char_type* typeStart = pos;
56 while (pos < end && *pos != '/') {
57 if (!IsHTTPTokenPoint(*pos)) {
58 return nullptr;
60 ++pos;
62 const char_type* typeEnd = pos;
63 if (typeStart == typeEnd) {
64 return nullptr;
67 // Step 5
68 if (pos == end) {
69 return nullptr;
72 // Step 6
73 ++pos;
75 // Step 7-9
76 const char_type* subtypeStart = pos;
77 const char_type* subtypeEnd = nullptr;
78 while (pos < end && *pos != ';') {
79 if (!IsHTTPTokenPoint(*pos)) {
80 // If we hit a whitespace, check that the rest of
81 // the subtype is whitespace, otherwise fail.
82 if (IsHTTPWhitespace(*pos)) {
83 subtypeEnd = pos;
84 ++pos;
85 while (pos < end && *pos != ';') {
86 if (!IsHTTPWhitespace(*pos)) {
87 return nullptr;
89 ++pos;
91 break;
93 return nullptr;
95 ++pos;
97 if (subtypeEnd == nullptr) {
98 subtypeEnd = pos;
100 if (subtypeStart == subtypeEnd) {
101 return nullptr;
104 // Step 10
105 nsTString<char_type> type;
106 nsTString<char_type> subtype;
107 for (const char_type* c = typeStart; c < typeEnd; ++c) {
108 type.Append(ToLowerCaseASCII(*c));
110 for (const char_type* c = subtypeStart; c < subtypeEnd; ++c) {
111 subtype.Append(ToLowerCaseASCII(*c));
113 mozilla::UniquePtr<TMimeType<char_type>> mimeType(
114 mozilla::MakeUnique<TMimeType<char_type>>(type, subtype));
116 // Step 11
117 while (pos < end) {
118 // Step 11.1
119 ++pos;
121 // Step 11.2
122 while (pos < end && IsHTTPWhitespace(*pos)) {
123 ++pos;
126 // Steps 11.3 and 11.4
127 nsTString<char_type> paramName;
128 bool paramNameHadInvalidChars = false;
129 while (pos < end && *pos != ';' && *pos != '=') {
130 if (!IsHTTPTokenPoint(*pos)) {
131 paramNameHadInvalidChars = true;
133 paramName.Append(ToLowerCaseASCII(*pos));
134 ++pos;
137 // Step 11.5
138 if (pos < end) {
139 if (*pos == ';') {
140 continue;
142 ++pos;
145 // Step 11.6
146 if (pos == end) {
147 break;
150 // Step 11.7
151 ParameterValue paramValue;
152 bool paramValueHadInvalidChars = false;
154 // Step 11.8
155 if (*pos == '"') {
156 // Step 11.8.1
157 ++pos;
159 // Step 11.8.2
160 while (true) {
161 // Step 11.8.2.1
162 while (pos < end && *pos != '"' && *pos != '\\') {
163 if (!IsHTTPQuotedStringTokenPoint(*pos)) {
164 paramValueHadInvalidChars = true;
166 if (!IsHTTPTokenPoint(*pos)) {
167 paramValue.mRequiresQuoting = true;
169 paramValue.Append(*pos);
170 ++pos;
173 // Step 11.8.2.2
174 if (pos < end && *pos == '\\') {
175 // Step 11.8.2.2.1
176 ++pos;
178 // Step 11.8.2.2.2
179 if (pos < end) {
180 if (!IsHTTPQuotedStringTokenPoint(*pos)) {
181 paramValueHadInvalidChars = true;
183 if (!IsHTTPTokenPoint(*pos)) {
184 paramValue.mRequiresQuoting = true;
186 paramValue.Append(*pos);
187 ++pos;
188 continue;
191 // Step 11.8.2.2.3
192 paramValue.Append('\\');
193 paramValue.mRequiresQuoting = true;
196 // Step 11.8.2.3
197 break;
200 // Step 11.8.3
201 while (pos < end && *pos != ';') {
202 ++pos;
205 // Step 11.9
206 } else {
207 // Step 11.9.1
208 const char_type* paramValueStart = pos;
209 while (pos < end && *pos != ';') {
210 ++pos;
213 // Step 11.9.2
214 const char_type* paramValueLastChar = pos - 1;
215 while (paramValueLastChar >= paramValueStart &&
216 IsHTTPWhitespace(*paramValueLastChar)) {
217 --paramValueLastChar;
220 // Step 11.9.3
221 if (paramValueStart > paramValueLastChar) {
222 continue;
225 for (const char_type* c = paramValueStart; c <= paramValueLastChar; ++c) {
226 if (!IsHTTPQuotedStringTokenPoint(*c)) {
227 paramValueHadInvalidChars = true;
229 if (!IsHTTPTokenPoint(*c)) {
230 paramValue.mRequiresQuoting = true;
232 paramValue.Append(*c);
236 // Step 11.10
237 if (!paramName.IsEmpty() && !paramNameHadInvalidChars &&
238 !paramValueHadInvalidChars) {
239 // XXX Is the assigned value used anywhere?
240 paramValue = mimeType->mParameters.LookupOrInsertWith(paramName, [&] {
241 mimeType->mParameterNames.AppendElement(paramName);
242 return paramValue;
247 // Step 12
248 return mimeType;
251 template <typename char_type>
252 void TMimeType<char_type>::Serialize(nsTSubstring<char_type>& aOutput) const {
253 aOutput.Assign(mType);
254 aOutput.AppendLiteral("/");
255 aOutput.Append(mSubtype);
256 for (uint32_t i = 0; i < mParameterNames.Length(); i++) {
257 auto name = mParameterNames[i];
258 aOutput.AppendLiteral(";");
259 aOutput.Append(name);
260 aOutput.AppendLiteral("=");
261 GetParameterValue(name, aOutput, true);
265 template <typename char_type>
266 void TMimeType<char_type>::GetFullType(nsTSubstring<char_type>& aOutput) const {
267 aOutput.Assign(mType);
268 aOutput.AppendLiteral("/");
269 aOutput.Append(mSubtype);
272 template <typename char_type>
273 bool TMimeType<char_type>::HasParameter(
274 const nsTSubstring<char_type>& aName) const {
275 return mParameters.Get(aName, nullptr);
278 template <typename char_type>
279 bool TMimeType<char_type>::GetParameterValue(
280 const nsTSubstring<char_type>& aName, nsTSubstring<char_type>& aOutput,
281 bool aAppend) const {
282 if (!aAppend) {
283 aOutput.Truncate();
286 ParameterValue value;
287 if (!mParameters.Get(aName, &value)) {
288 return false;
291 if (value.mRequiresQuoting || value.IsEmpty()) {
292 aOutput.AppendLiteral("\"");
293 const char_type* vcur = value.BeginReading();
294 const char_type* vend = value.EndReading();
295 while (vcur < vend) {
296 if (*vcur == '"' || *vcur == '\\') {
297 aOutput.AppendLiteral("\\");
299 aOutput.Append(*vcur);
300 vcur++;
302 aOutput.AppendLiteral("\"");
303 } else {
304 aOutput.Append(value);
307 return true;
310 template <typename char_type>
311 void TMimeType<char_type>::SetParameterValue(
312 const nsTSubstring<char_type>& aName,
313 const nsTSubstring<char_type>& aValue) {
314 mParameters.WithEntryHandle(aName, [&](auto&& entry) {
315 if (!entry) {
316 mParameterNames.AppendElement(aName);
318 ParameterValue value;
319 value.Append(aValue);
320 entry.InsertOrUpdate(std::move(value));
324 template mozilla::UniquePtr<TMimeType<char16_t>> TMimeType<char16_t>::Parse(
325 const nsTSubstring<char16_t>& aMimeType);
326 template mozilla::UniquePtr<TMimeType<char>> TMimeType<char>::Parse(
327 const nsTSubstring<char>& aMimeType);
328 template void TMimeType<char16_t>::Serialize(
329 nsTSubstring<char16_t>& aOutput) const;
330 template void TMimeType<char>::Serialize(nsTSubstring<char>& aOutput) const;
331 template void TMimeType<char16_t>::GetFullType(
332 nsTSubstring<char16_t>& aOutput) const;
333 template void TMimeType<char>::GetFullType(nsTSubstring<char>& aOutput) const;
334 template bool TMimeType<char16_t>::HasParameter(
335 const nsTSubstring<char16_t>& aName) const;
336 template bool TMimeType<char>::HasParameter(
337 const nsTSubstring<char>& aName) const;
338 template bool TMimeType<char16_t>::GetParameterValue(
339 const nsTSubstring<char16_t>& aName, nsTSubstring<char16_t>& aOutput,
340 bool aAppend) const;
341 template bool TMimeType<char>::GetParameterValue(
342 const nsTSubstring<char>& aName, nsTSubstring<char>& aOutput,
343 bool aAppend) const;
344 template void TMimeType<char16_t>::SetParameterValue(
345 const nsTSubstring<char16_t>& aName, const nsTSubstring<char16_t>& aValue);
346 template void TMimeType<char>::SetParameterValue(
347 const nsTSubstring<char>& aName, const nsTSubstring<char>& aValue);