Coverage Report

Created: 2018-09-25 14:53

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