Bug 1686668 [wpt PR 27185] - Update wpt metadata, a=testonly
[gecko.git] / dom / base / MimeType.cpp
blob73399bc0670989cab38b059c6632759331616cc2
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 !mimeType->mParameters.Get(paramName, &paramValue)) {
240 mimeType->mParameters.Put(paramName, paramValue);
241 mimeType->mParameterNames.AppendElement(paramName);
245 // Step 12
246 return mimeType;
249 template <typename char_type>
250 void TMimeType<char_type>::Serialize(nsTSubstring<char_type>& aOutput) const {
251 aOutput.Assign(mType);
252 aOutput.AppendLiteral("/");
253 aOutput.Append(mSubtype);
254 for (uint32_t i = 0; i < mParameterNames.Length(); i++) {
255 auto name = mParameterNames[i];
256 aOutput.AppendLiteral(";");
257 aOutput.Append(name);
258 aOutput.AppendLiteral("=");
259 GetParameterValue(name, aOutput, true);
263 template <typename char_type>
264 void TMimeType<char_type>::GetFullType(nsTSubstring<char_type>& aOutput) const {
265 aOutput.Assign(mType);
266 aOutput.AppendLiteral("/");
267 aOutput.Append(mSubtype);
270 template <typename char_type>
271 bool TMimeType<char_type>::HasParameter(
272 const nsTSubstring<char_type>& aName) const {
273 return mParameters.Get(aName, nullptr);
276 template <typename char_type>
277 bool TMimeType<char_type>::GetParameterValue(
278 const nsTSubstring<char_type>& aName, nsTSubstring<char_type>& aOutput,
279 bool aAppend) const {
280 if (!aAppend) {
281 aOutput.Truncate();
284 ParameterValue value;
285 if (!mParameters.Get(aName, &value)) {
286 return false;
289 if (value.mRequiresQuoting || value.IsEmpty()) {
290 aOutput.AppendLiteral("\"");
291 const char_type* vcur = value.BeginReading();
292 const char_type* vend = value.EndReading();
293 while (vcur < vend) {
294 if (*vcur == '"' || *vcur == '\\') {
295 aOutput.AppendLiteral("\\");
297 aOutput.Append(*vcur);
298 vcur++;
300 aOutput.AppendLiteral("\"");
301 } else {
302 aOutput.Append(value);
305 return true;
308 template <typename char_type>
309 void TMimeType<char_type>::SetParameterValue(
310 const nsTSubstring<char_type>& aName,
311 const nsTSubstring<char_type>& aValue) {
312 if (!mParameters.Get(aName, nullptr)) {
313 mParameterNames.AppendElement(aName);
315 ParameterValue value;
316 value.Append(aValue);
317 mParameters.Put(aName, value);
320 template mozilla::UniquePtr<TMimeType<char16_t>> TMimeType<char16_t>::Parse(
321 const nsTSubstring<char16_t>& aMimeType);
322 template mozilla::UniquePtr<TMimeType<char>> TMimeType<char>::Parse(
323 const nsTSubstring<char>& aMimeType);
324 template void TMimeType<char16_t>::Serialize(
325 nsTSubstring<char16_t>& aOutput) const;
326 template void TMimeType<char>::Serialize(nsTSubstring<char>& aOutput) const;
327 template void TMimeType<char16_t>::GetFullType(
328 nsTSubstring<char16_t>& aOutput) const;
329 template void TMimeType<char>::GetFullType(nsTSubstring<char>& aOutput) const;
330 template bool TMimeType<char16_t>::HasParameter(
331 const nsTSubstring<char16_t>& aName) const;
332 template bool TMimeType<char>::HasParameter(
333 const nsTSubstring<char>& aName) const;
334 template bool TMimeType<char16_t>::GetParameterValue(
335 const nsTSubstring<char16_t>& aName, nsTSubstring<char16_t>& aOutput,
336 bool aAppend) const;
337 template bool TMimeType<char>::GetParameterValue(
338 const nsTSubstring<char>& aName, nsTSubstring<char>& aOutput,
339 bool aAppend) const;
340 template void TMimeType<char16_t>::SetParameterValue(
341 const nsTSubstring<char16_t>& aName, const nsTSubstring<char16_t>& aValue);
342 template void TMimeType<char>::SetParameterValue(
343 const nsTSubstring<char>& aName, const nsTSubstring<char>& aValue);