/src/mozilla-central/dom/fetch/InternalResponse.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "InternalResponse.h" |
8 | | |
9 | | #include "mozilla/Assertions.h" |
10 | | #include "mozilla/dom/InternalHeaders.h" |
11 | | #include "mozilla/dom/cache/CacheTypes.h" |
12 | | #include "mozilla/ipc/PBackgroundSharedTypes.h" |
13 | | #include "mozilla/ipc/IPCStreamUtils.h" |
14 | | #include "nsIRandomGenerator.h" |
15 | | #include "nsIURI.h" |
16 | | #include "nsStreamUtils.h" |
17 | | |
18 | | namespace mozilla { |
19 | | namespace dom { |
20 | | |
21 | | namespace { |
22 | | |
23 | | // Const variable for generate padding size |
24 | | // XXX This will be tweaked to something more meaningful in Bug 1383656. |
25 | | const uint32_t kMaxRandomNumber = 102400; |
26 | | |
27 | | } // namespace |
28 | | |
29 | | InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText) |
30 | | : mType(ResponseType::Default) |
31 | | , mStatus(aStatus) |
32 | | , mStatusText(aStatusText) |
33 | | , mHeaders(new InternalHeaders(HeadersGuardEnum::Response)) |
34 | | , mBodySize(UNKNOWN_BODY_SIZE) |
35 | | , mPaddingSize(UNKNOWN_PADDING_SIZE) |
36 | | , mErrorCode(NS_OK) |
37 | 0 | { |
38 | 0 | } |
39 | | |
40 | | already_AddRefed<InternalResponse> |
41 | | InternalResponse::FromIPC(const IPCInternalResponse& aIPCResponse) |
42 | 0 | { |
43 | 0 | if (aIPCResponse.type() == ResponseType::Error) { |
44 | 0 | return InternalResponse::NetworkError(aIPCResponse.errorCode()); |
45 | 0 | } |
46 | 0 | |
47 | 0 | RefPtr<InternalResponse> response = |
48 | 0 | new InternalResponse(aIPCResponse.status(), |
49 | 0 | aIPCResponse.statusText()); |
50 | 0 |
|
51 | 0 | response->SetURLList(aIPCResponse.urlList()); |
52 | 0 |
|
53 | 0 | response->mHeaders = new InternalHeaders(aIPCResponse.headers(), |
54 | 0 | aIPCResponse.headersGuard()); |
55 | 0 |
|
56 | 0 | response->InitChannelInfo(aIPCResponse.channelInfo()); |
57 | 0 | if (aIPCResponse.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) { |
58 | 0 | UniquePtr<mozilla::ipc::PrincipalInfo> info(new mozilla::ipc::PrincipalInfo(aIPCResponse.principalInfo().get_PrincipalInfo())); |
59 | 0 | response->SetPrincipalInfo(std::move(info)); |
60 | 0 | } |
61 | 0 |
|
62 | 0 | nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aIPCResponse.body()); |
63 | 0 | response->SetBody(stream, aIPCResponse.bodySize()); |
64 | 0 |
|
65 | 0 | switch (aIPCResponse.type()) |
66 | 0 | { |
67 | 0 | case ResponseType::Basic: |
68 | 0 | response = response->BasicResponse(); |
69 | 0 | break; |
70 | 0 | case ResponseType::Cors: |
71 | 0 | response = response->CORSResponse(); |
72 | 0 | break; |
73 | 0 | case ResponseType::Default: |
74 | 0 | break; |
75 | 0 | case ResponseType::Opaque: |
76 | 0 | response = response->OpaqueResponse(); |
77 | 0 | break; |
78 | 0 | case ResponseType::Opaqueredirect: |
79 | 0 | response = response->OpaqueRedirectResponse(); |
80 | 0 | break; |
81 | 0 | default: |
82 | 0 | MOZ_CRASH("Unexpected ResponseType!"); |
83 | 0 | } |
84 | 0 | MOZ_ASSERT(response); |
85 | 0 |
|
86 | 0 | return response.forget(); |
87 | 0 | } |
88 | | |
89 | | InternalResponse::~InternalResponse() |
90 | 0 | { |
91 | 0 | } |
92 | | |
93 | | template void |
94 | | InternalResponse::ToIPC<nsIContentParent> |
95 | | (IPCInternalResponse* aIPCResponse, |
96 | | nsIContentParent* aManager, |
97 | | UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream); |
98 | | template void |
99 | | InternalResponse::ToIPC<nsIContentChild> |
100 | | (IPCInternalResponse* aIPCResponse, |
101 | | nsIContentChild* aManager, |
102 | | UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream); |
103 | | template void |
104 | | InternalResponse::ToIPC<mozilla::ipc::PBackgroundParent> |
105 | | (IPCInternalResponse* aIPCResponse, |
106 | | mozilla::ipc::PBackgroundParent* aManager, |
107 | | UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream); |
108 | | template void |
109 | | InternalResponse::ToIPC<mozilla::ipc::PBackgroundChild> |
110 | | (IPCInternalResponse* aIPCResponse, |
111 | | mozilla::ipc::PBackgroundChild* aManager, |
112 | | UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream); |
113 | | |
114 | | template<typename M> |
115 | | void |
116 | | InternalResponse::ToIPC(IPCInternalResponse* aIPCResponse, |
117 | | M* aManager, |
118 | | UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream) |
119 | 0 | { |
120 | 0 | MOZ_ASSERT(aIPCResponse); |
121 | 0 | aIPCResponse->type() = mType; |
122 | 0 | aIPCResponse->urlList() = mURLList; |
123 | 0 | aIPCResponse->status() = GetUnfilteredStatus(); |
124 | 0 | aIPCResponse->statusText() = GetUnfilteredStatusText(); |
125 | 0 |
|
126 | 0 | mHeaders->ToIPC(aIPCResponse->headers(), aIPCResponse->headersGuard()); |
127 | 0 |
|
128 | 0 | aIPCResponse->channelInfo() = mChannelInfo.AsIPCChannelInfo(); |
129 | 0 | if (mPrincipalInfo) { |
130 | 0 | aIPCResponse->principalInfo() = *mPrincipalInfo; |
131 | 0 | } else { |
132 | 0 | aIPCResponse->principalInfo() = void_t(); |
133 | 0 | } |
134 | 0 |
|
135 | 0 | nsCOMPtr<nsIInputStream> body; |
136 | 0 | int64_t bodySize; |
137 | 0 | GetUnfilteredBody(getter_AddRefs(body), &bodySize); |
138 | 0 |
|
139 | 0 | if (body) { |
140 | 0 | aAutoStream.reset(new mozilla::ipc::AutoIPCStream(aIPCResponse->body())); |
141 | 0 | DebugOnly<bool> ok = aAutoStream->Serialize(body, aManager); |
142 | 0 | MOZ_ASSERT(ok); |
143 | 0 | } else { |
144 | 0 | aIPCResponse->body() = void_t(); |
145 | 0 | } |
146 | 0 |
|
147 | 0 | aIPCResponse->bodySize() = bodySize; |
148 | 0 | } Unexecuted instantiation: void mozilla::dom::InternalResponse::ToIPC<mozilla::dom::nsIContentParent>(mozilla::dom::IPCInternalResponse*, mozilla::dom::nsIContentParent*, mozilla::UniquePtr<mozilla::ipc::AutoIPCStream, mozilla::DefaultDelete<mozilla::ipc::AutoIPCStream> >&) Unexecuted instantiation: void mozilla::dom::InternalResponse::ToIPC<mozilla::dom::nsIContentChild>(mozilla::dom::IPCInternalResponse*, mozilla::dom::nsIContentChild*, mozilla::UniquePtr<mozilla::ipc::AutoIPCStream, mozilla::DefaultDelete<mozilla::ipc::AutoIPCStream> >&) Unexecuted instantiation: void mozilla::dom::InternalResponse::ToIPC<mozilla::ipc::PBackgroundParent>(mozilla::dom::IPCInternalResponse*, mozilla::ipc::PBackgroundParent*, mozilla::UniquePtr<mozilla::ipc::AutoIPCStream, mozilla::DefaultDelete<mozilla::ipc::AutoIPCStream> >&) Unexecuted instantiation: void mozilla::dom::InternalResponse::ToIPC<mozilla::ipc::PBackgroundChild>(mozilla::dom::IPCInternalResponse*, mozilla::ipc::PBackgroundChild*, mozilla::UniquePtr<mozilla::ipc::AutoIPCStream, mozilla::DefaultDelete<mozilla::ipc::AutoIPCStream> >&) |
149 | | |
150 | | already_AddRefed<InternalResponse> |
151 | | InternalResponse::Clone(CloneType aCloneType) |
152 | 0 | { |
153 | 0 | RefPtr<InternalResponse> clone = CreateIncompleteCopy(); |
154 | 0 |
|
155 | 0 | clone->mHeaders = new InternalHeaders(*mHeaders); |
156 | 0 |
|
157 | 0 | // Make sure the clone response will have the same padding size. |
158 | 0 | clone->mPaddingInfo = mPaddingInfo; |
159 | 0 | clone->mPaddingSize = mPaddingSize; |
160 | 0 |
|
161 | 0 | if (mWrappedResponse) { |
162 | 0 | clone->mWrappedResponse = mWrappedResponse->Clone(aCloneType); |
163 | 0 | MOZ_ASSERT(!mBody); |
164 | 0 | return clone.forget(); |
165 | 0 | } |
166 | 0 |
|
167 | 0 | if (!mBody || aCloneType == eDontCloneInputStream) { |
168 | 0 | return clone.forget(); |
169 | 0 | } |
170 | 0 | |
171 | 0 | nsCOMPtr<nsIInputStream> clonedBody; |
172 | 0 | nsCOMPtr<nsIInputStream> replacementBody; |
173 | 0 |
|
174 | 0 | nsresult rv = NS_CloneInputStream(mBody, getter_AddRefs(clonedBody), |
175 | 0 | getter_AddRefs(replacementBody)); |
176 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } |
177 | 0 | |
178 | 0 | clone->mBody.swap(clonedBody); |
179 | 0 | if (replacementBody) { |
180 | 0 | mBody.swap(replacementBody); |
181 | 0 | } |
182 | 0 |
|
183 | 0 | return clone.forget(); |
184 | 0 | } |
185 | | |
186 | | already_AddRefed<InternalResponse> |
187 | | InternalResponse::BasicResponse() |
188 | 0 | { |
189 | 0 | MOZ_ASSERT(!mWrappedResponse, "Can't BasicResponse a already wrapped response"); |
190 | 0 | RefPtr<InternalResponse> basic = CreateIncompleteCopy(); |
191 | 0 | basic->mType = ResponseType::Basic; |
192 | 0 | basic->mHeaders = InternalHeaders::BasicHeaders(Headers()); |
193 | 0 | basic->mWrappedResponse = this; |
194 | 0 | return basic.forget(); |
195 | 0 | } |
196 | | |
197 | | already_AddRefed<InternalResponse> |
198 | | InternalResponse::CORSResponse() |
199 | 0 | { |
200 | 0 | MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response"); |
201 | 0 | RefPtr<InternalResponse> cors = CreateIncompleteCopy(); |
202 | 0 | cors->mType = ResponseType::Cors; |
203 | 0 | cors->mHeaders = InternalHeaders::CORSHeaders(Headers()); |
204 | 0 | cors->mWrappedResponse = this; |
205 | 0 | return cors.forget(); |
206 | 0 | } |
207 | | |
208 | | uint32_t |
209 | | InternalResponse::GetPaddingInfo() |
210 | 0 | { |
211 | 0 | // If it's an opaque response, the paddingInfo should be generated only when |
212 | 0 | // paddingSize is unknown size. |
213 | 0 | // If it's not, the paddingInfo should be nothing and the paddingSize should |
214 | 0 | // be unknown size. |
215 | 0 | MOZ_DIAGNOSTIC_ASSERT((mType == ResponseType::Opaque && |
216 | 0 | mPaddingSize == UNKNOWN_PADDING_SIZE && |
217 | 0 | mPaddingInfo.isSome()) || |
218 | 0 | (mType == ResponseType::Opaque && |
219 | 0 | mPaddingSize != UNKNOWN_PADDING_SIZE && |
220 | 0 | mPaddingInfo.isNothing()) || |
221 | 0 | (mType != ResponseType::Opaque && |
222 | 0 | mPaddingSize == UNKNOWN_PADDING_SIZE && |
223 | 0 | mPaddingInfo.isNothing())); |
224 | 0 | return mPaddingInfo.isSome() ? mPaddingInfo.ref() : 0; |
225 | 0 | } |
226 | | |
227 | | nsresult |
228 | | InternalResponse::GeneratePaddingInfo() |
229 | 0 | { |
230 | 0 | MOZ_DIAGNOSTIC_ASSERT(mType == ResponseType::Opaque); |
231 | 0 | MOZ_DIAGNOSTIC_ASSERT(mPaddingSize == UNKNOWN_PADDING_SIZE); |
232 | 0 |
|
233 | 0 | // Utilize random generator to generator a random number |
234 | 0 | nsresult rv; |
235 | 0 | uint32_t randomNumber = 0; |
236 | 0 | nsCOMPtr<nsIRandomGenerator> randomGenerator = |
237 | 0 | do_GetService("@mozilla.org/security/random-generator;1", &rv); |
238 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } |
239 | 0 | |
240 | 0 | MOZ_DIAGNOSTIC_ASSERT(randomGenerator); |
241 | 0 |
|
242 | 0 | uint8_t* buffer; |
243 | 0 | rv = randomGenerator->GenerateRandomBytes(sizeof(randomNumber), &buffer); |
244 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } |
245 | 0 | |
246 | 0 | memcpy(&randomNumber, buffer, sizeof(randomNumber)); |
247 | 0 | free(buffer); |
248 | 0 |
|
249 | 0 | mPaddingInfo.emplace(randomNumber % kMaxRandomNumber); |
250 | 0 |
|
251 | 0 | return rv; |
252 | 0 | } |
253 | | |
254 | | int64_t |
255 | | InternalResponse::GetPaddingSize() |
256 | 0 | { |
257 | 0 | // We initialize padding size to an unknown size (-1). After cached, we only |
258 | 0 | // pad opaque response. Opaque response's padding size might be unknown before |
259 | 0 | // cached. |
260 | 0 | MOZ_DIAGNOSTIC_ASSERT(mType == ResponseType::Opaque || |
261 | 0 | mPaddingSize == UNKNOWN_PADDING_SIZE); |
262 | 0 | MOZ_DIAGNOSTIC_ASSERT(mPaddingSize == UNKNOWN_PADDING_SIZE || |
263 | 0 | mPaddingSize >= 0); |
264 | 0 |
|
265 | 0 | return mPaddingSize; |
266 | 0 | } |
267 | | |
268 | | void |
269 | | InternalResponse::SetPaddingSize(int64_t aPaddingSize) |
270 | 0 | { |
271 | 0 | // We should only pad the opaque response. |
272 | 0 | MOZ_DIAGNOSTIC_ASSERT((mType == ResponseType::Opaque) != |
273 | 0 | (aPaddingSize == |
274 | 0 | InternalResponse::UNKNOWN_PADDING_SIZE)); |
275 | 0 | MOZ_DIAGNOSTIC_ASSERT(aPaddingSize == UNKNOWN_PADDING_SIZE || |
276 | 0 | aPaddingSize >= 0); |
277 | 0 |
|
278 | 0 | mPaddingSize = aPaddingSize; |
279 | 0 | } |
280 | | |
281 | | void |
282 | | InternalResponse::SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo) |
283 | 0 | { |
284 | 0 | mPrincipalInfo = std::move(aPrincipalInfo); |
285 | 0 | } |
286 | | |
287 | | LoadTainting |
288 | | InternalResponse::GetTainting() const |
289 | | { |
290 | | switch (mType) { |
291 | | case ResponseType::Cors: |
292 | | return LoadTainting::CORS; |
293 | | case ResponseType::Opaque: |
294 | | return LoadTainting::Opaque; |
295 | | default: |
296 | | return LoadTainting::Basic; |
297 | | } |
298 | | } |
299 | | |
300 | | already_AddRefed<InternalResponse> |
301 | | InternalResponse::Unfiltered() |
302 | 0 | { |
303 | 0 | RefPtr<InternalResponse> ref = mWrappedResponse; |
304 | 0 | if (!ref) { |
305 | 0 | ref = this; |
306 | 0 | } |
307 | 0 | return ref.forget(); |
308 | 0 | } |
309 | | |
310 | | already_AddRefed<InternalResponse> |
311 | | InternalResponse::OpaqueResponse() |
312 | 0 | { |
313 | 0 | MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response"); |
314 | 0 | RefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString()); |
315 | 0 | response->mType = ResponseType::Opaque; |
316 | 0 | response->mTerminationReason = mTerminationReason; |
317 | 0 | response->mChannelInfo = mChannelInfo; |
318 | 0 | if (mPrincipalInfo) { |
319 | 0 | response->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo); |
320 | 0 | } |
321 | 0 | response->mWrappedResponse = this; |
322 | 0 | return response.forget(); |
323 | 0 | } |
324 | | |
325 | | already_AddRefed<InternalResponse> |
326 | | InternalResponse::OpaqueRedirectResponse() |
327 | 0 | { |
328 | 0 | MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueRedirectResponse a already wrapped response"); |
329 | 0 | MOZ_ASSERT(!mURLList.IsEmpty(), "URLList should not be emtpy for internalResponse"); |
330 | 0 | RefPtr<InternalResponse> response = OpaqueResponse(); |
331 | 0 | response->mType = ResponseType::Opaqueredirect; |
332 | 0 | response->mURLList = mURLList; |
333 | 0 | return response.forget(); |
334 | 0 | } |
335 | | |
336 | | already_AddRefed<InternalResponse> |
337 | | InternalResponse::CreateIncompleteCopy() |
338 | 0 | { |
339 | 0 | RefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText); |
340 | 0 | copy->mType = mType; |
341 | 0 | copy->mTerminationReason = mTerminationReason; |
342 | 0 | copy->mURLList = mURLList; |
343 | 0 | copy->mChannelInfo = mChannelInfo; |
344 | 0 | if (mPrincipalInfo) { |
345 | 0 | copy->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo); |
346 | 0 | } |
347 | 0 | return copy.forget(); |
348 | 0 | } |
349 | | |
350 | | } // namespace dom |
351 | | } // namespace mozilla |