Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / fetch / InternalResponse.cpp
blob342a88eeeb9145f9ebb312919d9ea4b22b312ebb
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 #include "InternalResponse.h"
9 #include "mozilla/Assertions.h"
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/dom/FetchTypes.h"
12 #include "mozilla/dom/InternalHeaders.h"
13 #include "mozilla/dom/cache/CacheTypes.h"
14 #include "mozilla/ipc/PBackgroundSharedTypes.h"
15 #include "mozilla/ipc/IPCStreamUtils.h"
16 #include "mozilla/RandomNum.h"
17 #include "mozilla/RemoteLazyInputStreamStorage.h"
18 #include "nsIRandomGenerator.h"
19 #include "nsStreamUtils.h"
21 namespace mozilla::dom {
23 namespace {
25 // Const variable for generate padding size
26 // XXX This will be tweaked to something more meaningful in Bug 1383656.
27 const uint32_t kMaxRandomNumber = 102400;
29 nsCOMPtr<nsIInputStream> TakeStreamFromStorage(
30 const BodyStreamVariant& aVariant, int64_t aBodySize) {
31 MOZ_ASSERT(aVariant.type() == BodyStreamVariant::TParentToParentStream);
32 const auto& uuid = aVariant.get_ParentToParentStream().uuid();
34 auto storageOrErr = RemoteLazyInputStreamStorage::Get();
35 MOZ_ASSERT(storageOrErr.isOk());
36 auto storage = storageOrErr.unwrap();
37 auto stream = storage->ForgetStream(uuid);
38 MOZ_ASSERT(stream);
40 return stream;
43 } // namespace
45 InternalResponse::InternalResponse(uint16_t aStatus,
46 const nsACString& aStatusText,
47 RequestCredentials aCredentialsMode)
48 : mType(ResponseType::Default),
49 mStatus(aStatus),
50 mStatusText(aStatusText),
51 mHeaders(new InternalHeaders(HeadersGuardEnum::Response)),
52 mBodySize(UNKNOWN_BODY_SIZE),
53 mPaddingSize(UNKNOWN_PADDING_SIZE),
54 mErrorCode(NS_OK),
55 mCredentialsMode(aCredentialsMode) {}
57 /* static */ RefPtr<InternalResponse> InternalResponse::FromIPC(
58 const IPCInternalResponse& aIPCResponse) {
59 if (aIPCResponse.type() == ResponseType::Error) {
60 return InternalResponse::NetworkError(aIPCResponse.errorCode());
63 RefPtr<InternalResponse> response =
64 new InternalResponse(aIPCResponse.status(), aIPCResponse.statusText());
66 response->SetURLList(aIPCResponse.urlList());
67 response->mHeaders =
68 new InternalHeaders(aIPCResponse.headers(), aIPCResponse.headersGuard());
70 if (aIPCResponse.body()) {
71 auto bodySize = aIPCResponse.bodySize();
72 nsCOMPtr<nsIInputStream> body =
73 TakeStreamFromStorage(*aIPCResponse.body(), bodySize);
74 response->SetBody(body, bodySize);
77 response->SetAlternativeDataType(aIPCResponse.alternativeDataType());
79 if (aIPCResponse.alternativeBody()) {
80 nsCOMPtr<nsIInputStream> alternativeBody = TakeStreamFromStorage(
81 *aIPCResponse.alternativeBody(), UNKNOWN_BODY_SIZE);
82 response->SetAlternativeBody(alternativeBody);
85 response->InitChannelInfo(aIPCResponse.channelInfo());
87 if (aIPCResponse.principalInfo()) {
88 response->SetPrincipalInfo(MakeUnique<mozilla::ipc::PrincipalInfo>(
89 aIPCResponse.principalInfo().ref()));
92 switch (aIPCResponse.type()) {
93 case ResponseType::Basic:
94 response = response->BasicResponse();
95 break;
96 case ResponseType::Cors:
97 response = response->CORSResponse();
98 break;
99 case ResponseType::Default:
100 break;
101 case ResponseType::Opaque:
102 response = response->OpaqueResponse();
103 break;
104 case ResponseType::Opaqueredirect:
105 response = response->OpaqueRedirectResponse();
106 break;
107 default:
108 MOZ_CRASH("Unexpected ResponseType!");
111 MOZ_ASSERT(response);
113 return response;
116 InternalResponse::~InternalResponse() = default;
118 void InternalResponse::ToIPC(
119 IPCInternalResponse* aIPCResponse, mozilla::ipc::PBackgroundChild* aManager,
120 UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoBodyStream,
121 UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoAlternativeBodyStream) {
122 nsTArray<HeadersEntry> headers;
123 HeadersGuardEnum headersGuard;
124 UnfilteredHeaders()->ToIPC(headers, headersGuard);
126 Maybe<mozilla::ipc::PrincipalInfo> principalInfo =
127 mPrincipalInfo ? Some(*mPrincipalInfo) : Nothing();
129 // Note: all the arguments are copied rather than moved, which would be more
130 // efficient, because there's no move-friendly constructor generated.
131 *aIPCResponse =
132 IPCInternalResponse(mType, GetUnfilteredURLList(), GetUnfilteredStatus(),
133 GetUnfilteredStatusText(), headersGuard, headers,
134 Nothing(), static_cast<uint64_t>(UNKNOWN_BODY_SIZE),
135 mErrorCode, GetAlternativeDataType(), Nothing(),
136 mChannelInfo.AsIPCChannelInfo(), principalInfo);
138 nsCOMPtr<nsIInputStream> body;
139 int64_t bodySize;
140 GetUnfilteredBody(getter_AddRefs(body), &bodySize);
142 if (body) {
143 aIPCResponse->body().emplace(ChildToParentStream());
144 aIPCResponse->bodySize() = bodySize;
146 aAutoBodyStream.reset(new mozilla::ipc::AutoIPCStream(
147 aIPCResponse->body()->get_ChildToParentStream().stream()));
148 DebugOnly<bool> ok = aAutoBodyStream->Serialize(body, aManager);
149 MOZ_ASSERT(ok);
152 nsCOMPtr<nsIInputStream> alternativeBody = TakeAlternativeBody();
153 if (alternativeBody) {
154 aIPCResponse->alternativeBody().emplace(ChildToParentStream());
156 aAutoAlternativeBodyStream.reset(new mozilla::ipc::AutoIPCStream(
157 aIPCResponse->alternativeBody()->get_ChildToParentStream().stream()));
158 DebugOnly<bool> ok =
159 aAutoAlternativeBodyStream->Serialize(alternativeBody, aManager);
160 MOZ_ASSERT(ok);
164 already_AddRefed<InternalResponse> InternalResponse::Clone(
165 CloneType aCloneType) {
166 RefPtr<InternalResponse> clone = CreateIncompleteCopy();
168 clone->mHeaders = new InternalHeaders(*mHeaders);
170 // Make sure the clone response will have the same padding size.
171 clone->mPaddingInfo = mPaddingInfo;
172 clone->mPaddingSize = mPaddingSize;
174 clone->mCacheInfoChannel = mCacheInfoChannel;
176 if (mWrappedResponse) {
177 clone->mWrappedResponse = mWrappedResponse->Clone(aCloneType);
178 MOZ_ASSERT(!mBody);
179 return clone.forget();
182 if (!mBody || aCloneType == eDontCloneInputStream) {
183 return clone.forget();
186 nsCOMPtr<nsIInputStream> clonedBody;
187 nsCOMPtr<nsIInputStream> replacementBody;
189 nsresult rv = NS_CloneInputStream(mBody, getter_AddRefs(clonedBody),
190 getter_AddRefs(replacementBody));
191 if (NS_WARN_IF(NS_FAILED(rv))) {
192 return nullptr;
195 clone->mBody.swap(clonedBody);
196 if (replacementBody) {
197 mBody.swap(replacementBody);
200 return clone.forget();
203 already_AddRefed<InternalResponse> InternalResponse::BasicResponse() {
204 MOZ_ASSERT(!mWrappedResponse,
205 "Can't BasicResponse a already wrapped response");
206 RefPtr<InternalResponse> basic = CreateIncompleteCopy();
207 basic->mType = ResponseType::Basic;
208 basic->mHeaders = InternalHeaders::BasicHeaders(Headers());
209 basic->mWrappedResponse = this;
210 return basic.forget();
213 already_AddRefed<InternalResponse> InternalResponse::CORSResponse() {
214 MOZ_ASSERT(!mWrappedResponse,
215 "Can't CORSResponse a already wrapped response");
216 RefPtr<InternalResponse> cors = CreateIncompleteCopy();
217 cors->mType = ResponseType::Cors;
218 cors->mHeaders = InternalHeaders::CORSHeaders(Headers(), mCredentialsMode);
219 cors->mWrappedResponse = this;
220 return cors.forget();
223 uint32_t InternalResponse::GetPaddingInfo() {
224 // If it's an opaque response, the paddingInfo should be generated only when
225 // paddingSize is unknown size.
226 // If it's not, the paddingInfo should be nothing and the paddingSize should
227 // be unknown size.
228 MOZ_DIAGNOSTIC_ASSERT(
229 (mType == ResponseType::Opaque && mPaddingSize == UNKNOWN_PADDING_SIZE &&
230 mPaddingInfo.isSome()) ||
231 (mType == ResponseType::Opaque && mPaddingSize != UNKNOWN_PADDING_SIZE &&
232 mPaddingInfo.isNothing()) ||
233 (mType != ResponseType::Opaque && mPaddingSize == UNKNOWN_PADDING_SIZE &&
234 mPaddingInfo.isNothing()));
235 return mPaddingInfo.isSome() ? mPaddingInfo.ref() : 0;
238 nsresult InternalResponse::GeneratePaddingInfo() {
239 MOZ_DIAGNOSTIC_ASSERT(mType == ResponseType::Opaque);
240 MOZ_DIAGNOSTIC_ASSERT(mPaddingSize == UNKNOWN_PADDING_SIZE);
242 // Utilize random generator to generator a random number
243 nsresult rv;
244 uint32_t randomNumber = 0;
245 nsCOMPtr<nsIRandomGenerator> randomGenerator =
246 do_GetService("@mozilla.org/security/random-generator;1", &rv);
247 if (NS_WARN_IF(NS_FAILED(rv))) {
248 Maybe<uint64_t> maybeRandomNum = RandomUint64();
249 if (maybeRandomNum.isSome()) {
250 mPaddingInfo.emplace(uint32_t(maybeRandomNum.value() % kMaxRandomNumber));
251 return NS_OK;
253 return rv;
256 MOZ_DIAGNOSTIC_ASSERT(randomGenerator);
258 uint8_t* buffer;
259 rv = randomGenerator->GenerateRandomBytes(sizeof(randomNumber), &buffer);
260 if (NS_WARN_IF(NS_FAILED(rv))) {
261 Maybe<uint64_t> maybeRandomNum = RandomUint64();
262 if (maybeRandomNum.isSome()) {
263 mPaddingInfo.emplace(uint32_t(maybeRandomNum.value() % kMaxRandomNumber));
264 return NS_OK;
266 return rv;
269 memcpy(&randomNumber, buffer, sizeof(randomNumber));
270 free(buffer);
272 mPaddingInfo.emplace(randomNumber % kMaxRandomNumber);
274 return rv;
277 int64_t InternalResponse::GetPaddingSize() {
278 // We initialize padding size to an unknown size (-1). After cached, we only
279 // pad opaque response. Opaque response's padding size might be unknown before
280 // cached.
281 MOZ_DIAGNOSTIC_ASSERT(mType == ResponseType::Opaque ||
282 mPaddingSize == UNKNOWN_PADDING_SIZE);
283 MOZ_DIAGNOSTIC_ASSERT(mPaddingSize == UNKNOWN_PADDING_SIZE ||
284 mPaddingSize >= 0);
286 return mPaddingSize;
289 void InternalResponse::SetPaddingSize(int64_t aPaddingSize) {
290 // We should only pad the opaque response.
291 MOZ_DIAGNOSTIC_ASSERT(
292 (mType == ResponseType::Opaque) !=
293 (aPaddingSize == InternalResponse::UNKNOWN_PADDING_SIZE));
294 MOZ_DIAGNOSTIC_ASSERT(aPaddingSize == UNKNOWN_PADDING_SIZE ||
295 aPaddingSize >= 0);
297 mPaddingSize = aPaddingSize;
300 void InternalResponse::SetPrincipalInfo(
301 UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo) {
302 mPrincipalInfo = std::move(aPrincipalInfo);
305 LoadTainting InternalResponse::GetTainting() const {
306 switch (mType) {
307 case ResponseType::Cors:
308 return LoadTainting::CORS;
309 case ResponseType::Opaque:
310 return LoadTainting::Opaque;
311 default:
312 return LoadTainting::Basic;
316 already_AddRefed<InternalResponse> InternalResponse::Unfiltered() {
317 RefPtr<InternalResponse> ref = mWrappedResponse;
318 if (!ref) {
319 ref = this;
321 return ref.forget();
324 already_AddRefed<InternalResponse> InternalResponse::OpaqueResponse() {
325 MOZ_ASSERT(!mWrappedResponse,
326 "Can't OpaqueResponse a already wrapped response");
327 RefPtr<InternalResponse> response = new InternalResponse(0, ""_ns);
328 response->mType = ResponseType::Opaque;
329 response->mChannelInfo = mChannelInfo;
330 if (mPrincipalInfo) {
331 response->mPrincipalInfo =
332 MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
334 response->mWrappedResponse = this;
335 return response.forget();
338 already_AddRefed<InternalResponse> InternalResponse::OpaqueRedirectResponse() {
339 MOZ_ASSERT(!mWrappedResponse,
340 "Can't OpaqueRedirectResponse a already wrapped response");
341 MOZ_ASSERT(!mURLList.IsEmpty(),
342 "URLList should not be emtpy for internalResponse");
343 RefPtr<InternalResponse> response = OpaqueResponse();
344 response->mType = ResponseType::Opaqueredirect;
345 response->mURLList = mURLList.Clone();
346 return response.forget();
349 already_AddRefed<InternalResponse> InternalResponse::CreateIncompleteCopy() {
350 RefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
351 copy->mType = mType;
352 copy->mURLList = mURLList.Clone();
353 copy->mChannelInfo = mChannelInfo;
354 if (mPrincipalInfo) {
355 copy->mPrincipalInfo =
356 MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
358 return copy.forget();
361 } // namespace mozilla::dom