summaryrefslogtreecommitdiffstats
path: root/dom/cache/TypeUtils.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/cache/TypeUtils.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/cache/TypeUtils.cpp')
-rw-r--r--dom/cache/TypeUtils.cpp504
1 files changed, 504 insertions, 0 deletions
diff --git a/dom/cache/TypeUtils.cpp b/dom/cache/TypeUtils.cpp
new file mode 100644
index 000000000..2d4cb30eb
--- /dev/null
+++ b/dom/cache/TypeUtils.cpp
@@ -0,0 +1,504 @@
+/* -*- 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/cache/TypeUtils.h"
+
+#include "mozilla/Unused.h"
+#include "mozilla/dom/CacheBinding.h"
+#include "mozilla/dom/InternalRequest.h"
+#include "mozilla/dom/Request.h"
+#include "mozilla/dom/Response.h"
+#include "mozilla/dom/cache/CacheTypes.h"
+#include "mozilla/dom/cache/ReadStream.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "mozilla/ipc/PFileDescriptorSetChild.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+#include "mozilla/ipc/SendStream.h"
+#include "nsCOMPtr.h"
+#include "nsIAsyncInputStream.h"
+#include "nsIAsyncOutputStream.h"
+#include "nsIIPCSerializableInputStream.h"
+#include "nsQueryObject.h"
+#include "nsPromiseFlatString.h"
+#include "nsStreamUtils.h"
+#include "nsString.h"
+#include "nsURLParsers.h"
+#include "nsCRT.h"
+#include "nsHttp.h"
+
+namespace mozilla {
+namespace dom {
+namespace cache {
+
+using mozilla::ipc::AutoIPCStream;
+using mozilla::ipc::BackgroundChild;
+using mozilla::ipc::FileDescriptor;
+using mozilla::ipc::PBackgroundChild;
+using mozilla::ipc::PFileDescriptorSetChild;
+
+namespace {
+
+static bool
+HasVaryStar(mozilla::dom::InternalHeaders* aHeaders)
+{
+ nsCString varyHeaders;
+ ErrorResult rv;
+ aHeaders->Get(NS_LITERAL_CSTRING("vary"), varyHeaders, rv);
+ MOZ_ALWAYS_TRUE(!rv.Failed());
+
+ char* rawBuffer = varyHeaders.BeginWriting();
+ char* token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer);
+ for (; token;
+ token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer)) {
+ nsDependentCString header(token);
+ if (header.EqualsLiteral("*")) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+ToHeadersEntryList(nsTArray<HeadersEntry>& aOut, InternalHeaders* aHeaders)
+{
+ MOZ_DIAGNOSTIC_ASSERT(aHeaders);
+
+ AutoTArray<InternalHeaders::Entry, 16> entryList;
+ aHeaders->GetEntries(entryList);
+
+ for (uint32_t i = 0; i < entryList.Length(); ++i) {
+ InternalHeaders::Entry& entry = entryList[i];
+ aOut.AppendElement(HeadersEntry(entry.mName, entry.mValue));
+ }
+}
+
+} // namespace
+
+already_AddRefed<InternalRequest>
+TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
+ BodyAction aBodyAction, ErrorResult& aRv)
+{
+ if (aIn.IsRequest()) {
+ Request& request = aIn.GetAsRequest();
+
+ // Check and set bodyUsed flag immediately because its on Request
+ // instead of InternalRequest.
+ CheckAndSetBodyUsed(&request, aBodyAction, aRv);
+ if (aRv.Failed()) { return nullptr; }
+
+ return request.GetInternalRequest();
+ }
+
+ return ToInternalRequest(aIn.GetAsUSVString(), aRv);
+}
+
+already_AddRefed<InternalRequest>
+TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
+ BodyAction aBodyAction, ErrorResult& aRv)
+{
+
+ if (aIn.IsRequest()) {
+ RefPtr<Request> request = aIn.GetAsRequest().get();
+
+ // Check and set bodyUsed flag immediately because its on Request
+ // instead of InternalRequest.
+ CheckAndSetBodyUsed(request, aBodyAction, aRv);
+ if (aRv.Failed()) { return nullptr; }
+
+ return request->GetInternalRequest();
+ }
+
+ return ToInternalRequest(aIn.GetAsUSVString(), aRv);
+}
+
+void
+TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
+ BodyAction aBodyAction, SchemeAction aSchemeAction,
+ nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
+ ErrorResult& aRv)
+{
+ MOZ_DIAGNOSTIC_ASSERT(aIn);
+ aIn->GetMethod(aOut.method());
+ nsCString url(aIn->GetURLWithoutFragment());
+ bool schemeValid;
+ ProcessURL(url, &schemeValid, &aOut.urlWithoutQuery(), &aOut.urlQuery(), aRv);
+ if (aRv.Failed()) {
+ return;
+ }
+ if (!schemeValid) {
+ if (aSchemeAction == TypeErrorOnInvalidScheme) {
+ NS_ConvertUTF8toUTF16 urlUTF16(url);
+ aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Request"),
+ urlUTF16);
+ return;
+ }
+ }
+ aOut.urlFragment() = aIn->GetFragment();
+
+ aIn->GetReferrer(aOut.referrer());
+ aOut.referrerPolicy() = aIn->ReferrerPolicy_();
+ RefPtr<InternalHeaders> headers = aIn->Headers();
+ MOZ_DIAGNOSTIC_ASSERT(headers);
+ ToHeadersEntryList(aOut.headers(), headers);
+ aOut.headersGuard() = headers->Guard();
+ aOut.mode() = aIn->Mode();
+ aOut.credentials() = aIn->GetCredentialsMode();
+ aOut.contentPolicyType() = aIn->ContentPolicyType();
+ aOut.requestCache() = aIn->GetCacheMode();
+ aOut.requestRedirect() = aIn->GetRedirectMode();
+
+ aOut.integrity() = aIn->GetIntegrity();
+
+ if (aBodyAction == IgnoreBody) {
+ aOut.body() = void_t();
+ return;
+ }
+
+ // BodyUsed flag is checked and set previously in ToInternalRequest()
+
+ nsCOMPtr<nsIInputStream> stream;
+ aIn->GetBody(getter_AddRefs(stream));
+ SerializeCacheStream(stream, &aOut.body(), aStreamCleanupList, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+}
+
+void
+TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
+ InternalResponse& aIn, ErrorResult& aRv)
+{
+ aOut.type() = aIn.Type();
+
+ aIn.GetUnfilteredURLList(aOut.urlList());
+ AutoTArray<nsCString, 4> urlList;
+ aIn.GetURLList(urlList);
+
+ for (uint32_t i = 0; i < aOut.urlList().Length(); i++) {
+ MOZ_DIAGNOSTIC_ASSERT(!aOut.urlList()[i].IsEmpty());
+ // Pass all Response URL schemes through... The spec only requires we take
+ // action on invalid schemes for Request objects.
+ ProcessURL(aOut.urlList()[i], nullptr, nullptr, nullptr, aRv);
+ }
+
+ aOut.status() = aIn.GetUnfilteredStatus();
+ aOut.statusText() = aIn.GetUnfilteredStatusText();
+ RefPtr<InternalHeaders> headers = aIn.UnfilteredHeaders();
+ MOZ_DIAGNOSTIC_ASSERT(headers);
+ if (HasVaryStar(headers)) {
+ aRv.ThrowTypeError<MSG_RESPONSE_HAS_VARY_STAR>();
+ return;
+ }
+ ToHeadersEntryList(aOut.headers(), headers);
+ aOut.headersGuard() = headers->Guard();
+ aOut.channelInfo() = aIn.GetChannelInfo().AsIPCChannelInfo();
+ if (aIn.GetPrincipalInfo()) {
+ aOut.principalInfo() = *aIn.GetPrincipalInfo();
+ } else {
+ aOut.principalInfo() = void_t();
+ }
+}
+
+void
+TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn,
+ nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
+ ErrorResult& aRv)
+{
+ if (aIn.BodyUsed()) {
+ aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
+ return;
+ }
+
+ RefPtr<InternalResponse> ir = aIn.GetInternalResponse();
+ ToCacheResponseWithoutBody(aOut, *ir, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
+ nsCOMPtr<nsIInputStream> stream;
+ ir->GetUnfilteredBody(getter_AddRefs(stream));
+ if (stream) {
+ aIn.SetBodyUsed();
+ }
+
+ SerializeCacheStream(stream, &aOut.body(), aStreamCleanupList, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+}
+
+// static
+void
+TypeUtils::ToCacheQueryParams(CacheQueryParams& aOut,
+ const CacheQueryOptions& aIn)
+{
+ aOut.ignoreSearch() = aIn.mIgnoreSearch;
+ aOut.ignoreMethod() = aIn.mIgnoreMethod;
+ aOut.ignoreVary() = aIn.mIgnoreVary;
+ aOut.cacheNameSet() = aIn.mCacheName.WasPassed();
+ if (aOut.cacheNameSet()) {
+ aOut.cacheName() = aIn.mCacheName.Value();
+ } else {
+ aOut.cacheName() = NS_LITERAL_STRING("");
+ }
+}
+
+already_AddRefed<Response>
+TypeUtils::ToResponse(const CacheResponse& aIn)
+{
+ if (aIn.type() == ResponseType::Error) {
+ RefPtr<InternalResponse> error = InternalResponse::NetworkError();
+ RefPtr<Response> r = new Response(GetGlobalObject(), error);
+ return r.forget();
+ }
+
+ RefPtr<InternalResponse> ir = new InternalResponse(aIn.status(),
+ aIn.statusText());
+ ir->SetURLList(aIn.urlList());
+
+ RefPtr<InternalHeaders> internalHeaders =
+ ToInternalHeaders(aIn.headers(), aIn.headersGuard());
+ ErrorResult result;
+
+ // Be careful to fill the headers before setting the guard in order to
+ // correctly re-create the original headers.
+ ir->Headers()->Fill(*internalHeaders, result);
+ MOZ_DIAGNOSTIC_ASSERT(!result.Failed());
+ ir->Headers()->SetGuard(aIn.headersGuard(), result);
+ MOZ_DIAGNOSTIC_ASSERT(!result.Failed());
+
+ ir->InitChannelInfo(aIn.channelInfo());
+ if (aIn.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
+ UniquePtr<mozilla::ipc::PrincipalInfo> info(new mozilla::ipc::PrincipalInfo(aIn.principalInfo().get_PrincipalInfo()));
+ ir->SetPrincipalInfo(Move(info));
+ }
+
+ nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
+ ir->SetBody(stream, InternalResponse::UNKNOWN_BODY_SIZE);
+
+ switch (aIn.type())
+ {
+ case ResponseType::Basic:
+ ir = ir->BasicResponse();
+ break;
+ case ResponseType::Cors:
+ ir = ir->CORSResponse();
+ break;
+ case ResponseType::Default:
+ break;
+ case ResponseType::Opaque:
+ ir = ir->OpaqueResponse();
+ break;
+ case ResponseType::Opaqueredirect:
+ ir = ir->OpaqueRedirectResponse();
+ break;
+ default:
+ MOZ_CRASH("Unexpected ResponseType!");
+ }
+ MOZ_DIAGNOSTIC_ASSERT(ir);
+
+ RefPtr<Response> ref = new Response(GetGlobalObject(), ir);
+ return ref.forget();
+}
+already_AddRefed<InternalRequest>
+TypeUtils::ToInternalRequest(const CacheRequest& aIn)
+{
+ nsAutoCString url(aIn.urlWithoutQuery());
+ url.Append(aIn.urlQuery());
+ RefPtr<InternalRequest> internalRequest =
+ new InternalRequest(url, aIn.urlFragment());
+ internalRequest->SetMethod(aIn.method());
+ internalRequest->SetReferrer(aIn.referrer());
+ internalRequest->SetReferrerPolicy(aIn.referrerPolicy());
+ internalRequest->SetMode(aIn.mode());
+ internalRequest->SetCredentialsMode(aIn.credentials());
+ internalRequest->SetContentPolicyType(aIn.contentPolicyType());
+ internalRequest->SetCacheMode(aIn.requestCache());
+ internalRequest->SetRedirectMode(aIn.requestRedirect());
+ internalRequest->SetIntegrity(aIn.integrity());
+
+ RefPtr<InternalHeaders> internalHeaders =
+ ToInternalHeaders(aIn.headers(), aIn.headersGuard());
+ ErrorResult result;
+
+ // Be careful to fill the headers before setting the guard in order to
+ // correctly re-create the original headers.
+ internalRequest->Headers()->Fill(*internalHeaders, result);
+ MOZ_DIAGNOSTIC_ASSERT(!result.Failed());
+
+ internalRequest->Headers()->SetGuard(aIn.headersGuard(), result);
+ MOZ_DIAGNOSTIC_ASSERT(!result.Failed());
+
+ nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
+
+ internalRequest->SetBody(stream);
+
+ return internalRequest.forget();
+}
+
+already_AddRefed<Request>
+TypeUtils::ToRequest(const CacheRequest& aIn)
+{
+ RefPtr<InternalRequest> internalRequest = ToInternalRequest(aIn);
+ RefPtr<Request> request = new Request(GetGlobalObject(), internalRequest);
+ return request.forget();
+}
+
+// static
+already_AddRefed<InternalHeaders>
+TypeUtils::ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
+ HeadersGuardEnum aGuard)
+{
+ nsTArray<InternalHeaders::Entry> entryList(aHeadersEntryList.Length());
+
+ for (uint32_t i = 0; i < aHeadersEntryList.Length(); ++i) {
+ const HeadersEntry& headersEntry = aHeadersEntryList[i];
+ entryList.AppendElement(InternalHeaders::Entry(headersEntry.name(),
+ headersEntry.value()));
+ }
+
+ RefPtr<InternalHeaders> ref = new InternalHeaders(Move(entryList), aGuard);
+ return ref.forget();
+}
+
+// Utility function to remove the fragment from a URL, check its scheme, and optionally
+// provide a URL without the query. We're not using nsIURL or URL to do this because
+// they require going to the main thread.
+// static
+void
+TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
+ nsACString* aUrlWithoutQueryOut,nsACString* aUrlQueryOut,
+ ErrorResult& aRv)
+{
+ const nsAFlatCString& flatURL = PromiseFlatCString(aUrl);
+ const char* url = flatURL.get();
+
+ // off the main thread URL parsing using nsStdURLParser.
+ nsCOMPtr<nsIURLParser> urlParser = new nsStdURLParser();
+
+ uint32_t pathPos;
+ int32_t pathLen;
+ uint32_t schemePos;
+ int32_t schemeLen;
+ aRv = urlParser->ParseURL(url, flatURL.Length(), &schemePos, &schemeLen,
+ nullptr, nullptr, // ignore authority
+ &pathPos, &pathLen);
+ if (NS_WARN_IF(aRv.Failed())) { return; }
+
+ if (aSchemeValidOut) {
+ nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
+ *aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
+ scheme.LowerCaseEqualsLiteral("https");
+ }
+
+ uint32_t queryPos;
+ int32_t queryLen;
+
+ aRv = urlParser->ParsePath(url + pathPos, flatURL.Length() - pathPos,
+ nullptr, nullptr, // ignore filepath
+ &queryPos, &queryLen,
+ nullptr, nullptr);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
+ if (!aUrlWithoutQueryOut) {
+ return;
+ }
+
+ MOZ_DIAGNOSTIC_ASSERT(aUrlQueryOut);
+
+ if (queryLen < 0) {
+ *aUrlWithoutQueryOut = aUrl;
+ *aUrlQueryOut = EmptyCString();
+ return;
+ }
+
+ // ParsePath gives us query position relative to the start of the path
+ queryPos += pathPos;
+
+ *aUrlWithoutQueryOut = Substring(aUrl, 0, queryPos - 1);
+ *aUrlQueryOut = Substring(aUrl, queryPos - 1, queryLen + 1);
+}
+
+void
+TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
+ ErrorResult& aRv)
+{
+ MOZ_DIAGNOSTIC_ASSERT(aRequest);
+
+ if (aBodyAction == IgnoreBody) {
+ return;
+ }
+
+ if (aRequest->BodyUsed()) {
+ aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
+ return;
+ }
+
+ nsCOMPtr<nsIInputStream> stream;
+ aRequest->GetBody(getter_AddRefs(stream));
+ if (stream) {
+ aRequest->SetBodyUsed();
+ }
+}
+
+already_AddRefed<InternalRequest>
+TypeUtils::ToInternalRequest(const nsAString& aIn, ErrorResult& aRv)
+{
+ RequestOrUSVString requestOrString;
+ requestOrString.SetAsUSVString().Rebind(aIn.Data(), aIn.Length());
+
+ // Re-create a GlobalObject stack object so we can use webidl Constructors.
+ AutoJSAPI jsapi;
+ if (NS_WARN_IF(!jsapi.Init(GetGlobalObject()))) {
+ aRv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+ JSContext* cx = jsapi.cx();
+ GlobalObject global(cx, GetGlobalObject()->GetGlobalJSObject());
+ MOZ_DIAGNOSTIC_ASSERT(!global.Failed());
+
+ RefPtr<Request> request = Request::Constructor(global, requestOrString,
+ RequestInit(), aRv);
+ if (NS_WARN_IF(aRv.Failed())) { return nullptr; }
+
+ return request->GetInternalRequest();
+}
+
+void
+TypeUtils::SerializeCacheStream(nsIInputStream* aStream,
+ CacheReadStreamOrVoid* aStreamOut,
+ nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
+ ErrorResult& aRv)
+{
+ *aStreamOut = void_t();
+ if (!aStream) {
+ return;
+ }
+
+ RefPtr<ReadStream> controlled = do_QueryObject(aStream);
+ if (controlled) {
+ controlled->Serialize(aStreamOut, aStreamCleanupList, aRv);
+ return;
+ }
+
+ *aStreamOut = CacheReadStream();
+ CacheReadStream& cacheStream = aStreamOut->get_CacheReadStream();
+
+ cacheStream.controlChild() = nullptr;
+ cacheStream.controlParent() = nullptr;
+
+ UniquePtr<AutoIPCStream> autoStream(new AutoIPCStream(cacheStream.stream()));
+ autoStream->Serialize(aStream, GetIPCManager());
+
+ aStreamCleanupList.AppendElement(Move(autoStream));
+}
+
+} // namespace cache
+} // namespace dom
+} // namespace mozilla