Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=4 sw=2 sts=2 et cin: */
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
// HttpLog.h should generally be included first
8
#include "HttpLog.h"
9
10
#include "nsNetUtil.h"
11
12
#include "mozilla/AntiTrackingCommon.h"
13
#include "mozilla/Atomics.h"
14
#include "mozilla/Encoding.h"
15
#include "mozilla/LoadContext.h"
16
#include "mozilla/LoadInfo.h"
17
#include "mozilla/BasePrincipal.h"
18
#include "mozilla/Monitor.h"
19
#include "mozilla/StoragePrincipalHelper.h"
20
#include "mozilla/TaskQueue.h"
21
#include "mozilla/Telemetry.h"
22
#include "nsCategoryCache.h"
23
#include "nsContentUtils.h"
24
#include "nsFileStreams.h"
25
#include "nsHashKeys.h"
26
#include "nsHttp.h"
27
#include "nsIAsyncStreamCopier.h"
28
#include "nsIAuthPrompt.h"
29
#include "nsIAuthPrompt2.h"
30
#include "nsIAuthPromptAdapterFactory.h"
31
#include "nsIBufferedStreams.h"
32
#include "nsIChannelEventSink.h"
33
#include "nsIContentSniffer.h"
34
#include "mozilla/dom/Document.h"
35
#include "nsICookieService.h"
36
#include "nsIDownloader.h"
37
#include "nsIFileProtocolHandler.h"
38
#include "nsIFileStreams.h"
39
#include "nsIFileURL.h"
40
#include "nsIIDNService.h"
41
#include "nsIInputStreamChannel.h"
42
#include "nsIInputStreamPump.h"
43
#include "nsIInterfaceRequestorUtils.h"
44
#include "nsILoadContext.h"
45
#include "nsIMIMEHeaderParam.h"
46
#include "nsIMutable.h"
47
#include "nsINode.h"
48
#include "nsIObjectLoadingContent.h"
49
#include "nsIOfflineCacheUpdate.h"
50
#include "nsPersistentProperties.h"
51
#include "nsIPrivateBrowsingChannel.h"
52
#include "nsIPropertyBag2.h"
53
#include "nsIProtocolProxyService.h"
54
#include "mozilla/net/RedirectChannelRegistrar.h"
55
#include "nsRequestObserverProxy.h"
56
#include "nsIScriptSecurityManager.h"
57
#include "nsISensitiveInfoHiddenURI.h"
58
#include "nsISimpleStreamListener.h"
59
#include "nsISocketProvider.h"
60
#include "nsISocketProviderService.h"
61
#include "nsIStandardURL.h"
62
#include "nsIStreamLoader.h"
63
#include "nsIIncrementalStreamLoader.h"
64
#include "nsIStreamTransportService.h"
65
#include "nsStringStream.h"
66
#include "nsSyncStreamListener.h"
67
#include "nsITransport.h"
68
#include "nsIURIWithSpecialOrigin.h"
69
#include "nsIURLParser.h"
70
#include "nsIUUIDGenerator.h"
71
#include "nsIViewSourceChannel.h"
72
#include "nsInterfaceRequestorAgg.h"
73
#include "plstr.h"
74
#include "nsINestedURI.h"
75
#include "mozilla/dom/nsCSPUtils.h"
76
#include "mozilla/dom/nsMixedContentBlocker.h"
77
#include "mozilla/dom/BlobURLProtocolHandler.h"
78
#include "mozilla/net/HttpBaseChannel.h"
79
#include "nsIScriptError.h"
80
#include "nsISiteSecurityService.h"
81
#include "nsHttpHandler.h"
82
#include "nsNSSComponent.h"
83
#include "nsIRedirectHistoryEntry.h"
84
#ifdef MOZ_NEW_CERT_STORAGE
85
# include "nsICertStorage.h"
86
#else
87
# include "nsICertBlocklist.h"
88
#endif
89
#include "nsICertOverrideService.h"
90
#include "nsQueryObject.h"
91
#include "mozIThirdPartyUtil.h"
92
#include "../mime/nsMIMEHeaderParamImpl.h"
93
#include "nsStandardURL.h"
94
#include "nsChromeProtocolHandler.h"
95
#include "nsJSProtocolHandler.h"
96
#include "nsDataHandler.h"
97
#include "mozilla/dom/BlobURLProtocolHandler.h"
98
#include "nsStreamUtils.h"
99
#include "nsSocketTransportService2.h"
100
#include "nsViewSourceHandler.h"
101
#include "nsJARURI.h"
102
#include "nsIconURI.h"
103
#include "nsAboutProtocolHandler.h"
104
#include "nsResProtocolHandler.h"
105
#include "mozilla/net/ExtensionProtocolHandler.h"
106
#include <limits>
107
108
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
109
# include "nsNewMailnewsURI.h"
110
#endif
111
112
using namespace mozilla;
113
using namespace mozilla::net;
114
using mozilla::dom::BlobURLProtocolHandler;
115
using mozilla::dom::ClientInfo;
116
using mozilla::dom::PerformanceStorage;
117
using mozilla::dom::ServiceWorkerDescriptor;
118
119
#define MAX_RECURSION_COUNT 50
120
121
already_AddRefed<nsIIOService> do_GetIOService(nsresult* error /* = 0 */) {
122
nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
123
if (error) *error = io ? NS_OK : NS_ERROR_FAILURE;
124
return io.forget();
125
}
126
127
nsresult NS_NewLocalFileInputStream(nsIInputStream** result, nsIFile* file,
128
int32_t ioFlags /* = -1 */,
129
int32_t perm /* = -1 */,
130
int32_t behaviorFlags /* = 0 */) {
131
nsresult rv;
132
nsCOMPtr<nsIFileInputStream> in =
133
do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
134
if (NS_SUCCEEDED(rv)) {
135
rv = in->Init(file, ioFlags, perm, behaviorFlags);
136
if (NS_SUCCEEDED(rv)) in.forget(result);
137
}
138
return rv;
139
}
140
141
nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file,
142
int32_t ioFlags /* = -1 */,
143
int32_t perm /* = -1 */,
144
int32_t behaviorFlags /* = 0 */) {
145
nsresult rv;
146
nsCOMPtr<nsIFileOutputStream> out =
147
do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
148
if (NS_SUCCEEDED(rv)) {
149
rv = out->Init(file, ioFlags, perm, behaviorFlags);
150
if (NS_SUCCEEDED(rv)) out.forget(result);
151
}
152
return rv;
153
}
154
155
nsresult net_EnsureIOService(nsIIOService** ios, nsCOMPtr<nsIIOService>& grip) {
156
nsresult rv = NS_OK;
157
if (!*ios) {
158
grip = do_GetIOService(&rv);
159
*ios = grip;
160
}
161
return rv;
162
}
163
164
nsresult NS_NewFileURI(
165
nsIURI** result, nsIFile* spec,
166
nsIIOService*
167
ioService /* = nullptr */) // pass in nsIIOService to optimize callers
168
{
169
nsresult rv;
170
nsCOMPtr<nsIIOService> grip;
171
rv = net_EnsureIOService(&ioService, grip);
172
if (ioService) rv = ioService->NewFileURI(spec, result);
173
return rv;
174
}
175
176
nsresult NS_GetURIWithNewRef(nsIURI* aInput, const nsACString& aRef,
177
nsIURI** aOutput) {
178
if (NS_WARN_IF(!aInput || !aOutput)) {
179
return NS_ERROR_INVALID_ARG;
180
}
181
182
bool hasRef;
183
nsresult rv = aInput->GetHasRef(&hasRef);
184
185
nsAutoCString ref;
186
if (NS_SUCCEEDED(rv)) {
187
rv = aInput->GetRef(ref);
188
}
189
190
// If the ref is already equal to the new ref, we do not need to do anything.
191
// Also, if the GetRef failed (it could return NS_ERROR_NOT_IMPLEMENTED)
192
// we can assume SetRef would fail as well, so returning the original
193
// URI is OK.
194
if (NS_FAILED(rv) || (!hasRef && aRef.IsEmpty()) ||
195
(!aRef.IsEmpty() && aRef == ref)) {
196
nsCOMPtr<nsIURI> uri = aInput;
197
uri.forget(aOutput);
198
return NS_OK;
199
}
200
201
return NS_MutateURI(aInput).SetRef(aRef).Finalize(aOutput);
202
}
203
204
nsresult NS_GetURIWithoutRef(nsIURI* aInput, nsIURI** aOutput) {
205
return NS_GetURIWithNewRef(aInput, EmptyCString(), aOutput);
206
}
207
208
nsresult NS_NewChannelInternal(
209
nsIChannel** outChannel, nsIURI* aUri, nsILoadInfo* aLoadInfo,
210
PerformanceStorage* aPerformanceStorage /* = nullptr */,
211
nsILoadGroup* aLoadGroup /* = nullptr */,
212
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
213
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
214
nsIIOService* aIoService /* = nullptr */) {
215
// NS_NewChannelInternal is mostly called for channel redirects. We should
216
// allow the creation of a channel even if the original channel did not have a
217
// loadinfo attached.
218
NS_ENSURE_ARG_POINTER(outChannel);
219
220
nsCOMPtr<nsIIOService> grip;
221
nsresult rv = net_EnsureIOService(&aIoService, grip);
222
NS_ENSURE_SUCCESS(rv, rv);
223
224
nsCOMPtr<nsIChannel> channel;
225
rv = aIoService->NewChannelFromURIWithLoadInfo(aUri, aLoadInfo,
226
getter_AddRefs(channel));
227
NS_ENSURE_SUCCESS(rv, rv);
228
229
if (aLoadGroup) {
230
rv = channel->SetLoadGroup(aLoadGroup);
231
NS_ENSURE_SUCCESS(rv, rv);
232
}
233
234
if (aCallbacks) {
235
rv = channel->SetNotificationCallbacks(aCallbacks);
236
NS_ENSURE_SUCCESS(rv, rv);
237
}
238
239
#ifdef DEBUG
240
nsLoadFlags channelLoadFlags = 0;
241
channel->GetLoadFlags(&channelLoadFlags);
242
// Will be removed when we remove LOAD_REPLACE altogether
243
// This check is trying to catch protocol handlers that still
244
// try to set the LOAD_REPLACE flag.
245
MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
246
#endif
247
248
if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
249
rv = channel->SetLoadFlags(aLoadFlags);
250
NS_ENSURE_SUCCESS(rv, rv);
251
}
252
253
if (aPerformanceStorage) {
254
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
255
loadInfo->SetPerformanceStorage(aPerformanceStorage);
256
}
257
258
channel.forget(outChannel);
259
return NS_OK;
260
}
261
262
namespace {
263
264
void AssertLoadingPrincipalAndClientInfoMatch(
265
nsIPrincipal* aLoadingPrincipal, const ClientInfo& aLoadingClientInfo,
266
nsContentPolicyType aType) {
267
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
268
// Verify that the provided loading ClientInfo matches the loading
269
// principal. Unfortunately we can't just use nsIPrincipal::Equals() here
270
// because of some corner cases:
271
//
272
// 1. Worker debugger scripts want to use a system loading principal for
273
// worker scripts with a content principal. We exempt these from this
274
// check.
275
// 2. Null principals currently require exact object identity for
276
// nsIPrincipal::Equals() to return true. This doesn't work here because
277
// ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate
278
// a new object. To work around this we compare the principal origin
279
// string itself. If bug 1431771 is fixed then we could switch to
280
// Equals().
281
282
// Allow worker debugger to load with a system principal.
283
if (aLoadingPrincipal->IsSystemPrincipal() &&
284
(aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
285
aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
286
aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
287
aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS)) {
288
return;
289
}
290
291
// Perform a fast comparison for most principal checks.
292
nsCOMPtr<nsIPrincipal> clientPrincipal(aLoadingClientInfo.GetPrincipal());
293
if (aLoadingPrincipal->Equals(clientPrincipal)) {
294
return;
295
}
296
297
// Fall back to a slower origin equality test to support null principals.
298
nsAutoCString loadingOrigin;
299
MOZ_ALWAYS_SUCCEEDS(aLoadingPrincipal->GetOrigin(loadingOrigin));
300
301
nsAutoCString clientOrigin;
302
MOZ_ALWAYS_SUCCEEDS(clientPrincipal->GetOrigin(clientOrigin));
303
304
MOZ_DIAGNOSTIC_ASSERT(loadingOrigin == clientOrigin);
305
#endif
306
}
307
308
} // namespace
309
310
nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
311
nsIPrincipal* aLoadingPrincipal,
312
nsSecurityFlags aSecurityFlags,
313
nsContentPolicyType aContentPolicyType,
314
nsICookieSettings* aCookieSettings /* = nullptr */,
315
PerformanceStorage* aPerformanceStorage /* = nullptr */,
316
nsILoadGroup* aLoadGroup /* = nullptr */,
317
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
318
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
319
nsIIOService* aIoService /* = nullptr */) {
320
return NS_NewChannelInternal(
321
outChannel, aUri,
322
nullptr, // aLoadingNode,
323
aLoadingPrincipal,
324
nullptr, // aTriggeringPrincipal
325
Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
326
aContentPolicyType, aCookieSettings, aPerformanceStorage, aLoadGroup,
327
aCallbacks, aLoadFlags, aIoService);
328
}
329
330
nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
331
nsIPrincipal* aLoadingPrincipal,
332
const ClientInfo& aLoadingClientInfo,
333
const Maybe<ServiceWorkerDescriptor>& aController,
334
nsSecurityFlags aSecurityFlags,
335
nsContentPolicyType aContentPolicyType,
336
nsICookieSettings* aCookieSettings /* = nullptr */,
337
PerformanceStorage* aPerformanceStorage /* = nullptr */,
338
nsILoadGroup* aLoadGroup /* = nullptr */,
339
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
340
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
341
nsIIOService* aIoService /* = nullptr */) {
342
AssertLoadingPrincipalAndClientInfoMatch(
343
aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
344
345
Maybe<ClientInfo> loadingClientInfo;
346
loadingClientInfo.emplace(aLoadingClientInfo);
347
348
return NS_NewChannelInternal(outChannel, aUri,
349
nullptr, // aLoadingNode,
350
aLoadingPrincipal,
351
nullptr, // aTriggeringPrincipal
352
loadingClientInfo, aController, aSecurityFlags,
353
aContentPolicyType, aCookieSettings,
354
aPerformanceStorage, aLoadGroup, aCallbacks,
355
aLoadFlags, aIoService);
356
}
357
358
nsresult NS_NewChannelInternal(
359
nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
360
nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
361
const Maybe<ClientInfo>& aLoadingClientInfo,
362
const Maybe<ServiceWorkerDescriptor>& aController,
363
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
364
nsICookieSettings* aCookieSettings /* = nullptr */,
365
PerformanceStorage* aPerformanceStorage /* = nullptr */,
366
nsILoadGroup* aLoadGroup /* = nullptr */,
367
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
368
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
369
nsIIOService* aIoService /* = nullptr */) {
370
NS_ENSURE_ARG_POINTER(outChannel);
371
372
nsCOMPtr<nsIIOService> grip;
373
nsresult rv = net_EnsureIOService(&aIoService, grip);
374
NS_ENSURE_SUCCESS(rv, rv);
375
376
nsCOMPtr<nsIChannel> channel;
377
rv = aIoService->NewChannelFromURIWithClientAndController(
378
aUri, aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal,
379
aLoadingClientInfo, aController, aSecurityFlags, aContentPolicyType,
380
getter_AddRefs(channel));
381
if (NS_FAILED(rv)) {
382
return rv;
383
}
384
385
if (aLoadGroup) {
386
rv = channel->SetLoadGroup(aLoadGroup);
387
NS_ENSURE_SUCCESS(rv, rv);
388
}
389
390
if (aCallbacks) {
391
rv = channel->SetNotificationCallbacks(aCallbacks);
392
NS_ENSURE_SUCCESS(rv, rv);
393
}
394
395
#ifdef DEBUG
396
nsLoadFlags channelLoadFlags = 0;
397
channel->GetLoadFlags(&channelLoadFlags);
398
// Will be removed when we remove LOAD_REPLACE altogether
399
// This check is trying to catch protocol handlers that still
400
// try to set the LOAD_REPLACE flag.
401
MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
402
#endif
403
404
if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
405
rv = channel->SetLoadFlags(aLoadFlags);
406
NS_ENSURE_SUCCESS(rv, rv);
407
}
408
409
if (aPerformanceStorage || aCookieSettings) {
410
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
411
412
if (aPerformanceStorage) {
413
loadInfo->SetPerformanceStorage(aPerformanceStorage);
414
}
415
416
if (aCookieSettings) {
417
loadInfo->SetCookieSettings(aCookieSettings);
418
}
419
}
420
421
channel.forget(outChannel);
422
return NS_OK;
423
}
424
425
nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
426
NS_NewChannelWithTriggeringPrincipal(
427
nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
428
nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
429
nsContentPolicyType aContentPolicyType,
430
PerformanceStorage* aPerformanceStorage /* = nullptr */,
431
nsILoadGroup* aLoadGroup /* = nullptr */,
432
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
433
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
434
nsIIOService* aIoService /* = nullptr */) {
435
MOZ_ASSERT(aLoadingNode);
436
NS_ASSERTION(aTriggeringPrincipal,
437
"Can not create channel without a triggering Principal!");
438
return NS_NewChannelInternal(
439
outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
440
aTriggeringPrincipal, Maybe<ClientInfo>(),
441
Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
442
aLoadingNode->OwnerDoc()->CookieSettings(), aPerformanceStorage,
443
aLoadGroup, aCallbacks, aLoadFlags, aIoService);
444
}
445
446
// See NS_NewChannelInternal for usage and argument description
447
nsresult NS_NewChannelWithTriggeringPrincipal(
448
nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
449
nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
450
nsContentPolicyType aContentPolicyType,
451
nsICookieSettings* aCookieSettings /* = nullptr */,
452
PerformanceStorage* aPerformanceStorage /* = nullptr */,
453
nsILoadGroup* aLoadGroup /* = nullptr */,
454
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
455
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
456
nsIIOService* aIoService /* = nullptr */) {
457
NS_ASSERTION(aLoadingPrincipal,
458
"Can not create channel without a loading Principal!");
459
return NS_NewChannelInternal(
460
outChannel, aUri,
461
nullptr, // aLoadingNode
462
aLoadingPrincipal, aTriggeringPrincipal, Maybe<ClientInfo>(),
463
Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
464
aCookieSettings, aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags,
465
aIoService);
466
}
467
468
// See NS_NewChannelInternal for usage and argument description
469
nsresult NS_NewChannelWithTriggeringPrincipal(
470
nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
471
nsIPrincipal* aTriggeringPrincipal, const ClientInfo& aLoadingClientInfo,
472
const Maybe<ServiceWorkerDescriptor>& aController,
473
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
474
nsICookieSettings* aCookieSettings /* = nullptr */,
475
PerformanceStorage* aPerformanceStorage /* = nullptr */,
476
nsILoadGroup* aLoadGroup /* = nullptr */,
477
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
478
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
479
nsIIOService* aIoService /* = nullptr */) {
480
AssertLoadingPrincipalAndClientInfoMatch(
481
aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
482
483
Maybe<ClientInfo> loadingClientInfo;
484
loadingClientInfo.emplace(aLoadingClientInfo);
485
486
return NS_NewChannelInternal(
487
outChannel, aUri,
488
nullptr, // aLoadingNode
489
aLoadingPrincipal, aTriggeringPrincipal, loadingClientInfo, aController,
490
aSecurityFlags, aContentPolicyType, aCookieSettings, aPerformanceStorage,
491
aLoadGroup, aCallbacks, aLoadFlags, aIoService);
492
}
493
494
nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
495
nsINode* aLoadingNode, nsSecurityFlags aSecurityFlags,
496
nsContentPolicyType aContentPolicyType,
497
PerformanceStorage* aPerformanceStorage /* = nullptr */,
498
nsILoadGroup* aLoadGroup /* = nullptr */,
499
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
500
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
501
nsIIOService* aIoService /* = nullptr */) {
502
NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!");
503
return NS_NewChannelInternal(
504
outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
505
nullptr, // aTriggeringPrincipal
506
Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
507
aContentPolicyType, aLoadingNode->OwnerDoc()->CookieSettings(),
508
aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService);
509
}
510
511
nsresult NS_GetIsDocumentChannel(nsIChannel* aChannel, bool* aIsDocument) {
512
// Check if this channel is going to be used to create a document. If it has
513
// LOAD_DOCUMENT_URI set it is trivially creating a document. If
514
// LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a
515
// document, depending on its MIME type.
516
517
if (!aChannel || !aIsDocument) {
518
return NS_ERROR_NULL_POINTER;
519
}
520
*aIsDocument = false;
521
nsLoadFlags loadFlags;
522
nsresult rv = aChannel->GetLoadFlags(&loadFlags);
523
if (NS_FAILED(rv)) {
524
return rv;
525
}
526
if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
527
*aIsDocument = true;
528
return NS_OK;
529
}
530
if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) {
531
*aIsDocument = false;
532
return NS_OK;
533
}
534
nsAutoCString mimeType;
535
rv = aChannel->GetContentType(mimeType);
536
if (NS_FAILED(rv)) {
537
return rv;
538
}
539
if (nsContentUtils::HtmlObjectContentTypeForMIMEType(
540
mimeType, false, nullptr) == nsIObjectLoadingContent::TYPE_DOCUMENT) {
541
*aIsDocument = true;
542
return NS_OK;
543
}
544
*aIsDocument = false;
545
return NS_OK;
546
}
547
548
nsresult NS_MakeAbsoluteURI(nsACString& result, const nsACString& spec,
549
nsIURI* baseURI) {
550
nsresult rv;
551
if (!baseURI) {
552
NS_WARNING("It doesn't make sense to not supply a base URI");
553
result = spec;
554
rv = NS_OK;
555
} else if (spec.IsEmpty())
556
rv = baseURI->GetSpec(result);
557
else
558
rv = baseURI->Resolve(spec, result);
559
return rv;
560
}
561
562
nsresult NS_MakeAbsoluteURI(char** result, const char* spec, nsIURI* baseURI) {
563
nsresult rv;
564
nsAutoCString resultBuf;
565
rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
566
if (NS_SUCCEEDED(rv)) {
567
*result = ToNewCString(resultBuf);
568
if (!*result) rv = NS_ERROR_OUT_OF_MEMORY;
569
}
570
return rv;
571
}
572
573
nsresult NS_MakeAbsoluteURI(nsAString& result, const nsAString& spec,
574
nsIURI* baseURI) {
575
nsresult rv;
576
if (!baseURI) {
577
NS_WARNING("It doesn't make sense to not supply a base URI");
578
result = spec;
579
rv = NS_OK;
580
} else {
581
nsAutoCString resultBuf;
582
if (spec.IsEmpty())
583
rv = baseURI->GetSpec(resultBuf);
584
else
585
rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
586
if (NS_SUCCEEDED(rv)) CopyUTF8toUTF16(resultBuf, result);
587
}
588
return rv;
589
}
590
591
int32_t NS_GetDefaultPort(const char* scheme,
592
nsIIOService* ioService /* = nullptr */) {
593
nsresult rv;
594
595
// Getting the default port through the protocol handler has a lot of XPCOM
596
// overhead involved. We optimize the protocols that matter for Web pages
597
// (HTTP and HTTPS) by hardcoding their default ports here.
598
if (strncmp(scheme, "http", 4) == 0) {
599
if (scheme[4] == 's' && scheme[5] == '\0') {
600
return 443;
601
}
602
if (scheme[4] == '\0') {
603
return 80;
604
}
605
}
606
607
nsCOMPtr<nsIIOService> grip;
608
net_EnsureIOService(&ioService, grip);
609
if (!ioService) return -1;
610
611
nsCOMPtr<nsIProtocolHandler> handler;
612
rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
613
if (NS_FAILED(rv)) return -1;
614
int32_t port;
615
rv = handler->GetDefaultPort(&port);
616
return NS_SUCCEEDED(rv) ? port : -1;
617
}
618
619
/**
620
* This function is a helper function to apply the ToAscii conversion
621
* to a string
622
*/
623
bool NS_StringToACE(const nsACString& idn, nsACString& result) {
624
nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
625
if (!idnSrv) return false;
626
nsresult rv = idnSrv->ConvertUTF8toACE(idn, result);
627
if (NS_FAILED(rv)) return false;
628
629
return true;
630
}
631
632
int32_t NS_GetRealPort(nsIURI* aURI) {
633
int32_t port;
634
nsresult rv = aURI->GetPort(&port);
635
if (NS_FAILED(rv)) return -1;
636
637
if (port != -1) return port; // explicitly specified
638
639
// Otherwise, we have to get the default port from the protocol handler
640
641
// Need the scheme first
642
nsAutoCString scheme;
643
rv = aURI->GetScheme(scheme);
644
if (NS_FAILED(rv)) return -1;
645
646
return NS_GetDefaultPort(scheme.get());
647
}
648
649
nsresult NS_NewInputStreamChannelInternal(
650
nsIChannel** outChannel, nsIURI* aUri,
651
already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
652
const nsACString& aContentCharset, nsILoadInfo* aLoadInfo) {
653
nsresult rv;
654
nsCOMPtr<nsIInputStreamChannel> isc =
655
do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
656
NS_ENSURE_SUCCESS(rv, rv);
657
rv = isc->SetURI(aUri);
658
NS_ENSURE_SUCCESS(rv, rv);
659
660
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
661
rv = isc->SetContentStream(stream);
662
NS_ENSURE_SUCCESS(rv, rv);
663
664
nsCOMPtr<nsIChannel> channel = do_QueryInterface(isc, &rv);
665
NS_ENSURE_SUCCESS(rv, rv);
666
667
if (!aContentType.IsEmpty()) {
668
rv = channel->SetContentType(aContentType);
669
NS_ENSURE_SUCCESS(rv, rv);
670
}
671
672
if (!aContentCharset.IsEmpty()) {
673
rv = channel->SetContentCharset(aContentCharset);
674
NS_ENSURE_SUCCESS(rv, rv);
675
}
676
677
MOZ_ASSERT(aLoadInfo, "need a loadinfo to create a inputstreamchannel");
678
channel->SetLoadInfo(aLoadInfo);
679
680
// If we're sandboxed, make sure to clear any owner the channel
681
// might already have.
682
if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) {
683
channel->SetOwner(nullptr);
684
}
685
686
channel.forget(outChannel);
687
return NS_OK;
688
}
689
690
nsresult NS_NewInputStreamChannelInternal(
691
nsIChannel** outChannel, nsIURI* aUri,
692
already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
693
const nsACString& aContentCharset, nsINode* aLoadingNode,
694
nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
695
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType) {
696
nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
697
aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
698
aContentPolicyType);
699
if (!loadInfo) {
700
return NS_ERROR_UNEXPECTED;
701
}
702
703
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
704
705
return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
706
aContentType, aContentCharset,
707
loadInfo);
708
}
709
710
nsresult NS_NewInputStreamChannel(
711
nsIChannel** outChannel, nsIURI* aUri,
712
already_AddRefed<nsIInputStream> aStream, nsIPrincipal* aLoadingPrincipal,
713
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
714
const nsACString& aContentType /* = EmptyCString() */,
715
const nsACString& aContentCharset /* = EmptyCString() */) {
716
nsCOMPtr<nsIInputStream> stream = aStream;
717
return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
718
aContentType, aContentCharset,
719
nullptr, // aLoadingNode
720
aLoadingPrincipal,
721
nullptr, // aTriggeringPrincipal
722
aSecurityFlags, aContentPolicyType);
723
}
724
725
nsresult NS_NewInputStreamChannelInternal(nsIChannel** outChannel, nsIURI* aUri,
726
const nsAString& aData,
727
const nsACString& aContentType,
728
nsILoadInfo* aLoadInfo,
729
bool aIsSrcdocChannel /* = false */) {
730
nsresult rv;
731
nsCOMPtr<nsIStringInputStream> stream;
732
stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
733
NS_ENSURE_SUCCESS(rv, rv);
734
735
uint32_t len;
736
char* utf8Bytes = ToNewUTF8String(aData, &len);
737
rv = stream->AdoptData(utf8Bytes, len);
738
739
nsCOMPtr<nsIChannel> channel;
740
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aUri,
741
stream.forget(), aContentType,
742
NS_LITERAL_CSTRING("UTF-8"), aLoadInfo);
743
744
NS_ENSURE_SUCCESS(rv, rv);
745
746
if (aIsSrcdocChannel) {
747
nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(channel);
748
NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
749
inStrmChan->SetSrcdocData(aData);
750
}
751
channel.forget(outChannel);
752
return NS_OK;
753
}
754
755
nsresult NS_NewInputStreamChannelInternal(
756
nsIChannel** outChannel, nsIURI* aUri, const nsAString& aData,
757
const nsACString& aContentType, nsINode* aLoadingNode,
758
nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
759
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
760
bool aIsSrcdocChannel /* = false */) {
761
nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
762
aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
763
aContentPolicyType);
764
return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
765
loadInfo, aIsSrcdocChannel);
766
}
767
768
nsresult NS_NewInputStreamChannel(nsIChannel** outChannel, nsIURI* aUri,
769
const nsAString& aData,
770
const nsACString& aContentType,
771
nsIPrincipal* aLoadingPrincipal,
772
nsSecurityFlags aSecurityFlags,
773
nsContentPolicyType aContentPolicyType,
774
bool aIsSrcdocChannel /* = false */) {
775
return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
776
nullptr, // aLoadingNode
777
aLoadingPrincipal,
778
nullptr, // aTriggeringPrincipal
779
aSecurityFlags, aContentPolicyType,
780
aIsSrcdocChannel);
781
}
782
783
nsresult NS_NewInputStreamPump(
784
nsIInputStreamPump** aResult, already_AddRefed<nsIInputStream> aStream,
785
uint32_t aSegsize /* = 0 */, uint32_t aSegcount /* = 0 */,
786
bool aCloseWhenDone /* = false */,
787
nsIEventTarget* aMainThreadTarget /* = nullptr */) {
788
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
789
790
nsresult rv;
791
nsCOMPtr<nsIInputStreamPump> pump =
792
do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
793
if (NS_SUCCEEDED(rv)) {
794
rv = pump->Init(stream, aSegsize, aSegcount, aCloseWhenDone,
795
aMainThreadTarget);
796
if (NS_SUCCEEDED(rv)) {
797
*aResult = nullptr;
798
pump.swap(*aResult);
799
}
800
}
801
return rv;
802
}
803
804
nsresult NS_NewLoadGroup(nsILoadGroup** result, nsIRequestObserver* obs) {
805
nsresult rv;
806
nsCOMPtr<nsILoadGroup> group =
807
do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
808
if (NS_SUCCEEDED(rv)) {
809
rv = group->SetGroupObserver(obs);
810
if (NS_SUCCEEDED(rv)) {
811
*result = nullptr;
812
group.swap(*result);
813
}
814
}
815
return rv;
816
}
817
818
bool NS_IsReasonableHTTPHeaderValue(const nsACString& aValue) {
819
return mozilla::net::nsHttp::IsReasonableHeaderValue(aValue);
820
}
821
822
bool NS_IsValidHTTPToken(const nsACString& aToken) {
823
return mozilla::net::nsHttp::IsValidToken(aToken);
824
}
825
826
void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) {
827
mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest);
828
}
829
830
nsresult NS_NewLoadGroup(nsILoadGroup** aResult, nsIPrincipal* aPrincipal) {
831
using mozilla::LoadContext;
832
nsresult rv;
833
834
nsCOMPtr<nsILoadGroup> group =
835
do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
836
NS_ENSURE_SUCCESS(rv, rv);
837
838
RefPtr<LoadContext> loadContext = new LoadContext(aPrincipal);
839
rv = group->SetNotificationCallbacks(loadContext);
840
NS_ENSURE_SUCCESS(rv, rv);
841
842
group.forget(aResult);
843
return rv;
844
}
845
846
bool NS_LoadGroupMatchesPrincipal(nsILoadGroup* aLoadGroup,
847
nsIPrincipal* aPrincipal) {
848
if (!aPrincipal) {
849
return false;
850
}
851
852
// If this is a null principal then the load group doesn't really matter.
853
// The principal will not be allowed to perform any actions that actually
854
// use the load group. Unconditionally treat null principals as a match.
855
if (aPrincipal->GetIsNullPrincipal()) {
856
return true;
857
}
858
859
if (!aLoadGroup) {
860
return false;
861
}
862
863
nsCOMPtr<nsILoadContext> loadContext;
864
NS_QueryNotificationCallbacks(nullptr, aLoadGroup, NS_GET_IID(nsILoadContext),
865
getter_AddRefs(loadContext));
866
NS_ENSURE_TRUE(loadContext, false);
867
868
// Verify load context browser flag match the principal
869
bool contextInIsolatedBrowser;
870
nsresult rv =
871
loadContext->GetIsInIsolatedMozBrowserElement(&contextInIsolatedBrowser);
872
NS_ENSURE_SUCCESS(rv, false);
873
874
return contextInIsolatedBrowser ==
875
aPrincipal->GetIsInIsolatedMozBrowserElement();
876
}
877
878
nsresult NS_NewDownloader(nsIStreamListener** result,
879
nsIDownloadObserver* observer,
880
nsIFile* downloadLocation /* = nullptr */) {
881
nsresult rv;
882
nsCOMPtr<nsIDownloader> downloader =
883
do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
884
if (NS_SUCCEEDED(rv)) {
885
rv = downloader->Init(observer, downloadLocation);
886
if (NS_SUCCEEDED(rv)) {
887
downloader.forget(result);
888
}
889
}
890
return rv;
891
}
892
893
nsresult NS_NewIncrementalStreamLoader(
894
nsIIncrementalStreamLoader** result,
895
nsIIncrementalStreamLoaderObserver* observer) {
896
nsresult rv;
897
nsCOMPtr<nsIIncrementalStreamLoader> loader =
898
do_CreateInstance(NS_INCREMENTALSTREAMLOADER_CONTRACTID, &rv);
899
if (NS_SUCCEEDED(rv)) {
900
rv = loader->Init(observer);
901
if (NS_SUCCEEDED(rv)) {
902
*result = nullptr;
903
loader.swap(*result);
904
}
905
}
906
return rv;
907
}
908
909
nsresult NS_NewStreamLoader(
910
nsIStreamLoader** result, nsIStreamLoaderObserver* observer,
911
nsIRequestObserver* requestObserver /* = nullptr */) {
912
nsresult rv;
913
nsCOMPtr<nsIStreamLoader> loader =
914
do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
915
if (NS_SUCCEEDED(rv)) {
916
rv = loader->Init(observer, requestObserver);
917
if (NS_SUCCEEDED(rv)) {
918
*result = nullptr;
919
loader.swap(*result);
920
}
921
}
922
return rv;
923
}
924
925
nsresult NS_NewStreamLoaderInternal(
926
nsIStreamLoader** outStream, nsIURI* aUri,
927
nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
928
nsIPrincipal* aLoadingPrincipal, nsSecurityFlags aSecurityFlags,
929
nsContentPolicyType aContentPolicyType,
930
nsILoadGroup* aLoadGroup /* = nullptr */,
931
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
932
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
933
nsCOMPtr<nsIChannel> channel;
934
nsresult rv = NS_NewChannelInternal(
935
getter_AddRefs(channel), aUri, aLoadingNode, aLoadingPrincipal,
936
nullptr, // aTriggeringPrincipal
937
Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
938
aContentPolicyType,
939
nullptr, // nsICookieSettings
940
nullptr, // PerformanceStorage
941
aLoadGroup, aCallbacks, aLoadFlags);
942
943
NS_ENSURE_SUCCESS(rv, rv);
944
rv = NS_NewStreamLoader(outStream, aObserver);
945
NS_ENSURE_SUCCESS(rv, rv);
946
return channel->AsyncOpen(*outStream);
947
}
948
949
nsresult NS_NewStreamLoader(
950
nsIStreamLoader** outStream, nsIURI* aUri,
951
nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
952
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
953
nsILoadGroup* aLoadGroup /* = nullptr */,
954
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
955
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
956
NS_ASSERTION(aLoadingNode,
957
"Can not create stream loader without a loading Node!");
958
return NS_NewStreamLoaderInternal(
959
outStream, aUri, aObserver, aLoadingNode, aLoadingNode->NodePrincipal(),
960
aSecurityFlags, aContentPolicyType, aLoadGroup, aCallbacks, aLoadFlags);
961
}
962
963
nsresult NS_NewStreamLoader(
964
nsIStreamLoader** outStream, nsIURI* aUri,
965
nsIStreamLoaderObserver* aObserver, nsIPrincipal* aLoadingPrincipal,
966
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
967
nsILoadGroup* aLoadGroup /* = nullptr */,
968
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
969
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
970
return NS_NewStreamLoaderInternal(outStream, aUri, aObserver,
971
nullptr, // aLoadingNode
972
aLoadingPrincipal, aSecurityFlags,
973
aContentPolicyType, aLoadGroup, aCallbacks,
974
aLoadFlags);
975
}
976
977
nsresult NS_NewSyncStreamListener(nsIStreamListener** result,
978
nsIInputStream** stream) {
979
nsCOMPtr<nsISyncStreamListener> listener = nsSyncStreamListener::Create();
980
if (listener) {
981
nsresult rv = listener->GetInputStream(stream);
982
if (NS_SUCCEEDED(rv)) {
983
listener.forget(result);
984
}
985
return rv;
986
}
987
return NS_ERROR_FAILURE;
988
}
989
990
nsresult NS_ImplementChannelOpen(nsIChannel* channel, nsIInputStream** result) {
991
nsCOMPtr<nsIStreamListener> listener;
992
nsCOMPtr<nsIInputStream> stream;
993
nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
994
getter_AddRefs(stream));
995
NS_ENSURE_SUCCESS(rv, rv);
996
997
rv = NS_MaybeOpenChannelUsingAsyncOpen(channel, listener);
998
NS_ENSURE_SUCCESS(rv, rv);
999
1000
uint64_t n;
1001
// block until the initial response is received or an error occurs.
1002
rv = stream->Available(&n);
1003
NS_ENSURE_SUCCESS(rv, rv);
1004
1005
*result = nullptr;
1006
stream.swap(*result);
1007
1008
return NS_OK;
1009
}
1010
1011
nsresult NS_NewRequestObserverProxy(nsIRequestObserver** result,
1012
nsIRequestObserver* observer,
1013
nsISupports* context) {
1014
nsCOMPtr<nsIRequestObserverProxy> proxy = new nsRequestObserverProxy();
1015
nsresult rv = proxy->Init(observer, context);
1016
if (NS_SUCCEEDED(rv)) {
1017
proxy.forget(result);
1018
}
1019
return rv;
1020
}
1021
1022
nsresult NS_NewSimpleStreamListener(
1023
nsIStreamListener** result, nsIOutputStream* sink,
1024
nsIRequestObserver* observer /* = nullptr */) {
1025
nsresult rv;
1026
nsCOMPtr<nsISimpleStreamListener> listener =
1027
do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
1028
if (NS_SUCCEEDED(rv)) {
1029
rv = listener->Init(sink, observer);
1030
if (NS_SUCCEEDED(rv)) {
1031
listener.forget(result);
1032
}
1033
}
1034
return rv;
1035
}
1036
1037
nsresult NS_CheckPortSafety(int32_t port, const char* scheme,
1038
nsIIOService* ioService /* = nullptr */) {
1039
nsresult rv;
1040
nsCOMPtr<nsIIOService> grip;
1041
rv = net_EnsureIOService(&ioService, grip);
1042
if (ioService) {
1043
bool allow;
1044
rv = ioService->AllowPort(port, scheme, &allow);
1045
if (NS_SUCCEEDED(rv) && !allow) {
1046
NS_WARNING("port blocked");
1047
rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
1048
}
1049
}
1050
return rv;
1051
}
1052
1053
nsresult NS_CheckPortSafety(nsIURI* uri) {
1054
int32_t port;
1055
nsresult rv = uri->GetPort(&port);
1056
if (NS_FAILED(rv) || port == -1) // port undefined or default-valued
1057
return NS_OK;
1058
nsAutoCString scheme;
1059
uri->GetScheme(scheme);
1060
return NS_CheckPortSafety(port, scheme.get());
1061
}
1062
1063
nsresult NS_NewProxyInfo(const nsACString& type, const nsACString& host,
1064
int32_t port, uint32_t flags, nsIProxyInfo** result) {
1065
nsresult rv;
1066
nsCOMPtr<nsIProtocolProxyService> pps =
1067
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
1068
if (NS_SUCCEEDED(rv))
1069
rv = pps->NewProxyInfo(type, host, port, EmptyCString(), EmptyCString(),
1070
flags, UINT32_MAX, nullptr, result);
1071
return rv;
1072
}
1073
1074
nsresult NS_GetFileProtocolHandler(nsIFileProtocolHandler** result,
1075
nsIIOService* ioService /* = nullptr */) {
1076
nsresult rv;
1077
nsCOMPtr<nsIIOService> grip;
1078
rv = net_EnsureIOService(&ioService, grip);
1079
if (ioService) {
1080
nsCOMPtr<nsIProtocolHandler> handler;
1081
rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
1082
if (NS_SUCCEEDED(rv)) rv = CallQueryInterface(handler, result);
1083
}
1084
return rv;
1085
}
1086
1087
nsresult NS_GetFileFromURLSpec(const nsACString& inURL, nsIFile** result,
1088
nsIIOService* ioService /* = nullptr */) {
1089
nsresult rv;
1090
nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1091
rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1092
if (NS_SUCCEEDED(rv)) rv = fileHandler->GetFileFromURLSpec(inURL, result);
1093
return rv;
1094
}
1095
1096
nsresult NS_GetURLSpecFromFile(nsIFile* file, nsACString& url,
1097
nsIIOService* ioService /* = nullptr */) {
1098
nsresult rv;
1099
nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1100
rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1101
if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromFile(file, url);
1102
return rv;
1103
}
1104
1105
nsresult NS_GetURLSpecFromActualFile(nsIFile* file, nsACString& url,
1106
nsIIOService* ioService /* = nullptr */) {
1107
nsresult rv;
1108
nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1109
rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1110
if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromActualFile(file, url);
1111
return rv;
1112
}
1113
1114
nsresult NS_GetURLSpecFromDir(nsIFile* file, nsACString& url,
1115
nsIIOService* ioService /* = nullptr */) {
1116
nsresult rv;
1117
nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1118
rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1119
if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromDir(file, url);
1120
return rv;
1121
}
1122
1123
void NS_GetReferrerFromChannel(nsIChannel* channel, nsIURI** referrer) {
1124
*referrer = nullptr;
1125
1126
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
1127
if (props) {
1128
// We have to check for a property on a property bag because the
1129
// referrer may be empty for security reasons (for example, when loading
1130
// an http page with an https referrer).
1131
nsresult rv = props->GetPropertyAsInterface(
1132
NS_LITERAL_STRING("docshell.internalReferrer"), NS_GET_IID(nsIURI),
1133
reinterpret_cast<void**>(referrer));
1134
if (NS_FAILED(rv)) *referrer = nullptr;
1135
}
1136
1137
if (*referrer) {
1138
return;
1139
}
1140
1141
// if that didn't work, we can still try to get the referrer from the
1142
// nsIHttpChannel (if we can QI to it)
1143
nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
1144
if (!chan) {
1145
return;
1146
}
1147
1148
nsCOMPtr<nsIReferrerInfo> referrerInfo = chan->GetReferrerInfo();
1149
if (!referrerInfo) {
1150
return;
1151
}
1152
1153
referrerInfo->GetOriginalReferrer(referrer);
1154
}
1155
1156
already_AddRefed<nsINetUtil> do_GetNetUtil(nsresult* error /* = 0 */) {
1157
nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
1158
nsCOMPtr<nsINetUtil> util;
1159
if (io) util = do_QueryInterface(io);
1160
1161
if (error) *error = !!util ? NS_OK : NS_ERROR_FAILURE;
1162
return util.forget();
1163
}
1164
1165
nsresult NS_ParseRequestContentType(const nsACString& rawContentType,
1166
nsCString& contentType,
1167
nsCString& contentCharset) {
1168
// contentCharset is left untouched if not present in rawContentType
1169
nsresult rv;
1170
nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1171
NS_ENSURE_SUCCESS(rv, rv);
1172
nsCString charset;
1173
bool hadCharset;
1174
rv = util->ParseRequestContentType(rawContentType, charset, &hadCharset,
1175
contentType);
1176
if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
1177
return rv;
1178
}
1179
1180
nsresult NS_ParseResponseContentType(const nsACString& rawContentType,
1181
nsCString& contentType,
1182
nsCString& contentCharset) {
1183
// contentCharset is left untouched if not present in rawContentType
1184
nsresult rv;
1185
nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1186
NS_ENSURE_SUCCESS(rv, rv);
1187
nsCString charset;
1188
bool hadCharset;
1189
rv = util->ParseResponseContentType(rawContentType, charset, &hadCharset,
1190
contentType);
1191
if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
1192
return rv;
1193
}
1194
1195
nsresult NS_ExtractCharsetFromContentType(const nsACString& rawContentType,
1196
nsCString& contentCharset,
1197
bool* hadCharset,
1198
int32_t* charsetStart,
1199
int32_t* charsetEnd) {
1200
// contentCharset is left untouched if not present in rawContentType
1201
nsresult rv;
1202
nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1203
NS_ENSURE_SUCCESS(rv, rv);
1204
1205
return util->ExtractCharsetFromContentType(
1206
rawContentType, contentCharset, charsetStart, charsetEnd, hadCharset);
1207
}
1208
1209
nsresult NS_NewAtomicFileOutputStream(nsIOutputStream** result, nsIFile* file,
1210
int32_t ioFlags /* = -1 */,
1211
int32_t perm /* = -1 */,
1212
int32_t behaviorFlags /* = 0 */) {
1213
nsresult rv;
1214
nsCOMPtr<nsIFileOutputStream> out =
1215
do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1216
if (NS_SUCCEEDED(rv)) {
1217
rv = out->Init(file, ioFlags, perm, behaviorFlags);
1218
if (NS_SUCCEEDED(rv)) out.forget(result);
1219
}
1220
return rv;
1221
}
1222
1223
nsresult NS_NewSafeLocalFileOutputStream(nsIOutputStream** result,
1224
nsIFile* file,
1225
int32_t ioFlags /* = -1 */,
1226
int32_t perm /* = -1 */,
1227
int32_t behaviorFlags /* = 0 */) {
1228
nsresult rv;
1229
nsCOMPtr<nsIFileOutputStream> out =
1230
do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1231
if (NS_SUCCEEDED(rv)) {
1232
rv = out->Init(file, ioFlags, perm, behaviorFlags);
1233
if (NS_SUCCEEDED(rv)) out.forget(result);
1234
}
1235
return rv;
1236
}
1237
1238
nsresult NS_NewLocalFileStream(nsIFileStream** result, nsIFile* file,
1239
int32_t ioFlags /* = -1 */,
1240
int32_t perm /* = -1 */,
1241
int32_t behaviorFlags /* = 0 */) {
1242
nsCOMPtr<nsIFileStream> stream = new nsFileStream();
1243
nsresult rv = stream->Init(file, ioFlags, perm, behaviorFlags);
1244
if (NS_SUCCEEDED(rv)) {
1245
stream.forget(result);
1246
}
1247
return rv;
1248
}
1249
1250
nsresult NS_NewBufferedOutputStream(
1251
nsIOutputStream** aResult, already_AddRefed<nsIOutputStream> aOutputStream,
1252
uint32_t aBufferSize) {
1253
nsCOMPtr<nsIOutputStream> outputStream = std::move(aOutputStream);
1254
1255
nsresult rv;
1256
nsCOMPtr<nsIBufferedOutputStream> out =
1257
do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
1258
if (NS_SUCCEEDED(rv)) {
1259
rv = out->Init(outputStream, aBufferSize);
1260
if (NS_SUCCEEDED(rv)) {
1261
out.forget(aResult);
1262
}
1263
}
1264
return rv;
1265
}
1266
1267
MOZ_MUST_USE nsresult NS_NewBufferedInputStream(
1268
nsIInputStream** aResult, already_AddRefed<nsIInputStream> aInputStream,
1269
uint32_t aBufferSize) {
1270
nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
1271
1272
nsresult rv;
1273
nsCOMPtr<nsIBufferedInputStream> in =
1274
do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
1275
if (NS_SUCCEEDED(rv)) {
1276
rv = in->Init(inputStream, aBufferSize);
1277
if (NS_SUCCEEDED(rv)) {
1278
in.forget(aResult);
1279
}
1280
}
1281
return rv;
1282
}
1283
1284
namespace {
1285
1286
#define BUFFER_SIZE 8192
1287
1288
class BufferWriter final : public nsIInputStreamCallback {
1289
public:
1290
NS_DECL_THREADSAFE_ISUPPORTS
1291
1292
BufferWriter(nsIInputStream* aInputStream, void* aBuffer, int64_t aCount)
1293
: mMonitor("BufferWriter.mMonitor"),
1294
mInputStream(aInputStream),
1295
mBuffer(aBuffer),
1296
mCount(aCount),
1297
mWrittenData(0),
1298
mBufferType(aBuffer ? eExternal : eInternal),
1299
mBufferSize(0) {
1300
MOZ_ASSERT(aInputStream);
1301
MOZ_ASSERT(aCount == -1 || aCount > 0);
1302
MOZ_ASSERT_IF(mBuffer, aCount > 0);
1303
}
1304
1305
nsresult Write() {
1306
NS_ASSERT_OWNINGTHREAD(BufferWriter);
1307
1308
// Let's make the inputStream buffered if it's not.
1309
if (!NS_InputStreamIsBuffered(mInputStream)) {
1310
nsCOMPtr<nsIInputStream> bufferedStream;
1311
nsresult rv = NS_NewBufferedInputStream(
1312
getter_AddRefs(bufferedStream), mInputStream.forget(), BUFFER_SIZE);
1313
NS_ENSURE_SUCCESS(rv, rv);
1314
1315
mInputStream = bufferedStream;
1316
}
1317
1318
mAsyncInputStream = do_QueryInterface(mInputStream);
1319
1320
if (!mAsyncInputStream) {
1321
return WriteSync();
1322
}
1323
1324
// Let's use mAsyncInputStream only.
1325
mInputStream = nullptr;
1326
1327
return WriteAsync();
1328
}
1329
1330
uint64_t WrittenData() const {
1331
NS_ASSERT_OWNINGTHREAD(BufferWriter);
1332
return mWrittenData;
1333
}
1334
1335
void* StealBuffer() {
1336
NS_ASSERT_OWNINGTHREAD(BufferWriter);
1337
MOZ_ASSERT(mBufferType == eInternal);
1338
1339
void* buffer = mBuffer;
1340
1341
mBuffer = nullptr;
1342
mBufferSize = 0;
1343
1344
return buffer;
1345
}
1346
1347
private:
1348
~BufferWriter() {
1349
if (mBuffer && mBufferType == eInternal) {
1350
free(mBuffer);
1351
}
1352
1353
if (mTaskQueue) {
1354
mTaskQueue->BeginShutdown();
1355
}
1356
}
1357
1358
nsresult WriteSync() {
1359
NS_ASSERT_OWNINGTHREAD(BufferWriter);
1360
1361
uint64_t length = (uint64_t)mCount;
1362
1363
if (mCount == -1) {
1364
nsresult rv = mInputStream->Available(&length);
1365
NS_ENSURE_SUCCESS(rv, rv);
1366
1367
if (length == 0) {
1368
// nothing to read.
1369
return NS_OK;
1370
}
1371
}
1372
1373
if (mBufferType == eInternal) {
1374
mBuffer = malloc(length);
1375
if (NS_WARN_IF(!mBuffer)) {
1376
return NS_ERROR_OUT_OF_MEMORY;
1377
}
1378
}
1379
1380
uint32_t writtenData;
1381
nsresult rv = mInputStream->ReadSegments(NS_CopySegmentToBuffer, mBuffer,
1382
length, &writtenData);
1383
NS_ENSURE_SUCCESS(rv, rv);
1384
1385
mWrittenData = writtenData;
1386
return NS_OK;
1387
}
1388
1389
nsresult WriteAsync() {
1390
NS_ASSERT_OWNINGTHREAD(BufferWriter);
1391
1392
if (mCount > 0 && mBufferType == eInternal) {
1393
mBuffer = malloc(mCount);
1394
if (NS_WARN_IF(!mBuffer)) {
1395
return NS_ERROR_OUT_OF_MEMORY;
1396
}
1397
}
1398
1399
while (true) {
1400
if (mCount == -1 && !MaybeExpandBufferSize()) {
1401
return NS_ERROR_OUT_OF_MEMORY;
1402
}
1403
1404
uint64_t offset = mWrittenData;
1405
uint64_t length = mCount == -1 ? BUFFER_SIZE : mCount;
1406
1407
// Let's try to read data directly.
1408
uint32_t writtenData;
1409
nsresult rv = mAsyncInputStream->ReadSegments(
1410
NS_CopySegmentToBuffer, static_cast<char*>(mBuffer) + offset, length,
1411
&writtenData);
1412
1413
// Operation completed. Nothing more to read.
1414
if (NS_SUCCEEDED(rv) && writtenData == 0) {
1415
return NS_OK;
1416
}
1417
1418
// If we succeeded, let's try to read again.
1419
if (NS_SUCCEEDED(rv)) {
1420
mWrittenData += writtenData;
1421
if (mCount != -1) {
1422
MOZ_ASSERT(mCount >= writtenData);
1423
mCount -= writtenData;
1424
1425
// Is this the end of the reading?
1426
if (mCount == 0) {
1427
return NS_OK;
1428
}
1429
}
1430
1431
continue;
1432
}
1433
1434
// Async wait...
1435
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
1436
rv = MaybeCreateTaskQueue();
1437
if (NS_WARN_IF(NS_FAILED(rv))) {
1438
return rv;
1439
}
1440
1441
MonitorAutoLock lock(mMonitor);
1442
1443
rv = mAsyncInputStream->AsyncWait(this, 0, length, mTaskQueue);
1444
if (NS_WARN_IF(NS_FAILED(rv))) {
1445
return rv;
1446
}
1447
1448
lock.Wait();
1449
continue;
1450
}
1451
1452
// Otherwise, let's propagate the error.
1453
return rv;
1454
}
1455
1456
MOZ_ASSERT_UNREACHABLE("We should not be here");
1457
return NS_ERROR_FAILURE;
1458
}
1459
1460
nsresult MaybeCreateTaskQueue() {
1461
NS_ASSERT_OWNINGTHREAD(BufferWriter);
1462
1463
if (!mTaskQueue) {
1464
nsCOMPtr<nsIEventTarget> target =
1465
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
1466
if (!target) {
1467
return NS_ERROR_FAILURE;
1468
}
1469
1470
mTaskQueue = new TaskQueue(target.forget());
1471
}
1472
1473
return NS_OK;
1474
}
1475
1476
NS_IMETHOD
1477
OnInputStreamReady(nsIAsyncInputStream* aStream) override {
1478
MOZ_ASSERT(!NS_IsMainThread());
1479
1480
// We have something to read. Let's unlock the main-thread.
1481
MonitorAutoLock lock(mMonitor);
1482
lock.Notify();
1483
return NS_OK;
1484
}
1485
1486
bool MaybeExpandBufferSize() {
1487
NS_ASSERT_OWNINGTHREAD(BufferWriter);
1488
1489
MOZ_ASSERT(mCount == -1);
1490
1491
if (mBufferSize >= mWrittenData + BUFFER_SIZE) {
1492
// The buffer is big enough.
1493
return true;
1494
}
1495
1496
CheckedUint32 bufferSize =
1497
std::max<uint32_t>(static_cast<uint32_t>(mWrittenData), BUFFER_SIZE);
1498
while (bufferSize.isValid() &&
1499
bufferSize.value() < mWrittenData + BUFFER_SIZE) {
1500
bufferSize *= 2;
1501
}
1502
1503
if (!bufferSize.isValid()) {
1504
return false;
1505
}
1506
1507
void* buffer = realloc(mBuffer, bufferSize.value());
1508
if (!buffer) {
1509
return false;
1510
}
1511
1512
mBuffer = buffer;
1513
mBufferSize = bufferSize.value();
1514
return true;
1515
}
1516
1517
// All the members of this class are touched on the owning thread only. The
1518
// monitor is only used to communicate when there is more data to read.
1519
Monitor mMonitor;
1520
1521
nsCOMPtr<nsIInputStream> mInputStream;
1522
nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream;
1523
1524
RefPtr<TaskQueue> mTaskQueue;
1525
1526
void* mBuffer;
1527
int64_t mCount;
1528
uint64_t mWrittenData;
1529
1530
enum {
1531
// The buffer is allocated internally and this object must release it
1532
// in the DTOR if not stolen. The buffer can be reallocated.
1533
eInternal,
1534
1535
// The buffer is not owned by this object and it cannot be reallocated.
1536
eExternal,
1537
} mBufferType;
1538
1539
// The following set if needed for the async read.
1540
uint64_t mBufferSize;
1541
};
1542
1543
NS_IMPL_ISUPPORTS(BufferWriter, nsIInputStreamCallback)
1544
1545
} // anonymous namespace
1546
1547
nsresult NS_ReadInputStreamToBuffer(nsIInputStream* aInputStream, void** aDest,
1548
int64_t aCount, uint64_t* aWritten) {
1549
MOZ_ASSERT(aInputStream);
1550
MOZ_ASSERT(aCount >= -1);
1551
1552
uint64_t dummyWritten;
1553
if (!aWritten) {
1554
aWritten = &dummyWritten;
1555
}
1556
1557
if (aCount == 0) {
1558
*aWritten = 0;
1559
return NS_OK;
1560
}
1561
1562
// This will take care of allocating and reallocating aDest.
1563
RefPtr<BufferWriter> writer = new BufferWriter(aInputStream, *aDest, aCount);
1564
1565
nsresult rv = writer->Write();
1566
NS_ENSURE_SUCCESS(rv, rv);
1567
1568
*aWritten = writer->WrittenData();
1569
1570
if (!*aDest) {
1571
*aDest = writer->StealBuffer();
1572
}
1573
1574
return NS_OK;
1575
}
1576
1577
nsresult NS_ReadInputStreamToString(nsIInputStream* aInputStream,
1578
nsACString& aDest, int64_t aCount,
1579
uint64_t* aWritten) {
1580
uint64_t dummyWritten;
1581
if (!aWritten) {
1582
aWritten = &dummyWritten;
1583
}
1584
1585
// Nothing to do if aCount is 0.
1586
if (aCount == 0) {
1587
aDest.Truncate();
1588
*aWritten = 0;
1589
return NS_OK;
1590
}
1591
1592
// If we have the size, we can pre-allocate the buffer.
1593
if (aCount > 0) {
1594
if (NS_WARN_IF(aCount >= INT32_MAX) ||
1595
NS_WARN_IF(!aDest.SetLength(aCount, mozilla::fallible))) {
1596
return NS_ERROR_OUT_OF_MEMORY;
1597
}
1598
1599
void* dest = aDest.BeginWriting();
1600
nsresult rv =
1601
NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
1602
NS_ENSURE_SUCCESS(rv, rv);
1603
1604
if ((uint64_t)aCount > *aWritten) {
1605
aDest.Truncate(*aWritten);
1606
}
1607
1608
return NS_OK;
1609
}
1610
1611
// If the size is unknown, BufferWriter will allocate the buffer.
1612
void* dest = nullptr;
1613
nsresult rv =
1614
NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
1615
MOZ_ASSERT_IF(NS_FAILED(rv), dest == nullptr);
1616
NS_ENSURE_SUCCESS(rv, rv);
1617
1618
if (!dest) {
1619
MOZ_ASSERT(*aWritten == 0);
1620
aDest.Truncate();
1621
return NS_OK;
1622
}
1623
1624
aDest.Adopt(reinterpret_cast<char*>(dest), *aWritten);
1625
return NS_OK;
1626
}
1627
1628
nsresult NS_NewURI(
1629
nsIURI** result, const nsACString& spec, NotNull<const Encoding*> encoding,
1630
nsIURI* baseURI /* = nullptr */,
1631
nsIIOService*
1632
ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1633
{
1634
nsAutoCString charset;
1635
encoding->Name(charset);
1636
return NS_NewURI(result, spec, charset.get(), baseURI, ioService);
1637
}
1638
1639
nsresult NS_NewURI(
1640
nsIURI** result, const nsAString& aSpec,
1641
const char* charset /* = nullptr */, nsIURI* baseURI /* = nullptr */,
1642
nsIIOService*
1643
ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1644
{
1645
nsAutoCString spec;
1646
if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
1647
return NS_ERROR_OUT_OF_MEMORY;
1648
}
1649
return NS_NewURI(result, spec, charset, baseURI, ioService);
1650
}
1651
1652
nsresult NS_NewURI(
1653
nsIURI** result, const nsAString& aSpec, NotNull<const Encoding*> encoding,
1654
nsIURI* baseURI /* = nullptr */,
1655
nsIIOService*
1656
ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1657
{
1658
nsAutoCString spec;
1659
if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
1660
return NS_ERROR_OUT_OF_MEMORY;
1661
}
1662
return NS_NewURI(result, spec, encoding, baseURI, ioService);
1663
}
1664
1665
nsresult NS_NewURI(
1666
nsIURI** result, const char* spec, nsIURI* baseURI /* = nullptr */,
1667
nsIIOService*
1668
ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1669
{
1670
return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI,
1671
ioService);
1672
}
1673
1674
static nsresult NewStandardURI(const nsACString& aSpec, const char* aCharset,
1675
nsIURI* aBaseURI, int32_t aDefaultPort,
1676
nsIURI** aURI) {
1677
nsCOMPtr<nsIURI> base(aBaseURI);
1678
return NS_MutateURI(new nsStandardURL::Mutator())
1679
.Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
1680
nsIStandardURL::URLTYPE_AUTHORITY, aDefaultPort,
1681
nsCString(aSpec), aCharset, base, nullptr))
1682
.Finalize(aURI);
1683
}
1684
1685
extern MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount;
1686
1687
template <typename T>
1688
class TlsAutoIncrement {
1689
public:
1690
explicit TlsAutoIncrement(T& var) : mVar(var) {
1691
mValue = mVar.get();
1692
mVar.set(mValue + 1);
1693
}
1694
~TlsAutoIncrement() {
1695
typename T::Type value = mVar.get();
1696
MOZ_ASSERT(value == mValue + 1);
1697
mVar.set(value - 1);
1698
}
1699
1700
typename T::Type value() { return mValue; }
1701
1702
private:
1703
typename T::Type mValue;
1704
T& mVar;
1705
};
1706
1707
nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
1708
const char* aCharset /* = nullptr */,
1709
nsIURI* aBaseURI /* = nullptr */,
1710
nsIIOService* aIOService /* = nullptr */) {
1711
TlsAutoIncrement<decltype(gTlsURLRecursionCount)> inc(gTlsURLRecursionCount);
1712
if (inc.value() >= MAX_RECURSION_COUNT) {
1713
return NS_ERROR_MALFORMED_URI;
1714
}
1715
1716
nsAutoCString scheme;
1717
nsresult rv = net_ExtractURLScheme(aSpec, scheme);
1718
if (NS_FAILED(rv)) {
1719
// then aSpec is relative
1720
if (!aBaseURI) {
1721
return NS_ERROR_MALFORMED_URI;
1722
}
1723
1724
if (!aSpec.IsEmpty() && aSpec[0] == '#') {
1725
// Looks like a reference instead of a fully-specified URI.
1726
// --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
1727
return NS_GetURIWithNewRef(aBaseURI, aSpec, aURI);
1728
}
1729
1730
rv = aBaseURI->GetScheme(scheme);
1731
if (NS_FAILED(rv)) return rv;
1732
}
1733
1734
if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) {
1735
return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT,
1736
aURI);
1737
}
1738
if (scheme.EqualsLiteral("https") || scheme.EqualsLiteral("wss")) {
1739
return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT,
1740
aURI);
1741
}
1742
if (scheme.EqualsLiteral("ftp")) {
1743
return NewStandardURI(aSpec, aCharset, aBaseURI, 21, aURI);
1744
}
1745
if (scheme.EqualsLiteral("ssh")) {
1746
return NewStandardURI(aSpec, aCharset, aBaseURI, 22, aURI);
1747
}
1748
1749
if (scheme.EqualsLiteral("file")) {
1750
nsAutoCString buf(aSpec);
1751
#if defined(XP_WIN)
1752
buf.Truncate();