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 "nsIInputStream.h" 11 #include "nsISupportsImpl.h" 12 13 #include "mozilla/dom/ResponseBinding.h" 14 #include "mozilla/dom/ChannelInfo.h" 15 #include "mozilla/UniquePtr.h" 16 17 namespace mozilla { 18 namespace ipc { 19 class PrincipalInfo; 20 class AutoIPCStream; 21 } // namespace ipc 22 23 namespace dom { 24 25 class InternalHeaders; 26 class IPCInternalResponse; 27 28 class InternalResponse final 29 { 30 friend class FetchDriver; 31 32 public: 33 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse) 34 35 InternalResponse(uint16_t aStatus, const nsACString& aStatusText); 36 37 static already_AddRefed<InternalResponse> 38 FromIPC(const IPCInternalResponse& aIPCResponse); 39 40 template<typename M> 41 void 42 ToIPC(IPCInternalResponse* aIPCResponse, 43 M* aManager, 44 UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream); 45 46 already_AddRefed<InternalResponse> Clone(); 47 48 static already_AddRefed<InternalResponse> NetworkError()49 NetworkError() 50 { 51 RefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString()); 52 ErrorResult result; 53 response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result); 54 MOZ_ASSERT(!result.Failed()); 55 response->mType = ResponseType::Error; 56 return response.forget(); 57 } 58 59 already_AddRefed<InternalResponse> 60 OpaqueResponse(); 61 62 already_AddRefed<InternalResponse> 63 OpaqueRedirectResponse(); 64 65 already_AddRefed<InternalResponse> 66 BasicResponse(); 67 68 already_AddRefed<InternalResponse> 69 CORSResponse(); 70 71 ResponseType Type()72 Type() const 73 { 74 MOZ_ASSERT_IF(mType == ResponseType::Error, !mWrappedResponse); 75 MOZ_ASSERT_IF(mType == ResponseType::Default, !mWrappedResponse); 76 MOZ_ASSERT_IF(mType == ResponseType::Basic, mWrappedResponse); 77 MOZ_ASSERT_IF(mType == ResponseType::Cors, mWrappedResponse); 78 MOZ_ASSERT_IF(mType == ResponseType::Opaque, mWrappedResponse); 79 MOZ_ASSERT_IF(mType == ResponseType::Opaqueredirect, mWrappedResponse); 80 return mType; 81 } 82 83 bool IsError()84 IsError() const 85 { 86 return Type() == ResponseType::Error; 87 } 88 // GetUrl should return last fetch URL in response's url list and null if 89 // response's url list is the empty list. 90 const nsCString& GetURL()91 GetURL() const 92 { 93 // Empty urlList when response is a synthetic response. 94 if (mURLList.IsEmpty()) { 95 return EmptyCString(); 96 } 97 return mURLList.LastElement(); 98 } 99 void GetURLList(nsTArray<nsCString> & aURLList)100 GetURLList(nsTArray<nsCString>& aURLList) const 101 { 102 aURLList.Assign(mURLList); 103 } 104 const nsCString& GetUnfilteredURL()105 GetUnfilteredURL() const 106 { 107 if (mWrappedResponse) { 108 return mWrappedResponse->GetURL(); 109 } 110 return GetURL(); 111 } 112 void GetUnfilteredURLList(nsTArray<nsCString> & aURLList)113 GetUnfilteredURLList(nsTArray<nsCString>& aURLList) const 114 { 115 if (mWrappedResponse) { 116 return mWrappedResponse->GetURLList(aURLList); 117 } 118 119 return GetURLList(aURLList); 120 } 121 122 void SetURLList(const nsTArray<nsCString> & aURLList)123 SetURLList(const nsTArray<nsCString>& aURLList) 124 { 125 mURLList.Assign(aURLList); 126 127 #ifdef DEBUG 128 for(uint32_t i = 0; i < mURLList.Length(); ++i) { 129 MOZ_ASSERT(mURLList[i].Find(NS_LITERAL_CSTRING("#")) == kNotFound); 130 } 131 #endif 132 } 133 134 uint16_t GetStatus()135 GetStatus() const 136 { 137 return mStatus; 138 } 139 140 uint16_t GetUnfilteredStatus()141 GetUnfilteredStatus() const 142 { 143 if (mWrappedResponse) { 144 return mWrappedResponse->GetStatus(); 145 } 146 147 return GetStatus(); 148 } 149 150 const nsCString& GetStatusText()151 GetStatusText() const 152 { 153 return mStatusText; 154 } 155 156 const nsCString& GetUnfilteredStatusText()157 GetUnfilteredStatusText() const 158 { 159 if (mWrappedResponse) { 160 return mWrappedResponse->GetStatusText(); 161 } 162 163 return GetStatusText(); 164 } 165 166 InternalHeaders* Headers()167 Headers() 168 { 169 return mHeaders; 170 } 171 172 InternalHeaders* UnfilteredHeaders()173 UnfilteredHeaders() 174 { 175 if (mWrappedResponse) { 176 return mWrappedResponse->Headers(); 177 }; 178 179 return Headers(); 180 } 181 182 void 183 GetUnfilteredBody(nsIInputStream** aStream, int64_t* aBodySize = nullptr) 184 { 185 if (mWrappedResponse) { 186 MOZ_ASSERT(!mBody); 187 return mWrappedResponse->GetBody(aStream, aBodySize); 188 } 189 nsCOMPtr<nsIInputStream> stream = mBody; 190 stream.forget(aStream); 191 if (aBodySize) { 192 *aBodySize = mBodySize; 193 } 194 } 195 196 void 197 GetBody(nsIInputStream** aStream, int64_t* aBodySize = nullptr) 198 { 199 if (Type() == ResponseType::Opaque || 200 Type() == ResponseType::Opaqueredirect) { 201 *aStream = nullptr; 202 if (aBodySize) { 203 *aBodySize = UNKNOWN_BODY_SIZE; 204 } 205 return; 206 } 207 208 return GetUnfilteredBody(aStream, aBodySize); 209 } 210 211 void SetBody(nsIInputStream * aBody,int64_t aBodySize)212 SetBody(nsIInputStream* aBody, int64_t aBodySize) 213 { 214 if (mWrappedResponse) { 215 return mWrappedResponse->SetBody(aBody, aBodySize); 216 } 217 // A request's body may not be reset once set. 218 MOZ_ASSERT(!mBody); 219 MOZ_ASSERT(mBodySize == UNKNOWN_BODY_SIZE); 220 // Check arguments. 221 MOZ_ASSERT(aBodySize == UNKNOWN_BODY_SIZE || aBodySize >= 0); 222 // If body is not given, then size must be unknown. 223 MOZ_ASSERT_IF(!aBody, aBodySize == UNKNOWN_BODY_SIZE); 224 225 mBody = aBody; 226 mBodySize = aBodySize; 227 } 228 229 void InitChannelInfo(nsIChannel * aChannel)230 InitChannelInfo(nsIChannel* aChannel) 231 { 232 mChannelInfo.InitFromChannel(aChannel); 233 } 234 235 void InitChannelInfo(const mozilla::ipc::IPCChannelInfo & aChannelInfo)236 InitChannelInfo(const mozilla::ipc::IPCChannelInfo& aChannelInfo) 237 { 238 mChannelInfo.InitFromIPCChannelInfo(aChannelInfo); 239 } 240 241 void InitChannelInfo(const ChannelInfo & aChannelInfo)242 InitChannelInfo(const ChannelInfo& aChannelInfo) 243 { 244 mChannelInfo = aChannelInfo; 245 } 246 247 const ChannelInfo& GetChannelInfo()248 GetChannelInfo() const 249 { 250 return mChannelInfo; 251 } 252 253 const UniquePtr<mozilla::ipc::PrincipalInfo>& GetPrincipalInfo()254 GetPrincipalInfo() const 255 { 256 return mPrincipalInfo; 257 } 258 259 bool IsRedirected()260 IsRedirected() const 261 { 262 return mURLList.Length() > 1; 263 } 264 265 // Takes ownership of the principal info. 266 void 267 SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo); 268 269 LoadTainting 270 GetTainting() const; 271 272 already_AddRefed<InternalResponse> 273 Unfiltered(); 274 275 private: 276 ~InternalResponse(); 277 278 explicit InternalResponse(const InternalResponse& aOther) = delete; 279 InternalResponse& operator=(const InternalResponse&) = delete; 280 281 // Returns an instance of InternalResponse which is a copy of this 282 // InternalResponse, except headers, body and wrapped response (if any) which 283 // are left uninitialized. Used for cloning and filtering. 284 already_AddRefed<InternalResponse> CreateIncompleteCopy(); 285 286 ResponseType mType; 287 nsCString mTerminationReason; 288 // A response has an associated url list (a list of zero or more fetch URLs). 289 // Unless stated otherwise, it is the empty list. The current url is the last 290 // element in mURLlist 291 nsTArray<nsCString> mURLList; 292 const uint16_t mStatus; 293 const nsCString mStatusText; 294 RefPtr<InternalHeaders> mHeaders; 295 nsCOMPtr<nsIInputStream> mBody; 296 int64_t mBodySize; 297 public: 298 static const int64_t UNKNOWN_BODY_SIZE = -1; 299 private: 300 ChannelInfo mChannelInfo; 301 UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo; 302 303 // For filtered responses. 304 // Cache, and SW interception should always serialize/access the underlying 305 // unfiltered headers and when deserializing, create an InternalResponse 306 // with the unfiltered headers followed by wrapping it. 307 RefPtr<InternalResponse> mWrappedResponse; 308 }; 309 310 } // namespace dom 311 } // namespace mozilla 312 313 #endif // mozilla_dom_InternalResponse_h 314