Coverage Report

Created: 2018-09-25 14:53

/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