InternalResponse.h (12272B)
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/. */ 6 7 #ifndef mozilla_dom_InternalResponse_h 8 #define mozilla_dom_InternalResponse_h 9 10 #include "mozilla/UniquePtr.h" 11 #include "mozilla/dom/ChannelInfo.h" 12 #include "mozilla/dom/FetchTypes.h" 13 #include "mozilla/dom/InternalHeaders.h" 14 #include "mozilla/dom/RequestBinding.h" 15 #include "mozilla/dom/ResponseBinding.h" 16 #include "mozilla/dom/SafeRefPtr.h" 17 #include "nsICacheInfoChannel.h" 18 #include "nsIInputStream.h" 19 #include "nsISupportsImpl.h" 20 #include "nsProxyRelease.h" 21 22 namespace mozilla { 23 namespace ipc { 24 class PBackgroundChild; 25 class PBackgroundParent; 26 class PrincipalInfo; 27 } // namespace ipc 28 29 namespace dom { 30 31 class ChildToParentInternalResponse; 32 class InternalHeaders; 33 class ParentToChildInternalResponse; 34 class ParentToParentInternalResponse; 35 36 class InternalResponse final : public AtomicSafeRefCounted<InternalResponse> { 37 friend class FetchDriver; 38 39 public: 40 MOZ_DECLARE_REFCOUNTED_TYPENAME(InternalResponse) 41 42 InternalResponse( 43 uint16_t aStatus, const nsACString& aStatusText, 44 RequestCredentials aCredentialsMode = RequestCredentials::Omit); 45 46 static SafeRefPtr<InternalResponse> FromIPC( 47 const ParentToChildInternalResponse& aIPCResponse); 48 49 static SafeRefPtr<InternalResponse> FromIPC( 50 const ParentToParentInternalResponse& aIPCResponse); 51 52 void ToChildToParentInternalResponse( 53 ChildToParentInternalResponse* aIPCResponse, 54 mozilla::ipc::PBackgroundChild* aManager); 55 56 ParentToParentInternalResponse ToParentToParentInternalResponse(); 57 58 ParentToChildInternalResponse ToParentToChildInternalResponse(); 59 60 enum CloneType { 61 eCloneInputStream, 62 eDontCloneInputStream, 63 }; 64 65 SafeRefPtr<InternalResponse> Clone(CloneType aCloneType); 66 67 static SafeRefPtr<InternalResponse> NetworkError(nsresult aRv) { 68 MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(aRv)); 69 SafeRefPtr<InternalResponse> response = 70 MakeSafeRefPtr<InternalResponse>(0, ""_ns); 71 ErrorResult result; 72 response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result); 73 MOZ_ASSERT(!result.Failed()); 74 response->mType = ResponseType::Error; 75 response->mErrorCode = aRv; 76 return response; 77 } 78 79 SafeRefPtr<InternalResponse> OpaqueResponse(); 80 81 SafeRefPtr<InternalResponse> OpaqueRedirectResponse(); 82 83 SafeRefPtr<InternalResponse> BasicResponse(); 84 85 SafeRefPtr<InternalResponse> CORSResponse(); 86 87 ResponseType Type() const { 88 MOZ_ASSERT_IF(mType == ResponseType::Error, !mWrappedResponse); 89 MOZ_ASSERT_IF(mType == ResponseType::Default, !mWrappedResponse); 90 MOZ_ASSERT_IF(mType == ResponseType::Basic, mWrappedResponse); 91 MOZ_ASSERT_IF(mType == ResponseType::Cors, mWrappedResponse); 92 MOZ_ASSERT_IF(mType == ResponseType::Opaque, mWrappedResponse); 93 MOZ_ASSERT_IF(mType == ResponseType::Opaqueredirect, mWrappedResponse); 94 return mType; 95 } 96 97 bool IsError() const { return Type() == ResponseType::Error; } 98 // GetUrl should return last fetch URL in response's url list and null if 99 // response's url list is the empty list. 100 const nsCString& GetURL() const { 101 // Empty urlList when response is a synthetic response. 102 if (mURLList.IsEmpty()) { 103 return EmptyCString(); 104 } 105 return mURLList.LastElement(); 106 } 107 void GetURLList(nsTArray<nsCString>& aURLList) const { 108 aURLList.Assign(mURLList); 109 } 110 const nsCString& GetUnfilteredURL() const { 111 if (mWrappedResponse) { 112 return mWrappedResponse->GetURL(); 113 } 114 return GetURL(); 115 } 116 void GetUnfilteredURLList(nsTArray<nsCString>& aURLList) const { 117 if (mWrappedResponse) { 118 return mWrappedResponse->GetURLList(aURLList); 119 } 120 121 return GetURLList(aURLList); 122 } 123 124 nsTArray<nsCString> GetUnfilteredURLList() const { 125 nsTArray<nsCString> list; 126 GetUnfilteredURLList(list); 127 return list; 128 } 129 130 void SetURLList(const nsTArray<nsCString>& aURLList) { 131 mURLList.Assign(aURLList); 132 133 #ifdef DEBUG 134 for (uint32_t i = 0; i < mURLList.Length(); ++i) { 135 MOZ_ASSERT(mURLList[i].Find("#"_ns) == kNotFound); 136 } 137 #endif 138 } 139 140 uint16_t GetStatus() const { return mStatus; } 141 142 uint16_t GetUnfilteredStatus() const { 143 if (mWrappedResponse) { 144 return mWrappedResponse->GetStatus(); 145 } 146 147 return GetStatus(); 148 } 149 150 const nsCString& GetStatusText() const { return mStatusText; } 151 152 const nsCString& GetUnfilteredStatusText() const { 153 if (mWrappedResponse) { 154 return mWrappedResponse->GetStatusText(); 155 } 156 157 return GetStatusText(); 158 } 159 160 InternalHeaders* Headers() { return mHeaders; } 161 162 InternalHeaders* UnfilteredHeaders() { 163 if (mWrappedResponse) { 164 return mWrappedResponse->Headers(); 165 }; 166 167 return Headers(); 168 } 169 170 void GetUnfilteredBody(nsIInputStream** aStream, 171 int64_t* aBodySize = nullptr) { 172 if (mWrappedResponse) { 173 MOZ_ASSERT(!mBody); 174 return mWrappedResponse->GetBody(aStream, aBodySize); 175 } 176 nsCOMPtr<nsIInputStream> stream = mBody; 177 stream.forget(aStream); 178 if (aBodySize) { 179 *aBodySize = mBodySize; 180 } 181 } 182 183 void GetBody(nsIInputStream** aStream, int64_t* aBodySize = nullptr) { 184 if (Type() == ResponseType::Opaque || 185 Type() == ResponseType::Opaqueredirect) { 186 *aStream = nullptr; 187 if (aBodySize) { 188 *aBodySize = UNKNOWN_BODY_SIZE; 189 } 190 return; 191 } 192 193 GetUnfilteredBody(aStream, aBodySize); 194 } 195 196 void SetBodyBlobURISpec(nsACString& aBlobURISpec) { 197 mBodyBlobURISpec = aBlobURISpec; 198 } 199 200 const nsACString& BodyBlobURISpec() const { 201 if (mWrappedResponse) { 202 return mWrappedResponse->BodyBlobURISpec(); 203 } 204 return mBodyBlobURISpec; 205 } 206 207 void SetBodyLocalPath(nsAString& aLocalPath) { mBodyLocalPath = aLocalPath; } 208 209 const nsAString& BodyLocalPath() const { 210 if (mWrappedResponse) { 211 return mWrappedResponse->BodyLocalPath(); 212 } 213 return mBodyLocalPath; 214 } 215 216 void SetBody(nsIInputStream* aBody, int64_t aBodySize) { 217 if (mWrappedResponse) { 218 return mWrappedResponse->SetBody(aBody, aBodySize); 219 } 220 // A request's body may not be reset once set. 221 MOZ_ASSERT(!mBody); 222 MOZ_ASSERT(mBodySize == UNKNOWN_BODY_SIZE); 223 // Check arguments. 224 MOZ_ASSERT(aBodySize == UNKNOWN_BODY_SIZE || aBodySize >= 0); 225 // If body is not given, then size must be unknown. 226 MOZ_ASSERT_IF(!aBody, aBodySize == UNKNOWN_BODY_SIZE); 227 228 mBody = aBody; 229 mBodySize = aBodySize; 230 } 231 232 uint32_t GetPaddingInfo(); 233 234 nsresult GeneratePaddingInfo(); 235 236 int64_t GetPaddingSize(); 237 238 void SetPaddingSize(int64_t aPaddingSize); 239 240 void SetAlternativeDataType(const nsACString& aAltDataType) { 241 if (mWrappedResponse) { 242 return mWrappedResponse->SetAlternativeDataType(aAltDataType); 243 } 244 245 MOZ_DIAGNOSTIC_ASSERT(mAlternativeDataType.IsEmpty()); 246 247 mAlternativeDataType.Assign(aAltDataType); 248 } 249 250 const nsCString& GetAlternativeDataType() { 251 if (mWrappedResponse) { 252 return mWrappedResponse->GetAlternativeDataType(); 253 } 254 255 return mAlternativeDataType; 256 } 257 258 void SetAlternativeBody(nsIInputStream* aAlternativeBody) { 259 if (mWrappedResponse) { 260 return mWrappedResponse->SetAlternativeBody(aAlternativeBody); 261 } 262 // A request's body may not be reset once set. 263 MOZ_DIAGNOSTIC_ASSERT(!mAlternativeBody); 264 265 mAlternativeBody = aAlternativeBody; 266 } 267 268 already_AddRefed<nsIInputStream> TakeAlternativeBody() { 269 if (mWrappedResponse) { 270 return mWrappedResponse->TakeAlternativeBody(); 271 } 272 273 if (!mAlternativeBody) { 274 return nullptr; 275 } 276 277 // cleanup the non-alternative body here. 278 // Once alternative data is used, the real body is no need anymore. 279 mBody = nullptr; 280 mBodySize = UNKNOWN_BODY_SIZE; 281 return mAlternativeBody.forget(); 282 } 283 284 void SetCacheInfoChannel( 285 const nsMainThreadPtrHandle<nsICacheInfoChannel>& aCacheInfoChannel) { 286 if (mWrappedResponse) { 287 return mWrappedResponse->SetCacheInfoChannel(aCacheInfoChannel); 288 } 289 MOZ_ASSERT(!mCacheInfoChannel); 290 mCacheInfoChannel = aCacheInfoChannel; 291 } 292 293 nsMainThreadPtrHandle<nsICacheInfoChannel> TakeCacheInfoChannel() { 294 if (mWrappedResponse) { 295 return mWrappedResponse->TakeCacheInfoChannel(); 296 } 297 nsMainThreadPtrHandle<nsICacheInfoChannel> rtn = mCacheInfoChannel; 298 mCacheInfoChannel = nullptr; 299 return rtn; 300 } 301 302 bool HasCacheInfoChannel() const { 303 if (mWrappedResponse) { 304 return !!mWrappedResponse->HasCacheInfoChannel(); 305 } 306 return !!mCacheInfoChannel; 307 } 308 309 bool HasBeenCloned() const { return mCloned; } 310 311 void SetSerializeAsLazy(bool aAllow) { mSerializeAsLazy = aAllow; } 312 bool CanSerializeAsLazy() const { return mSerializeAsLazy; } 313 314 void InitChannelInfo(nsIChannel* aChannel) { 315 mChannelInfo.InitFromChannel(aChannel); 316 } 317 318 void InitChannelInfo(nsITransportSecurityInfo* aSecurityInfo) { 319 mChannelInfo.InitFromTransportSecurityInfo(aSecurityInfo); 320 } 321 322 void InitChannelInfo(const ChannelInfo& aChannelInfo) { 323 mChannelInfo = aChannelInfo; 324 } 325 326 const ChannelInfo& GetChannelInfo() const { return mChannelInfo; } 327 328 const UniquePtr<mozilla::ipc::PrincipalInfo>& GetPrincipalInfo() const { 329 return mPrincipalInfo; 330 } 331 332 bool IsRedirected() const { return mURLList.Length() > 1; } 333 334 nsresult GetErrorCode() const { return mErrorCode; } 335 336 // Takes ownership of the principal info. 337 void SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo); 338 339 LoadTainting GetTainting() const; 340 341 SafeRefPtr<InternalResponse> Unfiltered(); 342 343 InternalResponseMetadata GetMetadata(); 344 345 RequestCredentials GetCredentialsMode() const { 346 if (mWrappedResponse) { 347 return mWrappedResponse->GetCredentialsMode(); 348 } 349 return mCredentialsMode; 350 } 351 352 ~InternalResponse(); 353 354 private: 355 explicit InternalResponse(const InternalResponse& aOther) = delete; 356 InternalResponse& operator=(const InternalResponse&) = delete; 357 358 // Returns an instance of InternalResponse which is a copy of this 359 // InternalResponse, except headers, body and wrapped response (if any) which 360 // are left uninitialized. Used for cloning and filtering. 361 SafeRefPtr<InternalResponse> CreateIncompleteCopy(); 362 363 template <typename T> 364 static SafeRefPtr<InternalResponse> FromIPCTemplate(const T& aIPCResponse); 365 366 ResponseType mType; 367 // A response has an associated url list (a list of zero or more fetch URLs). 368 // Unless stated otherwise, it is the empty list. The current url is the last 369 // element in mURLlist 370 nsTArray<nsCString> mURLList; 371 const uint16_t mStatus; 372 const nsCString mStatusText; 373 RefPtr<InternalHeaders> mHeaders; 374 nsCOMPtr<nsIInputStream> mBody; 375 nsCString mBodyBlobURISpec; 376 nsString mBodyLocalPath; 377 int64_t mBodySize; 378 // It's used to passed to the CacheResponse to generate padding size. Once, we 379 // generate the padding size for resposne, we don't need it anymore. 380 Maybe<uint32_t> mPaddingInfo; 381 int64_t mPaddingSize; 382 nsresult mErrorCode; 383 RequestCredentials mCredentialsMode; 384 385 // For alternative data such as JS Bytecode cached in the HTTP cache. 386 nsCString mAlternativeDataType; 387 nsCOMPtr<nsIInputStream> mAlternativeBody; 388 nsMainThreadPtrHandle<nsICacheInfoChannel> mCacheInfoChannel; 389 bool mCloned; 390 // boolean to indicate the body/alternativeBody will be serialized as a 391 // RemoteLazyInputStream. 392 bool mSerializeAsLazy{true}; 393 394 public: 395 static constexpr int64_t UNKNOWN_BODY_SIZE = -1; 396 static constexpr int64_t UNKNOWN_PADDING_SIZE = -1; 397 398 private: 399 ChannelInfo mChannelInfo; 400 UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo; 401 402 // For filtered responses. 403 // Cache, and SW interception should always serialize/access the underlying 404 // unfiltered headers and when deserializing, create an InternalResponse 405 // with the unfiltered headers followed by wrapping it. 406 SafeRefPtr<InternalResponse> mWrappedResponse; 407 }; 408 409 ParentToChildInternalResponse ToParentToChild( 410 const ParentToParentInternalResponse& aResponse); 411 412 } // namespace dom 413 } // namespace mozilla 414 415 #endif // mozilla_dom_InternalResponse_h