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