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/. */
7 #ifndef mozilla_dom_InternalResponse_h
8 #define mozilla_dom_InternalResponse_h
10 #include "mozilla/dom/FetchTypes.h"
11 #include "nsIInputStream.h"
12 #include "nsICacheInfoChannel.h"
13 #include "nsISupportsImpl.h"
14 #include "nsProxyRelease.h"
16 #include "mozilla/dom/InternalHeaders.h"
17 #include "mozilla/dom/RequestBinding.h"
18 #include "mozilla/dom/ResponseBinding.h"
19 #include "mozilla/dom/ChannelInfo.h"
20 #include "mozilla/dom/SafeRefPtr.h"
21 #include "mozilla/NotNull.h"
22 #include "mozilla/UniquePtr.h"
26 class PBackgroundChild
;
27 class PBackgroundParent
;
33 class ChildToParentInternalResponse
;
34 class InternalHeaders
;
35 class ParentToChildInternalResponse
;
36 class ParentToParentInternalResponse
;
38 class InternalResponse final
: public AtomicSafeRefCounted
<InternalResponse
> {
39 friend class FetchDriver
;
42 MOZ_DECLARE_REFCOUNTED_TYPENAME(InternalResponse
)
45 uint16_t aStatus
, const nsACString
& aStatusText
,
46 RequestCredentials aCredentialsMode
= RequestCredentials::Omit
);
48 static SafeRefPtr
<InternalResponse
> FromIPC(
49 const ParentToChildInternalResponse
& aIPCResponse
);
51 static SafeRefPtr
<InternalResponse
> FromIPC(
52 const ParentToParentInternalResponse
& aIPCResponse
);
54 void ToChildToParentInternalResponse(
55 ChildToParentInternalResponse
* aIPCResponse
,
56 mozilla::ipc::PBackgroundChild
* aManager
);
58 ParentToParentInternalResponse
ToParentToParentInternalResponse();
60 ParentToChildInternalResponse
ToParentToChildInternalResponse(
61 NotNull
<mozilla::ipc::PBackgroundParent
*> aBackgroundParent
);
65 eDontCloneInputStream
,
68 SafeRefPtr
<InternalResponse
> Clone(CloneType aCloneType
);
70 static SafeRefPtr
<InternalResponse
> NetworkError(nsresult aRv
) {
71 MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(aRv
));
72 SafeRefPtr
<InternalResponse
> response
=
73 MakeSafeRefPtr
<InternalResponse
>(0, ""_ns
);
75 response
->Headers()->SetGuard(HeadersGuardEnum::Immutable
, result
);
76 MOZ_ASSERT(!result
.Failed());
77 response
->mType
= ResponseType::Error
;
78 response
->mErrorCode
= aRv
;
82 SafeRefPtr
<InternalResponse
> OpaqueResponse();
84 SafeRefPtr
<InternalResponse
> OpaqueRedirectResponse();
86 SafeRefPtr
<InternalResponse
> BasicResponse();
88 SafeRefPtr
<InternalResponse
> CORSResponse();
90 ResponseType
Type() const {
91 MOZ_ASSERT_IF(mType
== ResponseType::Error
, !mWrappedResponse
);
92 MOZ_ASSERT_IF(mType
== ResponseType::Default
, !mWrappedResponse
);
93 MOZ_ASSERT_IF(mType
== ResponseType::Basic
, mWrappedResponse
);
94 MOZ_ASSERT_IF(mType
== ResponseType::Cors
, mWrappedResponse
);
95 MOZ_ASSERT_IF(mType
== ResponseType::Opaque
, mWrappedResponse
);
96 MOZ_ASSERT_IF(mType
== ResponseType::Opaqueredirect
, mWrappedResponse
);
100 bool IsError() const { return Type() == ResponseType::Error
; }
101 // GetUrl should return last fetch URL in response's url list and null if
102 // response's url list is the empty list.
103 const nsCString
& GetURL() const {
104 // Empty urlList when response is a synthetic response.
105 if (mURLList
.IsEmpty()) {
106 return EmptyCString();
108 return mURLList
.LastElement();
110 void GetURLList(nsTArray
<nsCString
>& aURLList
) const {
111 aURLList
.Assign(mURLList
);
113 const nsCString
& GetUnfilteredURL() const {
114 if (mWrappedResponse
) {
115 return mWrappedResponse
->GetURL();
119 void GetUnfilteredURLList(nsTArray
<nsCString
>& aURLList
) const {
120 if (mWrappedResponse
) {
121 return mWrappedResponse
->GetURLList(aURLList
);
124 return GetURLList(aURLList
);
127 nsTArray
<nsCString
> GetUnfilteredURLList() const {
128 nsTArray
<nsCString
> list
;
129 GetUnfilteredURLList(list
);
133 void SetURLList(const nsTArray
<nsCString
>& aURLList
) {
134 mURLList
.Assign(aURLList
);
137 for (uint32_t i
= 0; i
< mURLList
.Length(); ++i
) {
138 MOZ_ASSERT(mURLList
[i
].Find("#"_ns
) == kNotFound
);
143 uint16_t GetStatus() const { return mStatus
; }
145 uint16_t GetUnfilteredStatus() const {
146 if (mWrappedResponse
) {
147 return mWrappedResponse
->GetStatus();
153 const nsCString
& GetStatusText() const { return mStatusText
; }
155 const nsCString
& GetUnfilteredStatusText() const {
156 if (mWrappedResponse
) {
157 return mWrappedResponse
->GetStatusText();
160 return GetStatusText();
163 InternalHeaders
* Headers() { return mHeaders
; }
165 InternalHeaders
* UnfilteredHeaders() {
166 if (mWrappedResponse
) {
167 return mWrappedResponse
->Headers();
173 void GetUnfilteredBody(nsIInputStream
** aStream
,
174 int64_t* aBodySize
= nullptr) {
175 if (mWrappedResponse
) {
177 return mWrappedResponse
->GetBody(aStream
, aBodySize
);
179 nsCOMPtr
<nsIInputStream
> stream
= mBody
;
180 stream
.forget(aStream
);
182 *aBodySize
= mBodySize
;
186 void GetBody(nsIInputStream
** aStream
, int64_t* aBodySize
= nullptr) {
187 if (Type() == ResponseType::Opaque
||
188 Type() == ResponseType::Opaqueredirect
) {
191 *aBodySize
= UNKNOWN_BODY_SIZE
;
196 GetUnfilteredBody(aStream
, aBodySize
);
199 void SetBodyBlobURISpec(nsACString
& aBlobURISpec
) {
200 mBodyBlobURISpec
= aBlobURISpec
;
203 const nsACString
& BodyBlobURISpec() const {
204 if (mWrappedResponse
) {
205 return mWrappedResponse
->BodyBlobURISpec();
207 return mBodyBlobURISpec
;
210 void SetBodyLocalPath(nsAString
& aLocalPath
) { mBodyLocalPath
= aLocalPath
; }
212 const nsAString
& BodyLocalPath() const {
213 if (mWrappedResponse
) {
214 return mWrappedResponse
->BodyLocalPath();
216 return mBodyLocalPath
;
219 void SetBody(nsIInputStream
* aBody
, int64_t aBodySize
) {
220 if (mWrappedResponse
) {
221 return mWrappedResponse
->SetBody(aBody
, aBodySize
);
223 // A request's body may not be reset once set.
225 MOZ_ASSERT(mBodySize
== UNKNOWN_BODY_SIZE
);
227 MOZ_ASSERT(aBodySize
== UNKNOWN_BODY_SIZE
|| aBodySize
>= 0);
228 // If body is not given, then size must be unknown.
229 MOZ_ASSERT_IF(!aBody
, aBodySize
== UNKNOWN_BODY_SIZE
);
232 mBodySize
= aBodySize
;
235 uint32_t GetPaddingInfo();
237 nsresult
GeneratePaddingInfo();
239 int64_t GetPaddingSize();
241 void SetPaddingSize(int64_t aPaddingSize
);
243 void SetAlternativeDataType(const nsACString
& aAltDataType
) {
244 if (mWrappedResponse
) {
245 return mWrappedResponse
->SetAlternativeDataType(aAltDataType
);
248 MOZ_DIAGNOSTIC_ASSERT(mAlternativeDataType
.IsEmpty());
250 mAlternativeDataType
.Assign(aAltDataType
);
253 const nsCString
& GetAlternativeDataType() {
254 if (mWrappedResponse
) {
255 return mWrappedResponse
->GetAlternativeDataType();
258 return mAlternativeDataType
;
261 void SetAlternativeBody(nsIInputStream
* aAlternativeBody
) {
262 if (mWrappedResponse
) {
263 return mWrappedResponse
->SetAlternativeBody(aAlternativeBody
);
265 // A request's body may not be reset once set.
266 MOZ_DIAGNOSTIC_ASSERT(!mAlternativeBody
);
268 mAlternativeBody
= aAlternativeBody
;
271 already_AddRefed
<nsIInputStream
> TakeAlternativeBody() {
272 if (mWrappedResponse
) {
273 return mWrappedResponse
->TakeAlternativeBody();
276 if (!mAlternativeBody
) {
280 // cleanup the non-alternative body here.
281 // Once alternative data is used, the real body is no need anymore.
283 mBodySize
= UNKNOWN_BODY_SIZE
;
284 return mAlternativeBody
.forget();
287 void SetCacheInfoChannel(
288 const nsMainThreadPtrHandle
<nsICacheInfoChannel
>& aCacheInfoChannel
) {
289 if (mWrappedResponse
) {
290 return mWrappedResponse
->SetCacheInfoChannel(aCacheInfoChannel
);
292 MOZ_ASSERT(!mCacheInfoChannel
);
293 mCacheInfoChannel
= aCacheInfoChannel
;
296 nsMainThreadPtrHandle
<nsICacheInfoChannel
> TakeCacheInfoChannel() {
297 if (mWrappedResponse
) {
298 return mWrappedResponse
->TakeCacheInfoChannel();
300 nsMainThreadPtrHandle
<nsICacheInfoChannel
> rtn
= mCacheInfoChannel
;
301 mCacheInfoChannel
= nullptr;
305 bool HasCacheInfoChannel() const {
306 if (mWrappedResponse
) {
307 return !!mWrappedResponse
->HasCacheInfoChannel();
309 return !!mCacheInfoChannel
;
312 bool HasBeenCloned() const { return mCloned
; }
314 void SetSerializeAsLazy(bool aAllow
) { mSerializeAsLazy
= aAllow
; }
315 bool CanSerializeAsLazy() const { return mSerializeAsLazy
; }
317 void InitChannelInfo(nsIChannel
* aChannel
) {
318 mChannelInfo
.InitFromChannel(aChannel
);
321 void InitChannelInfo(nsITransportSecurityInfo
* aSecurityInfo
) {
322 mChannelInfo
.InitFromTransportSecurityInfo(aSecurityInfo
);
325 void InitChannelInfo(const ChannelInfo
& aChannelInfo
) {
326 mChannelInfo
= aChannelInfo
;
329 const ChannelInfo
& GetChannelInfo() const { return mChannelInfo
; }
331 const UniquePtr
<mozilla::ipc::PrincipalInfo
>& GetPrincipalInfo() const {
332 return mPrincipalInfo
;
335 bool IsRedirected() const { return mURLList
.Length() > 1; }
337 nsresult
GetErrorCode() const { return mErrorCode
; }
339 // Takes ownership of the principal info.
340 void SetPrincipalInfo(UniquePtr
<mozilla::ipc::PrincipalInfo
> aPrincipalInfo
);
342 LoadTainting
GetTainting() const;
344 SafeRefPtr
<InternalResponse
> Unfiltered();
346 InternalResponseMetadata
GetMetadata();
348 RequestCredentials
GetCredentialsMode() const {
349 if (mWrappedResponse
) {
350 return mWrappedResponse
->GetCredentialsMode();
352 return mCredentialsMode
;
358 explicit InternalResponse(const InternalResponse
& aOther
) = delete;
359 InternalResponse
& operator=(const InternalResponse
&) = delete;
361 // Returns an instance of InternalResponse which is a copy of this
362 // InternalResponse, except headers, body and wrapped response (if any) which
363 // are left uninitialized. Used for cloning and filtering.
364 SafeRefPtr
<InternalResponse
> CreateIncompleteCopy();
366 template <typename T
>
367 static SafeRefPtr
<InternalResponse
> FromIPCTemplate(const T
& aIPCResponse
);
370 // A response has an associated url list (a list of zero or more fetch URLs).
371 // Unless stated otherwise, it is the empty list. The current url is the last
372 // element in mURLlist
373 nsTArray
<nsCString
> mURLList
;
374 const uint16_t mStatus
;
375 const nsCString mStatusText
;
376 RefPtr
<InternalHeaders
> mHeaders
;
377 nsCOMPtr
<nsIInputStream
> mBody
;
378 nsCString mBodyBlobURISpec
;
379 nsString mBodyLocalPath
;
381 // It's used to passed to the CacheResponse to generate padding size. Once, we
382 // generate the padding size for resposne, we don't need it anymore.
383 Maybe
<uint32_t> mPaddingInfo
;
384 int64_t mPaddingSize
;
386 RequestCredentials mCredentialsMode
;
388 // For alternative data such as JS Bytecode cached in the HTTP cache.
389 nsCString mAlternativeDataType
;
390 nsCOMPtr
<nsIInputStream
> mAlternativeBody
;
391 nsMainThreadPtrHandle
<nsICacheInfoChannel
> mCacheInfoChannel
;
393 // boolean to indicate the body/alternativeBody will be serialized as a
394 // RemoteLazyInputStream.
395 bool mSerializeAsLazy
{true};
398 static constexpr int64_t UNKNOWN_BODY_SIZE
= -1;
399 static constexpr int64_t UNKNOWN_PADDING_SIZE
= -1;
402 ChannelInfo mChannelInfo
;
403 UniquePtr
<mozilla::ipc::PrincipalInfo
> mPrincipalInfo
;
405 // For filtered responses.
406 // Cache, and SW interception should always serialize/access the underlying
407 // unfiltered headers and when deserializing, create an InternalResponse
408 // with the unfiltered headers followed by wrapping it.
409 SafeRefPtr
<InternalResponse
> mWrappedResponse
;
412 ParentToChildInternalResponse
ToParentToChild(
413 const ParentToParentInternalResponse
& aResponse
,
414 NotNull
<mozilla::ipc::PBackgroundParent
*> aBackgroundParent
);
417 } // namespace mozilla
419 #endif // mozilla_dom_InternalResponse_h