diff options
Diffstat (limited to 'dom/fetch/InternalResponse.h')
-rw-r--r-- | dom/fetch/InternalResponse.h | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/dom/fetch/InternalResponse.h b/dom/fetch/InternalResponse.h new file mode 100644 index 0000000000..f256d3ec5b --- /dev/null +++ b/dom/fetch/InternalResponse.h @@ -0,0 +1,383 @@ +/* -*- 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_InternalResponse_h +#define mozilla_dom_InternalResponse_h + +#include "nsIInputStream.h" +#include "nsICacheInfoChannel.h" +#include "nsISupportsImpl.h" +#include "nsProxyRelease.h" + +#include "mozilla/dom/InternalHeaders.h" +#include "mozilla/dom/RequestBinding.h" +#include "mozilla/dom/ResponseBinding.h" +#include "mozilla/dom/ChannelInfo.h" +#include "mozilla/UniquePtr.h" + +namespace mozilla { +namespace ipc { +class AutoIPCStream; +class PBackgroundChild; +class PrincipalInfo; +} // namespace ipc + +namespace dom { + +class IPCInternalResponse; +class InternalHeaders; + +class InternalResponse final { + friend class FetchDriver; + + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse) + + InternalResponse( + uint16_t aStatus, const nsACString& aStatusText, + RequestCredentials aCredentialsMode = RequestCredentials::Omit); + + static RefPtr<InternalResponse> FromIPC( + const IPCInternalResponse& aIPCResponse); + + // Note: the AutoIPCStreams must outlive the IPCInternalResponse. + void ToIPC( + IPCInternalResponse* aIPCResponse, + mozilla::ipc::PBackgroundChild* aManager, + UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoBodyStream, + UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoAlternativeBodyStream); + + enum CloneType { + eCloneInputStream, + eDontCloneInputStream, + }; + + already_AddRefed<InternalResponse> Clone(CloneType eCloneType); + + static already_AddRefed<InternalResponse> NetworkError(nsresult aRv) { + MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(aRv)); + RefPtr<InternalResponse> response = new InternalResponse(0, ""_ns); + ErrorResult result; + response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result); + MOZ_ASSERT(!result.Failed()); + response->mType = ResponseType::Error; + response->mErrorCode = aRv; + return response.forget(); + } + + already_AddRefed<InternalResponse> OpaqueResponse(); + + already_AddRefed<InternalResponse> OpaqueRedirectResponse(); + + already_AddRefed<InternalResponse> BasicResponse(); + + already_AddRefed<InternalResponse> CORSResponse(); + + ResponseType Type() const { + MOZ_ASSERT_IF(mType == ResponseType::Error, !mWrappedResponse); + MOZ_ASSERT_IF(mType == ResponseType::Default, !mWrappedResponse); + MOZ_ASSERT_IF(mType == ResponseType::Basic, mWrappedResponse); + MOZ_ASSERT_IF(mType == ResponseType::Cors, mWrappedResponse); + MOZ_ASSERT_IF(mType == ResponseType::Opaque, mWrappedResponse); + MOZ_ASSERT_IF(mType == ResponseType::Opaqueredirect, mWrappedResponse); + return mType; + } + + bool IsError() const { return Type() == ResponseType::Error; } + // GetUrl should return last fetch URL in response's url list and null if + // response's url list is the empty list. + const nsCString& GetURL() const { + // Empty urlList when response is a synthetic response. + if (mURLList.IsEmpty()) { + return EmptyCString(); + } + return mURLList.LastElement(); + } + void GetURLList(nsTArray<nsCString>& aURLList) const { + aURLList.Assign(mURLList); + } + const nsCString& GetUnfilteredURL() const { + if (mWrappedResponse) { + return mWrappedResponse->GetURL(); + } + return GetURL(); + } + void GetUnfilteredURLList(nsTArray<nsCString>& aURLList) const { + if (mWrappedResponse) { + return mWrappedResponse->GetURLList(aURLList); + } + + return GetURLList(aURLList); + } + + nsTArray<nsCString> GetUnfilteredURLList() const { + nsTArray<nsCString> list; + GetUnfilteredURLList(list); + return list; + } + + void SetURLList(const nsTArray<nsCString>& aURLList) { + mURLList.Assign(aURLList); + +#ifdef DEBUG + for (uint32_t i = 0; i < mURLList.Length(); ++i) { + MOZ_ASSERT(mURLList[i].Find("#"_ns) == kNotFound); + } +#endif + } + + uint16_t GetStatus() const { return mStatus; } + + uint16_t GetUnfilteredStatus() const { + if (mWrappedResponse) { + return mWrappedResponse->GetStatus(); + } + + return GetStatus(); + } + + const nsCString& GetStatusText() const { return mStatusText; } + + const nsCString& GetUnfilteredStatusText() const { + if (mWrappedResponse) { + return mWrappedResponse->GetStatusText(); + } + + return GetStatusText(); + } + + InternalHeaders* Headers() { return mHeaders; } + + InternalHeaders* UnfilteredHeaders() { + if (mWrappedResponse) { + return mWrappedResponse->Headers(); + }; + + return Headers(); + } + + void GetUnfilteredBody(nsIInputStream** aStream, + int64_t* aBodySize = nullptr) { + if (mWrappedResponse) { + MOZ_ASSERT(!mBody); + return mWrappedResponse->GetBody(aStream, aBodySize); + } + nsCOMPtr<nsIInputStream> stream = mBody; + stream.forget(aStream); + if (aBodySize) { + *aBodySize = mBodySize; + } + } + + void GetBody(nsIInputStream** aStream, int64_t* aBodySize = nullptr) { + if (Type() == ResponseType::Opaque || + Type() == ResponseType::Opaqueredirect) { + *aStream = nullptr; + if (aBodySize) { + *aBodySize = UNKNOWN_BODY_SIZE; + } + return; + } + + GetUnfilteredBody(aStream, aBodySize); + } + + void SetBodyBlobURISpec(nsACString& aBlobURISpec) { + mBodyBlobURISpec = aBlobURISpec; + } + + const nsACString& BodyBlobURISpec() const { + if (mWrappedResponse) { + return mWrappedResponse->BodyBlobURISpec(); + } + return mBodyBlobURISpec; + } + + void SetBodyLocalPath(nsAString& aLocalPath) { mBodyLocalPath = aLocalPath; } + + const nsAString& BodyLocalPath() const { + if (mWrappedResponse) { + return mWrappedResponse->BodyLocalPath(); + } + return mBodyLocalPath; + } + + void SetBody(nsIInputStream* aBody, int64_t aBodySize) { + if (mWrappedResponse) { + return mWrappedResponse->SetBody(aBody, aBodySize); + } + // A request's body may not be reset once set. + MOZ_ASSERT(!mBody); + MOZ_ASSERT(mBodySize == UNKNOWN_BODY_SIZE); + // Check arguments. + MOZ_ASSERT(aBodySize == UNKNOWN_BODY_SIZE || aBodySize >= 0); + // If body is not given, then size must be unknown. + MOZ_ASSERT_IF(!aBody, aBodySize == UNKNOWN_BODY_SIZE); + + mBody = aBody; + mBodySize = aBodySize; + } + + uint32_t GetPaddingInfo(); + + nsresult GeneratePaddingInfo(); + + int64_t GetPaddingSize(); + + void SetPaddingSize(int64_t aPaddingSize); + + void SetAlternativeDataType(const nsACString& aAltDataType) { + if (mWrappedResponse) { + return mWrappedResponse->SetAlternativeDataType(aAltDataType); + } + + MOZ_DIAGNOSTIC_ASSERT(mAlternativeDataType.IsEmpty()); + + mAlternativeDataType.Assign(aAltDataType); + } + + const nsCString& GetAlternativeDataType() { + if (mWrappedResponse) { + return mWrappedResponse->GetAlternativeDataType(); + } + + return mAlternativeDataType; + } + + void SetAlternativeBody(nsIInputStream* aAlternativeBody) { + if (mWrappedResponse) { + return mWrappedResponse->SetAlternativeBody(aAlternativeBody); + } + // A request's body may not be reset once set. + MOZ_DIAGNOSTIC_ASSERT(!mAlternativeBody); + + mAlternativeBody = aAlternativeBody; + } + + already_AddRefed<nsIInputStream> TakeAlternativeBody() { + if (mWrappedResponse) { + return mWrappedResponse->TakeAlternativeBody(); + } + + if (!mAlternativeBody) { + return nullptr; + } + + // cleanup the non-alternative body here. + // Once alternative data is used, the real body is no need anymore. + mBody = nullptr; + mBodySize = UNKNOWN_BODY_SIZE; + return mAlternativeBody.forget(); + } + + void SetCacheInfoChannel( + const nsMainThreadPtrHandle<nsICacheInfoChannel>& aCacheInfoChannel) { + if (mWrappedResponse) { + return mWrappedResponse->SetCacheInfoChannel(aCacheInfoChannel); + } + MOZ_ASSERT(!mCacheInfoChannel); + mCacheInfoChannel = aCacheInfoChannel; + } + + nsMainThreadPtrHandle<nsICacheInfoChannel> TakeCacheInfoChannel() { + if (mWrappedResponse) { + return mWrappedResponse->TakeCacheInfoChannel(); + } + nsMainThreadPtrHandle<nsICacheInfoChannel> rtn = mCacheInfoChannel; + mCacheInfoChannel = nullptr; + return rtn; + } + + bool HasCacheInfoChannel() const { + if (mWrappedResponse) { + return !!mWrappedResponse->HasCacheInfoChannel(); + } + return !!mCacheInfoChannel; + } + + void InitChannelInfo(nsIChannel* aChannel) { + mChannelInfo.InitFromChannel(aChannel); + } + + void InitChannelInfo(const mozilla::ipc::IPCChannelInfo& aChannelInfo) { + mChannelInfo.InitFromIPCChannelInfo(aChannelInfo); + } + + void InitChannelInfo(const ChannelInfo& aChannelInfo) { + mChannelInfo = aChannelInfo; + } + + const ChannelInfo& GetChannelInfo() const { return mChannelInfo; } + + const UniquePtr<mozilla::ipc::PrincipalInfo>& GetPrincipalInfo() const { + return mPrincipalInfo; + } + + bool IsRedirected() const { return mURLList.Length() > 1; } + + nsresult GetErrorCode() const { return mErrorCode; } + + // Takes ownership of the principal info. + void SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo); + + LoadTainting GetTainting() const; + + already_AddRefed<InternalResponse> Unfiltered(); + + private: + ~InternalResponse(); + + explicit InternalResponse(const InternalResponse& aOther) = delete; + InternalResponse& operator=(const InternalResponse&) = delete; + + // Returns an instance of InternalResponse which is a copy of this + // InternalResponse, except headers, body and wrapped response (if any) which + // are left uninitialized. Used for cloning and filtering. + already_AddRefed<InternalResponse> CreateIncompleteCopy(); + + ResponseType mType; + // A response has an associated url list (a list of zero or more fetch URLs). + // Unless stated otherwise, it is the empty list. The current url is the last + // element in mURLlist + nsTArray<nsCString> mURLList; + const uint16_t mStatus; + const nsCString mStatusText; + RefPtr<InternalHeaders> mHeaders; + nsCOMPtr<nsIInputStream> mBody; + nsCString mBodyBlobURISpec; + nsString mBodyLocalPath; + int64_t mBodySize; + // It's used to passed to the CacheResponse to generate padding size. Once, we + // generate the padding size for resposne, we don't need it anymore. + Maybe<uint32_t> mPaddingInfo; + int64_t mPaddingSize; + nsresult mErrorCode; + RequestCredentials mCredentialsMode; + + // For alternative data such as JS Bytecode cached in the HTTP cache. + nsCString mAlternativeDataType; + nsCOMPtr<nsIInputStream> mAlternativeBody; + nsMainThreadPtrHandle<nsICacheInfoChannel> mCacheInfoChannel; + + public: + static const int64_t UNKNOWN_BODY_SIZE = -1; + static const int64_t UNKNOWN_PADDING_SIZE = -1; + + private: + ChannelInfo mChannelInfo; + UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo; + + // For filtered responses. + // Cache, and SW interception should always serialize/access the underlying + // unfiltered headers and when deserializing, create an InternalResponse + // with the unfiltered headers followed by wrapping it. + RefPtr<InternalResponse> mWrappedResponse; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_InternalResponse_h |