--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -313,18 +313,18 @@ already_AddRefed<Promise>
FetchBody<Response>::ConsumeBody(ConsumeType aType, ErrorResult& aRv);
template <class Derived>
void
FetchBody<Derived>::SetMimeType(ErrorResult& aRv)
{
// Extract mime type.
nsTArray<nsCString> contentTypeValues;
- MOZ_ASSERT(DerivedClass()->Headers_());
- DerivedClass()->Headers_()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv);
+ MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
+ DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
// HTTP ABNF states Content-Type may have only one value.
// This is from the "parse a header value" of the fetch spec.
if (contentTypeValues.Length() == 1) {
mMimeType = contentTypeValues[0];
--- a/dom/fetch/Headers.cpp
+++ b/dom/fetch/Headers.cpp
@@ -5,23 +5,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/Headers.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/Preferences.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsContentUtils.h"
-#include "nsDOMString.h"
-#include "nsNetUtil.h"
-#include "nsPIDOMWindow.h"
-#include "nsReadableUtils.h"
-
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTING_ADDREF(Headers)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Headers)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Headers, mOwner)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Headers)
@@ -56,314 +49,65 @@ Headers::PrefEnabled(JSContext* aCx, JSO
}
// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
ErrorResult& aRv)
{
- nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports());
+ nsRefPtr<InternalHeaders> ih = new InternalHeaders();
+ nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports(), ih);
if (!aInit.WasPassed()) {
return headers.forget();
}
if (aInit.Value().IsHeaders()) {
- headers->Fill(aInit.Value().GetAsHeaders(), aRv);
+ ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv);
} else if (aInit.Value().IsByteStringSequenceSequence()) {
- headers->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
+ ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
} else if (aInit.Value().IsByteStringMozMap()) {
- headers->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
+ ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
}
if (aRv.Failed()) {
return nullptr;
}
return headers.forget();
}
// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
ErrorResult& aRv)
{
- nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports());
+ nsRefPtr<InternalHeaders> ih = new InternalHeaders();
+ nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports(), ih);
if (aInit.IsHeaders()) {
- headers->Fill(aInit.GetAsHeaders(), aRv);
+ ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv);
} else if (aInit.IsByteStringSequenceSequence()) {
- headers->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
+ ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
} else if (aInit.IsByteStringMozMap()) {
- headers->Fill(aInit.GetAsByteStringMozMap(), aRv);
+ ih->Fill(aInit.GetAsByteStringMozMap(), aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return headers.forget();
}
-Headers::Headers(const Headers& aOther)
- : mOwner(aOther.mOwner)
- , mGuard(aOther.mGuard)
-{
- ErrorResult result;
- Fill(aOther, result);
- MOZ_ASSERT(!result.Failed());
-}
-
-void
-Headers::Append(const nsACString& aName, const nsACString& aValue,
- ErrorResult& aRv)
-{
- nsAutoCString lowerName;
- ToLowerCase(aName, lowerName);
-
- if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) {
- return;
- }
-
- mList.AppendElement(Entry(lowerName, aValue));
-}
-
-void
-Headers::Delete(const nsACString& aName, ErrorResult& aRv)
-{
- nsAutoCString lowerName;
- ToLowerCase(aName, lowerName);
-
- if (IsInvalidMutableHeader(lowerName, nullptr, aRv)) {
- return;
- }
-
- // remove in reverse order to minimize copying
- for (int32_t i = mList.Length() - 1; i >= 0; --i) {
- if (lowerName == mList[i].mName) {
- mList.RemoveElementAt(i);
- }
- }
-}
-
-void
-Headers::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
-{
- nsAutoCString lowerName;
- ToLowerCase(aName, lowerName);
-
- if (IsInvalidName(lowerName, aRv)) {
- return;
- }
-
- for (uint32_t i = 0; i < mList.Length(); ++i) {
- if (lowerName == mList[i].mName) {
- aValue = mList[i].mValue;
- return;
- }
- }
-
- // No value found, so return null to content
- aValue.SetIsVoid(true);
-}
-
-void
-Headers::GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
- ErrorResult& aRv) const
-{
- nsAutoCString lowerName;
- ToLowerCase(aName, lowerName);
-
- if (IsInvalidName(lowerName, aRv)) {
- return;
- }
-
- aResults.SetLength(0);
- for (uint32_t i = 0; i < mList.Length(); ++i) {
- if (lowerName == mList[i].mName) {
- aResults.AppendElement(mList[i].mValue);
- }
- }
-}
-
-bool
-Headers::Has(const nsACString& aName, ErrorResult& aRv) const
-{
- nsAutoCString lowerName;
- ToLowerCase(aName, lowerName);
-
- if (IsInvalidName(lowerName, aRv)) {
- return false;
- }
-
- for (uint32_t i = 0; i < mList.Length(); ++i) {
- if (lowerName == mList[i].mName) {
- return true;
- }
- }
- return false;
-}
-
-void
-Headers::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
-{
- nsAutoCString lowerName;
- ToLowerCase(aName, lowerName);
-
- if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) {
- return;
- }
-
- int32_t firstIndex = INT32_MAX;
-
- // remove in reverse order to minimize copying
- for (int32_t i = mList.Length() - 1; i >= 0; --i) {
- if (lowerName == mList[i].mName) {
- firstIndex = std::min(firstIndex, i);
- mList.RemoveElementAt(i);
- }
- }
-
- if (firstIndex < INT32_MAX) {
- Entry* entry = mList.InsertElementAt(firstIndex);
- entry->mName = lowerName;
- entry->mValue = aValue;
- } else {
- mList.AppendElement(Entry(lowerName, aValue));
- }
-}
-
-void
-Headers::Clear()
-{
- mList.Clear();
-}
-
-void
-Headers::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
-{
- // Rather than re-validate all current headers, just require code to set
- // this prior to populating the Headers object. Allow setting immutable
- // late, though, as that is pretty much required to have a useful, immutable
- // headers object.
- if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
- aRv.Throw(NS_ERROR_FAILURE);
- }
- mGuard = aGuard;
-}
-
JSObject*
Headers::WrapObject(JSContext* aCx)
{
return mozilla::dom::HeadersBinding::Wrap(aCx, this);
}
Headers::~Headers()
{
}
-
-// static
-bool
-Headers::IsSimpleHeader(const nsACString& aName, const nsACString* aValue)
-{
- // Note, we must allow a null content-type value here to support
- // get("content-type"), but the IsInvalidValue() check will prevent null
- // from being set or appended.
- return aName.EqualsLiteral("accept") ||
- aName.EqualsLiteral("accept-language") ||
- aName.EqualsLiteral("content-language") ||
- (aName.EqualsLiteral("content-type") &&
- (!aValue || nsContentUtils::IsAllowedNonCorsContentType(*aValue)));
-}
-
-//static
-bool
-Headers::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
-{
- if (!NS_IsValidHTTPToken(aName)) {
- NS_ConvertUTF8toUTF16 label(aName);
- aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label);
- return true;
- }
-
- return false;
-}
-
-// static
-bool
-Headers::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv)
-{
- if (!NS_IsReasonableHTTPHeaderValue(aValue)) {
- NS_ConvertUTF8toUTF16 label(aValue);
- aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label);
- return true;
- }
- return false;
-}
-
-bool
-Headers::IsImmutable(ErrorResult& aRv) const
-{
- if (mGuard == HeadersGuardEnum::Immutable) {
- aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE);
- return true;
- }
- return false;
-}
-
-bool
-Headers::IsForbiddenRequestHeader(const nsACString& aName) const
-{
- return mGuard == HeadersGuardEnum::Request &&
- nsContentUtils::IsForbiddenRequestHeader(aName);
-}
-
-bool
-Headers::IsForbiddenRequestNoCorsHeader(const nsACString& aName,
- const nsACString* aValue) const
-{
- return mGuard == HeadersGuardEnum::Request_no_cors &&
- !IsSimpleHeader(aName, aValue);
-}
-
-bool
-Headers::IsForbiddenResponseHeader(const nsACString& aName) const
-{
- return mGuard == HeadersGuardEnum::Response &&
- nsContentUtils::IsForbiddenResponseHeader(aName);
-}
-
-void
-Headers::Fill(const Headers& aInit, ErrorResult& aRv)
-{
- const nsTArray<Entry>& list = aInit.mList;
- for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
- const Entry& entry = list[i];
- Append(entry.mName, entry.mValue, aRv);
- }
-}
-
-void
-Headers::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv)
-{
- for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
- const Sequence<nsCString>& tuple = aInit[i];
- if (tuple.Length() != 2) {
- aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE);
- return;
- }
- Append(tuple[0], tuple[1], aRv);
- }
-}
-
-void
-Headers::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
-{
- nsTArray<nsString> keys;
- aInit.GetKeys(keys);
- for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
- Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
- }
-}
} // namespace dom
} // namespace mozilla
--- a/dom/fetch/Headers.h
+++ b/dom/fetch/Headers.h
@@ -8,121 +8,122 @@
#define mozilla_dom_Headers_h
#include "mozilla/dom/HeadersBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsClassHashtable.h"
#include "nsWrapperCache.h"
+#include "InternalHeaders.h"
+
class nsPIDOMWindow;
namespace mozilla {
class ErrorResult;
namespace dom {
template<typename T> class MozMap;
class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
+/**
+ * This Headers class is only used to represent the content facing Headers
+ * object. It is actually backed by an InternalHeaders implementation. Gecko
+ * code should NEVER use this, except in the Request and Response
+ * implementations, where they must always be created from the backing
+ * InternalHeaders object.
+ */
class Headers MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Headers)
-private:
- struct Entry
- {
- Entry(const nsACString& aName, const nsACString& aValue)
- : mName(aName)
- , mValue(aValue)
- { }
+ friend class Request;
+ friend class Response;
- Entry() { }
-
- nsCString mName;
- nsCString mValue;
- };
-
+private:
nsCOMPtr<nsISupports> mOwner;
- HeadersGuardEnum mGuard;
- nsTArray<Entry> mList;
+ nsRefPtr<InternalHeaders> mInternalHeaders;
public:
- explicit Headers(nsISupports* aOwner, HeadersGuardEnum aGuard = HeadersGuardEnum::None)
+ explicit Headers(nsISupports* aOwner, InternalHeaders* aInternalHeaders)
: mOwner(aOwner)
- , mGuard(aGuard)
+ , mInternalHeaders(aInternalHeaders)
{
}
- explicit Headers(const Headers& aOther);
+ explicit Headers(const Headers& aOther) MOZ_DELETE;
static bool PrefEnabled(JSContext* cx, JSObject* obj);
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
ErrorResult& aRv);
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
ErrorResult& aRv);
void Append(const nsACString& aName, const nsACString& aValue,
- ErrorResult& aRv);
- void Delete(const nsACString& aName, ErrorResult& aRv);
- void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
+ ErrorResult& aRv)
+ {
+ mInternalHeaders->Append(aName, aValue, aRv);
+ }
+
+ void Delete(const nsACString& aName, ErrorResult& aRv)
+ {
+ mInternalHeaders->Delete(aName, aRv);
+ }
+
+ void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
+ {
+ mInternalHeaders->Get(aName, aValue, aRv);
+ }
+
void GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
- ErrorResult& aRv) const;
- bool Has(const nsACString& aName, ErrorResult& aRv) const;
- void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
+ ErrorResult& aRv) const
+ {
+ mInternalHeaders->GetAll(aName, aResults, aRv);
+ }
- void Clear();
+ bool Has(const nsACString& aName, ErrorResult& aRv) const
+ {
+ return mInternalHeaders->Has(aName, aRv);
+ }
+
+ void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
+ {
+ mInternalHeaders->Set(aName, aValue, aRv);
+ }
// ChromeOnly
- HeadersGuardEnum Guard() const { return mGuard; }
- void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
+ HeadersGuardEnum Guard() const
+ {
+ return mInternalHeaders->Guard();
+ }
+
+ void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
+ {
+ mInternalHeaders->SetGuard(aGuard, aRv);
+ }
virtual JSObject* WrapObject(JSContext* aCx);
nsISupports* GetParentObject() const { return mOwner; }
- void Fill(const Headers& aInit, ErrorResult& aRv);
private:
- // Since Headers is also an nsISupports, the above constructor can
- // accidentally be invoked as new Headers(Headers*[, implied None guard]) when
- // the intention is to use the copy constructor. Explicitly disallow it.
- Headers(Headers* aOther) MOZ_DELETE;
-
virtual ~Headers();
- static bool IsSimpleHeader(const nsACString& aName,
- const nsACString* aValue = nullptr);
- static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
- static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
- bool IsImmutable(ErrorResult& aRv) const;
- bool IsForbiddenRequestHeader(const nsACString& aName) const;
- bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
- const nsACString* aValue = nullptr) const;
- bool IsForbiddenResponseHeader(const nsACString& aName) const;
-
- bool IsInvalidMutableHeader(const nsACString& aName,
- const nsACString* aValue,
- ErrorResult& aRv) const
+ InternalHeaders*
+ GetInternalHeaders() const
{
- return IsInvalidName(aName, aRv) ||
- (aValue && IsInvalidValue(*aValue, aRv)) ||
- IsImmutable(aRv) ||
- IsForbiddenRequestHeader(aName) ||
- IsForbiddenRequestNoCorsHeader(aName, aValue) ||
- IsForbiddenResponseHeader(aName);
+ return mInternalHeaders;
}
-
- void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
- void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Headers_h
new file mode 100644
--- /dev/null
+++ b/dom/fetch/InternalHeaders.cpp
@@ -0,0 +1,272 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/InternalHeaders.h"
+
+#include "mozilla/ErrorResult.h"
+
+#include "nsCharSeparatedTokenizer.h"
+#include "nsContentUtils.h"
+#include "nsNetUtil.h"
+#include "nsReadableUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+void
+InternalHeaders::Append(const nsACString& aName, const nsACString& aValue,
+ ErrorResult& aRv)
+{
+ nsAutoCString lowerName;
+ ToLowerCase(aName, lowerName);
+
+ if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
+ return;
+ }
+
+ mList.AppendElement(Entry(lowerName, aValue));
+}
+
+void
+InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv)
+{
+ nsAutoCString lowerName;
+ ToLowerCase(aName, lowerName);
+
+ if (IsInvalidMutableHeader(lowerName, aRv)) {
+ return;
+ }
+
+ // remove in reverse order to minimize copying
+ for (int32_t i = mList.Length() - 1; i >= 0; --i) {
+ if (lowerName == mList[i].mName) {
+ mList.RemoveElementAt(i);
+ }
+ }
+}
+
+void
+InternalHeaders::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
+{
+ nsAutoCString lowerName;
+ ToLowerCase(aName, lowerName);
+
+ if (IsInvalidName(lowerName, aRv)) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < mList.Length(); ++i) {
+ if (lowerName == mList[i].mName) {
+ aValue = mList[i].mValue;
+ return;
+ }
+ }
+
+ // No value found, so return null to content
+ aValue.SetIsVoid(true);
+}
+
+void
+InternalHeaders::GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
+ ErrorResult& aRv) const
+{
+ nsAutoCString lowerName;
+ ToLowerCase(aName, lowerName);
+
+ if (IsInvalidName(lowerName, aRv)) {
+ return;
+ }
+
+ aResults.SetLength(0);
+ for (uint32_t i = 0; i < mList.Length(); ++i) {
+ if (lowerName == mList[i].mName) {
+ aResults.AppendElement(mList[i].mValue);
+ }
+ }
+}
+
+bool
+InternalHeaders::Has(const nsACString& aName, ErrorResult& aRv) const
+{
+ nsAutoCString lowerName;
+ ToLowerCase(aName, lowerName);
+
+ if (IsInvalidName(lowerName, aRv)) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < mList.Length(); ++i) {
+ if (lowerName == mList[i].mName) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
+{
+ nsAutoCString lowerName;
+ ToLowerCase(aName, lowerName);
+
+ if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
+ return;
+ }
+
+ int32_t firstIndex = INT32_MAX;
+
+ // remove in reverse order to minimize copying
+ for (int32_t i = mList.Length() - 1; i >= 0; --i) {
+ if (lowerName == mList[i].mName) {
+ firstIndex = std::min(firstIndex, i);
+ mList.RemoveElementAt(i);
+ }
+ }
+
+ if (firstIndex < INT32_MAX) {
+ Entry* entry = mList.InsertElementAt(firstIndex);
+ entry->mName = lowerName;
+ entry->mValue = aValue;
+ } else {
+ mList.AppendElement(Entry(lowerName, aValue));
+ }
+}
+
+void
+InternalHeaders::Clear()
+{
+ mList.Clear();
+}
+
+void
+InternalHeaders::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
+{
+ // Rather than re-validate all current headers, just require code to set
+ // this prior to populating the InternalHeaders object. Allow setting immutable
+ // late, though, as that is pretty much required to have a useful, immutable
+ // headers object.
+ if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ }
+ mGuard = aGuard;
+}
+
+InternalHeaders::~InternalHeaders()
+{
+}
+
+// static
+bool
+InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue)
+{
+ // Note, we must allow a null content-type value here to support
+ // get("content-type"), but the IsInvalidValue() check will prevent null
+ // from being set or appended.
+ return aName.EqualsLiteral("accept") ||
+ aName.EqualsLiteral("accept-language") ||
+ aName.EqualsLiteral("content-language") ||
+ (aName.EqualsLiteral("content-type") &&
+ nsContentUtils::IsAllowedNonCorsContentType(aValue));
+}
+
+//static
+bool
+InternalHeaders::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
+{
+ if (!NS_IsValidHTTPToken(aName)) {
+ NS_ConvertUTF8toUTF16 label(aName);
+ aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label);
+ return true;
+ }
+
+ return false;
+}
+
+// static
+bool
+InternalHeaders::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv)
+{
+ if (!NS_IsReasonableHTTPHeaderValue(aValue)) {
+ NS_ConvertUTF8toUTF16 label(aValue);
+ aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label);
+ return true;
+ }
+ return false;
+}
+
+bool
+InternalHeaders::IsImmutable(ErrorResult& aRv) const
+{
+ if (mGuard == HeadersGuardEnum::Immutable) {
+ aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE);
+ return true;
+ }
+ return false;
+}
+
+bool
+InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName) const
+{
+ return mGuard == HeadersGuardEnum::Request &&
+ nsContentUtils::IsForbiddenRequestHeader(aName);
+}
+
+bool
+InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName) const
+{
+ return mGuard == HeadersGuardEnum::Request_no_cors &&
+ !IsSimpleHeader(aName, EmptyCString());
+}
+
+bool
+InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName,
+ const nsACString& aValue) const
+{
+ return mGuard == HeadersGuardEnum::Request_no_cors &&
+ !IsSimpleHeader(aName, aValue);
+}
+
+bool
+InternalHeaders::IsForbiddenResponseHeader(const nsACString& aName) const
+{
+ return mGuard == HeadersGuardEnum::Response &&
+ nsContentUtils::IsForbiddenResponseHeader(aName);
+}
+
+void
+InternalHeaders::Fill(const InternalHeaders& aInit, ErrorResult& aRv)
+{
+ const nsTArray<Entry>& list = aInit.mList;
+ for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
+ const Entry& entry = list[i];
+ Append(entry.mName, entry.mValue, aRv);
+ }
+}
+
+void
+InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv)
+{
+ for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
+ const Sequence<nsCString>& tuple = aInit[i];
+ if (tuple.Length() != 2) {
+ aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE);
+ return;
+ }
+ Append(tuple[0], tuple[1], aRv);
+ }
+}
+
+void
+InternalHeaders::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
+{
+ nsTArray<nsString> keys;
+ aInit.GetKeys(keys);
+ for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
+ Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
+ }
+}
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/fetch/InternalHeaders.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_InternalHeaders_h
+#define mozilla_dom_InternalHeaders_h
+
+// needed for HeadersGuardEnum.
+#include "mozilla/dom/HeadersBinding.h"
+#include "mozilla/dom/UnionTypes.h"
+
+#include "nsClassHashtable.h"
+#include "nsWrapperCache.h"
+
+class nsPIDOMWindow;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+template<typename T> class MozMap;
+class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
+
+class InternalHeaders MOZ_FINAL
+{
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalHeaders)
+
+private:
+ struct Entry
+ {
+ Entry(const nsACString& aName, const nsACString& aValue)
+ : mName(aName)
+ , mValue(aValue)
+ { }
+
+ Entry() { }
+
+ nsCString mName;
+ nsCString mValue;
+ };
+
+ HeadersGuardEnum mGuard;
+ nsTArray<Entry> mList;
+
+public:
+ explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None)
+ : mGuard(aGuard)
+ {
+ }
+
+ explicit InternalHeaders(const InternalHeaders& aOther)
+ : mGuard(aOther.mGuard)
+ {
+ ErrorResult result;
+ Fill(aOther, result);
+ MOZ_ASSERT(!result.Failed());
+ }
+
+ void Append(const nsACString& aName, const nsACString& aValue,
+ ErrorResult& aRv);
+ void Delete(const nsACString& aName, ErrorResult& aRv);
+ void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
+ void GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
+ ErrorResult& aRv) const;
+ bool Has(const nsACString& aName, ErrorResult& aRv) const;
+ void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
+
+ void Clear();
+
+ HeadersGuardEnum Guard() const { return mGuard; }
+ void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
+
+ void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
+ void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
+ void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
+private:
+ virtual ~InternalHeaders();
+
+ static bool IsSimpleHeader(const nsACString& aName,
+ const nsACString& aValue);
+ static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
+ static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
+ bool IsImmutable(ErrorResult& aRv) const;
+ bool IsForbiddenRequestHeader(const nsACString& aName) const;
+ bool IsForbiddenRequestNoCorsHeader(const nsACString& aName) const;
+ bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
+ const nsACString& aValue) const;
+ bool IsForbiddenResponseHeader(const nsACString& aName) const;
+
+ bool IsInvalidMutableHeader(const nsACString& aName,
+ ErrorResult& aRv) const
+ {
+ return IsInvalidMutableHeader(aName, EmptyCString(), aRv);
+ }
+
+ bool IsInvalidMutableHeader(const nsACString& aName,
+ const nsACString& aValue,
+ ErrorResult& aRv) const
+ {
+ return IsInvalidName(aName, aRv) ||
+ IsInvalidValue(aValue, aRv) ||
+ IsImmutable(aRv) ||
+ IsForbiddenRequestHeader(aName) ||
+ IsForbiddenRequestNoCorsHeader(aName, aValue) ||
+ IsForbiddenResponseHeader(aName);
+ }
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InternalHeaders_h
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -19,17 +19,17 @@ namespace dom {
// The global is used to extract the principal.
already_AddRefed<InternalRequest>
InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const
{
nsRefPtr<InternalRequest> copy = new InternalRequest();
copy->mURL.Assign(mURL);
copy->SetMethod(mMethod);
- copy->mHeaders = new Headers(*mHeaders);
+ copy->mHeaders = new InternalHeaders(*mHeaders);
copy->mBodyStream = mBodyStream;
copy->mPreserveContentCodings = true;
if (NS_IsMainThread()) {
nsIPrincipal* principal = aGlobal->PrincipalOrNull();
MOZ_ASSERT(principal);
aRv = nsContentUtils::GetASCIIOrigin(principal, copy->mOrigin);
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -1,17 +1,18 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_InternalRequest_h
#define mozilla_dom_InternalRequest_h
-#include "mozilla/dom/Headers.h"
+#include "mozilla/dom/HeadersBinding.h"
+#include "mozilla/dom/InternalHeaders.h"
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsIContentPolicy.h"
#include "nsIInputStream.h"
#include "nsISupportsImpl.h"
class nsIDocument;
@@ -50,17 +51,17 @@ public:
{
RESPONSETAINT_BASIC,
RESPONSETAINT_CORS,
RESPONSETAINT_OPAQUE,
};
explicit InternalRequest()
: mMethod("GET")
- , mHeaders(new Headers(nullptr, HeadersGuardEnum::None))
+ , mHeaders(new InternalHeaders(HeadersGuardEnum::None))
, mContextFrameType(FRAMETYPE_NONE)
, mReferrerType(REFERRER_CLIENT)
, mMode(RequestMode::No_cors)
, mCredentialsMode(RequestCredentials::Omit)
, mResponseTainting(RESPONSETAINT_BASIC)
, mRedirectCount(0)
, mAuthenticationFlag(false)
, mForceOriginHeader(false)
@@ -154,16 +155,22 @@ public:
}
bool
IsSynchronous() const
{
return mSynchronous;
}
+ RequestMode
+ Mode() const
+ {
+ return mMode;
+ }
+
void
SetMode(RequestMode aMode)
{
mMode = aMode;
}
void
SetCredentialsMode(RequestCredentials aCredentialsMode)
@@ -172,18 +179,18 @@ public:
}
nsContentPolicyType
GetContext() const
{
return mContext;
}
- Headers*
- Headers_()
+ InternalHeaders*
+ Headers()
{
return mHeaders;
}
bool
ForceOriginHeader()
{
return mForceOriginHeader;
@@ -220,17 +227,17 @@ private:
void
SetURL(const nsACString& aURL)
{
mURL.Assign(aURL);
}
nsCString mMethod;
nsCString mURL;
- nsRefPtr<Headers> mHeaders;
+ nsRefPtr<InternalHeaders> mHeaders;
nsCOMPtr<nsIInputStream> mBodyStream;
// nsContentPolicyType does not cover the complete set defined in the spec,
// but it is a good start.
nsContentPolicyType mContext;
nsCString mOrigin;
--- a/dom/fetch/InternalResponse.cpp
+++ b/dom/fetch/InternalResponse.cpp
@@ -2,23 +2,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "InternalResponse.h"
#include "nsIDOMFile.h"
-#include "mozilla/dom/Headers.h"
+#include "mozilla/dom/InternalHeaders.h"
namespace mozilla {
namespace dom {
InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText)
: mType(ResponseType::Default)
, mStatus(aStatus)
, mStatusText(aStatusText)
- , mHeaders(new Headers(nullptr, HeadersGuardEnum::Response))
+ , mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
{
}
} // namespace dom
} // namespace mozilla
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -1,23 +1,26 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_InternalResponse_h
#define mozilla_dom_InternalResponse_h
+#include "nsIInputStream.h"
#include "nsISupportsImpl.h"
#include "mozilla/dom/ResponseBinding.h"
namespace mozilla {
namespace dom {
+class InternalHeaders;
+
class InternalResponse MOZ_FINAL
{
friend class FetchDriver;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse)
InternalResponse(uint16_t aStatus, const nsACString& aStatusText);
@@ -58,18 +61,18 @@ public:
}
const nsCString&
GetStatusText() const
{
return mStatusText;
}
- Headers*
- Headers_()
+ InternalHeaders*
+ Headers()
{
return mHeaders;
}
void
GetBody(nsIInputStream** aStream)
{
nsCOMPtr<nsIInputStream> stream = mBody;
@@ -86,17 +89,17 @@ private:
~InternalResponse()
{ }
ResponseType mType;
nsCString mTerminationReason;
nsCString mURL;
const uint16_t mStatus;
const nsCString mStatusText;
- nsRefPtr<Headers> mHeaders;
+ nsRefPtr<InternalHeaders> mHeaders;
nsCOMPtr<nsIInputStream> mBody;
nsCString mContentType;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_InternalResponse_h
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -17,17 +17,17 @@
#include "WorkerPrivate.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner, mHeaders)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest)
: FetchBody<Request>()
@@ -150,83 +150,95 @@ Request::Constructor(const GlobalObject&
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
return nullptr;
}
ToUpperCase(method);
request->SetMethod(method);
}
- nsRefPtr<Request> domRequest = new Request(global, request);
- nsRefPtr<Headers> domRequestHeaders = domRequest->Headers_();
+ nsRefPtr<InternalHeaders> requestHeaders = request->Headers();
- nsRefPtr<Headers> headers;
+ nsRefPtr<InternalHeaders> headers;
if (aInit.mHeaders.WasPassed()) {
- headers = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
+ nsRefPtr<Headers> h = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
if (aRv.Failed()) {
return nullptr;
}
+ headers = h->GetInternalHeaders();
} else {
- headers = new Headers(*domRequestHeaders);
+ headers = new InternalHeaders(*requestHeaders);
}
- domRequestHeaders->Clear();
+ requestHeaders->Clear();
- if (domRequest->Mode() == RequestMode::No_cors) {
+ if (request->Mode() == RequestMode::No_cors) {
nsCString method;
- domRequest->GetMethod(method);
+ request->GetMethod(method);
ToLowerCase(method);
if (!method.EqualsASCII("get") &&
!method.EqualsASCII("head") &&
!method.EqualsASCII("post")) {
NS_ConvertUTF8toUTF16 label(method);
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
return nullptr;
}
- domRequestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
+ requestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
- domRequestHeaders->Fill(*headers, aRv);
+ requestHeaders->Fill(*headers, aRv);
if (aRv.Failed()) {
return nullptr;
}
if (aInit.mBody.WasPassed()) {
const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
nsCOMPtr<nsIInputStream> stream;
nsCString contentType;
aRv = ExtractByteStreamFromBody(bodyInit,
getter_AddRefs(stream), contentType);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
request->SetBody(stream);
if (!contentType.IsVoid() &&
- !domRequestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
- domRequestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
- contentType, aRv);
+ !requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
+ requestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
+ contentType, aRv);
}
if (aRv.Failed()) {
return nullptr;
}
}
+ nsRefPtr<Request> domRequest = new Request(global, request);
domRequest->SetMimeType(aRv);
return domRequest.forget();
}
already_AddRefed<Request>
Request::Clone() const
{
// FIXME(nsm): Bug 1073231. This is incorrect, but the clone method isn't
// well defined yet.
nsRefPtr<Request> request = new Request(mOwner,
new InternalRequest(*mRequest));
return request.forget();
}
+
+Headers*
+Request::Headers_()
+{
+ if (!mHeaders) {
+ mHeaders = new Headers(mOwner, mRequest->Headers());
+ }
+
+ return mHeaders;
+}
+
} // namespace dom
} // namespace mozilla
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -17,16 +17,17 @@
#include "mozilla/dom/UnionTypes.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class Headers;
+class InternalHeaders;
class Promise;
class Request MOZ_FINAL : public nsISupports
, public nsWrapperCache
, public FetchBody<Request>
{
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
@@ -71,17 +72,23 @@ public:
aReferrer.AsAString() = EmptyString();
return;
}
// FIXME(nsm): Spec doesn't say what to do if referrer is client.
aReferrer.AsAString() = NS_ConvertUTF8toUTF16(mRequest->mReferrerURL);
}
- Headers* Headers_() const { return mRequest->Headers_(); }
+ InternalHeaders*
+ GetInternalHeaders() const
+ {
+ return mRequest->Headers();
+ }
+
+ Headers* Headers_();
void
GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); }
static already_AddRefed<Request>
Constructor(const GlobalObject& aGlobal, const RequestOrScalarValueString& aInput,
const RequestInit& aInit, ErrorResult& rv);
@@ -95,14 +102,16 @@ public:
already_AddRefed<InternalRequest>
GetInternalRequest();
private:
~Request();
nsCOMPtr<nsIGlobalObject> mOwner;
nsRefPtr<InternalRequest> mRequest;
+ // Lazily created.
+ nsRefPtr<Headers> mHeaders;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Request_h
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -17,17 +17,17 @@
#include "InternalResponse.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTING_ADDREF(Response)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Response)
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner, mHeaders)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse)
: FetchBody<Response>()
@@ -93,41 +93,41 @@ Response::Constructor(const GlobalObject
nsRefPtr<InternalResponse> internalResponse =
new InternalResponse(aInit.mStatus, statusText);
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
nsRefPtr<Response> r = new Response(global, internalResponse);
if (aInit.mHeaders.WasPassed()) {
- internalResponse->Headers_()->Clear();
+ internalResponse->Headers()->Clear();
// Instead of using Fill, create an object to allow the constructor to
// unwrap the HeadersInit.
nsRefPtr<Headers> headers =
Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
if (aRv.Failed()) {
return nullptr;
}
- internalResponse->Headers_()->Fill(*headers, aRv);
+ internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
if (aBody.WasPassed()) {
nsCOMPtr<nsIInputStream> bodyStream;
nsCString contentType;
aRv = ExtractByteStreamFromBody(aBody.Value(), getter_AddRefs(bodyStream), contentType);
internalResponse->SetBody(bodyStream);
if (!contentType.IsVoid() &&
- !internalResponse->Headers_()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
- internalResponse->Headers_()->Append(NS_LITERAL_CSTRING("Content-Type"), contentType, aRv);
+ !internalResponse->Headers()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
+ internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"), contentType, aRv);
}
if (aRv.Failed()) {
return nullptr;
}
}
r->SetMimeType(aRv);
@@ -144,10 +144,20 @@ Response::Clone()
}
void
Response::SetBody(nsIInputStream* aBody)
{
// FIXME(nsm): Do we flip bodyUsed here?
mInternalResponse->SetBody(aBody);
}
+
+Headers*
+Response::Headers_()
+{
+ if (!mHeaders) {
+ mHeaders = new Headers(mOwner, mInternalResponse->Headers());
+ }
+
+ return mHeaders;
+}
} // namespace dom
} // namespace mozilla
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -16,16 +16,17 @@
#include "InternalResponse.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class Headers;
+class InternalHeaders;
class Promise;
class Response MOZ_FINAL : public nsISupports
, public nsWrapperCache
, public FetchBody<Response>
{
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response)
@@ -60,18 +61,23 @@ public:
}
void
GetStatusText(nsCString& aStatusText) const
{
aStatusText = mInternalResponse->GetStatusText();
}
- Headers*
- Headers_() const { return mInternalResponse->Headers_(); }
+ InternalHeaders*
+ GetInternalHeaders() const
+ {
+ return mInternalResponse->Headers();
+ }
+
+ Headers* Headers_();
void
GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); }
static already_AddRefed<Response>
Error(const GlobalObject& aGlobal);
static already_AddRefed<Response>
@@ -92,14 +98,16 @@ public:
void
SetBody(nsIInputStream* aBody);
private:
~Response();
nsCOMPtr<nsIGlobalObject> mOwner;
nsRefPtr<InternalResponse> mInternalResponse;
+ // Lazily created
+ nsRefPtr<Headers> mHeaders;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Response_h
--- a/dom/fetch/moz.build
+++ b/dom/fetch/moz.build
@@ -2,25 +2,27 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'Fetch.h',
'Headers.h',
+ 'InternalHeaders.h',
'InternalRequest.h',
'InternalResponse.h',
'Request.h',
'Response.h',
]
UNIFIED_SOURCES += [
'Fetch.cpp',
'Headers.cpp',
+ 'InternalHeaders.cpp',
'InternalRequest.cpp',
'InternalResponse.cpp',
'Request.cpp',
'Response.cpp',
]
LOCAL_INCLUDES += [
'../workers',