InternalHeaders.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/dom/InternalHeaders.h"
  6. #include "mozilla/dom/FetchTypes.h"
  7. #include "mozilla/ErrorResult.h"
  8. #include "nsCharSeparatedTokenizer.h"
  9. #include "nsContentUtils.h"
  10. #include "nsNetUtil.h"
  11. #include "nsReadableUtils.h"
  12. namespace mozilla {
  13. namespace dom {
  14. InternalHeaders::InternalHeaders(const nsTArray<Entry>&& aHeaders,
  15. HeadersGuardEnum aGuard)
  16. : mGuard(aGuard)
  17. , mList(aHeaders)
  18. , mListDirty(true)
  19. {
  20. }
  21. InternalHeaders::InternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
  22. HeadersGuardEnum aGuard)
  23. : mGuard(aGuard)
  24. , mListDirty(true)
  25. {
  26. for (const HeadersEntry& headersEntry : aHeadersEntryList) {
  27. mList.AppendElement(Entry(headersEntry.name(), headersEntry.value()));
  28. }
  29. }
  30. void
  31. InternalHeaders::ToIPC(nsTArray<HeadersEntry>& aIPCHeaders,
  32. HeadersGuardEnum& aGuard)
  33. {
  34. aGuard = mGuard;
  35. aIPCHeaders.Clear();
  36. for (Entry& entry : mList) {
  37. aIPCHeaders.AppendElement(HeadersEntry(entry.mName, entry.mValue));
  38. }
  39. }
  40. void
  41. InternalHeaders::Append(const nsACString& aName, const nsACString& aValue,
  42. ErrorResult& aRv)
  43. {
  44. nsAutoCString lowerName;
  45. ToLowerCase(aName, lowerName);
  46. if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
  47. return;
  48. }
  49. SetListDirty();
  50. mList.AppendElement(Entry(lowerName, aValue));
  51. }
  52. void
  53. InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv)
  54. {
  55. nsAutoCString lowerName;
  56. ToLowerCase(aName, lowerName);
  57. if (IsInvalidMutableHeader(lowerName, aRv)) {
  58. return;
  59. }
  60. SetListDirty();
  61. // remove in reverse order to minimize copying
  62. for (int32_t i = mList.Length() - 1; i >= 0; --i) {
  63. if (lowerName == mList[i].mName) {
  64. mList.RemoveElementAt(i);
  65. }
  66. }
  67. }
  68. void
  69. InternalHeaders::Get(const nsACString& aName, nsACString& aValue, ErrorResult& aRv) const
  70. {
  71. nsAutoCString lowerName;
  72. ToLowerCase(aName, lowerName);
  73. if (IsInvalidName(lowerName, aRv)) {
  74. return;
  75. }
  76. const char* delimiter = ",";
  77. bool firstValueFound = false;
  78. for (uint32_t i = 0; i < mList.Length(); ++i) {
  79. if (lowerName == mList[i].mName) {
  80. if (firstValueFound) {
  81. aValue += delimiter;
  82. }
  83. aValue += mList[i].mValue;
  84. firstValueFound = true;
  85. }
  86. }
  87. // No value found, so return null to content
  88. if (!firstValueFound) {
  89. aValue.SetIsVoid(true);
  90. }
  91. }
  92. void
  93. InternalHeaders::GetFirst(const nsACString& aName, nsACString& aValue, ErrorResult& aRv) const
  94. {
  95. nsAutoCString lowerName;
  96. ToLowerCase(aName, lowerName);
  97. if (IsInvalidName(lowerName, aRv)) {
  98. return;
  99. }
  100. for (uint32_t i = 0; i < mList.Length(); ++i) {
  101. if (lowerName == mList[i].mName) {
  102. aValue = mList[i].mValue;
  103. return;
  104. }
  105. }
  106. // No value found, so return null to content
  107. aValue.SetIsVoid(true);
  108. }
  109. bool
  110. InternalHeaders::Has(const nsACString& aName, ErrorResult& aRv) const
  111. {
  112. nsAutoCString lowerName;
  113. ToLowerCase(aName, lowerName);
  114. if (IsInvalidName(lowerName, aRv)) {
  115. return false;
  116. }
  117. for (uint32_t i = 0; i < mList.Length(); ++i) {
  118. if (lowerName == mList[i].mName) {
  119. return true;
  120. }
  121. }
  122. return false;
  123. }
  124. void
  125. InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
  126. {
  127. nsAutoCString lowerName;
  128. ToLowerCase(aName, lowerName);
  129. if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
  130. return;
  131. }
  132. SetListDirty();
  133. int32_t firstIndex = INT32_MAX;
  134. // remove in reverse order to minimize copying
  135. for (int32_t i = mList.Length() - 1; i >= 0; --i) {
  136. if (lowerName == mList[i].mName) {
  137. firstIndex = std::min(firstIndex, i);
  138. mList.RemoveElementAt(i);
  139. }
  140. }
  141. if (firstIndex < INT32_MAX) {
  142. Entry* entry = mList.InsertElementAt(firstIndex);
  143. entry->mName = lowerName;
  144. entry->mValue = aValue;
  145. } else {
  146. mList.AppendElement(Entry(lowerName, aValue));
  147. }
  148. }
  149. void
  150. InternalHeaders::Clear()
  151. {
  152. SetListDirty();
  153. mList.Clear();
  154. }
  155. void
  156. InternalHeaders::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
  157. {
  158. // The guard is only checked during ::Set() and ::Append() in the spec. It
  159. // does not require revalidating headers already set.
  160. mGuard = aGuard;
  161. }
  162. InternalHeaders::~InternalHeaders()
  163. {
  164. }
  165. // static
  166. bool
  167. InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue)
  168. {
  169. // Note, we must allow a null content-type value here to support
  170. // get("content-type"), but the IsInvalidValue() check will prevent null
  171. // from being set or appended.
  172. return aName.EqualsLiteral("accept") ||
  173. aName.EqualsLiteral("accept-language") ||
  174. aName.EqualsLiteral("content-language") ||
  175. (aName.EqualsLiteral("content-type") &&
  176. nsContentUtils::IsAllowedNonCorsContentType(aValue));
  177. }
  178. // static
  179. bool
  180. InternalHeaders::IsRevalidationHeader(const nsACString& aName)
  181. {
  182. return aName.EqualsLiteral("if-modified-since") ||
  183. aName.EqualsLiteral("if-none-match") ||
  184. aName.EqualsLiteral("if-unmodified-since") ||
  185. aName.EqualsLiteral("if-match") ||
  186. aName.EqualsLiteral("if-range");
  187. }
  188. //static
  189. bool
  190. InternalHeaders::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
  191. {
  192. if (!NS_IsValidHTTPToken(aName)) {
  193. NS_ConvertUTF8toUTF16 label(aName);
  194. aRv.ThrowTypeError<MSG_INVALID_HEADER_NAME>(label);
  195. return true;
  196. }
  197. return false;
  198. }
  199. // static
  200. bool
  201. InternalHeaders::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv)
  202. {
  203. if (!NS_IsReasonableHTTPHeaderValue(aValue)) {
  204. NS_ConvertUTF8toUTF16 label(aValue);
  205. aRv.ThrowTypeError<MSG_INVALID_HEADER_VALUE>(label);
  206. return true;
  207. }
  208. return false;
  209. }
  210. bool
  211. InternalHeaders::IsImmutable(ErrorResult& aRv) const
  212. {
  213. if (mGuard == HeadersGuardEnum::Immutable) {
  214. aRv.ThrowTypeError<MSG_HEADERS_IMMUTABLE>();
  215. return true;
  216. }
  217. return false;
  218. }
  219. bool
  220. InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName) const
  221. {
  222. return mGuard == HeadersGuardEnum::Request &&
  223. nsContentUtils::IsForbiddenRequestHeader(aName);
  224. }
  225. bool
  226. InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName) const
  227. {
  228. return mGuard == HeadersGuardEnum::Request_no_cors &&
  229. !IsSimpleHeader(aName, EmptyCString());
  230. }
  231. bool
  232. InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName,
  233. const nsACString& aValue) const
  234. {
  235. return mGuard == HeadersGuardEnum::Request_no_cors &&
  236. !IsSimpleHeader(aName, aValue);
  237. }
  238. bool
  239. InternalHeaders::IsForbiddenResponseHeader(const nsACString& aName) const
  240. {
  241. return mGuard == HeadersGuardEnum::Response &&
  242. nsContentUtils::IsForbiddenResponseHeader(aName);
  243. }
  244. void
  245. InternalHeaders::Fill(const InternalHeaders& aInit, ErrorResult& aRv)
  246. {
  247. const nsTArray<Entry>& list = aInit.mList;
  248. for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
  249. const Entry& entry = list[i];
  250. Append(entry.mName, entry.mValue, aRv);
  251. }
  252. }
  253. void
  254. InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv)
  255. {
  256. for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
  257. const Sequence<nsCString>& tuple = aInit[i];
  258. if (tuple.Length() != 2) {
  259. aRv.ThrowTypeError<MSG_INVALID_HEADER_SEQUENCE>();
  260. return;
  261. }
  262. Append(tuple[0], tuple[1], aRv);
  263. }
  264. }
  265. void
  266. InternalHeaders::Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv)
  267. {
  268. for (auto& entry : aInit.Entries()) {
  269. Append(entry.mKey, entry.mValue, aRv);
  270. if (aRv.Failed()) {
  271. return;
  272. }
  273. }
  274. }
  275. bool
  276. InternalHeaders::HasOnlySimpleHeaders() const
  277. {
  278. for (uint32_t i = 0; i < mList.Length(); ++i) {
  279. if (!IsSimpleHeader(mList[i].mName, mList[i].mValue)) {
  280. return false;
  281. }
  282. }
  283. return true;
  284. }
  285. bool
  286. InternalHeaders::HasRevalidationHeaders() const
  287. {
  288. for (uint32_t i = 0; i < mList.Length(); ++i) {
  289. if (IsRevalidationHeader(mList[i].mName)) {
  290. return true;
  291. }
  292. }
  293. return false;
  294. }
  295. // static
  296. already_AddRefed<InternalHeaders>
  297. InternalHeaders::BasicHeaders(InternalHeaders* aHeaders)
  298. {
  299. RefPtr<InternalHeaders> basic = new InternalHeaders(*aHeaders);
  300. ErrorResult result;
  301. // The Set-Cookie headers cannot be invalid mutable headers, so the Delete
  302. // must succeed.
  303. basic->Delete(NS_LITERAL_CSTRING("Set-Cookie"), result);
  304. MOZ_ASSERT(!result.Failed());
  305. basic->Delete(NS_LITERAL_CSTRING("Set-Cookie2"), result);
  306. MOZ_ASSERT(!result.Failed());
  307. return basic.forget();
  308. }
  309. // static
  310. already_AddRefed<InternalHeaders>
  311. InternalHeaders::CORSHeaders(InternalHeaders* aHeaders)
  312. {
  313. RefPtr<InternalHeaders> cors = new InternalHeaders(aHeaders->mGuard);
  314. ErrorResult result;
  315. nsAutoCString acExposedNames;
  316. aHeaders->GetFirst(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"), acExposedNames, result);
  317. MOZ_ASSERT(!result.Failed());
  318. AutoTArray<nsCString, 5> exposeNamesArray;
  319. nsCCharSeparatedTokenizer exposeTokens(acExposedNames, ',');
  320. while (exposeTokens.hasMoreTokens()) {
  321. const nsDependentCSubstring& token = exposeTokens.nextToken();
  322. if (token.IsEmpty()) {
  323. continue;
  324. }
  325. if (!NS_IsValidHTTPToken(token)) {
  326. NS_WARNING("Got invalid HTTP token in Access-Control-Expose-Headers. Header value is:");
  327. NS_WARNING(acExposedNames.get());
  328. exposeNamesArray.Clear();
  329. break;
  330. }
  331. exposeNamesArray.AppendElement(token);
  332. }
  333. nsCaseInsensitiveCStringArrayComparator comp;
  334. for (uint32_t i = 0; i < aHeaders->mList.Length(); ++i) {
  335. const Entry& entry = aHeaders->mList[i];
  336. if (entry.mName.EqualsASCII("cache-control") ||
  337. entry.mName.EqualsASCII("content-language") ||
  338. entry.mName.EqualsASCII("content-type") ||
  339. entry.mName.EqualsASCII("expires") ||
  340. entry.mName.EqualsASCII("last-modified") ||
  341. entry.mName.EqualsASCII("pragma") ||
  342. exposeNamesArray.Contains(entry.mName, comp)) {
  343. cors->Append(entry.mName, entry.mValue, result);
  344. MOZ_ASSERT(!result.Failed());
  345. }
  346. }
  347. return cors.forget();
  348. }
  349. void
  350. InternalHeaders::GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const
  351. {
  352. MOZ_ASSERT(aEntries.IsEmpty());
  353. aEntries.AppendElements(mList);
  354. }
  355. void
  356. InternalHeaders::GetUnsafeHeaders(nsTArray<nsCString>& aNames) const
  357. {
  358. MOZ_ASSERT(aNames.IsEmpty());
  359. for (uint32_t i = 0; i < mList.Length(); ++i) {
  360. const Entry& header = mList[i];
  361. if (!InternalHeaders::IsSimpleHeader(header.mName, header.mValue)) {
  362. aNames.AppendElement(header.mName);
  363. }
  364. }
  365. }
  366. void
  367. InternalHeaders::MaybeSortList()
  368. {
  369. class Comparator {
  370. public:
  371. bool Equals(const Entry& aA, const Entry& aB) const
  372. {
  373. return aA.mName == aB.mName;
  374. }
  375. bool LessThan(const Entry& aA, const Entry& aB) const
  376. {
  377. return aA.mName < aB.mName;
  378. }
  379. };
  380. if (!mListDirty) {
  381. return;
  382. }
  383. mListDirty = false;
  384. Comparator comparator;
  385. mSortedList.Clear();
  386. for (const Entry& entry : mList) {
  387. bool found = false;
  388. for (Entry& sortedEntry : mSortedList) {
  389. if (sortedEntry.mName == entry.mName) {
  390. sortedEntry.mValue += ", ";
  391. sortedEntry.mValue += entry.mValue;
  392. found = true;
  393. break;
  394. }
  395. }
  396. if (!found) {
  397. mSortedList.InsertElementSorted(entry, comparator);
  398. }
  399. }
  400. }
  401. void
  402. InternalHeaders::SetListDirty()
  403. {
  404. mSortedList.Clear();
  405. mListDirty = true;
  406. }
  407. } // namespace dom
  408. } // namespace mozilla