Bug 1526591 - Remove devtools.inspector.shapesHighlighter.enabled pref. r=rcaliman
[gecko.git] / netwerk / base / nsNetUtil.cpp
blob31373039d0cd1dd06beea2a63fd23b3776b50143
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/. */
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
10 #include "nsNetUtil.h"
12 #include "mozilla/Atomics.h"
13 #include "mozilla/Encoding.h"
14 #include "mozilla/LoadContext.h"
15 #include "mozilla/LoadInfo.h"
16 #include "mozilla/BasePrincipal.h"
17 #include "mozilla/Monitor.h"
18 #include "mozilla/TaskQueue.h"
19 #include "mozilla/Telemetry.h"
20 #include "nsCategoryCache.h"
21 #include "nsContentUtils.h"
22 #include "nsFileStreams.h"
23 #include "nsHashKeys.h"
24 #include "nsHttp.h"
25 #include "nsIAsyncStreamCopier.h"
26 #include "nsIAuthPrompt.h"
27 #include "nsIAuthPrompt2.h"
28 #include "nsIAuthPromptAdapterFactory.h"
29 #include "nsIBufferedStreams.h"
30 #include "nsIChannelEventSink.h"
31 #include "nsIContentSniffer.h"
32 #include "mozilla/dom/Document.h"
33 #include "nsIDownloader.h"
34 #include "nsIFileProtocolHandler.h"
35 #include "nsIFileStreams.h"
36 #include "nsIFileURL.h"
37 #include "nsIIDNService.h"
38 #include "nsIInputStreamChannel.h"
39 #include "nsIInputStreamPump.h"
40 #include "nsIInterfaceRequestorUtils.h"
41 #include "nsILoadContext.h"
42 #include "nsIMIMEHeaderParam.h"
43 #include "nsIMutable.h"
44 #include "nsINode.h"
45 #include "nsIObjectLoadingContent.h"
46 #include "nsIOfflineCacheUpdate.h"
47 #include "nsPersistentProperties.h"
48 #include "nsIPrivateBrowsingChannel.h"
49 #include "nsIPropertyBag2.h"
50 #include "nsIProtocolProxyService.h"
51 #include "mozilla/net/RedirectChannelRegistrar.h"
52 #include "nsRequestObserverProxy.h"
53 #include "nsIScriptSecurityManager.h"
54 #include "nsISensitiveInfoHiddenURI.h"
55 #include "nsISimpleStreamListener.h"
56 #include "nsISocketProvider.h"
57 #include "nsISocketProviderService.h"
58 #include "nsIStandardURL.h"
59 #include "nsIStreamLoader.h"
60 #include "nsIIncrementalStreamLoader.h"
61 #include "nsIStreamTransportService.h"
62 #include "nsStringStream.h"
63 #include "nsSyncStreamListener.h"
64 #include "nsITransport.h"
65 #include "nsIURIWithSpecialOrigin.h"
66 #include "nsIURLParser.h"
67 #include "nsIUUIDGenerator.h"
68 #include "nsIViewSourceChannel.h"
69 #include "nsInterfaceRequestorAgg.h"
70 #include "plstr.h"
71 #include "nsINestedURI.h"
72 #include "mozilla/dom/nsCSPUtils.h"
73 #include "mozilla/dom/nsMixedContentBlocker.h"
74 #include "mozilla/dom/BlobURLProtocolHandler.h"
75 #include "mozilla/net/HttpBaseChannel.h"
76 #include "nsIScriptError.h"
77 #include "nsISiteSecurityService.h"
78 #include "nsHttpHandler.h"
79 #include "nsNSSComponent.h"
80 #include "nsIRedirectHistoryEntry.h"
81 #include "nsICertBlocklist.h"
82 #include "nsICertOverrideService.h"
83 #include "nsQueryObject.h"
84 #include "mozIThirdPartyUtil.h"
85 #include "../mime/nsMIMEHeaderParamImpl.h"
87 #include <limits>
89 using namespace mozilla;
90 using namespace mozilla::net;
91 using mozilla::dom::BlobURLProtocolHandler;
92 using mozilla::dom::ClientInfo;
93 using mozilla::dom::PerformanceStorage;
94 using mozilla::dom::ServiceWorkerDescriptor;
96 #define DEFAULT_RP 3
97 #define DEFAULT_PRIVATE_RP 2
99 static uint32_t sDefaultRp = DEFAULT_RP;
100 static uint32_t defaultPrivateRp = DEFAULT_PRIVATE_RP;
102 already_AddRefed<nsIIOService> do_GetIOService(nsresult *error /* = 0 */) {
103 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
104 if (error) *error = io ? NS_OK : NS_ERROR_FAILURE;
105 return io.forget();
108 nsresult NS_NewLocalFileInputStream(nsIInputStream **result, nsIFile *file,
109 int32_t ioFlags /* = -1 */,
110 int32_t perm /* = -1 */,
111 int32_t behaviorFlags /* = 0 */) {
112 nsresult rv;
113 nsCOMPtr<nsIFileInputStream> in =
114 do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
115 if (NS_SUCCEEDED(rv)) {
116 rv = in->Init(file, ioFlags, perm, behaviorFlags);
117 if (NS_SUCCEEDED(rv)) in.forget(result);
119 return rv;
122 nsresult NS_NewLocalFileOutputStream(nsIOutputStream **result, nsIFile *file,
123 int32_t ioFlags /* = -1 */,
124 int32_t perm /* = -1 */,
125 int32_t behaviorFlags /* = 0 */) {
126 nsresult rv;
127 nsCOMPtr<nsIFileOutputStream> out =
128 do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
129 if (NS_SUCCEEDED(rv)) {
130 rv = out->Init(file, ioFlags, perm, behaviorFlags);
131 if (NS_SUCCEEDED(rv)) out.forget(result);
133 return rv;
136 nsresult net_EnsureIOService(nsIIOService **ios, nsCOMPtr<nsIIOService> &grip) {
137 nsresult rv = NS_OK;
138 if (!*ios) {
139 grip = do_GetIOService(&rv);
140 *ios = grip;
142 return rv;
145 nsresult NS_NewFileURI(
146 nsIURI **result, nsIFile *spec,
147 nsIIOService
148 *ioService /* = nullptr */) // pass in nsIIOService to optimize callers
150 nsresult rv;
151 nsCOMPtr<nsIIOService> grip;
152 rv = net_EnsureIOService(&ioService, grip);
153 if (ioService) rv = ioService->NewFileURI(spec, result);
154 return rv;
157 nsresult NS_GetURIWithNewRef(nsIURI *aInput, const nsACString &aRef,
158 nsIURI **aOutput) {
159 if (NS_WARN_IF(!aInput || !aOutput)) {
160 return NS_ERROR_INVALID_ARG;
163 bool hasRef;
164 nsresult rv = aInput->GetHasRef(&hasRef);
166 nsAutoCString ref;
167 if (NS_SUCCEEDED(rv)) {
168 rv = aInput->GetRef(ref);
171 // If the ref is already equal to the new ref, we do not need to do anything.
172 // Also, if the GetRef failed (it could return NS_ERROR_NOT_IMPLEMENTED)
173 // we can assume SetRef would fail as well, so returning the original
174 // URI is OK.
175 if (NS_FAILED(rv) || (!hasRef && aRef.IsEmpty()) ||
176 (!aRef.IsEmpty() && aRef == ref)) {
177 nsCOMPtr<nsIURI> uri = aInput;
178 uri.forget(aOutput);
179 return NS_OK;
182 return NS_MutateURI(aInput).SetRef(aRef).Finalize(aOutput);
185 nsresult NS_GetURIWithoutRef(nsIURI *aInput, nsIURI **aOutput) {
186 return NS_GetURIWithNewRef(aInput, EmptyCString(), aOutput);
189 nsresult NS_NewChannelInternal(
190 nsIChannel **outChannel, nsIURI *aUri, nsILoadInfo *aLoadInfo,
191 PerformanceStorage *aPerformanceStorage /* = nullptr */,
192 nsILoadGroup *aLoadGroup /* = nullptr */,
193 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
194 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
195 nsIIOService *aIoService /* = nullptr */) {
196 // NS_NewChannelInternal is mostly called for channel redirects. We should
197 // allow the creation of a channel even if the original channel did not have a
198 // loadinfo attached.
199 NS_ENSURE_ARG_POINTER(outChannel);
201 nsCOMPtr<nsIIOService> grip;
202 nsresult rv = net_EnsureIOService(&aIoService, grip);
203 NS_ENSURE_SUCCESS(rv, rv);
205 nsCOMPtr<nsIChannel> channel;
206 rv = aIoService->NewChannelFromURIWithLoadInfo(aUri, aLoadInfo,
207 getter_AddRefs(channel));
208 NS_ENSURE_SUCCESS(rv, rv);
210 if (aLoadGroup) {
211 rv = channel->SetLoadGroup(aLoadGroup);
212 NS_ENSURE_SUCCESS(rv, rv);
215 if (aCallbacks) {
216 rv = channel->SetNotificationCallbacks(aCallbacks);
217 NS_ENSURE_SUCCESS(rv, rv);
220 #ifdef DEBUG
221 nsLoadFlags channelLoadFlags = 0;
222 channel->GetLoadFlags(&channelLoadFlags);
223 // Will be removed when we remove LOAD_REPLACE altogether
224 // This check is trying to catch protocol handlers that still
225 // try to set the LOAD_REPLACE flag.
226 MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
227 #endif
229 if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
230 rv = channel->SetLoadFlags(aLoadFlags);
231 NS_ENSURE_SUCCESS(rv, rv);
234 if (aPerformanceStorage) {
235 nsCOMPtr<nsILoadInfo> loadInfo;
236 rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
237 NS_ENSURE_SUCCESS(rv, rv);
239 loadInfo->SetPerformanceStorage(aPerformanceStorage);
242 channel.forget(outChannel);
243 return NS_OK;
246 namespace {
248 void AssertLoadingPrincipalAndClientInfoMatch(
249 nsIPrincipal *aLoadingPrincipal, const ClientInfo &aLoadingClientInfo,
250 nsContentPolicyType aType) {
251 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
252 // Verify that the provided loading ClientInfo matches the loading
253 // principal. Unfortunately we can't just use nsIPrincipal::Equals() here
254 // because of some corner cases:
256 // 1. Worker debugger scripts want to use a system loading principal for
257 // worker scripts with a content principal. We exempt these from this
258 // check.
259 // 2. Null principals currently require exact object identity for
260 // nsIPrincipal::Equals() to return true. This doesn't work here because
261 // ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate
262 // a new object. To work around this we compare the principal origin
263 // string itself. If bug 1431771 is fixed then we could switch to
264 // Equals().
266 // Allow worker debugger to load with a system principal.
267 if (aLoadingPrincipal->IsSystemPrincipal() &&
268 (aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
269 aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
270 aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
271 aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS)) {
272 return;
275 // Perform a fast comparison for most principal checks.
276 nsCOMPtr<nsIPrincipal> clientPrincipal(aLoadingClientInfo.GetPrincipal());
277 if (aLoadingPrincipal->Equals(clientPrincipal)) {
278 return;
281 // Fall back to a slower origin equality test to support null principals.
282 nsAutoCString loadingOrigin;
283 MOZ_ALWAYS_SUCCEEDS(aLoadingPrincipal->GetOrigin(loadingOrigin));
285 nsAutoCString clientOrigin;
286 MOZ_ALWAYS_SUCCEEDS(clientPrincipal->GetOrigin(clientOrigin));
288 MOZ_DIAGNOSTIC_ASSERT(loadingOrigin == clientOrigin);
289 #endif
292 } // namespace
294 nsresult NS_NewChannel(nsIChannel **outChannel, nsIURI *aUri,
295 nsIPrincipal *aLoadingPrincipal,
296 nsSecurityFlags aSecurityFlags,
297 nsContentPolicyType aContentPolicyType,
298 PerformanceStorage *aPerformanceStorage /* nullptr */,
299 nsILoadGroup *aLoadGroup /* = nullptr */,
300 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
301 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
302 nsIIOService *aIoService /* = nullptr */) {
303 return NS_NewChannelInternal(outChannel, aUri,
304 nullptr, // aLoadingNode,
305 aLoadingPrincipal,
306 nullptr, // aTriggeringPrincipal
307 Maybe<ClientInfo>(),
308 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
309 aContentPolicyType, aPerformanceStorage,
310 aLoadGroup, aCallbacks, aLoadFlags, aIoService);
313 nsresult NS_NewChannel(nsIChannel **outChannel, nsIURI *aUri,
314 nsIPrincipal *aLoadingPrincipal,
315 const ClientInfo &aLoadingClientInfo,
316 const Maybe<ServiceWorkerDescriptor> &aController,
317 nsSecurityFlags aSecurityFlags,
318 nsContentPolicyType aContentPolicyType,
319 PerformanceStorage *aPerformanceStorage /* nullptr */,
320 nsILoadGroup *aLoadGroup /* = nullptr */,
321 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
322 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
323 nsIIOService *aIoService /* = nullptr */) {
324 AssertLoadingPrincipalAndClientInfoMatch(
325 aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
327 Maybe<ClientInfo> loadingClientInfo;
328 loadingClientInfo.emplace(aLoadingClientInfo);
330 return NS_NewChannelInternal(outChannel, aUri,
331 nullptr, // aLoadingNode,
332 aLoadingPrincipal,
333 nullptr, // aTriggeringPrincipal
334 loadingClientInfo, aController, aSecurityFlags,
335 aContentPolicyType, aPerformanceStorage,
336 aLoadGroup, aCallbacks, aLoadFlags, aIoService);
339 nsresult NS_NewChannelInternal(
340 nsIChannel **outChannel, nsIURI *aUri, nsINode *aLoadingNode,
341 nsIPrincipal *aLoadingPrincipal, nsIPrincipal *aTriggeringPrincipal,
342 const Maybe<ClientInfo> &aLoadingClientInfo,
343 const Maybe<ServiceWorkerDescriptor> &aController,
344 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
345 PerformanceStorage *aPerformanceStorage /* nullptr */,
346 nsILoadGroup *aLoadGroup /* = nullptr */,
347 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
348 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
349 nsIIOService *aIoService /* = nullptr */) {
350 NS_ENSURE_ARG_POINTER(outChannel);
352 nsCOMPtr<nsIIOService> grip;
353 nsresult rv = net_EnsureIOService(&aIoService, grip);
354 NS_ENSURE_SUCCESS(rv, rv);
356 nsCOMPtr<nsIChannel> channel;
357 rv = aIoService->NewChannelFromURIWithClientAndController(
358 aUri, aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal,
359 aLoadingClientInfo, aController, aSecurityFlags, aContentPolicyType,
360 getter_AddRefs(channel));
361 if (NS_FAILED(rv)) {
362 return rv;
365 if (aLoadGroup) {
366 rv = channel->SetLoadGroup(aLoadGroup);
367 NS_ENSURE_SUCCESS(rv, rv);
370 if (aCallbacks) {
371 rv = channel->SetNotificationCallbacks(aCallbacks);
372 NS_ENSURE_SUCCESS(rv, rv);
375 #ifdef DEBUG
376 nsLoadFlags channelLoadFlags = 0;
377 channel->GetLoadFlags(&channelLoadFlags);
378 // Will be removed when we remove LOAD_REPLACE altogether
379 // This check is trying to catch protocol handlers that still
380 // try to set the LOAD_REPLACE flag.
381 MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
382 #endif
384 if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
385 rv = channel->SetLoadFlags(aLoadFlags);
386 NS_ENSURE_SUCCESS(rv, rv);
389 if (aPerformanceStorage) {
390 nsCOMPtr<nsILoadInfo> loadInfo;
391 rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
392 NS_ENSURE_SUCCESS(rv, rv);
394 loadInfo->SetPerformanceStorage(aPerformanceStorage);
397 channel.forget(outChannel);
398 return NS_OK;
401 nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
402 NS_NewChannelWithTriggeringPrincipal(
403 nsIChannel **outChannel, nsIURI *aUri, nsINode *aLoadingNode,
404 nsIPrincipal *aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
405 nsContentPolicyType aContentPolicyType,
406 PerformanceStorage *aPerformanceStorage /* = nullptr */,
407 nsILoadGroup *aLoadGroup /* = nullptr */,
408 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
409 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
410 nsIIOService *aIoService /* = nullptr */) {
411 MOZ_ASSERT(aLoadingNode);
412 NS_ASSERTION(aTriggeringPrincipal,
413 "Can not create channel without a triggering Principal!");
414 return NS_NewChannelInternal(
415 outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
416 aTriggeringPrincipal, Maybe<ClientInfo>(),
417 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
418 aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService);
421 // See NS_NewChannelInternal for usage and argument description
422 nsresult NS_NewChannelWithTriggeringPrincipal(
423 nsIChannel **outChannel, nsIURI *aUri, nsIPrincipal *aLoadingPrincipal,
424 nsIPrincipal *aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
425 nsContentPolicyType aContentPolicyType,
426 PerformanceStorage *aPerformanceStorage /* = nullptr */,
427 nsILoadGroup *aLoadGroup /* = nullptr */,
428 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
429 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
430 nsIIOService *aIoService /* = nullptr */) {
431 NS_ASSERTION(aLoadingPrincipal,
432 "Can not create channel without a loading Principal!");
433 return NS_NewChannelInternal(
434 outChannel, aUri,
435 nullptr, // aLoadingNode
436 aLoadingPrincipal, aTriggeringPrincipal, Maybe<ClientInfo>(),
437 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
438 aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService);
441 // See NS_NewChannelInternal for usage and argument description
442 nsresult NS_NewChannelWithTriggeringPrincipal(
443 nsIChannel **outChannel, nsIURI *aUri, nsIPrincipal *aLoadingPrincipal,
444 nsIPrincipal *aTriggeringPrincipal, const ClientInfo &aLoadingClientInfo,
445 const Maybe<ServiceWorkerDescriptor> &aController,
446 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
447 PerformanceStorage *aPerformanceStorage /* = nullptr */,
448 nsILoadGroup *aLoadGroup /* = nullptr */,
449 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
450 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
451 nsIIOService *aIoService /* = nullptr */) {
452 AssertLoadingPrincipalAndClientInfoMatch(
453 aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
455 Maybe<ClientInfo> loadingClientInfo;
456 loadingClientInfo.emplace(aLoadingClientInfo);
458 return NS_NewChannelInternal(outChannel, aUri,
459 nullptr, // aLoadingNode
460 aLoadingPrincipal, aTriggeringPrincipal,
461 loadingClientInfo, aController, aSecurityFlags,
462 aContentPolicyType, aPerformanceStorage,
463 aLoadGroup, aCallbacks, aLoadFlags, aIoService);
466 nsresult NS_NewChannel(nsIChannel **outChannel, nsIURI *aUri,
467 nsINode *aLoadingNode, nsSecurityFlags aSecurityFlags,
468 nsContentPolicyType aContentPolicyType,
469 PerformanceStorage *aPerformanceStorage /* = nullptr */,
470 nsILoadGroup *aLoadGroup /* = nullptr */,
471 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
472 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
473 nsIIOService *aIoService /* = nullptr */) {
474 NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!");
475 return NS_NewChannelInternal(
476 outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
477 nullptr, // aTriggeringPrincipal
478 Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
479 aContentPolicyType, aPerformanceStorage, aLoadGroup, aCallbacks,
480 aLoadFlags, aIoService);
483 nsresult NS_GetIsDocumentChannel(nsIChannel *aChannel, bool *aIsDocument) {
484 // Check if this channel is going to be used to create a document. If it has
485 // LOAD_DOCUMENT_URI set it is trivially creating a document. If
486 // LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a
487 // document, depending on its MIME type.
489 if (!aChannel || !aIsDocument) {
490 return NS_ERROR_NULL_POINTER;
492 *aIsDocument = false;
493 nsLoadFlags loadFlags;
494 nsresult rv = aChannel->GetLoadFlags(&loadFlags);
495 if (NS_FAILED(rv)) {
496 return rv;
498 if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
499 *aIsDocument = true;
500 return NS_OK;
502 if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) {
503 *aIsDocument = false;
504 return NS_OK;
506 nsAutoCString mimeType;
507 rv = aChannel->GetContentType(mimeType);
508 if (NS_FAILED(rv)) {
509 return rv;
511 if (nsContentUtils::HtmlObjectContentTypeForMIMEType(
512 mimeType, false, nullptr) == nsIObjectLoadingContent::TYPE_DOCUMENT) {
513 *aIsDocument = true;
514 return NS_OK;
516 *aIsDocument = false;
517 return NS_OK;
520 nsresult NS_MakeAbsoluteURI(nsACString &result, const nsACString &spec,
521 nsIURI *baseURI) {
522 nsresult rv;
523 if (!baseURI) {
524 NS_WARNING("It doesn't make sense to not supply a base URI");
525 result = spec;
526 rv = NS_OK;
527 } else if (spec.IsEmpty())
528 rv = baseURI->GetSpec(result);
529 else
530 rv = baseURI->Resolve(spec, result);
531 return rv;
534 nsresult NS_MakeAbsoluteURI(char **result, const char *spec, nsIURI *baseURI) {
535 nsresult rv;
536 nsAutoCString resultBuf;
537 rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
538 if (NS_SUCCEEDED(rv)) {
539 *result = ToNewCString(resultBuf);
540 if (!*result) rv = NS_ERROR_OUT_OF_MEMORY;
542 return rv;
545 nsresult NS_MakeAbsoluteURI(nsAString &result, const nsAString &spec,
546 nsIURI *baseURI) {
547 nsresult rv;
548 if (!baseURI) {
549 NS_WARNING("It doesn't make sense to not supply a base URI");
550 result = spec;
551 rv = NS_OK;
552 } else {
553 nsAutoCString resultBuf;
554 if (spec.IsEmpty())
555 rv = baseURI->GetSpec(resultBuf);
556 else
557 rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
558 if (NS_SUCCEEDED(rv)) CopyUTF8toUTF16(resultBuf, result);
560 return rv;
563 int32_t NS_GetDefaultPort(const char *scheme,
564 nsIIOService *ioService /* = nullptr */) {
565 nsresult rv;
567 // Getting the default port through the protocol handler has a lot of XPCOM
568 // overhead involved. We optimize the protocols that matter for Web pages
569 // (HTTP and HTTPS) by hardcoding their default ports here.
570 if (strncmp(scheme, "http", 4) == 0) {
571 if (scheme[4] == 's' && scheme[5] == '\0') {
572 return 443;
574 if (scheme[4] == '\0') {
575 return 80;
579 nsCOMPtr<nsIIOService> grip;
580 net_EnsureIOService(&ioService, grip);
581 if (!ioService) return -1;
583 nsCOMPtr<nsIProtocolHandler> handler;
584 rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
585 if (NS_FAILED(rv)) return -1;
586 int32_t port;
587 rv = handler->GetDefaultPort(&port);
588 return NS_SUCCEEDED(rv) ? port : -1;
592 * This function is a helper function to apply the ToAscii conversion
593 * to a string
595 bool NS_StringToACE(const nsACString &idn, nsACString &result) {
596 nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
597 if (!idnSrv) return false;
598 nsresult rv = idnSrv->ConvertUTF8toACE(idn, result);
599 if (NS_FAILED(rv)) return false;
601 return true;
604 int32_t NS_GetRealPort(nsIURI *aURI) {
605 int32_t port;
606 nsresult rv = aURI->GetPort(&port);
607 if (NS_FAILED(rv)) return -1;
609 if (port != -1) return port; // explicitly specified
611 // Otherwise, we have to get the default port from the protocol handler
613 // Need the scheme first
614 nsAutoCString scheme;
615 rv = aURI->GetScheme(scheme);
616 if (NS_FAILED(rv)) return -1;
618 return NS_GetDefaultPort(scheme.get());
621 nsresult NS_NewInputStreamChannelInternal(
622 nsIChannel **outChannel, nsIURI *aUri,
623 already_AddRefed<nsIInputStream> aStream, const nsACString &aContentType,
624 const nsACString &aContentCharset, nsILoadInfo *aLoadInfo) {
625 nsresult rv;
626 nsCOMPtr<nsIInputStreamChannel> isc =
627 do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
628 NS_ENSURE_SUCCESS(rv, rv);
629 rv = isc->SetURI(aUri);
630 NS_ENSURE_SUCCESS(rv, rv);
632 nsCOMPtr<nsIInputStream> stream = std::move(aStream);
633 rv = isc->SetContentStream(stream);
634 NS_ENSURE_SUCCESS(rv, rv);
636 nsCOMPtr<nsIChannel> channel = do_QueryInterface(isc, &rv);
637 NS_ENSURE_SUCCESS(rv, rv);
639 if (!aContentType.IsEmpty()) {
640 rv = channel->SetContentType(aContentType);
641 NS_ENSURE_SUCCESS(rv, rv);
644 if (!aContentCharset.IsEmpty()) {
645 rv = channel->SetContentCharset(aContentCharset);
646 NS_ENSURE_SUCCESS(rv, rv);
649 channel->SetLoadInfo(aLoadInfo);
651 // If we're sandboxed, make sure to clear any owner the channel
652 // might already have.
653 if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) {
654 channel->SetOwner(nullptr);
657 channel.forget(outChannel);
658 return NS_OK;
661 nsresult NS_NewInputStreamChannelInternal(
662 nsIChannel **outChannel, nsIURI *aUri,
663 already_AddRefed<nsIInputStream> aStream, const nsACString &aContentType,
664 const nsACString &aContentCharset, nsINode *aLoadingNode,
665 nsIPrincipal *aLoadingPrincipal, nsIPrincipal *aTriggeringPrincipal,
666 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType) {
667 nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
668 aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
669 aContentPolicyType);
670 if (!loadInfo) {
671 return NS_ERROR_UNEXPECTED;
674 nsCOMPtr<nsIInputStream> stream = std::move(aStream);
676 return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
677 aContentType, aContentCharset,
678 loadInfo);
681 nsresult NS_NewInputStreamChannel(
682 nsIChannel **outChannel, nsIURI *aUri,
683 already_AddRefed<nsIInputStream> aStream, nsIPrincipal *aLoadingPrincipal,
684 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
685 const nsACString &aContentType /* = EmptyCString() */,
686 const nsACString &aContentCharset /* = EmptyCString() */) {
687 nsCOMPtr<nsIInputStream> stream = aStream;
688 return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
689 aContentType, aContentCharset,
690 nullptr, // aLoadingNode
691 aLoadingPrincipal,
692 nullptr, // aTriggeringPrincipal
693 aSecurityFlags, aContentPolicyType);
696 nsresult NS_NewInputStreamChannelInternal(nsIChannel **outChannel, nsIURI *aUri,
697 const nsAString &aData,
698 const nsACString &aContentType,
699 nsILoadInfo *aLoadInfo,
700 bool aIsSrcdocChannel /* = false */) {
701 nsresult rv;
702 nsCOMPtr<nsIStringInputStream> stream;
703 stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
704 NS_ENSURE_SUCCESS(rv, rv);
706 uint32_t len;
707 char *utf8Bytes = ToNewUTF8String(aData, &len);
708 rv = stream->AdoptData(utf8Bytes, len);
710 nsCOMPtr<nsIChannel> channel;
711 rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aUri,
712 stream.forget(), aContentType,
713 NS_LITERAL_CSTRING("UTF-8"), aLoadInfo);
715 NS_ENSURE_SUCCESS(rv, rv);
717 if (aIsSrcdocChannel) {
718 nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(channel);
719 NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
720 inStrmChan->SetSrcdocData(aData);
722 channel.forget(outChannel);
723 return NS_OK;
726 nsresult NS_NewInputStreamChannelInternal(
727 nsIChannel **outChannel, nsIURI *aUri, const nsAString &aData,
728 const nsACString &aContentType, nsINode *aLoadingNode,
729 nsIPrincipal *aLoadingPrincipal, nsIPrincipal *aTriggeringPrincipal,
730 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
731 bool aIsSrcdocChannel /* = false */) {
732 nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
733 aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
734 aContentPolicyType);
735 return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
736 loadInfo, aIsSrcdocChannel);
739 nsresult NS_NewInputStreamChannel(nsIChannel **outChannel, nsIURI *aUri,
740 const nsAString &aData,
741 const nsACString &aContentType,
742 nsIPrincipal *aLoadingPrincipal,
743 nsSecurityFlags aSecurityFlags,
744 nsContentPolicyType aContentPolicyType,
745 bool aIsSrcdocChannel /* = false */) {
746 return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
747 nullptr, // aLoadingNode
748 aLoadingPrincipal,
749 nullptr, // aTriggeringPrincipal
750 aSecurityFlags, aContentPolicyType,
751 aIsSrcdocChannel);
754 nsresult NS_NewInputStreamPump(
755 nsIInputStreamPump **aResult, already_AddRefed<nsIInputStream> aStream,
756 uint32_t aSegsize /* = 0 */, uint32_t aSegcount /* = 0 */,
757 bool aCloseWhenDone /* = false */,
758 nsIEventTarget *aMainThreadTarget /* = nullptr */) {
759 nsCOMPtr<nsIInputStream> stream = std::move(aStream);
761 nsresult rv;
762 nsCOMPtr<nsIInputStreamPump> pump =
763 do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
764 if (NS_SUCCEEDED(rv)) {
765 rv = pump->Init(stream, aSegsize, aSegcount, aCloseWhenDone,
766 aMainThreadTarget);
767 if (NS_SUCCEEDED(rv)) {
768 *aResult = nullptr;
769 pump.swap(*aResult);
772 return rv;
775 nsresult NS_NewLoadGroup(nsILoadGroup **result, nsIRequestObserver *obs) {
776 nsresult rv;
777 nsCOMPtr<nsILoadGroup> group =
778 do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
779 if (NS_SUCCEEDED(rv)) {
780 rv = group->SetGroupObserver(obs);
781 if (NS_SUCCEEDED(rv)) {
782 *result = nullptr;
783 group.swap(*result);
786 return rv;
789 bool NS_IsReasonableHTTPHeaderValue(const nsACString &aValue) {
790 return mozilla::net::nsHttp::IsReasonableHeaderValue(aValue);
793 bool NS_IsValidHTTPToken(const nsACString &aToken) {
794 return mozilla::net::nsHttp::IsValidToken(aToken);
797 void NS_TrimHTTPWhitespace(const nsACString &aSource, nsACString &aDest) {
798 mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest);
801 nsresult NS_NewLoadGroup(nsILoadGroup **aResult, nsIPrincipal *aPrincipal) {
802 using mozilla::LoadContext;
803 nsresult rv;
805 nsCOMPtr<nsILoadGroup> group =
806 do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
807 NS_ENSURE_SUCCESS(rv, rv);
809 RefPtr<LoadContext> loadContext = new LoadContext(aPrincipal);
810 rv = group->SetNotificationCallbacks(loadContext);
811 NS_ENSURE_SUCCESS(rv, rv);
813 group.forget(aResult);
814 return rv;
817 bool NS_LoadGroupMatchesPrincipal(nsILoadGroup *aLoadGroup,
818 nsIPrincipal *aPrincipal) {
819 if (!aPrincipal) {
820 return false;
823 // If this is a null principal then the load group doesn't really matter.
824 // The principal will not be allowed to perform any actions that actually
825 // use the load group. Unconditionally treat null principals as a match.
826 if (aPrincipal->GetIsNullPrincipal()) {
827 return true;
830 if (!aLoadGroup) {
831 return false;
834 nsCOMPtr<nsILoadContext> loadContext;
835 NS_QueryNotificationCallbacks(nullptr, aLoadGroup, NS_GET_IID(nsILoadContext),
836 getter_AddRefs(loadContext));
837 NS_ENSURE_TRUE(loadContext, false);
839 // Verify load context browser flag match the principal
840 bool contextInIsolatedBrowser;
841 nsresult rv =
842 loadContext->GetIsInIsolatedMozBrowserElement(&contextInIsolatedBrowser);
843 NS_ENSURE_SUCCESS(rv, false);
845 return contextInIsolatedBrowser ==
846 aPrincipal->GetIsInIsolatedMozBrowserElement();
849 nsresult NS_NewDownloader(nsIStreamListener **result,
850 nsIDownloadObserver *observer,
851 nsIFile *downloadLocation /* = nullptr */) {
852 nsresult rv;
853 nsCOMPtr<nsIDownloader> downloader =
854 do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
855 if (NS_SUCCEEDED(rv)) {
856 rv = downloader->Init(observer, downloadLocation);
857 if (NS_SUCCEEDED(rv)) {
858 downloader.forget(result);
861 return rv;
864 nsresult NS_NewIncrementalStreamLoader(
865 nsIIncrementalStreamLoader **result,
866 nsIIncrementalStreamLoaderObserver *observer) {
867 nsresult rv;
868 nsCOMPtr<nsIIncrementalStreamLoader> loader =
869 do_CreateInstance(NS_INCREMENTALSTREAMLOADER_CONTRACTID, &rv);
870 if (NS_SUCCEEDED(rv)) {
871 rv = loader->Init(observer);
872 if (NS_SUCCEEDED(rv)) {
873 *result = nullptr;
874 loader.swap(*result);
877 return rv;
880 nsresult NS_NewStreamLoader(
881 nsIStreamLoader **result, nsIStreamLoaderObserver *observer,
882 nsIRequestObserver *requestObserver /* = nullptr */) {
883 nsresult rv;
884 nsCOMPtr<nsIStreamLoader> loader =
885 do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
886 if (NS_SUCCEEDED(rv)) {
887 rv = loader->Init(observer, requestObserver);
888 if (NS_SUCCEEDED(rv)) {
889 *result = nullptr;
890 loader.swap(*result);
893 return rv;
896 nsresult NS_NewStreamLoaderInternal(
897 nsIStreamLoader **outStream, nsIURI *aUri,
898 nsIStreamLoaderObserver *aObserver, nsINode *aLoadingNode,
899 nsIPrincipal *aLoadingPrincipal, nsSecurityFlags aSecurityFlags,
900 nsContentPolicyType aContentPolicyType,
901 nsILoadGroup *aLoadGroup /* = nullptr */,
902 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
903 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
904 nsIURI *aReferrer /* = nullptr */) {
905 nsCOMPtr<nsIChannel> channel;
906 nsresult rv = NS_NewChannelInternal(
907 getter_AddRefs(channel), aUri, aLoadingNode, aLoadingPrincipal,
908 nullptr, // aTriggeringPrincipal
909 Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
910 aContentPolicyType,
911 nullptr, // PerformanceStorage
912 aLoadGroup, aCallbacks, aLoadFlags);
914 NS_ENSURE_SUCCESS(rv, rv);
915 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
916 if (httpChannel) {
917 rv = httpChannel->SetReferrer(aReferrer);
918 MOZ_ASSERT(NS_SUCCEEDED(rv));
920 rv = NS_NewStreamLoader(outStream, aObserver);
921 NS_ENSURE_SUCCESS(rv, rv);
922 return channel->AsyncOpen2(*outStream);
925 nsresult NS_NewStreamLoader(
926 nsIStreamLoader **outStream, nsIURI *aUri,
927 nsIStreamLoaderObserver *aObserver, nsINode *aLoadingNode,
928 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
929 nsILoadGroup *aLoadGroup /* = nullptr */,
930 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
931 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
932 nsIURI *aReferrer /* = nullptr */) {
933 NS_ASSERTION(aLoadingNode,
934 "Can not create stream loader without a loading Node!");
935 return NS_NewStreamLoaderInternal(
936 outStream, aUri, aObserver, aLoadingNode, aLoadingNode->NodePrincipal(),
937 aSecurityFlags, aContentPolicyType, aLoadGroup, aCallbacks, aLoadFlags,
938 aReferrer);
941 nsresult NS_NewStreamLoader(
942 nsIStreamLoader **outStream, nsIURI *aUri,
943 nsIStreamLoaderObserver *aObserver, nsIPrincipal *aLoadingPrincipal,
944 nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
945 nsILoadGroup *aLoadGroup /* = nullptr */,
946 nsIInterfaceRequestor *aCallbacks /* = nullptr */,
947 nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
948 nsIURI *aReferrer /* = nullptr */) {
949 return NS_NewStreamLoaderInternal(outStream, aUri, aObserver,
950 nullptr, // aLoadingNode
951 aLoadingPrincipal, aSecurityFlags,
952 aContentPolicyType, aLoadGroup, aCallbacks,
953 aLoadFlags, aReferrer);
956 nsresult NS_NewSyncStreamListener(nsIStreamListener **result,
957 nsIInputStream **stream) {
958 nsCOMPtr<nsISyncStreamListener> listener = nsSyncStreamListener::Create();
959 if (listener) {
960 nsresult rv = listener->GetInputStream(stream);
961 if (NS_SUCCEEDED(rv)) {
962 listener.forget(result);
964 return rv;
966 return NS_ERROR_FAILURE;
969 nsresult NS_ImplementChannelOpen(nsIChannel *channel, nsIInputStream **result) {
970 nsCOMPtr<nsIStreamListener> listener;
971 nsCOMPtr<nsIInputStream> stream;
972 nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
973 getter_AddRefs(stream));
974 NS_ENSURE_SUCCESS(rv, rv);
976 rv = NS_MaybeOpenChannelUsingAsyncOpen2(channel, listener);
977 NS_ENSURE_SUCCESS(rv, rv);
979 uint64_t n;
980 // block until the initial response is received or an error occurs.
981 rv = stream->Available(&n);
982 NS_ENSURE_SUCCESS(rv, rv);
984 *result = nullptr;
985 stream.swap(*result);
987 return NS_OK;
990 nsresult NS_NewRequestObserverProxy(nsIRequestObserver **result,
991 nsIRequestObserver *observer,
992 nsISupports *context) {
993 nsCOMPtr<nsIRequestObserverProxy> proxy = new nsRequestObserverProxy();
994 nsresult rv = proxy->Init(observer, context);
995 if (NS_SUCCEEDED(rv)) {
996 proxy.forget(result);
998 return rv;
1001 nsresult NS_NewSimpleStreamListener(
1002 nsIStreamListener **result, nsIOutputStream *sink,
1003 nsIRequestObserver *observer /* = nullptr */) {
1004 nsresult rv;
1005 nsCOMPtr<nsISimpleStreamListener> listener =
1006 do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
1007 if (NS_SUCCEEDED(rv)) {
1008 rv = listener->Init(sink, observer);
1009 if (NS_SUCCEEDED(rv)) {
1010 listener.forget(result);
1013 return rv;
1016 nsresult NS_CheckPortSafety(int32_t port, const char *scheme,
1017 nsIIOService *ioService /* = nullptr */) {
1018 nsresult rv;
1019 nsCOMPtr<nsIIOService> grip;
1020 rv = net_EnsureIOService(&ioService, grip);
1021 if (ioService) {
1022 bool allow;
1023 rv = ioService->AllowPort(port, scheme, &allow);
1024 if (NS_SUCCEEDED(rv) && !allow) {
1025 NS_WARNING("port blocked");
1026 rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
1029 return rv;
1032 nsresult NS_CheckPortSafety(nsIURI *uri) {
1033 int32_t port;
1034 nsresult rv = uri->GetPort(&port);
1035 if (NS_FAILED(rv) || port == -1) // port undefined or default-valued
1036 return NS_OK;
1037 nsAutoCString scheme;
1038 uri->GetScheme(scheme);
1039 return NS_CheckPortSafety(port, scheme.get());
1042 nsresult NS_NewProxyInfo(const nsACString &type, const nsACString &host,
1043 int32_t port, uint32_t flags, nsIProxyInfo **result) {
1044 nsresult rv;
1045 nsCOMPtr<nsIProtocolProxyService> pps =
1046 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
1047 if (NS_SUCCEEDED(rv))
1048 rv =
1049 pps->NewProxyInfo(type, host, port, flags, UINT32_MAX, nullptr, result);
1050 return rv;
1053 nsresult NS_GetFileProtocolHandler(nsIFileProtocolHandler **result,
1054 nsIIOService *ioService /* = nullptr */) {
1055 nsresult rv;
1056 nsCOMPtr<nsIIOService> grip;
1057 rv = net_EnsureIOService(&ioService, grip);
1058 if (ioService) {
1059 nsCOMPtr<nsIProtocolHandler> handler;
1060 rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
1061 if (NS_SUCCEEDED(rv)) rv = CallQueryInterface(handler, result);
1063 return rv;
1066 nsresult NS_GetFileFromURLSpec(const nsACString &inURL, nsIFile **result,
1067 nsIIOService *ioService /* = nullptr */) {
1068 nsresult rv;
1069 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1070 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1071 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetFileFromURLSpec(inURL, result);
1072 return rv;
1075 nsresult NS_GetURLSpecFromFile(nsIFile *file, nsACString &url,
1076 nsIIOService *ioService /* = nullptr */) {
1077 nsresult rv;
1078 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1079 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1080 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromFile(file, url);
1081 return rv;
1084 nsresult NS_GetURLSpecFromActualFile(nsIFile *file, nsACString &url,
1085 nsIIOService *ioService /* = nullptr */) {
1086 nsresult rv;
1087 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1088 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1089 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromActualFile(file, url);
1090 return rv;
1093 nsresult NS_GetURLSpecFromDir(nsIFile *file, nsACString &url,
1094 nsIIOService *ioService /* = nullptr */) {
1095 nsresult rv;
1096 nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1097 rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1098 if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromDir(file, url);
1099 return rv;
1102 nsresult NS_GetReferrerFromChannel(nsIChannel *channel, nsIURI **referrer) {
1103 nsresult rv = NS_ERROR_NOT_AVAILABLE;
1104 *referrer = nullptr;
1106 nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
1107 if (props) {
1108 // We have to check for a property on a property bag because the
1109 // referrer may be empty for security reasons (for example, when loading
1110 // an http page with an https referrer).
1111 rv = props->GetPropertyAsInterface(
1112 NS_LITERAL_STRING("docshell.internalReferrer"), NS_GET_IID(nsIURI),
1113 reinterpret_cast<void **>(referrer));
1114 if (NS_FAILED(rv)) *referrer = nullptr;
1117 // if that didn't work, we can still try to get the referrer from the
1118 // nsIHttpChannel (if we can QI to it)
1119 if (!(*referrer)) {
1120 nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
1121 if (chan) {
1122 rv = chan->GetReferrer(referrer);
1123 if (NS_FAILED(rv)) *referrer = nullptr;
1126 return rv;
1129 already_AddRefed<nsINetUtil> do_GetNetUtil(nsresult *error /* = 0 */) {
1130 nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
1131 nsCOMPtr<nsINetUtil> util;
1132 if (io) util = do_QueryInterface(io);
1134 if (error) *error = !!util ? NS_OK : NS_ERROR_FAILURE;
1135 return util.forget();
1138 nsresult NS_ParseRequestContentType(const nsACString &rawContentType,
1139 nsCString &contentType,
1140 nsCString &contentCharset) {
1141 // contentCharset is left untouched if not present in rawContentType
1142 nsresult rv;
1143 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1144 NS_ENSURE_SUCCESS(rv, rv);
1145 nsCString charset;
1146 bool hadCharset;
1147 rv = util->ParseRequestContentType(rawContentType, charset, &hadCharset,
1148 contentType);
1149 if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
1150 return rv;
1153 nsresult NS_ParseResponseContentType(const nsACString &rawContentType,
1154 nsCString &contentType,
1155 nsCString &contentCharset) {
1156 // contentCharset is left untouched if not present in rawContentType
1157 nsresult rv;
1158 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1159 NS_ENSURE_SUCCESS(rv, rv);
1160 nsCString charset;
1161 bool hadCharset;
1162 rv = util->ParseResponseContentType(rawContentType, charset, &hadCharset,
1163 contentType);
1164 if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
1165 return rv;
1168 nsresult NS_ExtractCharsetFromContentType(const nsACString &rawContentType,
1169 nsCString &contentCharset,
1170 bool *hadCharset,
1171 int32_t *charsetStart,
1172 int32_t *charsetEnd) {
1173 // contentCharset is left untouched if not present in rawContentType
1174 nsresult rv;
1175 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1176 NS_ENSURE_SUCCESS(rv, rv);
1178 return util->ExtractCharsetFromContentType(
1179 rawContentType, contentCharset, charsetStart, charsetEnd, hadCharset);
1182 nsresult NS_NewAtomicFileOutputStream(nsIOutputStream **result, nsIFile *file,
1183 int32_t ioFlags /* = -1 */,
1184 int32_t perm /* = -1 */,
1185 int32_t behaviorFlags /* = 0 */) {
1186 nsresult rv;
1187 nsCOMPtr<nsIFileOutputStream> out =
1188 do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1189 if (NS_SUCCEEDED(rv)) {
1190 rv = out->Init(file, ioFlags, perm, behaviorFlags);
1191 if (NS_SUCCEEDED(rv)) out.forget(result);
1193 return rv;
1196 nsresult NS_NewSafeLocalFileOutputStream(nsIOutputStream **result,
1197 nsIFile *file,
1198 int32_t ioFlags /* = -1 */,
1199 int32_t perm /* = -1 */,
1200 int32_t behaviorFlags /* = 0 */) {
1201 nsresult rv;
1202 nsCOMPtr<nsIFileOutputStream> out =
1203 do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1204 if (NS_SUCCEEDED(rv)) {
1205 rv = out->Init(file, ioFlags, perm, behaviorFlags);
1206 if (NS_SUCCEEDED(rv)) out.forget(result);
1208 return rv;
1211 nsresult NS_NewLocalFileStream(nsIFileStream **result, nsIFile *file,
1212 int32_t ioFlags /* = -1 */,
1213 int32_t perm /* = -1 */,
1214 int32_t behaviorFlags /* = 0 */) {
1215 nsCOMPtr<nsIFileStream> stream = new nsFileStream();
1216 nsresult rv = stream->Init(file, ioFlags, perm, behaviorFlags);
1217 if (NS_SUCCEEDED(rv)) {
1218 stream.forget(result);
1220 return rv;
1223 nsresult NS_NewBufferedOutputStream(
1224 nsIOutputStream **aResult, already_AddRefed<nsIOutputStream> aOutputStream,
1225 uint32_t aBufferSize) {
1226 nsCOMPtr<nsIOutputStream> outputStream = std::move(aOutputStream);
1228 nsresult rv;
1229 nsCOMPtr<nsIBufferedOutputStream> out =
1230 do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
1231 if (NS_SUCCEEDED(rv)) {
1232 rv = out->Init(outputStream, aBufferSize);
1233 if (NS_SUCCEEDED(rv)) {
1234 out.forget(aResult);
1237 return rv;
1240 MOZ_MUST_USE nsresult NS_NewBufferedInputStream(
1241 nsIInputStream **aResult, already_AddRefed<nsIInputStream> aInputStream,
1242 uint32_t aBufferSize) {
1243 nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
1245 nsresult rv;
1246 nsCOMPtr<nsIBufferedInputStream> in =
1247 do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
1248 if (NS_SUCCEEDED(rv)) {
1249 rv = in->Init(inputStream, aBufferSize);
1250 if (NS_SUCCEEDED(rv)) {
1251 in.forget(aResult);
1254 return rv;
1257 namespace {
1259 #define BUFFER_SIZE 8192
1261 class BufferWriter final : public nsIInputStreamCallback {
1262 public:
1263 NS_DECL_THREADSAFE_ISUPPORTS
1265 BufferWriter(nsIInputStream *aInputStream, void *aBuffer, int64_t aCount)
1266 : mMonitor("BufferWriter.mMonitor"),
1267 mInputStream(aInputStream),
1268 mBuffer(aBuffer),
1269 mCount(aCount),
1270 mWrittenData(0),
1271 mBufferType(aBuffer ? eExternal : eInternal),
1272 mBufferSize(0) {
1273 MOZ_ASSERT(aInputStream);
1274 MOZ_ASSERT(aCount == -1 || aCount > 0);
1275 MOZ_ASSERT_IF(mBuffer, aCount > 0);
1278 nsresult Write() {
1279 NS_ASSERT_OWNINGTHREAD(BufferWriter);
1281 // Let's make the inputStream buffered if it's not.
1282 if (!NS_InputStreamIsBuffered(mInputStream)) {
1283 nsCOMPtr<nsIInputStream> bufferedStream;
1284 nsresult rv = NS_NewBufferedInputStream(
1285 getter_AddRefs(bufferedStream), mInputStream.forget(), BUFFER_SIZE);
1286 NS_ENSURE_SUCCESS(rv, rv);
1288 mInputStream = bufferedStream;
1291 mAsyncInputStream = do_QueryInterface(mInputStream);
1293 if (!mAsyncInputStream) {
1294 return WriteSync();
1297 // Let's use mAsyncInputStream only.
1298 mInputStream = nullptr;
1300 return WriteAsync();
1303 uint64_t WrittenData() const {
1304 NS_ASSERT_OWNINGTHREAD(BufferWriter);
1305 return mWrittenData;
1308 void *StealBuffer() {
1309 NS_ASSERT_OWNINGTHREAD(BufferWriter);
1310 MOZ_ASSERT(mBufferType == eInternal);
1312 void *buffer = mBuffer;
1314 mBuffer = nullptr;
1315 mBufferSize = 0;
1317 return buffer;
1320 private:
1321 ~BufferWriter() {
1322 if (mBuffer && mBufferType == eInternal) {
1323 free(mBuffer);
1326 if (mTaskQueue) {
1327 mTaskQueue->BeginShutdown();
1331 nsresult WriteSync() {
1332 NS_ASSERT_OWNINGTHREAD(BufferWriter);
1334 uint64_t length = (uint64_t)mCount;
1336 if (mCount == -1) {
1337 nsresult rv = mInputStream->Available(&length);
1338 NS_ENSURE_SUCCESS(rv, rv);
1340 if (length == 0) {
1341 // nothing to read.
1342 return NS_OK;
1346 if (mBufferType == eInternal) {
1347 mBuffer = malloc(length);
1348 if (NS_WARN_IF(!mBuffer)) {
1349 return NS_ERROR_OUT_OF_MEMORY;
1353 uint32_t writtenData;
1354 nsresult rv = mInputStream->ReadSegments(NS_CopySegmentToBuffer, mBuffer,
1355 length, &writtenData);
1356 NS_ENSURE_SUCCESS(rv, rv);
1358 mWrittenData = writtenData;
1359 return NS_OK;
1362 nsresult WriteAsync() {
1363 NS_ASSERT_OWNINGTHREAD(BufferWriter);
1365 if (mCount > 0 && mBufferType == eInternal) {
1366 mBuffer = malloc(mCount);
1367 if (NS_WARN_IF(!mBuffer)) {
1368 return NS_ERROR_OUT_OF_MEMORY;
1372 while (true) {
1373 if (mCount == -1 && !MaybeExpandBufferSize()) {
1374 return NS_ERROR_OUT_OF_MEMORY;
1377 uint64_t offset = mWrittenData;
1378 uint64_t length = mCount == -1 ? BUFFER_SIZE : mCount;
1380 // Let's try to read data directly.
1381 uint32_t writtenData;
1382 nsresult rv = mAsyncInputStream->ReadSegments(
1383 NS_CopySegmentToBuffer, static_cast<char *>(mBuffer) + offset, length,
1384 &writtenData);
1386 // Operation completed. Nothing more to read.
1387 if (NS_SUCCEEDED(rv) && writtenData == 0) {
1388 return NS_OK;
1391 // If we succeeded, let's try to read again.
1392 if (NS_SUCCEEDED(rv)) {
1393 mWrittenData += writtenData;
1394 if (mCount != -1) {
1395 MOZ_ASSERT(mCount >= writtenData);
1396 mCount -= writtenData;
1398 // Is this the end of the reading?
1399 if (mCount == 0) {
1400 return NS_OK;
1404 continue;
1407 // Async wait...
1408 if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
1409 rv = MaybeCreateTaskQueue();
1410 if (NS_WARN_IF(NS_FAILED(rv))) {
1411 return rv;
1414 MonitorAutoLock lock(mMonitor);
1416 rv = mAsyncInputStream->AsyncWait(this, 0, length, mTaskQueue);
1417 if (NS_WARN_IF(NS_FAILED(rv))) {
1418 return rv;
1421 lock.Wait();
1422 continue;
1425 // Otherwise, let's propagate the error.
1426 return rv;
1429 MOZ_ASSERT_UNREACHABLE("We should not be here");
1430 return NS_ERROR_FAILURE;
1433 nsresult MaybeCreateTaskQueue() {
1434 NS_ASSERT_OWNINGTHREAD(BufferWriter);
1436 if (!mTaskQueue) {
1437 nsCOMPtr<nsIEventTarget> target =
1438 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
1439 if (!target) {
1440 return NS_ERROR_FAILURE;
1443 mTaskQueue = new TaskQueue(target.forget());
1446 return NS_OK;
1449 NS_IMETHOD
1450 OnInputStreamReady(nsIAsyncInputStream *aStream) override {
1451 MOZ_ASSERT(!NS_IsMainThread());
1453 // We have something to read. Let's unlock the main-thread.
1454 MonitorAutoLock lock(mMonitor);
1455 lock.Notify();
1456 return NS_OK;
1459 bool MaybeExpandBufferSize() {
1460 NS_ASSERT_OWNINGTHREAD(BufferWriter);
1462 MOZ_ASSERT(mCount == -1);
1464 if (mBufferSize >= mWrittenData + BUFFER_SIZE) {
1465 // The buffer is big enough.
1466 return true;
1469 CheckedUint32 bufferSize =
1470 std::max<uint32_t>(static_cast<uint32_t>(mWrittenData), BUFFER_SIZE);
1471 while (bufferSize.isValid() &&
1472 bufferSize.value() < mWrittenData + BUFFER_SIZE) {
1473 bufferSize *= 2;
1476 if (!bufferSize.isValid()) {
1477 return false;
1480 void *buffer = realloc(mBuffer, bufferSize.value());
1481 if (!buffer) {
1482 return false;
1485 mBuffer = buffer;
1486 mBufferSize = bufferSize.value();
1487 return true;
1490 // All the members of this class are touched on the owning thread only. The
1491 // monitor is only used to communicate when there is more data to read.
1492 Monitor mMonitor;
1494 nsCOMPtr<nsIInputStream> mInputStream;
1495 nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream;
1497 RefPtr<TaskQueue> mTaskQueue;
1499 void *mBuffer;
1500 int64_t mCount;
1501 uint64_t mWrittenData;
1503 enum {
1504 // The buffer is allocated internally and this object must release it
1505 // in the DTOR if not stolen. The buffer can be reallocated.
1506 eInternal,
1508 // The buffer is not owned by this object and it cannot be reallocated.
1509 eExternal,
1510 } mBufferType;
1512 // The following set if needed for the async read.
1513 uint64_t mBufferSize;
1516 NS_IMPL_ISUPPORTS(BufferWriter, nsIInputStreamCallback)
1518 } // anonymous namespace
1520 nsresult NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream, void **aDest,
1521 int64_t aCount, uint64_t *aWritten) {
1522 MOZ_ASSERT(aInputStream);
1523 MOZ_ASSERT(aCount >= -1);
1525 uint64_t dummyWritten;
1526 if (!aWritten) {
1527 aWritten = &dummyWritten;
1530 if (aCount == 0) {
1531 *aWritten = 0;
1532 return NS_OK;
1535 // This will take care of allocating and reallocating aDest.
1536 RefPtr<BufferWriter> writer = new BufferWriter(aInputStream, *aDest, aCount);
1538 nsresult rv = writer->Write();
1539 NS_ENSURE_SUCCESS(rv, rv);
1541 *aWritten = writer->WrittenData();
1543 if (!*aDest) {
1544 *aDest = writer->StealBuffer();
1547 return NS_OK;
1550 nsresult NS_ReadInputStreamToString(nsIInputStream *aInputStream,
1551 nsACString &aDest, int64_t aCount,
1552 uint64_t *aWritten) {
1553 uint64_t dummyWritten;
1554 if (!aWritten) {
1555 aWritten = &dummyWritten;
1558 // Nothing to do if aCount is 0.
1559 if (aCount == 0) {
1560 aDest.Truncate();
1561 *aWritten = 0;
1562 return NS_OK;
1565 // If we have the size, we can pre-allocate the buffer.
1566 if (aCount > 0) {
1567 if (NS_WARN_IF(aCount >= INT32_MAX) ||
1568 NS_WARN_IF(!aDest.SetLength(aCount, mozilla::fallible))) {
1569 return NS_ERROR_OUT_OF_MEMORY;
1572 void *dest = aDest.BeginWriting();
1573 nsresult rv =
1574 NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
1575 NS_ENSURE_SUCCESS(rv, rv);
1577 if ((uint64_t)aCount > *aWritten) {
1578 aDest.Truncate(*aWritten);
1581 return NS_OK;
1584 // If the size is unknown, BufferWriter will allocate the buffer.
1585 void *dest = nullptr;
1586 nsresult rv =
1587 NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
1588 MOZ_ASSERT_IF(NS_FAILED(rv), dest == nullptr);
1589 NS_ENSURE_SUCCESS(rv, rv);
1591 if (!dest) {
1592 MOZ_ASSERT(*aWritten == 0);
1593 aDest.Truncate();
1594 return NS_OK;
1597 aDest.Adopt(reinterpret_cast<char *>(dest), *aWritten);
1598 return NS_OK;
1601 nsresult NS_NewURI(
1602 nsIURI **result, const nsACString &spec,
1603 const char *charset /* = nullptr */, nsIURI *baseURI /* = nullptr */,
1604 nsIIOService
1605 *ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1607 nsresult rv;
1608 nsCOMPtr<nsIIOService> grip;
1609 rv = net_EnsureIOService(&ioService, grip);
1610 if (ioService) rv = ioService->NewURI(spec, charset, baseURI, result);
1611 return rv;
1614 nsresult NS_NewURI(
1615 nsIURI **result, const nsACString &spec, NotNull<const Encoding *> encoding,
1616 nsIURI *baseURI /* = nullptr */,
1617 nsIIOService
1618 *ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1620 nsAutoCString charset;
1621 encoding->Name(charset);
1622 return NS_NewURI(result, spec, charset.get(), baseURI, ioService);
1625 nsresult NS_NewURI(
1626 nsIURI **result, const nsAString &spec, const char *charset /* = nullptr */,
1627 nsIURI *baseURI /* = nullptr */,
1628 nsIIOService
1629 *ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1631 return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), charset, baseURI,
1632 ioService);
1635 nsresult NS_NewURI(
1636 nsIURI **result, const nsAString &spec, NotNull<const Encoding *> encoding,
1637 nsIURI *baseURI /* = nullptr */,
1638 nsIIOService
1639 *ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1641 return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), encoding, baseURI,
1642 ioService);
1645 nsresult NS_NewURI(
1646 nsIURI **result, const char *spec, nsIURI *baseURI /* = nullptr */,
1647 nsIIOService
1648 *ioService /* = nullptr */) // pass in nsIIOService to optimize callers
1650 return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI,
1651 ioService);
1654 nsresult NS_GetSanitizedURIStringFromURI(nsIURI *aUri,
1655 nsAString &aSanitizedSpec) {
1656 aSanitizedSpec.Truncate();
1658 nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(aUri);
1659 nsAutoCString cSpec;
1660 nsresult rv;
1661 if (safeUri) {
1662 rv = safeUri->GetSensitiveInfoHiddenSpec(cSpec);
1663 } else {
1664 rv = aUri->GetSpec(cSpec);
1667 if (NS_SUCCEEDED(rv)) {
1668 aSanitizedSpec.Assign(NS_ConvertUTF8toUTF16(cSpec));
1670 return rv;
1673 nsresult NS_LoadPersistentPropertiesFromURISpec(
1674 nsIPersistentProperties **outResult, const nsACString &aSpec) {
1675 nsCOMPtr<nsIURI> uri;
1676 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpec);
1677 NS_ENSURE_SUCCESS(rv, rv);
1679 nsCOMPtr<nsIChannel> channel;
1680 rv = NS_NewChannel(getter_AddRefs(channel), uri,
1681 nsContentUtils::GetSystemPrincipal(),
1682 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1683 nsIContentPolicy::TYPE_OTHER);
1684 NS_ENSURE_SUCCESS(rv, rv);
1685 nsCOMPtr<nsIInputStream> in;
1686 rv = channel->Open2(getter_AddRefs(in));
1687 NS_ENSURE_SUCCESS(rv, rv);
1689 nsCOMPtr<nsIPersistentProperties> properties = new nsPersistentProperties();
1690 rv = properties->Load(in);
1691 NS_ENSURE_SUCCESS(rv, rv);
1693 properties.swap(*outResult);
1694 return NS_OK;
1697 bool NS_UsePrivateBrowsing(nsIChannel *channel) {
1698 OriginAttributes attrs;
1699 bool result = NS_GetOriginAttributes(channel, attrs);
1700 NS_ENSURE_TRUE(result, result);
1701 return attrs.mPrivateBrowsingId > 0;
1704 bool NS_GetOriginAttributes(nsIChannel *aChannel,
1705 mozilla::OriginAttributes &aAttributes) {
1706 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
1707 // For some channels, they might not have loadInfo, like
1708 // ExternalHelperAppParent..
1709 if (loadInfo) {
1710 loadInfo->GetOriginAttributes(&aAttributes);
1713 bool isPrivate = false;
1714 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(aChannel);
1715 if (pbChannel) {
1716 nsresult rv = pbChannel->GetIsChannelPrivate(&isPrivate);
1717 NS_ENSURE_SUCCESS(rv, false);
1718 } else {
1719 // Some channels may not implement nsIPrivateBrowsingChannel
1720 nsCOMPtr<nsILoadContext> loadContext;
1721 NS_QueryNotificationCallbacks(aChannel, loadContext);
1722 isPrivate = loadContext && loadContext->UsePrivateBrowsing();
1724 aAttributes.SyncAttributesWithPrivateBrowsing(isPrivate);
1725 return true;
1728 bool NS_HasBeenCrossOrigin(nsIChannel *aChannel, bool aReport) {
1729 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
1730 MOZ_RELEASE_ASSERT(
1731 loadInfo,
1732 "Origin tracking only works for channels created with a loadinfo");
1734 if (!loadInfo) {
1735 return false;
1738 // TYPE_DOCUMENT loads have a null LoadingPrincipal and can not be cross
1739 // origin.
1740 if (!loadInfo->LoadingPrincipal()) {
1741 return false;
1744 // Always treat tainted channels as cross-origin.
1745 if (loadInfo->GetTainting() != LoadTainting::Basic) {
1746 return true;
1749 nsCOMPtr<nsIPrincipal> loadingPrincipal = loadInfo->LoadingPrincipal();
1750 uint32_t mode = loadInfo->GetSecurityMode();
1751 bool dataInherits =
1752 mode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS ||
1753 mode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS ||
1754 mode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
1756 bool aboutBlankInherits = dataInherits && loadInfo->GetAboutBlankInherits();
1758 for (nsIRedirectHistoryEntry *redirectHistoryEntry :
1759 loadInfo->RedirectChain()) {
1760 nsCOMPtr<nsIPrincipal> principal;
1761 redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal));
1762 if (!principal) {
1763 return true;
1766 nsCOMPtr<nsIURI> uri;
1767 principal->GetURI(getter_AddRefs(uri));
1768 if (!uri) {
1769 return true;
1772 if (aboutBlankInherits && NS_IsAboutBlank(uri)) {
1773 continue;
1776 if (NS_FAILED(loadingPrincipal->CheckMayLoad(uri, aReport, dataInherits))) {
1777 return true;
1781 nsCOMPtr<nsIURI> uri;
1782 NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
1783 if (!uri) {
1784 return true;
1787 if (aboutBlankInherits && NS_IsAboutBlank(uri)) {
1788 return false;
1791 return NS_FAILED(loadingPrincipal->CheckMayLoad(uri, aReport, dataInherits));
1794 bool NS_IsSafeTopLevelNav(nsIChannel *aChannel) {
1795 if (!aChannel) {
1796 return false;
1798 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
1799 if (!loadInfo) {
1800 return false;
1802 if (loadInfo->GetExternalContentPolicyType() !=
1803 nsIContentPolicy::TYPE_DOCUMENT) {
1804 return false;
1806 RefPtr<HttpBaseChannel> baseChan = do_QueryObject(aChannel);
1807 if (!baseChan) {
1808 return false;
1810 nsHttpRequestHead *requestHead = baseChan->GetRequestHead();
1811 if (!requestHead) {
1812 return false;
1814 return requestHead->IsSafeMethod();
1817 bool NS_IsSameSiteForeign(nsIChannel *aChannel, nsIURI *aHostURI) {
1818 if (!aChannel) {
1819 return false;
1821 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
1822 if (!loadInfo) {
1823 return false;
1826 // Do not treat loads triggered by web extensions as foreign
1827 nsCOMPtr<nsIURI> channelURI;
1828 NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
1829 if (BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
1830 ->AddonAllowsLoad(channelURI)) {
1831 return false;
1834 nsCOMPtr<nsIURI> uri;
1835 if (loadInfo->GetExternalContentPolicyType() ==
1836 nsIContentPolicy::TYPE_DOCUMENT) {
1837 // for loads of TYPE_DOCUMENT we query the hostURI from the
1838 // triggeringPricnipal which returns the URI of the document that caused the
1839 // navigation.
1840 loadInfo->TriggeringPrincipal()->GetURI(getter_AddRefs(uri));
1841 } else {
1842 uri = aHostURI;
1845 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
1846 do_GetService(THIRDPARTYUTIL_CONTRACTID);
1847 if (!thirdPartyUtil) {
1848 return false;
1851 bool isForeign = true;
1852 nsresult rv = thirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
1853 // if we are dealing with a cross origin request, we can return here
1854 // because we already know the request is 'foreign'.
1855 if (NS_FAILED(rv) || isForeign) {
1856 return true;
1859 // for loads of TYPE_SUBDOCUMENT we have to perform an additional test,
1860 // because a cross-origin iframe might perform a navigation to a same-origin
1861 // iframe which would send same-site cookies. Hence, if the iframe navigation
1862 // was triggered by a cross-origin triggeringPrincipal, we treat the load as
1863 // foreign.
1864 if (loadInfo->GetExternalContentPolicyType() ==
1865 nsIContentPolicy::TYPE_SUBDOCUMENT) {
1866 nsCOMPtr<nsIURI> triggeringPrincipalURI;
1867 loadInfo->TriggeringPrincipal()->GetURI(
1868 getter_AddRefs(triggeringPrincipalURI));
1869 rv = thirdPartyUtil->IsThirdPartyChannel(aChannel, triggeringPrincipalURI,
1870 &isForeign);
1871 if (NS_FAILED(rv) || isForeign) {
1872 return true;
1876 // for the purpose of same-site cookies we have to treat any cross-origin
1877 // redirects as foreign. E.g. cross-site to same-site redirect is a problem
1878 // with regards to CSRF.
1880 nsCOMPtr<nsIPrincipal> redirectPrincipal;
1881 nsCOMPtr<nsIURI> redirectURI;
1882 for (nsIRedirectHistoryEntry *entry : loadInfo->RedirectChain()) {
1883 entry->GetPrincipal(getter_AddRefs(redirectPrincipal));
1884 if (redirectPrincipal) {
1885 redirectPrincipal->GetURI(getter_AddRefs(redirectURI));
1886 rv = thirdPartyUtil->IsThirdPartyChannel(aChannel, redirectURI,
1887 &isForeign);
1888 // if at any point we encounter a cross-origin redirect we can return.
1889 if (NS_FAILED(rv) || isForeign) {
1890 return true;
1894 return isForeign;
1897 bool NS_ShouldCheckAppCache(nsIPrincipal *aPrincipal) {
1898 uint32_t privateBrowsingId = 0;
1899 nsresult rv = aPrincipal->GetPrivateBrowsingId(&privateBrowsingId);
1900 if (NS_SUCCEEDED(rv) && (privateBrowsingId > 0)) {
1901 return false;
1904 nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
1905 do_GetService("@mozilla.org/offlinecacheupdate-service;1");
1906 if (!offlineService) {
1907 return false;
1910 bool allowed;
1911 rv = offlineService->OfflineAppAllowed(aPrincipal, nullptr, &allowed);
1912 return NS_SUCCEEDED(rv) && allowed;
1915 void NS_WrapAuthPrompt(nsIAuthPrompt *aAuthPrompt,
1916 nsIAuthPrompt2 **aAuthPrompt2) {
1917 nsCOMPtr<nsIAuthPromptAdapterFactory> factory =
1918 do_GetService(NS_AUTHPROMPT_ADAPTER_FACTORY_CONTRACTID);
1919 if (!factory) return;
1921 NS_WARNING("Using deprecated nsIAuthPrompt");
1922 factory->CreateAdapter(aAuthPrompt, aAuthPrompt2);
1925 void NS_QueryAuthPrompt2(nsIInterfaceRequestor *aCallbacks,
1926 nsIAuthPrompt2 **aAuthPrompt) {
1927 CallGetInterface(aCallbacks, aAuthPrompt);
1928 if (*aAuthPrompt) return;
1930 // Maybe only nsIAuthPrompt is provided and we have to wrap it.
1931 nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks));
1932 if (!prompt) return;
1934 NS_WrapAuthPrompt(prompt, aAuthPrompt);
1937 void NS_QueryAuthPrompt2(nsIChannel *aChannel, nsIAuthPrompt2 **aAuthPrompt) {
1938 *aAuthPrompt = nullptr;
1940 // We want to use any auth prompt we can find on the channel's callbacks,
1941 // and if that fails use the loadgroup's prompt (if any)
1942 // Therefore, we can't just use NS_QueryNotificationCallbacks, because
1943 // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's
1944 // nsIAuthPrompt.
1945 nsCOMPtr<nsIInterfaceRequestor> callbacks;
1946 aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
1947 if (callbacks) {
1948 NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
1949 if (*aAuthPrompt) return;
1952 nsCOMPtr<nsILoadGroup> group;
1953 aChannel->GetLoadGroup(getter_AddRefs(group));
1954 if (!group) return;
1956 group->GetNotificationCallbacks(getter_AddRefs(callbacks));
1957 if (!callbacks) return;
1958 NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
1961 nsresult NS_NewNotificationCallbacksAggregation(
1962 nsIInterfaceRequestor *callbacks, nsILoadGroup *loadGroup,
1963 nsIEventTarget *target, nsIInterfaceRequestor **result) {
1964 nsCOMPtr<nsIInterfaceRequestor> cbs;
1965 if (loadGroup) loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
1966 return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result);
1969 nsresult NS_NewNotificationCallbacksAggregation(
1970 nsIInterfaceRequestor *callbacks, nsILoadGroup *loadGroup,
1971 nsIInterfaceRequestor **result) {
1972 return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr,
1973 result);
1976 nsresult NS_DoImplGetInnermostURI(nsINestedURI *nestedURI, nsIURI **result) {
1977 MOZ_ASSERT(nestedURI, "Must have a nested URI!");
1978 MOZ_ASSERT(!*result, "Must have null *result");
1980 nsCOMPtr<nsIURI> inner;
1981 nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner));
1982 NS_ENSURE_SUCCESS(rv, rv);
1984 // We may need to loop here until we reach the innermost
1985 // URI.
1986 nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner));
1987 while (nestedInner) {
1988 rv = nestedInner->GetInnerURI(getter_AddRefs(inner));
1989 NS_ENSURE_SUCCESS(rv, rv);
1990 nestedInner = do_QueryInterface(inner);
1993 // Found the innermost one if we reach here.
1994 inner.swap(*result);
1996 return rv;
1999 nsresult NS_ImplGetInnermostURI(nsINestedURI *nestedURI, nsIURI **result) {
2000 // Make it safe to use swap()
2001 *result = nullptr;
2003 return NS_DoImplGetInnermostURI(nestedURI, result);
2006 already_AddRefed<nsIURI> NS_GetInnermostURI(nsIURI *aURI) {
2007 MOZ_ASSERT(aURI, "Must have URI");
2009 nsCOMPtr<nsIURI> uri = aURI;
2011 nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri));
2012 if (!nestedURI) {
2013 return uri.forget();
2016 nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
2017 if (NS_FAILED(rv)) {
2018 return nullptr;
2021 return uri.forget();
2024 nsresult NS_GetFinalChannelURI(nsIChannel *channel, nsIURI **uri) {
2025 *uri = nullptr;
2027 nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
2028 if (loadInfo) {
2029 nsCOMPtr<nsIURI> resultPrincipalURI;
2030 loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
2031 if (resultPrincipalURI) {
2032 resultPrincipalURI.forget(uri);
2033 return NS_OK;
2037 return channel->GetOriginalURI(uri);
2040 nsresult NS_URIChainHasFlags(nsIURI *uri, uint32_t flags, bool *result) {
2041 nsresult rv;
2042 nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
2043 NS_ENSURE_SUCCESS(rv, rv);
2045 return util->URIChainHasFlags(uri, flags, result);
2048 uint32_t NS_SecurityHashURI(nsIURI *aURI) {
2049 nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
2051 nsAutoCString scheme;
2052 uint32_t schemeHash = 0;
2053 if (NS_SUCCEEDED(baseURI->GetScheme(scheme)))
2054 schemeHash = mozilla::HashString(scheme);
2056 // TODO figure out how to hash file:// URIs
2057 if (scheme.EqualsLiteral("file")) return schemeHash; // sad face
2059 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
2060 bool hasFlag;
2061 if (NS_FAILED(NS_URIChainHasFlags(
2062 baseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) ||
2063 hasFlag) {
2064 nsAutoCString spec;
2065 uint32_t specHash;
2066 nsresult res = baseURI->GetSpec(spec);
2067 if (NS_SUCCEEDED(res))
2068 specHash = mozilla::HashString(spec);
2069 else
2070 specHash = static_cast<uint32_t>(res);
2071 return specHash;
2073 #endif
2075 nsAutoCString host;
2076 uint32_t hostHash = 0;
2077 if (NS_SUCCEEDED(baseURI->GetAsciiHost(host)))
2078 hostHash = mozilla::HashString(host);
2080 return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI));
2083 bool NS_SecurityCompareURIs(nsIURI *aSourceURI, nsIURI *aTargetURI,
2084 bool aStrictFileOriginPolicy) {
2085 nsresult rv;
2087 // Note that this is not an Equals() test on purpose -- for URIs that don't
2088 // support host/port, we want equality to basically be object identity, for
2089 // security purposes. Otherwise, for example, two javascript: URIs that
2090 // are otherwise unrelated could end up "same origin", which would be
2091 // unfortunate.
2092 if (aSourceURI && aSourceURI == aTargetURI) {
2093 return true;
2096 if (!aTargetURI || !aSourceURI) {
2097 return false;
2100 // If either URI is a nested URI, get the base URI
2101 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
2102 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
2104 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
2105 // Check if either URI has a special origin.
2106 nsCOMPtr<nsIURI> origin;
2107 nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin =
2108 do_QueryInterface(sourceBaseURI);
2109 if (uriWithSpecialOrigin) {
2110 rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
2111 if (NS_WARN_IF(NS_FAILED(rv))) {
2112 return false;
2114 MOZ_ASSERT(origin);
2115 sourceBaseURI = origin;
2117 uriWithSpecialOrigin = do_QueryInterface(targetBaseURI);
2118 if (uriWithSpecialOrigin) {
2119 rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
2120 if (NS_WARN_IF(NS_FAILED(rv))) {
2121 return false;
2123 MOZ_ASSERT(origin);
2124 targetBaseURI = origin;
2126 #endif
2128 nsCOMPtr<nsIPrincipal> sourceBlobPrincipal;
2129 if (BlobURLProtocolHandler::GetBlobURLPrincipal(
2130 sourceBaseURI, getter_AddRefs(sourceBlobPrincipal))) {
2131 nsCOMPtr<nsIURI> sourceBlobOwnerURI;
2132 rv = sourceBlobPrincipal->GetURI(getter_AddRefs(sourceBlobOwnerURI));
2133 if (NS_SUCCEEDED(rv)) {
2134 sourceBaseURI = sourceBlobOwnerURI;
2138 nsCOMPtr<nsIPrincipal> targetBlobPrincipal;
2139 if (BlobURLProtocolHandler::GetBlobURLPrincipal(
2140 targetBaseURI, getter_AddRefs(targetBlobPrincipal))) {
2141 nsCOMPtr<nsIURI> targetBlobOwnerURI;
2142 rv = targetBlobPrincipal->GetURI(getter_AddRefs(targetBlobOwnerURI));
2143 if (NS_SUCCEEDED(rv)) {
2144 targetBaseURI = targetBlobOwnerURI;
2148 if (!sourceBaseURI || !targetBaseURI) return false;
2150 // Compare schemes
2151 nsAutoCString targetScheme;
2152 bool sameScheme = false;
2153 if (NS_FAILED(targetBaseURI->GetScheme(targetScheme)) ||
2154 NS_FAILED(sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme)) ||
2155 !sameScheme) {
2156 // Not same-origin if schemes differ
2157 return false;
2160 // For file scheme, reject unless the files are identical. See
2161 // NS_RelaxStrictFileOriginPolicy for enforcing file same-origin checking
2162 if (targetScheme.EqualsLiteral("file")) {
2163 // in traditional unsafe behavior all files are the same origin
2164 if (!aStrictFileOriginPolicy) return true;
2166 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
2167 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
2169 if (!sourceFileURL || !targetFileURL) return false;
2171 nsCOMPtr<nsIFile> sourceFile, targetFile;
2173 sourceFileURL->GetFile(getter_AddRefs(sourceFile));
2174 targetFileURL->GetFile(getter_AddRefs(targetFile));
2176 if (!sourceFile || !targetFile) return false;
2178 // Otherwise they had better match
2179 bool filesAreEqual = false;
2180 rv = sourceFile->Equals(targetFile, &filesAreEqual);
2181 return NS_SUCCEEDED(rv) && filesAreEqual;
2184 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
2185 bool hasFlag;
2186 if (NS_FAILED(NS_URIChainHasFlags(
2187 targetBaseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) ||
2188 hasFlag) {
2189 // URIs with this flag have the whole spec as a distinct trust
2190 // domain; use the whole spec for comparison
2191 nsAutoCString targetSpec;
2192 nsAutoCString sourceSpec;
2193 return (NS_SUCCEEDED(targetBaseURI->GetSpec(targetSpec)) &&
2194 NS_SUCCEEDED(sourceBaseURI->GetSpec(sourceSpec)) &&
2195 targetSpec.Equals(sourceSpec));
2197 #endif
2199 // Compare hosts
2200 nsAutoCString targetHost;
2201 nsAutoCString sourceHost;
2202 if (NS_FAILED(targetBaseURI->GetAsciiHost(targetHost)) ||
2203 NS_FAILED(sourceBaseURI->GetAsciiHost(sourceHost))) {
2204 return false;
2207 nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI));
2208 nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI));
2209 if (!targetURL || !sourceURL) {
2210 return false;
2213 if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator())) {
2214 return false;
2217 return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI);
2220 bool NS_URIIsLocalFile(nsIURI *aURI) {
2221 nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
2223 bool isFile;
2224 return util &&
2225 NS_SUCCEEDED(util->ProtocolHasFlags(
2226 aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile)) &&
2227 isFile;
2230 bool NS_RelaxStrictFileOriginPolicy(nsIURI *aTargetURI, nsIURI *aSourceURI,
2231 bool aAllowDirectoryTarget /* = false */) {
2232 if (!NS_URIIsLocalFile(aTargetURI)) {
2233 // This is probably not what the caller intended
2234 MOZ_ASSERT_UNREACHABLE(
2235 "NS_RelaxStrictFileOriginPolicy called with non-file URI");
2236 return false;
2239 if (!NS_URIIsLocalFile(aSourceURI)) {
2240 // If the source is not also a file: uri then forget it
2241 // (don't want resource: principals in a file: doc)
2243 // note: we're not de-nesting jar: uris here, we want to
2244 // keep archive content bottled up in its own little island
2245 return false;
2249 // pull out the internal files
2251 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(aTargetURI));
2252 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(aSourceURI));
2253 nsCOMPtr<nsIFile> targetFile;
2254 nsCOMPtr<nsIFile> sourceFile;
2255 bool targetIsDir;
2257 // Make sure targetFile is not a directory (bug 209234)
2258 // and that it exists w/out unescaping (bug 395343)
2259 if (!sourceFileURL || !targetFileURL ||
2260 NS_FAILED(targetFileURL->GetFile(getter_AddRefs(targetFile))) ||
2261 NS_FAILED(sourceFileURL->GetFile(getter_AddRefs(sourceFile))) ||
2262 !targetFile || !sourceFile || NS_FAILED(targetFile->Normalize()) ||
2263 #ifndef MOZ_WIDGET_ANDROID
2264 NS_FAILED(sourceFile->Normalize()) ||
2265 #endif
2266 (!aAllowDirectoryTarget &&
2267 (NS_FAILED(targetFile->IsDirectory(&targetIsDir)) || targetIsDir))) {
2268 return false;
2272 // If the file to be loaded is in a subdirectory of the source
2273 // (or same-dir if source is not a directory) then it will
2274 // inherit its source principal and be scriptable by that source.
2276 bool sourceIsDir;
2277 bool allowed = false;
2278 nsresult rv = sourceFile->IsDirectory(&sourceIsDir);
2279 if (NS_SUCCEEDED(rv) && sourceIsDir) {
2280 rv = sourceFile->Contains(targetFile, &allowed);
2281 } else {
2282 nsCOMPtr<nsIFile> sourceParent;
2283 rv = sourceFile->GetParent(getter_AddRefs(sourceParent));
2284 if (NS_SUCCEEDED(rv) && sourceParent) {
2285 rv = sourceParent->Equals(targetFile, &allowed);
2286 if (NS_FAILED(rv) || !allowed) {
2287 rv = sourceParent->Contains(targetFile, &allowed);
2288 } else {
2289 MOZ_ASSERT(aAllowDirectoryTarget,
2290 "sourceFile->Parent == targetFile, but targetFile "
2291 "should've been disallowed if it is a directory");
2296 if (NS_SUCCEEDED(rv) && allowed) {
2297 return true;
2300 return false;
2303 bool NS_IsInternalSameURIRedirect(nsIChannel *aOldChannel,
2304 nsIChannel *aNewChannel, uint32_t aFlags) {
2305 if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
2306 return false;
2309 nsCOMPtr<nsIURI> oldURI, newURI;
2310 aOldChannel->GetURI(getter_AddRefs(oldURI));
2311 aNewChannel->GetURI(getter_AddRefs(newURI));
2313 if (!oldURI || !newURI) {
2314 return false;
2317 bool res;
2318 return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
2321 bool NS_IsHSTSUpgradeRedirect(nsIChannel *aOldChannel, nsIChannel *aNewChannel,
2322 uint32_t aFlags) {
2323 if (!(aFlags & nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
2324 return false;
2327 nsCOMPtr<nsIURI> oldURI, newURI;
2328 aOldChannel->GetURI(getter_AddRefs(oldURI));
2329 aNewChannel->GetURI(getter_AddRefs(newURI));
2331 if (!oldURI || !newURI) {
2332 return false;
2335 bool isHttp;
2336 if (NS_FAILED(oldURI->SchemeIs("http", &isHttp)) || !isHttp) {
2337 return false;
2340 nsCOMPtr<nsIURI> upgradedURI;
2341 nsresult rv = NS_GetSecureUpgradedURI(oldURI, getter_AddRefs(upgradedURI));
2342 if (NS_FAILED(rv)) {
2343 return false;
2346 bool res;
2347 return NS_SUCCEEDED(upgradedURI->Equals(newURI, &res)) && res;
2350 nsresult NS_LinkRedirectChannels(uint32_t channelId,
2351 nsIParentChannel *parentChannel,
2352 nsIChannel **_result) {
2353 nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
2354 RedirectChannelRegistrar::GetOrCreate();
2355 MOZ_ASSERT(registrar);
2357 return registrar->LinkChannels(channelId, parentChannel, _result);
2360 nsresult NS_MaybeOpenChannelUsingOpen2(nsIChannel *aChannel,
2361 nsIInputStream **aStream) {
2362 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
2363 if (loadInfo && loadInfo->GetSecurityMode() != 0) {
2364 return aChannel->Open2(aStream);
2366 return aChannel->Open(aStream);
2369 nsresult NS_MaybeOpenChannelUsingAsyncOpen2(nsIChannel *aChannel,
2370 nsIStreamListener *aListener) {
2371 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
2372 if (loadInfo && loadInfo->GetSecurityMode() != 0) {
2373 return aChannel->AsyncOpen2(aListener);
2375 return aChannel->AsyncOpen(aListener, nullptr);
2378 /** Given the first (disposition) token from a Content-Disposition header,
2379 * tell whether it indicates the content is inline or attachment
2380 * @param aDispToken the disposition token from the content-disposition header
2382 uint32_t NS_GetContentDispositionFromToken(const nsAString &aDispToken) {
2383 // RFC 2183, section 2.8 says that an unknown disposition
2384 // value should be treated as "attachment"
2385 // If all of these tests eval to false, then we have a content-disposition of
2386 // "attachment" or unknown
2387 if (aDispToken.IsEmpty() || aDispToken.LowerCaseEqualsLiteral("inline") ||
2388 // Broken sites just send
2389 // Content-Disposition: filename="file"
2390 // without a disposition token... screen those out.
2391 StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename"))
2392 return nsIChannel::DISPOSITION_INLINE;
2394 return nsIChannel::DISPOSITION_ATTACHMENT;
2397 uint32_t NS_GetContentDispositionFromHeader(const nsACString &aHeader,
2398 nsIChannel *aChan /* = nullptr */) {
2399 nsresult rv;
2400 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
2401 do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
2402 if (NS_FAILED(rv)) return nsIChannel::DISPOSITION_ATTACHMENT;
2404 nsAutoString dispToken;
2405 rv = mimehdrpar->GetParameterHTTP(aHeader, "", EmptyCString(), true, nullptr,
2406 dispToken);
2408 if (NS_FAILED(rv)) {
2409 // special case (see bug 272541): empty disposition type handled as "inline"
2410 if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY)
2411 return nsIChannel::DISPOSITION_INLINE;
2412 return nsIChannel::DISPOSITION_ATTACHMENT;
2415 return NS_GetContentDispositionFromToken(dispToken);
2418 nsresult NS_GetFilenameFromDisposition(nsAString &aFilename,
2419 const nsACString &aDisposition,
2420 nsIURI *aURI /* = nullptr */) {
2421 aFilename.Truncate();
2423 nsresult rv;
2424 nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
2425 do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
2426 if (NS_FAILED(rv)) return rv;
2428 // Get the value of 'filename' parameter
2429 rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename", EmptyCString(),
2430 true, nullptr, aFilename);
2432 if (NS_FAILED(rv)) {
2433 aFilename.Truncate();
2434 return rv;
2437 if (aFilename.IsEmpty()) return NS_ERROR_NOT_AVAILABLE;
2439 return NS_OK;
2442 void net_EnsurePSMInit() {
2443 nsresult rv;
2444 nsCOMPtr<nsISupports> psm = do_GetService(PSM_COMPONENT_CONTRACTID, &rv);
2445 MOZ_ASSERT(NS_SUCCEEDED(rv));
2447 nsCOMPtr<nsISupports> sss = do_GetService(NS_SSSERVICE_CONTRACTID);
2448 nsCOMPtr<nsISupports> cbl = do_GetService(NS_CERTBLOCKLIST_CONTRACTID);
2449 nsCOMPtr<nsISupports> cos = do_GetService(NS_CERTOVERRIDE_CONTRACTID);
2452 bool NS_IsAboutBlank(nsIURI *uri) {
2453 // GetSpec can be expensive for some URIs, so check the scheme first.
2454 bool isAbout = false;
2455 if (NS_FAILED(uri->SchemeIs("about", &isAbout)) || !isAbout) {
2456 return false;
2459 return uri->GetSpecOrDefault().EqualsLiteral("about:blank");
2462 nsresult NS_GenerateHostPort(const nsCString &host, int32_t port,
2463 nsACString &hostLine) {
2464 if (strchr(host.get(), ':')) {
2465 // host is an IPv6 address literal and must be encapsulated in []'s
2466 hostLine.Assign('[');
2467 // scope id is not needed for Host header.
2468 int scopeIdPos = host.FindChar('%');
2469 if (scopeIdPos == -1)
2470 hostLine.Append(host);
2471 else if (scopeIdPos > 0)
2472 hostLine.Append(Substring(host, 0, scopeIdPos));
2473 else
2474 return NS_ERROR_MALFORMED_URI;
2475 hostLine.Append(']');
2476 } else
2477 hostLine.Assign(host);
2478 if (port != -1) {
2479 hostLine.Append(':');
2480 hostLine.AppendInt(port);
2482 return NS_OK;
2485 void NS_SniffContent(const char *aSnifferType, nsIRequest *aRequest,
2486 const uint8_t *aData, uint32_t aLength,
2487 nsACString &aSniffedType) {
2488 typedef nsCategoryCache<nsIContentSniffer> ContentSnifferCache;
2489 extern ContentSnifferCache *gNetSniffers;
2490 extern ContentSnifferCache *gDataSniffers;
2491 ContentSnifferCache *cache = nullptr;
2492 if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) {
2493 if (!gNetSniffers) {
2494 gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY);
2496 cache = gNetSniffers;
2497 } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) {
2498 if (!gDataSniffers) {
2499 gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY);
2501 cache = gDataSniffers;
2502 } else {
2503 // Invalid content sniffer type was requested
2504 MOZ_ASSERT(false);
2505 return;
2508 nsCOMArray<nsIContentSniffer> sniffers;
2509 cache->GetEntries(sniffers);
2510 for (int32_t i = 0; i < sniffers.Count(); ++i) {
2511 nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength,
2512 aSniffedType);
2513 if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
2514 return;
2518 aSniffedType.Truncate();
2521 bool NS_IsSrcdocChannel(nsIChannel *aChannel) {
2522 bool isSrcdoc;
2523 nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
2524 if (isr) {
2525 isr->GetIsSrcdocChannel(&isSrcdoc);
2526 return isSrcdoc;
2528 nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
2529 if (vsc) {
2530 nsresult rv = vsc->GetIsSrcdocChannel(&isSrcdoc);
2531 if (NS_SUCCEEDED(rv)) {
2532 return isSrcdoc;
2535 return false;
2538 nsresult NS_ShouldSecureUpgrade(nsIURI *aURI, nsILoadInfo *aLoadInfo,
2539 nsIPrincipal *aChannelResultPrincipal,
2540 bool aPrivateBrowsing, bool aAllowSTS,
2541 const OriginAttributes &aOriginAttributes,
2542 bool &aShouldUpgrade) {
2543 // Even if we're in private browsing mode, we still enforce existing STS
2544 // data (it is read-only).
2545 // if the connection is not using SSL and either the exact host matches or
2546 // a superdomain wants to force HTTPS, do it.
2547 bool isHttps = false;
2548 nsresult rv = aURI->SchemeIs("https", &isHttps);
2549 NS_ENSURE_SUCCESS(rv, rv);
2551 if (!isHttps &&
2552 !nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aURI)) {
2553 if (aLoadInfo) {
2554 // If any of the documents up the chain to the root document makes use of
2555 // the CSP directive 'upgrade-insecure-requests', then it's time to
2556 // fulfill the promise to CSP and mixed content blocking to upgrade the
2557 // channel from http to https.
2558 if (aLoadInfo->GetUpgradeInsecureRequests() ||
2559 aLoadInfo->GetBrowserUpgradeInsecureRequests()) {
2560 // let's log a message to the console that we are upgrading a request
2561 nsAutoCString scheme;
2562 aURI->GetScheme(scheme);
2563 // append the additional 's' for security to the scheme :-)
2564 scheme.AppendLiteral("s");
2565 NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
2566 NS_ConvertUTF8toUTF16 reportScheme(scheme);
2568 if (aLoadInfo->GetUpgradeInsecureRequests()) {
2569 const char16_t *params[] = {reportSpec.get(), reportScheme.get()};
2570 uint32_t innerWindowId = aLoadInfo->GetInnerWindowID();
2571 CSP_LogLocalizedStr(
2572 "upgradeInsecureRequest", params, ArrayLength(params),
2573 EmptyString(), // aSourceFile
2574 EmptyString(), // aScriptSample
2575 0, // aLineNumber
2576 0, // aColumnNumber
2577 nsIScriptError::warningFlag,
2578 NS_LITERAL_CSTRING("upgradeInsecureRequest"), innerWindowId,
2579 !!aLoadInfo->GetOriginAttributes().mPrivateBrowsingId);
2580 Telemetry::AccumulateCategorical(
2581 Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::CSP);
2582 } else {
2583 RefPtr<dom::Document> doc;
2584 nsINode *node = aLoadInfo->LoadingNode();
2585 if (node) {
2586 doc = node->OwnerDoc();
2589 nsAutoString brandName;
2590 nsresult rv = nsContentUtils::GetLocalizedString(
2591 nsContentUtils::eBRAND_PROPERTIES, "brandShortName", brandName);
2592 if (NS_SUCCEEDED(rv)) {
2593 const char16_t *params[] = {brandName.get(), reportSpec.get(),
2594 reportScheme.get()};
2595 nsContentUtils::ReportToConsole(
2596 nsIScriptError::warningFlag,
2597 NS_LITERAL_CSTRING("DATA_URI_BLOCKED"), doc,
2598 nsContentUtils::eSECURITY_PROPERTIES,
2599 "BrowserUpgradeInsecureDisplayRequest", params,
2600 ArrayLength(params));
2602 Telemetry::AccumulateCategorical(
2603 Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::BrowserDisplay);
2606 aShouldUpgrade = true;
2607 return NS_OK;
2611 // enforce Strict-Transport-Security
2612 nsISiteSecurityService *sss = gHttpHandler->GetSSService();
2613 NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
2615 bool isStsHost = false;
2616 uint32_t hstsSource = 0;
2617 uint32_t flags =
2618 aPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
2619 rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
2620 aOriginAttributes, nullptr, &hstsSource, &isStsHost);
2622 // if the SSS check fails, it's likely because this load is on a
2623 // malformed URI or something else in the setup is wrong, so any error
2624 // should be reported.
2625 NS_ENSURE_SUCCESS(rv, rv);
2627 if (isStsHost) {
2628 LOG(("nsHttpChannel::Connect() STS permissions found\n"));
2629 if (aAllowSTS) {
2630 Telemetry::AccumulateCategorical(
2631 Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::STS);
2632 aShouldUpgrade = true;
2633 switch (hstsSource) {
2634 case nsISiteSecurityService::SOURCE_PRELOAD_LIST:
2635 Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 0);
2636 break;
2637 case nsISiteSecurityService::SOURCE_ORGANIC_REQUEST:
2638 Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 1);
2639 break;
2640 case nsISiteSecurityService::SOURCE_UNKNOWN:
2641 default:
2642 // record this as an organic request
2643 Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 1);
2644 break;
2646 return NS_OK;
2648 Telemetry::AccumulateCategorical(
2649 Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::PrefBlockedSTS);
2650 } else {
2651 Telemetry::AccumulateCategorical(
2652 Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::NoReasonToUpgrade);
2654 } else {
2655 Telemetry::AccumulateCategorical(
2656 Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::AlreadyHTTPS);
2658 aShouldUpgrade = false;
2659 return NS_OK;
2662 nsresult NS_GetSecureUpgradedURI(nsIURI *aURI, nsIURI **aUpgradedURI) {
2663 NS_MutateURI mutator(aURI);
2664 mutator.SetScheme(
2665 NS_LITERAL_CSTRING("https")); // Change the scheme to HTTPS:
2667 // Change the default port to 443:
2668 nsCOMPtr<nsIStandardURL> stdURL = do_QueryInterface(aURI);
2669 if (stdURL) {
2670 mutator.Apply(
2671 NS_MutatorMethod(&nsIStandardURLMutator::SetDefaultPort, 443, nullptr));
2672 } else {
2673 // If we don't have a nsStandardURL, fall back to using GetPort/SetPort.
2674 // XXXdholbert Is this function even called with a non-nsStandardURL arg,
2675 // in practice?
2676 NS_WARNING("Calling NS_GetSecureUpgradedURI for non nsStandardURL");
2677 int32_t oldPort = -1;
2678 nsresult rv = aURI->GetPort(&oldPort);
2679 if (NS_FAILED(rv)) return rv;
2681 // Keep any nonstandard ports so only the scheme is changed.
2682 // For example:
2683 // http://foo.com:80 -> https://foo.com:443
2684 // http://foo.com:81 -> https://foo.com:81
2686 if (oldPort == 80 || oldPort == -1) {
2687 mutator.SetPort(-1);
2688 } else {
2689 mutator.SetPort(oldPort);
2693 return mutator.Finalize(aUpgradedURI);
2696 nsresult NS_CompareLoadInfoAndLoadContext(nsIChannel *aChannel) {
2697 nsCOMPtr<nsILoadInfo> loadInfo;
2698 aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
2700 nsCOMPtr<nsILoadContext> loadContext;
2701 NS_QueryNotificationCallbacks(aChannel, loadContext);
2702 if (!loadInfo || !loadContext) {
2703 return NS_OK;
2706 // We try to skip about:newtab.
2707 // about:newtab will use SystemPrincipal to download thumbnails through
2708 // https:// and blob URLs.
2709 bool isAboutPage = false;
2710 nsINode *node = loadInfo->LoadingNode();
2711 if (node) {
2712 nsIURI *uri = node->OwnerDoc()->GetDocumentURI();
2713 nsresult rv = uri->SchemeIs("about", &isAboutPage);
2714 NS_ENSURE_SUCCESS(rv, rv);
2717 if (isAboutPage) {
2718 return NS_OK;
2721 // We skip the favicon loading here. The favicon loading might be
2722 // triggered by the XUL image. For that case, the loadContext will have
2723 // default originAttributes since the XUL image uses SystemPrincipal, but
2724 // the loadInfo will use originAttributes from the content. Thus, the
2725 // originAttributes between loadInfo and loadContext will be different.
2726 // That's why we have to skip the comparison for the favicon loading.
2727 if (nsContentUtils::IsSystemPrincipal(loadInfo->LoadingPrincipal()) &&
2728 loadInfo->InternalContentPolicyType() ==
2729 nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
2730 return NS_OK;
2733 bool loadContextIsInBE = false;
2734 nsresult rv =
2735 loadContext->GetIsInIsolatedMozBrowserElement(&loadContextIsInBE);
2736 if (NS_FAILED(rv)) {
2737 return NS_ERROR_UNEXPECTED;
2740 OriginAttributes originAttrsLoadInfo = loadInfo->GetOriginAttributes();
2741 OriginAttributes originAttrsLoadContext;
2742 loadContext->GetOriginAttributes(originAttrsLoadContext);
2744 LOG(
2745 ("NS_CompareLoadInfoAndLoadContext - loadInfo: %d, %d, %d; "
2746 "loadContext: %d %d, %d. [channel=%p]",
2747 originAttrsLoadInfo.mInIsolatedMozBrowser,
2748 originAttrsLoadInfo.mUserContextId,
2749 originAttrsLoadInfo.mPrivateBrowsingId, loadContextIsInBE,
2750 originAttrsLoadContext.mUserContextId,
2751 originAttrsLoadContext.mPrivateBrowsingId, aChannel));
2753 MOZ_ASSERT(originAttrsLoadInfo.mInIsolatedMozBrowser == loadContextIsInBE,
2754 "The value of InIsolatedMozBrowser in the loadContext and in "
2755 "the loadInfo are not the same!");
2757 MOZ_ASSERT(originAttrsLoadInfo.mUserContextId ==
2758 originAttrsLoadContext.mUserContextId,
2759 "The value of mUserContextId in the loadContext and in the "
2760 "loadInfo are not the same!");
2762 MOZ_ASSERT(originAttrsLoadInfo.mPrivateBrowsingId ==
2763 originAttrsLoadContext.mPrivateBrowsingId,
2764 "The value of mPrivateBrowsingId in the loadContext and in the "
2765 "loadInfo are not the same!");
2767 return NS_OK;
2770 uint32_t NS_GetDefaultReferrerPolicy(bool privateBrowsing) {
2771 static bool preferencesInitialized = false;
2773 if (!preferencesInitialized) {
2774 mozilla::Preferences::AddUintVarCache(
2775 &sDefaultRp, "network.http.referer.defaultPolicy", DEFAULT_RP);
2776 mozilla::Preferences::AddUintVarCache(
2777 &defaultPrivateRp, "network.http.referer.defaultPolicy.pbmode",
2778 DEFAULT_PRIVATE_RP);
2779 preferencesInitialized = true;
2782 uint32_t defaultToUse;
2783 if (privateBrowsing) {
2784 defaultToUse = defaultPrivateRp;
2785 } else {
2786 defaultToUse = sDefaultRp;
2789 switch (defaultToUse) {
2790 case 0:
2791 return nsIHttpChannel::REFERRER_POLICY_NO_REFERRER;
2792 case 1:
2793 return nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN;
2794 case 2:
2795 return nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN;
2798 return nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
2801 bool NS_IsOffline() {
2802 bool offline = true;
2803 bool connectivity = true;
2804 nsCOMPtr<nsIIOService> ios = do_GetIOService();
2805 if (ios) {
2806 ios->GetOffline(&offline);
2807 ios->GetConnectivity(&connectivity);
2809 return offline || !connectivity;
2812 namespace mozilla {
2813 namespace net {
2815 bool InScriptableRange(int64_t val) {
2816 return (val <= kJS_MAX_SAFE_INTEGER) && (val >= kJS_MIN_SAFE_INTEGER);
2819 bool InScriptableRange(uint64_t val) { return val <= kJS_MAX_SAFE_UINTEGER; }
2821 nsresult GetParameterHTTP(const nsACString &aHeaderVal, const char *aParamName,
2822 nsAString &aResult) {
2823 return nsMIMEHeaderParamImpl::GetParameterHTTP(aHeaderVal, aParamName,
2824 aResult);
2827 bool SchemeIsHTTP(nsIURI *aURI) {
2828 MOZ_ASSERT(aURI);
2829 return aURI->SchemeIs("http");
2832 bool SchemeIsHTTPS(nsIURI *aURI) {
2833 MOZ_ASSERT(aURI);
2834 return aURI->SchemeIs("https");
2837 bool SchemeIsJavascript(nsIURI *aURI) {
2838 MOZ_ASSERT(aURI);
2839 return aURI->SchemeIs("javascript");
2842 bool SchemeIsChrome(nsIURI *aURI) {
2843 MOZ_ASSERT(aURI);
2844 return aURI->SchemeIs("chrome");
2847 bool SchemeIsAbout(nsIURI *aURI) {
2848 MOZ_ASSERT(aURI);
2849 return aURI->SchemeIs("about");
2852 bool SchemeIsBlob(nsIURI *aURI) {
2853 MOZ_ASSERT(aURI);
2854 return aURI->SchemeIs("blob");
2857 bool SchemeIsFile(nsIURI *aURI) {
2858 MOZ_ASSERT(aURI);
2859 return aURI->SchemeIs("file");
2862 bool SchemeIsData(nsIURI *aURI) {
2863 MOZ_ASSERT(aURI);
2864 return aURI->SchemeIs("data");
2867 bool SchemeIsWYCIWYG(nsIURI *aURI) {
2868 MOZ_ASSERT(aURI);
2869 return aURI->SchemeIs("wyciwyg");
2872 bool SchemeIsViewSource(nsIURI *aURI) {
2873 MOZ_ASSERT(aURI);
2874 return aURI->SchemeIs("view-source");
2877 bool SchemeIsResource(nsIURI *aURI) {
2878 MOZ_ASSERT(aURI);
2879 return aURI->SchemeIs("resource");
2882 bool SchemeIsFTP(nsIURI *aURI) {
2883 MOZ_ASSERT(aURI);
2884 return aURI->SchemeIs("ftp");
2887 } // namespace net
2888 } // namespace mozilla