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/. */
8 #include "nsUnicharUtils.h"
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;
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
42 const char_type
* pos
= aMimeType
.BeginReading();
43 const char_type
* end
= aMimeType
.EndReading();
44 while (pos
< end
&& IsHTTPWhitespace(*pos
)) {
50 while (end
> pos
&& IsHTTPWhitespace(*(end
- 1))) {
55 const char_type
* typeStart
= pos
;
56 while (pos
< end
&& *pos
!= '/') {
57 if (!IsHTTPTokenPoint(*pos
)) {
62 const char_type
* typeEnd
= pos
;
63 if (typeStart
== typeEnd
) {
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
)) {
85 while (pos
< end
&& *pos
!= ';') {
86 if (!IsHTTPWhitespace(*pos
)) {
97 if (subtypeEnd
== nullptr) {
100 if (subtypeStart
== subtypeEnd
) {
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
));
122 while (pos
< end
&& IsHTTPWhitespace(*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
));
151 ParameterValue paramValue
;
152 bool paramValueHadInvalidChars
= false;
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
);
174 if (pos
< end
&& *pos
== '\\') {
180 if (!IsHTTPQuotedStringTokenPoint(*pos
)) {
181 paramValueHadInvalidChars
= true;
183 if (!IsHTTPTokenPoint(*pos
)) {
184 paramValue
.mRequiresQuoting
= true;
186 paramValue
.Append(*pos
);
192 paramValue
.Append('\\');
193 paramValue
.mRequiresQuoting
= true;
201 while (pos
< end
&& *pos
!= ';') {
208 const char_type
* paramValueStart
= pos
;
209 while (pos
< end
&& *pos
!= ';') {
214 const char_type
* paramValueLastChar
= pos
- 1;
215 while (paramValueLastChar
>= paramValueStart
&&
216 IsHTTPWhitespace(*paramValueLastChar
)) {
217 --paramValueLastChar
;
221 if (paramValueStart
> paramValueLastChar
) {
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
);
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
);
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 {
286 ParameterValue value
;
287 if (!mParameters
.Get(aName
, &value
)) {
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
);
302 aOutput
.AppendLiteral("\"");
304 aOutput
.Append(value
);
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
) {
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
,
341 template bool TMimeType
<char>::GetParameterValue(
342 const nsTSubstring
<char>& aName
, nsTSubstring
<char>& aOutput
,
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
);