1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=4 sw=2 sts=2 et cin: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
9 
10 #include "nsNetUtil.h"
11 
12 #include "mozilla/Atomics.h"
13 #include "mozilla/BasePrincipal.h"
14 #include "mozilla/Components.h"
15 #include "mozilla/Encoding.h"
16 #include "mozilla/LoadContext.h"
17 #include "mozilla/LoadInfo.h"
18 #include "mozilla/Monitor.h"
19 #include "mozilla/StaticPrefs_network.h"
20 #include "mozilla/StaticPrefs_privacy.h"
21 #include "mozilla/StoragePrincipalHelper.h"
22 #include "mozilla/TaskQueue.h"
23 #include "mozilla/Telemetry.h"
24 #include "nsBufferedStreams.h"
25 #include "nsCategoryCache.h"
26 #include "nsComponentManagerUtils.h"
27 #include "nsContentUtils.h"
28 #include "nsFileStreams.h"
29 #include "nsHashKeys.h"
30 #include "nsHttp.h"
31 #include "nsMimeTypes.h"
32 #include "nsIAuthPrompt.h"
33 #include "nsIAuthPrompt2.h"
34 #include "nsIAuthPromptAdapterFactory.h"
35 #include "nsIBufferedStreams.h"
36 #include "nsBufferedStreams.h"
37 #include "nsIChannelEventSink.h"
38 #include "nsIContentSniffer.h"
39 #include "mozilla/dom/Document.h"
40 #include "nsIDownloader.h"
41 #include "nsIFileProtocolHandler.h"
42 #include "nsIFileStreams.h"
43 #include "nsIFileURL.h"
44 #include "nsIIDNService.h"
45 #include "nsIInputStreamChannel.h"
46 #include "nsIInputStreamPump.h"
47 #include "nsIInterfaceRequestorUtils.h"
48 #include "nsILoadContext.h"
49 #include "nsIMIMEHeaderParam.h"
50 #include "nsINode.h"
51 #include "nsIObjectLoadingContent.h"
52 #include "nsPersistentProperties.h"
53 #include "nsIPrivateBrowsingChannel.h"
54 #include "nsIPropertyBag2.h"
55 #include "nsIProtocolProxyService.h"
56 #include "mozilla/net/RedirectChannelRegistrar.h"
57 #include "nsRequestObserverProxy.h"
58 #include "nsISensitiveInfoHiddenURI.h"
59 #include "nsISimpleStreamListener.h"
60 #include "nsISocketProvider.h"
61 #include "nsIStandardURL.h"
62 #include "nsIStreamLoader.h"
63 #include "nsIIncrementalStreamLoader.h"
64 #include "nsStringStream.h"
65 #include "nsSyncStreamListener.h"
66 #include "nsITextToSubURI.h"
67 #include "nsIURIWithSpecialOrigin.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/nsHTTPSOnlyUtils.h"
74 #include "mozilla/dom/nsMixedContentBlocker.h"
75 #include "mozilla/dom/BlobURLProtocolHandler.h"
76 #include "mozilla/net/HttpBaseChannel.h"
77 #include "nsIScriptError.h"
78 #include "nsISiteSecurityService.h"
79 #include "nsHttpHandler.h"
80 #include "nsNSSComponent.h"
81 #include "nsIRedirectHistoryEntry.h"
82 #include "nsICertStorage.h"
83 #include "nsICertOverrideService.h"
84 #include "nsQueryObject.h"
85 #include "mozIThirdPartyUtil.h"
86 #include "../mime/nsMIMEHeaderParamImpl.h"
87 #include "nsStandardURL.h"
88 #include "DefaultURI.h"
89 #include "nsChromeProtocolHandler.h"
90 #include "nsJSProtocolHandler.h"
91 #include "nsDataHandler.h"
92 #include "mozilla/dom/BlobURLProtocolHandler.h"
93 #include "nsStreamUtils.h"
94 #include "nsSocketTransportService2.h"
95 #include "nsViewSourceHandler.h"
96 #include "nsJARURI.h"
97 #include "nsIconURI.h"
98 #include "nsAboutProtocolHandler.h"
99 #include "nsResProtocolHandler.h"
100 #include "mozilla/net/ExtensionProtocolHandler.h"
101 #include "mozilla/net/PageThumbProtocolHandler.h"
102 #include "mozilla/net/SFVService.h"
103 #include <limits>
104 
105 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
106 #  include "nsNewMailnewsURI.h"
107 #endif
108 
109 using namespace mozilla;
110 using namespace mozilla::net;
111 using mozilla::dom::BlobURLProtocolHandler;
112 using mozilla::dom::ClientInfo;
113 using mozilla::dom::PerformanceStorage;
114 using mozilla::dom::ServiceWorkerDescriptor;
115 
116 #define MAX_RECURSION_COUNT 50
117 
do_GetIOService(nsresult * error)118 already_AddRefed<nsIIOService> do_GetIOService(nsresult* error /* = 0 */) {
119   nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service();
120   if (error) *error = io ? NS_OK : NS_ERROR_FAILURE;
121   return io.forget();
122 }
123 
NS_NewLocalFileInputStream(nsIInputStream ** result,nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)124 nsresult NS_NewLocalFileInputStream(nsIInputStream** result, nsIFile* file,
125                                     int32_t ioFlags /* = -1 */,
126                                     int32_t perm /* = -1 */,
127                                     int32_t behaviorFlags /* = 0 */) {
128   nsresult rv;
129   nsCOMPtr<nsIFileInputStream> in =
130       do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
131   if (NS_SUCCEEDED(rv)) {
132     rv = in->Init(file, ioFlags, perm, behaviorFlags);
133     if (NS_SUCCEEDED(rv)) in.forget(result);
134   }
135   return rv;
136 }
137 
NS_NewLocalFileInputStream(nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)138 Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewLocalFileInputStream(
139     nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
140     int32_t behaviorFlags /* = 0 */) {
141   nsCOMPtr<nsIInputStream> stream;
142   const nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file,
143                                                  ioFlags, perm, behaviorFlags);
144   if (NS_SUCCEEDED(rv)) {
145     return stream;
146   }
147   return Err(rv);
148 }
149 
NS_NewLocalFileOutputStream(nsIOutputStream ** result,nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)150 nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file,
151                                      int32_t ioFlags /* = -1 */,
152                                      int32_t perm /* = -1 */,
153                                      int32_t behaviorFlags /* = 0 */) {
154   nsresult rv;
155   nsCOMPtr<nsIFileOutputStream> out =
156       do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
157   if (NS_SUCCEEDED(rv)) {
158     rv = out->Init(file, ioFlags, perm, behaviorFlags);
159     if (NS_SUCCEEDED(rv)) out.forget(result);
160   }
161   return rv;
162 }
163 
NS_NewLocalFileOutputStream(nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)164 Result<nsCOMPtr<nsIOutputStream>, nsresult> NS_NewLocalFileOutputStream(
165     nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
166     int32_t behaviorFlags /* = 0 */) {
167   nsCOMPtr<nsIOutputStream> stream;
168   const nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), file,
169                                                   ioFlags, perm, behaviorFlags);
170   if (NS_SUCCEEDED(rv)) {
171     return stream;
172   }
173   return Err(rv);
174 }
175 
NS_NewLocalFileOutputStream(nsIOutputStream ** result,const mozilla::ipc::FileDescriptor & fd)176 nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result,
177                                      const mozilla::ipc::FileDescriptor& fd) {
178   nsCOMPtr<nsIFileOutputStream> out;
179   nsFileOutputStream::Create(nullptr, NS_GET_IID(nsIFileOutputStream),
180                              getter_AddRefs(out));
181 
182   nsresult rv =
183       static_cast<nsFileOutputStream*>(out.get())->InitWithFileDescriptor(fd);
184   if (NS_FAILED(rv)) {
185     return rv;
186   }
187 
188   out.forget(result);
189   return NS_OK;
190 }
191 
net_EnsureIOService(nsIIOService ** ios,nsCOMPtr<nsIIOService> & grip)192 nsresult net_EnsureIOService(nsIIOService** ios, nsCOMPtr<nsIIOService>& grip) {
193   nsresult rv = NS_OK;
194   if (!*ios) {
195     grip = do_GetIOService(&rv);
196     *ios = grip;
197   }
198   return rv;
199 }
200 
NS_NewFileURI(nsIURI ** result,nsIFile * spec,nsIIOService * ioService)201 nsresult NS_NewFileURI(
202     nsIURI** result, nsIFile* spec,
203     nsIIOService*
204         ioService /* = nullptr */)  // pass in nsIIOService to optimize callers
205 {
206   nsresult rv;
207   nsCOMPtr<nsIIOService> grip;
208   rv = net_EnsureIOService(&ioService, grip);
209   if (ioService) rv = ioService->NewFileURI(spec, result);
210   return rv;
211 }
212 
NS_GetURIWithNewRef(nsIURI * aInput,const nsACString & aRef,nsIURI ** aOutput)213 nsresult NS_GetURIWithNewRef(nsIURI* aInput, const nsACString& aRef,
214                              nsIURI** aOutput) {
215   MOZ_DIAGNOSTIC_ASSERT(aRef.IsEmpty() || aRef[0] == '#');
216 
217   if (NS_WARN_IF(!aInput || !aOutput)) {
218     return NS_ERROR_INVALID_ARG;
219   }
220 
221   bool hasRef;
222   nsresult rv = aInput->GetHasRef(&hasRef);
223 
224   nsAutoCString ref;
225   if (NS_SUCCEEDED(rv)) {
226     rv = aInput->GetRef(ref);
227   }
228 
229   // If the ref is already equal to the new ref, we do not need to do anything.
230   // Also, if the GetRef failed (it could return NS_ERROR_NOT_IMPLEMENTED)
231   // we can assume SetRef would fail as well, so returning the original
232   // URI is OK.
233   //
234   // Note that aRef contains the hash, but ref doesn't, so need to account for
235   // that in the equality check.
236   if (NS_FAILED(rv) || (!hasRef && aRef.IsEmpty()) ||
237       (!aRef.IsEmpty() && hasRef &&
238        Substring(aRef.Data() + 1, aRef.Length() - 1) == ref)) {
239     nsCOMPtr<nsIURI> uri = aInput;
240     uri.forget(aOutput);
241     return NS_OK;
242   }
243 
244   return NS_MutateURI(aInput).SetRef(aRef).Finalize(aOutput);
245 }
246 
NS_GetURIWithoutRef(nsIURI * aInput,nsIURI ** aOutput)247 nsresult NS_GetURIWithoutRef(nsIURI* aInput, nsIURI** aOutput) {
248   return NS_GetURIWithNewRef(aInput, ""_ns, aOutput);
249 }
250 
NS_NewChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,nsILoadInfo * aLoadInfo,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService)251 nsresult NS_NewChannelInternal(
252     nsIChannel** outChannel, nsIURI* aUri, nsILoadInfo* aLoadInfo,
253     PerformanceStorage* aPerformanceStorage /* = nullptr */,
254     nsILoadGroup* aLoadGroup /* = nullptr */,
255     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
256     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
257     nsIIOService* aIoService /* = nullptr */) {
258   // NS_NewChannelInternal is mostly called for channel redirects. We should
259   // allow the creation of a channel even if the original channel did not have a
260   // loadinfo attached.
261   NS_ENSURE_ARG_POINTER(outChannel);
262 
263   nsCOMPtr<nsIIOService> grip;
264   nsresult rv = net_EnsureIOService(&aIoService, grip);
265   NS_ENSURE_SUCCESS(rv, rv);
266 
267   nsCOMPtr<nsIChannel> channel;
268   rv = aIoService->NewChannelFromURIWithLoadInfo(aUri, aLoadInfo,
269                                                  getter_AddRefs(channel));
270   NS_ENSURE_SUCCESS(rv, rv);
271 
272   if (aLoadGroup) {
273     rv = channel->SetLoadGroup(aLoadGroup);
274     NS_ENSURE_SUCCESS(rv, rv);
275   }
276 
277   if (aCallbacks) {
278     rv = channel->SetNotificationCallbacks(aCallbacks);
279     NS_ENSURE_SUCCESS(rv, rv);
280   }
281 
282 #ifdef DEBUG
283   nsLoadFlags channelLoadFlags = 0;
284   channel->GetLoadFlags(&channelLoadFlags);
285   // Will be removed when we remove LOAD_REPLACE altogether
286   // This check is trying to catch protocol handlers that still
287   // try to set the LOAD_REPLACE flag.
288   MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
289 #endif
290 
291   if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
292     rv = channel->SetLoadFlags(aLoadFlags);
293     NS_ENSURE_SUCCESS(rv, rv);
294   }
295 
296   if (aPerformanceStorage) {
297     nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
298     loadInfo->SetPerformanceStorage(aPerformanceStorage);
299   }
300 
301   channel.forget(outChannel);
302   return NS_OK;
303 }
304 
305 namespace {
306 
AssertLoadingPrincipalAndClientInfoMatch(nsIPrincipal * aLoadingPrincipal,const ClientInfo & aLoadingClientInfo,nsContentPolicyType aType)307 void AssertLoadingPrincipalAndClientInfoMatch(
308     nsIPrincipal* aLoadingPrincipal, const ClientInfo& aLoadingClientInfo,
309     nsContentPolicyType aType) {
310 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
311   // Verify that the provided loading ClientInfo matches the loading
312   // principal.  Unfortunately we can't just use nsIPrincipal::Equals() here
313   // because of some corner cases:
314   //
315   //  1. Worker debugger scripts want to use a system loading principal for
316   //     worker scripts with a content principal.  We exempt these from this
317   //     check.
318   //  2. Null principals currently require exact object identity for
319   //     nsIPrincipal::Equals() to return true.  This doesn't work here because
320   //     ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate
321   //     a new object.  To work around this we compare the principal origin
322   //     string itself.  If bug 1431771 is fixed then we could switch to
323   //     Equals().
324 
325   // Allow worker debugger to load with a system principal.
326   if (aLoadingPrincipal->IsSystemPrincipal() &&
327       (aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
328        aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
329        aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
330        aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS)) {
331     return;
332   }
333 
334   // Perform a fast comparison for most principal checks.
335   auto clientPrincipalOrErr(aLoadingClientInfo.GetPrincipal());
336   if (clientPrincipalOrErr.isOk()) {
337     nsCOMPtr<nsIPrincipal> clientPrincipal = clientPrincipalOrErr.unwrap();
338     if (aLoadingPrincipal->Equals(clientPrincipal)) {
339       return;
340     }
341     // Fall back to a slower origin equality test to support null principals.
342     nsAutoCString loadingOrigin;
343     MOZ_ALWAYS_SUCCEEDS(aLoadingPrincipal->GetOrigin(loadingOrigin));
344 
345     nsAutoCString clientOrigin;
346     MOZ_ALWAYS_SUCCEEDS(clientPrincipal->GetOrigin(clientOrigin));
347 
348     MOZ_DIAGNOSTIC_ASSERT(loadingOrigin == clientOrigin);
349   }
350 #endif
351 }
352 
353 }  // namespace
354 
NS_NewChannel(nsIChannel ** outChannel,nsIURI * aUri,nsIPrincipal * aLoadingPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsICookieJarSettings * aCookieJarSettings,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService,uint32_t aSandboxFlags)355 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
356                        nsIPrincipal* aLoadingPrincipal,
357                        nsSecurityFlags aSecurityFlags,
358                        nsContentPolicyType aContentPolicyType,
359                        nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
360                        PerformanceStorage* aPerformanceStorage /* = nullptr */,
361                        nsILoadGroup* aLoadGroup /* = nullptr */,
362                        nsIInterfaceRequestor* aCallbacks /* = nullptr */,
363                        nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
364                        nsIIOService* aIoService /* = nullptr */,
365                        uint32_t aSandboxFlags /* = 0 */) {
366   return NS_NewChannelInternal(
367       outChannel, aUri,
368       nullptr,  // aLoadingNode,
369       aLoadingPrincipal,
370       nullptr,  // aTriggeringPrincipal
371       Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
372       aContentPolicyType, aCookieJarSettings, aPerformanceStorage, aLoadGroup,
373       aCallbacks, aLoadFlags, aIoService, aSandboxFlags);
374 }
375 
NS_NewChannel(nsIChannel ** outChannel,nsIURI * aUri,nsIPrincipal * aLoadingPrincipal,const ClientInfo & aLoadingClientInfo,const Maybe<ServiceWorkerDescriptor> & aController,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsICookieJarSettings * aCookieJarSettings,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService,uint32_t aSandboxFlags)376 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
377                        nsIPrincipal* aLoadingPrincipal,
378                        const ClientInfo& aLoadingClientInfo,
379                        const Maybe<ServiceWorkerDescriptor>& aController,
380                        nsSecurityFlags aSecurityFlags,
381                        nsContentPolicyType aContentPolicyType,
382                        nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
383                        PerformanceStorage* aPerformanceStorage /* = nullptr */,
384                        nsILoadGroup* aLoadGroup /* = nullptr */,
385                        nsIInterfaceRequestor* aCallbacks /* = nullptr */,
386                        nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
387                        nsIIOService* aIoService /* = nullptr */,
388                        uint32_t aSandboxFlags /* = 0 */) {
389   AssertLoadingPrincipalAndClientInfoMatch(
390       aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
391 
392   Maybe<ClientInfo> loadingClientInfo;
393   loadingClientInfo.emplace(aLoadingClientInfo);
394 
395   return NS_NewChannelInternal(outChannel, aUri,
396                                nullptr,  // aLoadingNode,
397                                aLoadingPrincipal,
398                                nullptr,  // aTriggeringPrincipal
399                                loadingClientInfo, aController, aSecurityFlags,
400                                aContentPolicyType, aCookieJarSettings,
401                                aPerformanceStorage, aLoadGroup, aCallbacks,
402                                aLoadFlags, aIoService, aSandboxFlags);
403 }
404 
NS_NewChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,nsINode * aLoadingNode,nsIPrincipal * aLoadingPrincipal,nsIPrincipal * aTriggeringPrincipal,const Maybe<ClientInfo> & aLoadingClientInfo,const Maybe<ServiceWorkerDescriptor> & aController,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsICookieJarSettings * aCookieJarSettings,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService,uint32_t aSandboxFlags)405 nsresult NS_NewChannelInternal(
406     nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
407     nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
408     const Maybe<ClientInfo>& aLoadingClientInfo,
409     const Maybe<ServiceWorkerDescriptor>& aController,
410     nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
411     nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
412     PerformanceStorage* aPerformanceStorage /* = nullptr */,
413     nsILoadGroup* aLoadGroup /* = nullptr */,
414     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
415     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
416     nsIIOService* aIoService /* = nullptr */,
417     uint32_t aSandboxFlags /* = 0 */) {
418   NS_ENSURE_ARG_POINTER(outChannel);
419 
420   nsCOMPtr<nsIIOService> grip;
421   nsresult rv = net_EnsureIOService(&aIoService, grip);
422   NS_ENSURE_SUCCESS(rv, rv);
423 
424   nsCOMPtr<nsIChannel> channel;
425   rv = aIoService->NewChannelFromURIWithClientAndController(
426       aUri, aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal,
427       aLoadingClientInfo, aController, aSecurityFlags, aContentPolicyType,
428       aSandboxFlags, getter_AddRefs(channel));
429   if (NS_FAILED(rv)) {
430     return rv;
431   }
432 
433   if (aLoadGroup) {
434     rv = channel->SetLoadGroup(aLoadGroup);
435     NS_ENSURE_SUCCESS(rv, rv);
436   }
437 
438   if (aCallbacks) {
439     rv = channel->SetNotificationCallbacks(aCallbacks);
440     NS_ENSURE_SUCCESS(rv, rv);
441   }
442 
443 #ifdef DEBUG
444   nsLoadFlags channelLoadFlags = 0;
445   channel->GetLoadFlags(&channelLoadFlags);
446   // Will be removed when we remove LOAD_REPLACE altogether
447   // This check is trying to catch protocol handlers that still
448   // try to set the LOAD_REPLACE flag.
449   MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
450 #endif
451 
452   if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
453     rv = channel->SetLoadFlags(aLoadFlags);
454     NS_ENSURE_SUCCESS(rv, rv);
455   }
456 
457   if (aPerformanceStorage || aCookieJarSettings) {
458     nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
459 
460     if (aPerformanceStorage) {
461       loadInfo->SetPerformanceStorage(aPerformanceStorage);
462     }
463 
464     if (aCookieJarSettings) {
465       loadInfo->SetCookieJarSettings(aCookieJarSettings);
466     }
467   }
468 
469   channel.forget(outChannel);
470   return NS_OK;
471 }
472 
473 nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
NS_NewChannelWithTriggeringPrincipal(nsIChannel ** outChannel,nsIURI * aUri,nsINode * aLoadingNode,nsIPrincipal * aTriggeringPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService)474 NS_NewChannelWithTriggeringPrincipal(
475     nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
476     nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
477     nsContentPolicyType aContentPolicyType,
478     PerformanceStorage* aPerformanceStorage /* = nullptr */,
479     nsILoadGroup* aLoadGroup /* = nullptr */,
480     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
481     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
482     nsIIOService* aIoService /* = nullptr */) {
483   MOZ_ASSERT(aLoadingNode);
484   NS_ASSERTION(aTriggeringPrincipal,
485                "Can not create channel without a triggering Principal!");
486   return NS_NewChannelInternal(
487       outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
488       aTriggeringPrincipal, Maybe<ClientInfo>(),
489       Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
490       aLoadingNode->OwnerDoc()->CookieJarSettings(), aPerformanceStorage,
491       aLoadGroup, aCallbacks, aLoadFlags, aIoService);
492 }
493 
494 // See NS_NewChannelInternal for usage and argument description
NS_NewChannelWithTriggeringPrincipal(nsIChannel ** outChannel,nsIURI * aUri,nsIPrincipal * aLoadingPrincipal,nsIPrincipal * aTriggeringPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsICookieJarSettings * aCookieJarSettings,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService)495 nsresult NS_NewChannelWithTriggeringPrincipal(
496     nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
497     nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
498     nsContentPolicyType aContentPolicyType,
499     nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
500     PerformanceStorage* aPerformanceStorage /* = nullptr */,
501     nsILoadGroup* aLoadGroup /* = nullptr */,
502     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
503     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
504     nsIIOService* aIoService /* = nullptr */) {
505   NS_ASSERTION(aLoadingPrincipal,
506                "Can not create channel without a loading Principal!");
507   return NS_NewChannelInternal(
508       outChannel, aUri,
509       nullptr,  // aLoadingNode
510       aLoadingPrincipal, aTriggeringPrincipal, Maybe<ClientInfo>(),
511       Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
512       aCookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks,
513       aLoadFlags, aIoService);
514 }
515 
516 // See NS_NewChannelInternal for usage and argument description
NS_NewChannelWithTriggeringPrincipal(nsIChannel ** outChannel,nsIURI * aUri,nsIPrincipal * aLoadingPrincipal,nsIPrincipal * aTriggeringPrincipal,const ClientInfo & aLoadingClientInfo,const Maybe<ServiceWorkerDescriptor> & aController,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsICookieJarSettings * aCookieJarSettings,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService)517 nsresult NS_NewChannelWithTriggeringPrincipal(
518     nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
519     nsIPrincipal* aTriggeringPrincipal, const ClientInfo& aLoadingClientInfo,
520     const Maybe<ServiceWorkerDescriptor>& aController,
521     nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
522     nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
523     PerformanceStorage* aPerformanceStorage /* = nullptr */,
524     nsILoadGroup* aLoadGroup /* = nullptr */,
525     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
526     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
527     nsIIOService* aIoService /* = nullptr */) {
528   AssertLoadingPrincipalAndClientInfoMatch(
529       aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
530 
531   Maybe<ClientInfo> loadingClientInfo;
532   loadingClientInfo.emplace(aLoadingClientInfo);
533 
534   return NS_NewChannelInternal(
535       outChannel, aUri,
536       nullptr,  // aLoadingNode
537       aLoadingPrincipal, aTriggeringPrincipal, loadingClientInfo, aController,
538       aSecurityFlags, aContentPolicyType, aCookieJarSettings,
539       aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService);
540 }
541 
NS_NewChannel(nsIChannel ** outChannel,nsIURI * aUri,nsINode * aLoadingNode,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,PerformanceStorage * aPerformanceStorage,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags,nsIIOService * aIoService,uint32_t aSandboxFlags)542 nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
543                        nsINode* aLoadingNode, nsSecurityFlags aSecurityFlags,
544                        nsContentPolicyType aContentPolicyType,
545                        PerformanceStorage* aPerformanceStorage /* = nullptr */,
546                        nsILoadGroup* aLoadGroup /* = nullptr */,
547                        nsIInterfaceRequestor* aCallbacks /* = nullptr */,
548                        nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
549                        nsIIOService* aIoService /* = nullptr */,
550                        uint32_t aSandboxFlags /* = 0 */) {
551   NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!");
552   return NS_NewChannelInternal(
553       outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
554       nullptr,  // aTriggeringPrincipal
555       Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
556       aContentPolicyType, aLoadingNode->OwnerDoc()->CookieJarSettings(),
557       aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService,
558       aSandboxFlags);
559 }
560 
NS_GetIsDocumentChannel(nsIChannel * aChannel,bool * aIsDocument)561 nsresult NS_GetIsDocumentChannel(nsIChannel* aChannel, bool* aIsDocument) {
562   // Check if this channel is going to be used to create a document. If it has
563   // LOAD_DOCUMENT_URI set it is trivially creating a document. If
564   // LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a
565   // document, depending on its MIME type.
566 
567   if (!aChannel || !aIsDocument) {
568     return NS_ERROR_NULL_POINTER;
569   }
570   *aIsDocument = false;
571   nsLoadFlags loadFlags;
572   nsresult rv = aChannel->GetLoadFlags(&loadFlags);
573   if (NS_FAILED(rv)) {
574     return rv;
575   }
576   if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
577     *aIsDocument = true;
578     return NS_OK;
579   }
580   if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) {
581     *aIsDocument = false;
582     return NS_OK;
583   }
584   nsAutoCString mimeType;
585   rv = aChannel->GetContentType(mimeType);
586   if (NS_FAILED(rv)) {
587     return rv;
588   }
589   if (nsContentUtils::HtmlObjectContentTypeForMIMEType(
590           mimeType, false, nullptr) == nsIObjectLoadingContent::TYPE_DOCUMENT) {
591     *aIsDocument = true;
592     return NS_OK;
593   }
594   *aIsDocument = false;
595   return NS_OK;
596 }
597 
NS_MakeAbsoluteURI(nsACString & result,const nsACString & spec,nsIURI * baseURI)598 nsresult NS_MakeAbsoluteURI(nsACString& result, const nsACString& spec,
599                             nsIURI* baseURI) {
600   nsresult rv;
601   if (!baseURI) {
602     NS_WARNING("It doesn't make sense to not supply a base URI");
603     result = spec;
604     rv = NS_OK;
605   } else if (spec.IsEmpty()) {
606     rv = baseURI->GetSpec(result);
607   } else {
608     rv = baseURI->Resolve(spec, result);
609   }
610   return rv;
611 }
612 
NS_MakeAbsoluteURI(char ** result,const char * spec,nsIURI * baseURI)613 nsresult NS_MakeAbsoluteURI(char** result, const char* spec, nsIURI* baseURI) {
614   nsresult rv;
615   nsAutoCString resultBuf;
616   rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
617   if (NS_SUCCEEDED(rv)) {
618     *result = ToNewCString(resultBuf, mozilla::fallible);
619     if (!*result) rv = NS_ERROR_OUT_OF_MEMORY;
620   }
621   return rv;
622 }
623 
NS_MakeAbsoluteURI(nsAString & result,const nsAString & spec,nsIURI * baseURI)624 nsresult NS_MakeAbsoluteURI(nsAString& result, const nsAString& spec,
625                             nsIURI* baseURI) {
626   nsresult rv;
627   if (!baseURI) {
628     NS_WARNING("It doesn't make sense to not supply a base URI");
629     result = spec;
630     rv = NS_OK;
631   } else {
632     nsAutoCString resultBuf;
633     if (spec.IsEmpty()) {
634       rv = baseURI->GetSpec(resultBuf);
635     } else {
636       rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
637     }
638     if (NS_SUCCEEDED(rv)) CopyUTF8toUTF16(resultBuf, result);
639   }
640   return rv;
641 }
642 
NS_GetDefaultPort(const char * scheme,nsIIOService * ioService)643 int32_t NS_GetDefaultPort(const char* scheme,
644                           nsIIOService* ioService /* = nullptr */) {
645   nsresult rv;
646 
647   // Getting the default port through the protocol handler has a lot of XPCOM
648   // overhead involved.  We optimize the protocols that matter for Web pages
649   // (HTTP and HTTPS) by hardcoding their default ports here.
650   if (strncmp(scheme, "http", 4) == 0) {
651     if (scheme[4] == 's' && scheme[5] == '\0') {
652       return 443;
653     }
654     if (scheme[4] == '\0') {
655       return 80;
656     }
657   }
658 
659   nsCOMPtr<nsIIOService> grip;
660   net_EnsureIOService(&ioService, grip);
661   if (!ioService) return -1;
662 
663   nsCOMPtr<nsIProtocolHandler> handler;
664   rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
665   if (NS_FAILED(rv)) return -1;
666   int32_t port;
667   rv = handler->GetDefaultPort(&port);
668   return NS_SUCCEEDED(rv) ? port : -1;
669 }
670 
671 /**
672  * This function is a helper function to apply the ToAscii conversion
673  * to a string
674  */
NS_StringToACE(const nsACString & idn,nsACString & result)675 bool NS_StringToACE(const nsACString& idn, nsACString& result) {
676   nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
677   if (!idnSrv) return false;
678   nsresult rv = idnSrv->ConvertUTF8toACE(idn, result);
679   return NS_SUCCEEDED(rv);
680 }
681 
NS_GetRealPort(nsIURI * aURI)682 int32_t NS_GetRealPort(nsIURI* aURI) {
683   int32_t port;
684   nsresult rv = aURI->GetPort(&port);
685   if (NS_FAILED(rv)) return -1;
686 
687   if (port != -1) return port;  // explicitly specified
688 
689   // Otherwise, we have to get the default port from the protocol handler
690 
691   // Need the scheme first
692   nsAutoCString scheme;
693   rv = aURI->GetScheme(scheme);
694   if (NS_FAILED(rv)) return -1;
695 
696   return NS_GetDefaultPort(scheme.get());
697 }
698 
NS_NewInputStreamChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,already_AddRefed<nsIInputStream> aStream,const nsACString & aContentType,const nsACString & aContentCharset,nsILoadInfo * aLoadInfo)699 nsresult NS_NewInputStreamChannelInternal(
700     nsIChannel** outChannel, nsIURI* aUri,
701     already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
702     const nsACString& aContentCharset, nsILoadInfo* aLoadInfo) {
703   nsresult rv;
704   nsCOMPtr<nsIInputStreamChannel> isc =
705       do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
706   NS_ENSURE_SUCCESS(rv, rv);
707   rv = isc->SetURI(aUri);
708   NS_ENSURE_SUCCESS(rv, rv);
709 
710   nsCOMPtr<nsIInputStream> stream = std::move(aStream);
711   rv = isc->SetContentStream(stream);
712   NS_ENSURE_SUCCESS(rv, rv);
713 
714   nsCOMPtr<nsIChannel> channel = do_QueryInterface(isc, &rv);
715   NS_ENSURE_SUCCESS(rv, rv);
716 
717   if (!aContentType.IsEmpty()) {
718     rv = channel->SetContentType(aContentType);
719     NS_ENSURE_SUCCESS(rv, rv);
720   }
721 
722   if (!aContentCharset.IsEmpty()) {
723     rv = channel->SetContentCharset(aContentCharset);
724     NS_ENSURE_SUCCESS(rv, rv);
725   }
726 
727   MOZ_ASSERT(aLoadInfo, "need a loadinfo to create a inputstreamchannel");
728   channel->SetLoadInfo(aLoadInfo);
729 
730   // If we're sandboxed, make sure to clear any owner the channel
731   // might already have.
732   if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) {
733     channel->SetOwner(nullptr);
734   }
735 
736   channel.forget(outChannel);
737   return NS_OK;
738 }
739 
NS_NewInputStreamChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,already_AddRefed<nsIInputStream> aStream,const nsACString & aContentType,const nsACString & aContentCharset,nsINode * aLoadingNode,nsIPrincipal * aLoadingPrincipal,nsIPrincipal * aTriggeringPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType)740 nsresult NS_NewInputStreamChannelInternal(
741     nsIChannel** outChannel, nsIURI* aUri,
742     already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
743     const nsACString& aContentCharset, nsINode* aLoadingNode,
744     nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
745     nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType) {
746   nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
747       aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
748       aContentPolicyType);
749   if (!loadInfo) {
750     return NS_ERROR_UNEXPECTED;
751   }
752 
753   nsCOMPtr<nsIInputStream> stream = std::move(aStream);
754 
755   return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
756                                           aContentType, aContentCharset,
757                                           loadInfo);
758 }
759 
NS_NewInputStreamChannel(nsIChannel ** outChannel,nsIURI * aUri,already_AddRefed<nsIInputStream> aStream,nsIPrincipal * aLoadingPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,const nsACString & aContentType,const nsACString & aContentCharset)760 nsresult NS_NewInputStreamChannel(
761     nsIChannel** outChannel, nsIURI* aUri,
762     already_AddRefed<nsIInputStream> aStream, nsIPrincipal* aLoadingPrincipal,
763     nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
764     const nsACString& aContentType /* = ""_ns */,
765     const nsACString& aContentCharset /* = ""_ns */) {
766   nsCOMPtr<nsIInputStream> stream = aStream;
767   return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
768                                           aContentType, aContentCharset,
769                                           nullptr,  // aLoadingNode
770                                           aLoadingPrincipal,
771                                           nullptr,  // aTriggeringPrincipal
772                                           aSecurityFlags, aContentPolicyType);
773 }
774 
NS_NewInputStreamChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,const nsAString & aData,const nsACString & aContentType,nsILoadInfo * aLoadInfo,bool aIsSrcdocChannel)775 nsresult NS_NewInputStreamChannelInternal(nsIChannel** outChannel, nsIURI* aUri,
776                                           const nsAString& aData,
777                                           const nsACString& aContentType,
778                                           nsILoadInfo* aLoadInfo,
779                                           bool aIsSrcdocChannel /* = false */) {
780   nsresult rv;
781   nsCOMPtr<nsIStringInputStream> stream;
782   stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
783   NS_ENSURE_SUCCESS(rv, rv);
784 
785   uint32_t len;
786   char* utf8Bytes = ToNewUTF8String(aData, &len);
787   rv = stream->AdoptData(utf8Bytes, len);
788 
789   nsCOMPtr<nsIChannel> channel;
790   rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aUri,
791                                         stream.forget(), aContentType,
792                                         "UTF-8"_ns, aLoadInfo);
793 
794   NS_ENSURE_SUCCESS(rv, rv);
795 
796   if (aIsSrcdocChannel) {
797     nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(channel);
798     NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
799     inStrmChan->SetSrcdocData(aData);
800   }
801   channel.forget(outChannel);
802   return NS_OK;
803 }
804 
NS_NewInputStreamChannelInternal(nsIChannel ** outChannel,nsIURI * aUri,const nsAString & aData,const nsACString & aContentType,nsINode * aLoadingNode,nsIPrincipal * aLoadingPrincipal,nsIPrincipal * aTriggeringPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,bool aIsSrcdocChannel)805 nsresult NS_NewInputStreamChannelInternal(
806     nsIChannel** outChannel, nsIURI* aUri, const nsAString& aData,
807     const nsACString& aContentType, nsINode* aLoadingNode,
808     nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
809     nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
810     bool aIsSrcdocChannel /* = false */) {
811   nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
812       aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
813       aContentPolicyType);
814   return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
815                                           loadInfo, aIsSrcdocChannel);
816 }
817 
NS_NewInputStreamChannel(nsIChannel ** outChannel,nsIURI * aUri,const nsAString & aData,const nsACString & aContentType,nsIPrincipal * aLoadingPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,bool aIsSrcdocChannel)818 nsresult NS_NewInputStreamChannel(nsIChannel** outChannel, nsIURI* aUri,
819                                   const nsAString& aData,
820                                   const nsACString& aContentType,
821                                   nsIPrincipal* aLoadingPrincipal,
822                                   nsSecurityFlags aSecurityFlags,
823                                   nsContentPolicyType aContentPolicyType,
824                                   bool aIsSrcdocChannel /* = false */) {
825   return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
826                                           nullptr,  // aLoadingNode
827                                           aLoadingPrincipal,
828                                           nullptr,  // aTriggeringPrincipal
829                                           aSecurityFlags, aContentPolicyType,
830                                           aIsSrcdocChannel);
831 }
832 
NS_NewInputStreamPump(nsIInputStreamPump ** aResult,already_AddRefed<nsIInputStream> aStream,uint32_t aSegsize,uint32_t aSegcount,bool aCloseWhenDone,nsIEventTarget * aMainThreadTarget)833 nsresult NS_NewInputStreamPump(
834     nsIInputStreamPump** aResult, already_AddRefed<nsIInputStream> aStream,
835     uint32_t aSegsize /* = 0 */, uint32_t aSegcount /* = 0 */,
836     bool aCloseWhenDone /* = false */,
837     nsIEventTarget* aMainThreadTarget /* = nullptr */) {
838   nsCOMPtr<nsIInputStream> stream = std::move(aStream);
839 
840   nsresult rv;
841   nsCOMPtr<nsIInputStreamPump> pump =
842       do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
843   if (NS_SUCCEEDED(rv)) {
844     rv = pump->Init(stream, aSegsize, aSegcount, aCloseWhenDone,
845                     aMainThreadTarget);
846     if (NS_SUCCEEDED(rv)) {
847       *aResult = nullptr;
848       pump.swap(*aResult);
849     }
850   }
851   return rv;
852 }
853 
NS_NewLoadGroup(nsILoadGroup ** result,nsIRequestObserver * obs)854 nsresult NS_NewLoadGroup(nsILoadGroup** result, nsIRequestObserver* obs) {
855   nsresult rv;
856   nsCOMPtr<nsILoadGroup> group =
857       do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
858   if (NS_SUCCEEDED(rv)) {
859     rv = group->SetGroupObserver(obs);
860     if (NS_SUCCEEDED(rv)) {
861       *result = nullptr;
862       group.swap(*result);
863     }
864   }
865   return rv;
866 }
867 
NS_IsReasonableHTTPHeaderValue(const nsACString & aValue)868 bool NS_IsReasonableHTTPHeaderValue(const nsACString& aValue) {
869   return mozilla::net::nsHttp::IsReasonableHeaderValue(aValue);
870 }
871 
NS_IsValidHTTPToken(const nsACString & aToken)872 bool NS_IsValidHTTPToken(const nsACString& aToken) {
873   return mozilla::net::nsHttp::IsValidToken(aToken);
874 }
875 
NS_TrimHTTPWhitespace(const nsACString & aSource,nsACString & aDest)876 void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) {
877   mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest);
878 }
879 
NS_NewLoadGroup(nsILoadGroup ** aResult,nsIPrincipal * aPrincipal)880 nsresult NS_NewLoadGroup(nsILoadGroup** aResult, nsIPrincipal* aPrincipal) {
881   using mozilla::LoadContext;
882   nsresult rv;
883 
884   nsCOMPtr<nsILoadGroup> group =
885       do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
886   NS_ENSURE_SUCCESS(rv, rv);
887 
888   RefPtr<LoadContext> loadContext = new LoadContext(aPrincipal);
889   rv = group->SetNotificationCallbacks(loadContext);
890   NS_ENSURE_SUCCESS(rv, rv);
891 
892   group.forget(aResult);
893   return rv;
894 }
895 
NS_LoadGroupMatchesPrincipal(nsILoadGroup * aLoadGroup,nsIPrincipal * aPrincipal)896 bool NS_LoadGroupMatchesPrincipal(nsILoadGroup* aLoadGroup,
897                                   nsIPrincipal* aPrincipal) {
898   if (!aPrincipal) {
899     return false;
900   }
901 
902   // If this is a null principal then the load group doesn't really matter.
903   // The principal will not be allowed to perform any actions that actually
904   // use the load group.  Unconditionally treat null principals as a match.
905   if (aPrincipal->GetIsNullPrincipal()) {
906     return true;
907   }
908 
909   if (!aLoadGroup) {
910     return false;
911   }
912 
913   nsCOMPtr<nsILoadContext> loadContext;
914   NS_QueryNotificationCallbacks(nullptr, aLoadGroup, NS_GET_IID(nsILoadContext),
915                                 getter_AddRefs(loadContext));
916   NS_ENSURE_TRUE(loadContext, false);
917 
918   return true;
919 }
920 
NS_NewDownloader(nsIStreamListener ** result,nsIDownloadObserver * observer,nsIFile * downloadLocation)921 nsresult NS_NewDownloader(nsIStreamListener** result,
922                           nsIDownloadObserver* observer,
923                           nsIFile* downloadLocation /* = nullptr */) {
924   nsresult rv;
925   nsCOMPtr<nsIDownloader> downloader =
926       do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
927   if (NS_SUCCEEDED(rv)) {
928     rv = downloader->Init(observer, downloadLocation);
929     if (NS_SUCCEEDED(rv)) {
930       downloader.forget(result);
931     }
932   }
933   return rv;
934 }
935 
NS_NewIncrementalStreamLoader(nsIIncrementalStreamLoader ** result,nsIIncrementalStreamLoaderObserver * observer)936 nsresult NS_NewIncrementalStreamLoader(
937     nsIIncrementalStreamLoader** result,
938     nsIIncrementalStreamLoaderObserver* observer) {
939   nsresult rv;
940   nsCOMPtr<nsIIncrementalStreamLoader> loader =
941       do_CreateInstance(NS_INCREMENTALSTREAMLOADER_CONTRACTID, &rv);
942   if (NS_SUCCEEDED(rv)) {
943     rv = loader->Init(observer);
944     if (NS_SUCCEEDED(rv)) {
945       *result = nullptr;
946       loader.swap(*result);
947     }
948   }
949   return rv;
950 }
951 
NS_NewStreamLoader(nsIStreamLoader ** result,nsIStreamLoaderObserver * observer,nsIRequestObserver * requestObserver)952 nsresult NS_NewStreamLoader(
953     nsIStreamLoader** result, nsIStreamLoaderObserver* observer,
954     nsIRequestObserver* requestObserver /* = nullptr */) {
955   nsresult rv;
956   nsCOMPtr<nsIStreamLoader> loader =
957       do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
958   if (NS_SUCCEEDED(rv)) {
959     rv = loader->Init(observer, requestObserver);
960     if (NS_SUCCEEDED(rv)) {
961       *result = nullptr;
962       loader.swap(*result);
963     }
964   }
965   return rv;
966 }
967 
NS_NewStreamLoaderInternal(nsIStreamLoader ** outStream,nsIURI * aUri,nsIStreamLoaderObserver * aObserver,nsINode * aLoadingNode,nsIPrincipal * aLoadingPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags)968 nsresult NS_NewStreamLoaderInternal(
969     nsIStreamLoader** outStream, nsIURI* aUri,
970     nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
971     nsIPrincipal* aLoadingPrincipal, nsSecurityFlags aSecurityFlags,
972     nsContentPolicyType aContentPolicyType,
973     nsILoadGroup* aLoadGroup /* = nullptr */,
974     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
975     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
976   nsCOMPtr<nsIChannel> channel;
977   nsresult rv = NS_NewChannelInternal(
978       getter_AddRefs(channel), aUri, aLoadingNode, aLoadingPrincipal,
979       nullptr,  // aTriggeringPrincipal
980       Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
981       aContentPolicyType,
982       nullptr,  // nsICookieJarSettings
983       nullptr,  // PerformanceStorage
984       aLoadGroup, aCallbacks, aLoadFlags);
985 
986   NS_ENSURE_SUCCESS(rv, rv);
987   rv = NS_NewStreamLoader(outStream, aObserver);
988   NS_ENSURE_SUCCESS(rv, rv);
989   return channel->AsyncOpen(*outStream);
990 }
991 
NS_NewStreamLoader(nsIStreamLoader ** outStream,nsIURI * aUri,nsIStreamLoaderObserver * aObserver,nsINode * aLoadingNode,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags)992 nsresult NS_NewStreamLoader(
993     nsIStreamLoader** outStream, nsIURI* aUri,
994     nsIStreamLoaderObserver* aObserver, nsINode* aLoadingNode,
995     nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
996     nsILoadGroup* aLoadGroup /* = nullptr */,
997     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
998     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
999   NS_ASSERTION(aLoadingNode,
1000                "Can not create stream loader without a loading Node!");
1001   return NS_NewStreamLoaderInternal(
1002       outStream, aUri, aObserver, aLoadingNode, aLoadingNode->NodePrincipal(),
1003       aSecurityFlags, aContentPolicyType, aLoadGroup, aCallbacks, aLoadFlags);
1004 }
1005 
NS_NewStreamLoader(nsIStreamLoader ** outStream,nsIURI * aUri,nsIStreamLoaderObserver * aObserver,nsIPrincipal * aLoadingPrincipal,nsSecurityFlags aSecurityFlags,nsContentPolicyType aContentPolicyType,nsILoadGroup * aLoadGroup,nsIInterfaceRequestor * aCallbacks,nsLoadFlags aLoadFlags)1006 nsresult NS_NewStreamLoader(
1007     nsIStreamLoader** outStream, nsIURI* aUri,
1008     nsIStreamLoaderObserver* aObserver, nsIPrincipal* aLoadingPrincipal,
1009     nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
1010     nsILoadGroup* aLoadGroup /* = nullptr */,
1011     nsIInterfaceRequestor* aCallbacks /* = nullptr */,
1012     nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */) {
1013   return NS_NewStreamLoaderInternal(outStream, aUri, aObserver,
1014                                     nullptr,  // aLoadingNode
1015                                     aLoadingPrincipal, aSecurityFlags,
1016                                     aContentPolicyType, aLoadGroup, aCallbacks,
1017                                     aLoadFlags);
1018 }
1019 
NS_NewSyncStreamListener(nsIStreamListener ** result,nsIInputStream ** stream)1020 nsresult NS_NewSyncStreamListener(nsIStreamListener** result,
1021                                   nsIInputStream** stream) {
1022   nsCOMPtr<nsISyncStreamListener> listener = nsSyncStreamListener::Create();
1023   if (listener) {
1024     nsresult rv = listener->GetInputStream(stream);
1025     if (NS_SUCCEEDED(rv)) {
1026       listener.forget(result);
1027     }
1028     return rv;
1029   }
1030   return NS_ERROR_FAILURE;
1031 }
1032 
NS_ImplementChannelOpen(nsIChannel * channel,nsIInputStream ** result)1033 nsresult NS_ImplementChannelOpen(nsIChannel* channel, nsIInputStream** result) {
1034   nsCOMPtr<nsIStreamListener> listener;
1035   nsCOMPtr<nsIInputStream> stream;
1036   nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
1037                                          getter_AddRefs(stream));
1038   NS_ENSURE_SUCCESS(rv, rv);
1039 
1040   rv = NS_MaybeOpenChannelUsingAsyncOpen(channel, listener);
1041   NS_ENSURE_SUCCESS(rv, rv);
1042 
1043   uint64_t n;
1044   // block until the initial response is received or an error occurs.
1045   rv = stream->Available(&n);
1046   NS_ENSURE_SUCCESS(rv, rv);
1047 
1048   *result = nullptr;
1049   stream.swap(*result);
1050 
1051   return NS_OK;
1052 }
1053 
NS_NewRequestObserverProxy(nsIRequestObserver ** result,nsIRequestObserver * observer,nsISupports * context)1054 nsresult NS_NewRequestObserverProxy(nsIRequestObserver** result,
1055                                     nsIRequestObserver* observer,
1056                                     nsISupports* context) {
1057   nsCOMPtr<nsIRequestObserverProxy> proxy = new nsRequestObserverProxy();
1058   nsresult rv = proxy->Init(observer, context);
1059   if (NS_SUCCEEDED(rv)) {
1060     proxy.forget(result);
1061   }
1062   return rv;
1063 }
1064 
NS_NewSimpleStreamListener(nsIStreamListener ** result,nsIOutputStream * sink,nsIRequestObserver * observer)1065 nsresult NS_NewSimpleStreamListener(
1066     nsIStreamListener** result, nsIOutputStream* sink,
1067     nsIRequestObserver* observer /* = nullptr */) {
1068   nsresult rv;
1069   nsCOMPtr<nsISimpleStreamListener> listener =
1070       do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
1071   if (NS_SUCCEEDED(rv)) {
1072     rv = listener->Init(sink, observer);
1073     if (NS_SUCCEEDED(rv)) {
1074       listener.forget(result);
1075     }
1076   }
1077   return rv;
1078 }
1079 
NS_CheckPortSafety(int32_t port,const char * scheme,nsIIOService * ioService)1080 nsresult NS_CheckPortSafety(int32_t port, const char* scheme,
1081                             nsIIOService* ioService /* = nullptr */) {
1082   nsresult rv;
1083   nsCOMPtr<nsIIOService> grip;
1084   rv = net_EnsureIOService(&ioService, grip);
1085   if (ioService) {
1086     bool allow;
1087     rv = ioService->AllowPort(port, scheme, &allow);
1088     if (NS_SUCCEEDED(rv) && !allow) {
1089       NS_WARNING("port blocked");
1090       rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
1091     }
1092   }
1093   return rv;
1094 }
1095 
NS_CheckPortSafety(nsIURI * uri)1096 nsresult NS_CheckPortSafety(nsIURI* uri) {
1097   int32_t port;
1098   nsresult rv = uri->GetPort(&port);
1099   if (NS_FAILED(rv) || port == -1) {  // port undefined or default-valued
1100     return NS_OK;
1101   }
1102   nsAutoCString scheme;
1103   uri->GetScheme(scheme);
1104   return NS_CheckPortSafety(port, scheme.get());
1105 }
1106 
NS_NewProxyInfo(const nsACString & type,const nsACString & host,int32_t port,uint32_t flags,nsIProxyInfo ** result)1107 nsresult NS_NewProxyInfo(const nsACString& type, const nsACString& host,
1108                          int32_t port, uint32_t flags, nsIProxyInfo** result) {
1109   nsresult rv;
1110   nsCOMPtr<nsIProtocolProxyService> pps =
1111       do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
1112   if (NS_SUCCEEDED(rv)) {
1113     rv = pps->NewProxyInfo(type, host, port, ""_ns, ""_ns, flags, UINT32_MAX,
1114                            nullptr, result);
1115   }
1116   return rv;
1117 }
1118 
NS_GetFileProtocolHandler(nsIFileProtocolHandler ** result,nsIIOService * ioService)1119 nsresult NS_GetFileProtocolHandler(nsIFileProtocolHandler** result,
1120                                    nsIIOService* ioService /* = nullptr */) {
1121   nsresult rv;
1122   nsCOMPtr<nsIIOService> grip;
1123   rv = net_EnsureIOService(&ioService, grip);
1124   if (ioService) {
1125     nsCOMPtr<nsIProtocolHandler> handler;
1126     rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
1127     if (NS_SUCCEEDED(rv)) rv = CallQueryInterface(handler, result);
1128   }
1129   return rv;
1130 }
1131 
NS_GetFileFromURLSpec(const nsACString & inURL,nsIFile ** result,nsIIOService * ioService)1132 nsresult NS_GetFileFromURLSpec(const nsACString& inURL, nsIFile** result,
1133                                nsIIOService* ioService /* = nullptr */) {
1134   nsresult rv;
1135   nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1136   rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1137   if (NS_SUCCEEDED(rv)) rv = fileHandler->GetFileFromURLSpec(inURL, result);
1138   return rv;
1139 }
1140 
NS_GetURLSpecFromFile(nsIFile * file,nsACString & url,nsIIOService * ioService)1141 nsresult NS_GetURLSpecFromFile(nsIFile* file, nsACString& url,
1142                                nsIIOService* ioService /* = nullptr */) {
1143   nsresult rv;
1144   nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1145   rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1146   if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromFile(file, url);
1147   return rv;
1148 }
1149 
NS_GetURLSpecFromActualFile(nsIFile * file,nsACString & url,nsIIOService * ioService)1150 nsresult NS_GetURLSpecFromActualFile(nsIFile* file, nsACString& url,
1151                                      nsIIOService* ioService /* = nullptr */) {
1152   nsresult rv;
1153   nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1154   rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1155   if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromActualFile(file, url);
1156   return rv;
1157 }
1158 
NS_GetURLSpecFromDir(nsIFile * file,nsACString & url,nsIIOService * ioService)1159 nsresult NS_GetURLSpecFromDir(nsIFile* file, nsACString& url,
1160                               nsIIOService* ioService /* = nullptr */) {
1161   nsresult rv;
1162   nsCOMPtr<nsIFileProtocolHandler> fileHandler;
1163   rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
1164   if (NS_SUCCEEDED(rv)) rv = fileHandler->GetURLSpecFromDir(file, url);
1165   return rv;
1166 }
1167 
NS_GetReferrerFromChannel(nsIChannel * channel,nsIURI ** referrer)1168 void NS_GetReferrerFromChannel(nsIChannel* channel, nsIURI** referrer) {
1169   *referrer = nullptr;
1170 
1171   if (nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(channel)) {
1172     // We have to check for a property on a property bag because the
1173     // referrer may be empty for security reasons (for example, when loading
1174     // an http page with an https referrer).
1175     nsresult rv;
1176     nsCOMPtr<nsIURI> uri(
1177         do_GetProperty(props, u"docshell.internalReferrer"_ns, &rv));
1178     if (NS_SUCCEEDED(rv)) {
1179       uri.forget(referrer);
1180       return;
1181     }
1182   }
1183 
1184   // if that didn't work, we can still try to get the referrer from the
1185   // nsIHttpChannel (if we can QI to it)
1186   nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
1187   if (!chan) {
1188     return;
1189   }
1190 
1191   nsCOMPtr<nsIReferrerInfo> referrerInfo = chan->GetReferrerInfo();
1192   if (!referrerInfo) {
1193     return;
1194   }
1195 
1196   referrerInfo->GetOriginalReferrer(referrer);
1197 }
1198 
do_GetNetUtil(nsresult * error)1199 already_AddRefed<nsINetUtil> do_GetNetUtil(nsresult* error /* = 0 */) {
1200   nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service();
1201   nsCOMPtr<nsINetUtil> util;
1202   if (io) util = do_QueryInterface(io);
1203 
1204   if (error) *error = !!util ? NS_OK : NS_ERROR_FAILURE;
1205   return util.forget();
1206 }
1207 
NS_ParseRequestContentType(const nsACString & rawContentType,nsCString & contentType,nsCString & contentCharset)1208 nsresult NS_ParseRequestContentType(const nsACString& rawContentType,
1209                                     nsCString& contentType,
1210                                     nsCString& contentCharset) {
1211   // contentCharset is left untouched if not present in rawContentType
1212   nsresult rv;
1213   nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1214   NS_ENSURE_SUCCESS(rv, rv);
1215   nsCString charset;
1216   bool hadCharset;
1217   rv = util->ParseRequestContentType(rawContentType, charset, &hadCharset,
1218                                      contentType);
1219   if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
1220   return rv;
1221 }
1222 
NS_ParseResponseContentType(const nsACString & rawContentType,nsCString & contentType,nsCString & contentCharset)1223 nsresult NS_ParseResponseContentType(const nsACString& rawContentType,
1224                                      nsCString& contentType,
1225                                      nsCString& contentCharset) {
1226   // contentCharset is left untouched if not present in rawContentType
1227   nsresult rv;
1228   nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1229   NS_ENSURE_SUCCESS(rv, rv);
1230   nsCString charset;
1231   bool hadCharset;
1232   rv = util->ParseResponseContentType(rawContentType, charset, &hadCharset,
1233                                       contentType);
1234   if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset;
1235   return rv;
1236 }
1237 
NS_ExtractCharsetFromContentType(const nsACString & rawContentType,nsCString & contentCharset,bool * hadCharset,int32_t * charsetStart,int32_t * charsetEnd)1238 nsresult NS_ExtractCharsetFromContentType(const nsACString& rawContentType,
1239                                           nsCString& contentCharset,
1240                                           bool* hadCharset,
1241                                           int32_t* charsetStart,
1242                                           int32_t* charsetEnd) {
1243   // contentCharset is left untouched if not present in rawContentType
1244   nsresult rv;
1245   nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
1246   NS_ENSURE_SUCCESS(rv, rv);
1247 
1248   return util->ExtractCharsetFromContentType(
1249       rawContentType, contentCharset, charsetStart, charsetEnd, hadCharset);
1250 }
1251 
NS_NewAtomicFileOutputStream(nsIOutputStream ** result,nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)1252 nsresult NS_NewAtomicFileOutputStream(nsIOutputStream** result, nsIFile* file,
1253                                       int32_t ioFlags /* = -1 */,
1254                                       int32_t perm /* = -1 */,
1255                                       int32_t behaviorFlags /* = 0 */) {
1256   nsresult rv;
1257   nsCOMPtr<nsIFileOutputStream> out =
1258       do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1259   if (NS_SUCCEEDED(rv)) {
1260     rv = out->Init(file, ioFlags, perm, behaviorFlags);
1261     if (NS_SUCCEEDED(rv)) out.forget(result);
1262   }
1263   return rv;
1264 }
1265 
NS_NewSafeLocalFileOutputStream(nsIOutputStream ** result,nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)1266 nsresult NS_NewSafeLocalFileOutputStream(nsIOutputStream** result,
1267                                          nsIFile* file,
1268                                          int32_t ioFlags /* = -1 */,
1269                                          int32_t perm /* = -1 */,
1270                                          int32_t behaviorFlags /* = 0 */) {
1271   nsresult rv;
1272   nsCOMPtr<nsIFileOutputStream> out =
1273       do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
1274   if (NS_SUCCEEDED(rv)) {
1275     rv = out->Init(file, ioFlags, perm, behaviorFlags);
1276     if (NS_SUCCEEDED(rv)) out.forget(result);
1277   }
1278   return rv;
1279 }
1280 
NS_NewLocalFileStream(nsIFileStream ** result,nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)1281 nsresult NS_NewLocalFileStream(nsIFileStream** result, nsIFile* file,
1282                                int32_t ioFlags /* = -1 */,
1283                                int32_t perm /* = -1 */,
1284                                int32_t behaviorFlags /* = 0 */) {
1285   nsCOMPtr<nsIFileStream> stream = new nsFileStream();
1286   nsresult rv = stream->Init(file, ioFlags, perm, behaviorFlags);
1287   if (NS_SUCCEEDED(rv)) {
1288     stream.forget(result);
1289   }
1290   return rv;
1291 }
1292 
NS_NewLocalFileStream(nsIFile * file,int32_t ioFlags,int32_t perm,int32_t behaviorFlags)1293 mozilla::Result<nsCOMPtr<nsIFileStream>, nsresult> NS_NewLocalFileStream(
1294     nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
1295     int32_t behaviorFlags /* = 0 */) {
1296   nsCOMPtr<nsIFileStream> stream;
1297   const nsresult rv = NS_NewLocalFileStream(getter_AddRefs(stream), file,
1298                                             ioFlags, perm, behaviorFlags);
1299   if (NS_SUCCEEDED(rv)) {
1300     return stream;
1301   }
1302   return Err(rv);
1303 }
1304 
NS_NewBufferedOutputStream(nsIOutputStream ** aResult,already_AddRefed<nsIOutputStream> aOutputStream,uint32_t aBufferSize)1305 nsresult NS_NewBufferedOutputStream(
1306     nsIOutputStream** aResult, already_AddRefed<nsIOutputStream> aOutputStream,
1307     uint32_t aBufferSize) {
1308   nsCOMPtr<nsIOutputStream> outputStream = std::move(aOutputStream);
1309 
1310   nsresult rv;
1311   nsCOMPtr<nsIBufferedOutputStream> out =
1312       do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
1313   if (NS_SUCCEEDED(rv)) {
1314     rv = out->Init(outputStream, aBufferSize);
1315     if (NS_SUCCEEDED(rv)) {
1316       out.forget(aResult);
1317     }
1318   }
1319   return rv;
1320 }
1321 
NS_NewBufferedInputStream(nsIInputStream ** aResult,already_AddRefed<nsIInputStream> aInputStream,uint32_t aBufferSize)1322 [[nodiscard]] nsresult NS_NewBufferedInputStream(
1323     nsIInputStream** aResult, already_AddRefed<nsIInputStream> aInputStream,
1324     uint32_t aBufferSize) {
1325   nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
1326 
1327   nsCOMPtr<nsIBufferedInputStream> in;
1328   nsresult rv = nsBufferedInputStream::Create(
1329       nullptr, NS_GET_IID(nsIBufferedInputStream), getter_AddRefs(in));
1330   if (NS_SUCCEEDED(rv)) {
1331     rv = in->Init(inputStream, aBufferSize);
1332     if (NS_SUCCEEDED(rv)) {
1333       *aResult = static_cast<nsBufferedInputStream*>(in.get())
1334                      ->GetInputStream()
1335                      .take();
1336     }
1337   }
1338   return rv;
1339 }
1340 
NS_NewBufferedInputStream(already_AddRefed<nsIInputStream> aInputStream,uint32_t aBufferSize)1341 Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewBufferedInputStream(
1342     already_AddRefed<nsIInputStream> aInputStream, uint32_t aBufferSize) {
1343   nsCOMPtr<nsIInputStream> stream;
1344   const nsresult rv = NS_NewBufferedInputStream(
1345       getter_AddRefs(stream), std::move(aInputStream), aBufferSize);
1346   if (NS_SUCCEEDED(rv)) {
1347     return stream;
1348   }
1349   return Err(rv);
1350 }
1351 
1352 namespace {
1353 
1354 #define BUFFER_SIZE 8192
1355 
1356 class BufferWriter final : public nsIInputStreamCallback {
1357  public:
1358   NS_DECL_THREADSAFE_ISUPPORTS
1359 
BufferWriter(nsIInputStream * aInputStream,void * aBuffer,int64_t aCount)1360   BufferWriter(nsIInputStream* aInputStream, void* aBuffer, int64_t aCount)
1361       : mMonitor("BufferWriter.mMonitor"),
1362         mInputStream(aInputStream),
1363         mBuffer(aBuffer),
1364         mCount(aCount),
1365         mWrittenData(0),
1366         mBufferType(aBuffer ? eExternal : eInternal),
1367         mBufferSize(0) {
1368     MOZ_ASSERT(aInputStream);
1369     MOZ_ASSERT(aCount == -1 || aCount > 0);
1370     MOZ_ASSERT_IF(mBuffer, aCount > 0);
1371   }
1372 
Write()1373   nsresult Write() {
1374     NS_ASSERT_OWNINGTHREAD(BufferWriter);
1375 
1376     // Let's make the inputStream buffered if it's not.
1377     if (!NS_InputStreamIsBuffered(mInputStream)) {
1378       nsCOMPtr<nsIInputStream> bufferedStream;
1379       nsresult rv = NS_NewBufferedInputStream(
1380           getter_AddRefs(bufferedStream), mInputStream.forget(), BUFFER_SIZE);
1381       NS_ENSURE_SUCCESS(rv, rv);
1382 
1383       mInputStream = bufferedStream;
1384     }
1385 
1386     mAsyncInputStream = do_QueryInterface(mInputStream);
1387 
1388     if (!mAsyncInputStream) {
1389       return WriteSync();
1390     }
1391 
1392     // Let's use mAsyncInputStream only.
1393     mInputStream = nullptr;
1394 
1395     return WriteAsync();
1396   }
1397 
WrittenData() const1398   uint64_t WrittenData() const {
1399     NS_ASSERT_OWNINGTHREAD(BufferWriter);
1400     return mWrittenData;
1401   }
1402 
StealBuffer()1403   void* StealBuffer() {
1404     NS_ASSERT_OWNINGTHREAD(BufferWriter);
1405     MOZ_ASSERT(mBufferType == eInternal);
1406 
1407     void* buffer = mBuffer;
1408 
1409     mBuffer = nullptr;
1410     mBufferSize = 0;
1411 
1412     return buffer;
1413   }
1414 
1415  private:
~BufferWriter()1416   ~BufferWriter() {
1417     if (mBuffer && mBufferType == eInternal) {
1418       free(mBuffer);
1419     }
1420 
1421     if (mTaskQueue) {
1422       mTaskQueue->BeginShutdown();
1423     }
1424   }
1425 
WriteSync()1426   nsresult WriteSync() {
1427     NS_ASSERT_OWNINGTHREAD(BufferWriter);
1428 
1429     uint64_t length = (uint64_t)mCount;
1430 
1431     if (mCount == -1) {
1432       nsresult rv = mInputStream->Available(&length);
1433       NS_ENSURE_SUCCESS(rv, rv);
1434 
1435       if (length == 0) {
1436         // nothing to read.
1437         return NS_OK;
1438       }
1439     }
1440 
1441     if (mBufferType == eInternal) {
1442       mBuffer = malloc(length);
1443       if (NS_WARN_IF(!mBuffer)) {
1444         return NS_ERROR_OUT_OF_MEMORY;
1445       }
1446     }
1447 
1448     uint32_t writtenData;
1449     nsresult rv = mInputStream->ReadSegments(NS_CopySegmentToBuffer, mBuffer,
1450                                              length, &writtenData);
1451     NS_ENSURE_SUCCESS(rv, rv);
1452 
1453     mWrittenData = writtenData;
1454     return NS_OK;
1455   }
1456 
WriteAsync()1457   nsresult WriteAsync() {
1458     NS_ASSERT_OWNINGTHREAD(BufferWriter);
1459 
1460     if (mCount > 0 && mBufferType == eInternal) {
1461       mBuffer = malloc(mCount);
1462       if (NS_WARN_IF(!mBuffer)) {
1463         return NS_ERROR_OUT_OF_MEMORY;
1464       }
1465     }
1466 
1467     while (true) {
1468       if (mCount == -1 && !MaybeExpandBufferSize()) {
1469         return NS_ERROR_OUT_OF_MEMORY;
1470       }
1471 
1472       uint64_t offset = mWrittenData;
1473       uint64_t length = mCount == -1 ? BUFFER_SIZE : mCount;
1474 
1475       // Let's try to read data directly.
1476       uint32_t writtenData;
1477       nsresult rv = mAsyncInputStream->ReadSegments(
1478           NS_CopySegmentToBuffer, static_cast<char*>(mBuffer) + offset, length,
1479           &writtenData);
1480 
1481       // Operation completed. Nothing more to read.
1482       if (NS_SUCCEEDED(rv) && writtenData == 0) {
1483         return NS_OK;
1484       }
1485 
1486       // If we succeeded, let's try to read again.
1487       if (NS_SUCCEEDED(rv)) {
1488         mWrittenData += writtenData;
1489         if (mCount != -1) {
1490           MOZ_ASSERT(mCount >= writtenData);
1491           mCount -= writtenData;
1492 
1493           // Is this the end of the reading?
1494           if (mCount == 0) {
1495             return NS_OK;
1496           }
1497         }
1498 
1499         continue;
1500       }
1501 
1502       // Async wait...
1503       if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
1504         rv = MaybeCreateTaskQueue();
1505         if (NS_WARN_IF(NS_FAILED(rv))) {
1506           return rv;
1507         }
1508 
1509         MonitorAutoLock lock(mMonitor);
1510 
1511         rv = mAsyncInputStream->AsyncWait(this, 0, length, mTaskQueue);
1512         if (NS_WARN_IF(NS_FAILED(rv))) {
1513           return rv;
1514         }
1515 
1516         lock.Wait();
1517         continue;
1518       }
1519 
1520       // Otherwise, let's propagate the error.
1521       return rv;
1522     }
1523 
1524     MOZ_ASSERT_UNREACHABLE("We should not be here");
1525     return NS_ERROR_FAILURE;
1526   }
1527 
MaybeCreateTaskQueue()1528   nsresult MaybeCreateTaskQueue() {
1529     NS_ASSERT_OWNINGTHREAD(BufferWriter);
1530 
1531     if (!mTaskQueue) {
1532       nsCOMPtr<nsIEventTarget> target =
1533           do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
1534       if (!target) {
1535         return NS_ERROR_FAILURE;
1536       }
1537 
1538       mTaskQueue = new TaskQueue(target.forget());
1539     }
1540 
1541     return NS_OK;
1542   }
1543 
1544   NS_IMETHOD
OnInputStreamReady(nsIAsyncInputStream * aStream)1545   OnInputStreamReady(nsIAsyncInputStream* aStream) override {
1546     MOZ_ASSERT(!NS_IsMainThread());
1547 
1548     // We have something to read. Let's unlock the main-thread.
1549     MonitorAutoLock lock(mMonitor);
1550     lock.Notify();
1551     return NS_OK;
1552   }
1553 
MaybeExpandBufferSize()1554   bool MaybeExpandBufferSize() {
1555     NS_ASSERT_OWNINGTHREAD(BufferWriter);
1556 
1557     MOZ_ASSERT(mCount == -1);
1558 
1559     if (mBufferSize >= mWrittenData + BUFFER_SIZE) {
1560       // The buffer is big enough.
1561       return true;
1562     }
1563 
1564     CheckedUint32 bufferSize =
1565         std::max<uint32_t>(static_cast<uint32_t>(mWrittenData), BUFFER_SIZE);
1566     while (bufferSize.isValid() &&
1567            bufferSize.value() < mWrittenData + BUFFER_SIZE) {
1568       bufferSize *= 2;
1569     }
1570 
1571     if (!bufferSize.isValid()) {
1572       return false;
1573     }
1574 
1575     void* buffer = realloc(mBuffer, bufferSize.value());
1576     if (!buffer) {
1577       return false;
1578     }
1579 
1580     mBuffer = buffer;
1581     mBufferSize = bufferSize.value();
1582     return true;
1583   }
1584 
1585   // All the members of this class are touched on the owning thread only. The
1586   // monitor is only used to communicate when there is more data to read.
1587   Monitor mMonitor;
1588 
1589   nsCOMPtr<nsIInputStream> mInputStream;
1590   nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream;
1591 
1592   RefPtr<TaskQueue> mTaskQueue;
1593 
1594   void* mBuffer;
1595   int64_t mCount;
1596   uint64_t mWrittenData;
1597 
1598   enum {
1599     // The buffer is allocated internally and this object must release it
1600     // in the DTOR if not stolen. The buffer can be reallocated.
1601     eInternal,
1602 
1603     // The buffer is not owned by this object and it cannot be reallocated.
1604     eExternal,
1605   } mBufferType;
1606 
1607   // The following set if needed for the async read.
1608   uint64_t mBufferSize;
1609 };
1610 
1611 NS_IMPL_ISUPPORTS(BufferWriter, nsIInputStreamCallback)
1612 
1613 }  // anonymous namespace
1614 
NS_ReadInputStreamToBuffer(nsIInputStream * aInputStream,void ** aDest,int64_t aCount,uint64_t * aWritten)1615 nsresult NS_ReadInputStreamToBuffer(nsIInputStream* aInputStream, void** aDest,
1616                                     int64_t aCount, uint64_t* aWritten) {
1617   MOZ_ASSERT(aInputStream);
1618   MOZ_ASSERT(aCount >= -1);
1619 
1620   uint64_t dummyWritten;
1621   if (!aWritten) {
1622     aWritten = &dummyWritten;
1623   }
1624 
1625   if (aCount == 0) {
1626     *aWritten = 0;
1627     return NS_OK;
1628   }
1629 
1630   // This will take care of allocating and reallocating aDest.
1631   RefPtr<BufferWriter> writer = new BufferWriter(aInputStream, *aDest, aCount);
1632 
1633   nsresult rv = writer->Write();
1634   NS_ENSURE_SUCCESS(rv, rv);
1635 
1636   *aWritten = writer->WrittenData();
1637 
1638   if (!*aDest) {
1639     *aDest = writer->StealBuffer();
1640   }
1641 
1642   return NS_OK;
1643 }
1644 
NS_ReadInputStreamToString(nsIInputStream * aInputStream,nsACString & aDest,int64_t aCount,uint64_t * aWritten)1645 nsresult NS_ReadInputStreamToString(nsIInputStream* aInputStream,
1646                                     nsACString& aDest, int64_t aCount,
1647                                     uint64_t* aWritten) {
1648   uint64_t dummyWritten;
1649   if (!aWritten) {
1650     aWritten = &dummyWritten;
1651   }
1652 
1653   // Nothing to do if aCount is 0.
1654   if (aCount == 0) {
1655     aDest.Truncate();
1656     *aWritten = 0;
1657     return NS_OK;
1658   }
1659 
1660   // If we have the size, we can pre-allocate the buffer.
1661   if (aCount > 0) {
1662     if (NS_WARN_IF(aCount >= INT32_MAX) ||
1663         NS_WARN_IF(!aDest.SetLength(aCount, mozilla::fallible))) {
1664       return NS_ERROR_OUT_OF_MEMORY;
1665     }
1666 
1667     void* dest = aDest.BeginWriting();
1668     nsresult rv =
1669         NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
1670     NS_ENSURE_SUCCESS(rv, rv);
1671 
1672     if ((uint64_t)aCount > *aWritten) {
1673       aDest.Truncate(*aWritten);
1674     }
1675 
1676     return NS_OK;
1677   }
1678 
1679   // If the size is unknown, BufferWriter will allocate the buffer.
1680   void* dest = nullptr;
1681   nsresult rv =
1682       NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount, aWritten);
1683   MOZ_ASSERT_IF(NS_FAILED(rv), dest == nullptr);
1684   NS_ENSURE_SUCCESS(rv, rv);
1685 
1686   if (!dest) {
1687     MOZ_ASSERT(*aWritten == 0);
1688     aDest.Truncate();
1689     return NS_OK;
1690   }
1691 
1692   aDest.Adopt(reinterpret_cast<char*>(dest), *aWritten);
1693   return NS_OK;
1694 }
1695 
NS_NewURI(nsIURI ** result,const nsACString & spec,NotNull<const Encoding * > encoding,nsIURI * baseURI)1696 nsresult NS_NewURI(nsIURI** result, const nsACString& spec,
1697                    NotNull<const Encoding*> encoding,
1698                    nsIURI* baseURI /* = nullptr */) {
1699   nsAutoCString charset;
1700   encoding->Name(charset);
1701   return NS_NewURI(result, spec, charset.get(), baseURI);
1702 }
1703 
NS_NewURI(nsIURI ** result,const nsAString & aSpec,const char * charset,nsIURI * baseURI)1704 nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec,
1705                    const char* charset /* = nullptr */,
1706                    nsIURI* baseURI /* = nullptr */) {
1707   nsAutoCString spec;
1708   if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
1709     return NS_ERROR_OUT_OF_MEMORY;
1710   }
1711   return NS_NewURI(result, spec, charset, baseURI);
1712 }
1713 
NS_NewURI(nsIURI ** result,const nsAString & aSpec,NotNull<const Encoding * > encoding,nsIURI * baseURI)1714 nsresult NS_NewURI(nsIURI** result, const nsAString& aSpec,
1715                    NotNull<const Encoding*> encoding,
1716                    nsIURI* baseURI /* = nullptr */) {
1717   nsAutoCString spec;
1718   if (!AppendUTF16toUTF8(aSpec, spec, mozilla::fallible)) {
1719     return NS_ERROR_OUT_OF_MEMORY;
1720   }
1721   return NS_NewURI(result, spec, encoding, baseURI);
1722 }
1723 
NS_NewURI(nsIURI ** result,const char * spec,nsIURI * baseURI)1724 nsresult NS_NewURI(nsIURI** result, const char* spec,
1725                    nsIURI* baseURI /* = nullptr */) {
1726   return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI);
1727 }
1728 
NewStandardURI(const nsACString & aSpec,const char * aCharset,nsIURI * aBaseURI,int32_t aDefaultPort,nsIURI ** aURI)1729 static nsresult NewStandardURI(const nsACString& aSpec, const char* aCharset,
1730                                nsIURI* aBaseURI, int32_t aDefaultPort,
1731                                nsIURI** aURI) {
1732   nsCOMPtr<nsIURI> base(aBaseURI);
1733   return NS_MutateURI(new nsStandardURL::Mutator())
1734       .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
1735                               nsIStandardURL::URLTYPE_AUTHORITY, aDefaultPort,
1736                               nsCString(aSpec), aCharset, base, nullptr))
1737       .Finalize(aURI);
1738 }
1739 
1740 extern MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount;
1741 
1742 template <typename T>
1743 class TlsAutoIncrement {
1744  public:
TlsAutoIncrement(T & var)1745   explicit TlsAutoIncrement(T& var) : mVar(var) {
1746     mValue = mVar.get();
1747     mVar.set(mValue + 1);
1748   }
~TlsAutoIncrement()1749   ~TlsAutoIncrement() {
1750     typename T::Type value = mVar.get();
1751     MOZ_ASSERT(value == mValue + 1);
1752     mVar.set(value - 1);
1753   }
1754 
value()1755   typename T::Type value() { return mValue; }
1756 
1757  private:
1758   typename T::Type mValue;
1759   T& mVar;
1760 };
1761 
NS_NewURI(nsIURI ** aURI,const nsACString & aSpec,const char * aCharset,nsIURI * aBaseURI)1762 nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
1763                    const char* aCharset /* = nullptr */,
1764                    nsIURI* aBaseURI /* = nullptr */) {
1765   TlsAutoIncrement<decltype(gTlsURLRecursionCount)> inc(gTlsURLRecursionCount);
1766   if (inc.value() >= MAX_RECURSION_COUNT) {
1767     return NS_ERROR_MALFORMED_URI;
1768   }
1769 
1770   nsCOMPtr<nsIIOService> ioService = do_GetIOService();
1771   if (!ioService) {
1772     // Individual protocol handlers unfortunately rely on the ioservice, let's
1773     // return an error here instead of causing unpredictable crashes later.
1774     return NS_ERROR_NOT_AVAILABLE;
1775   }
1776 
1777   nsAutoCString scheme;
1778   nsresult rv = net_ExtractURLScheme(aSpec, scheme);
1779   if (NS_FAILED(rv)) {
1780     // then aSpec is relative
1781     if (!aBaseURI) {
1782       return NS_ERROR_MALFORMED_URI;
1783     }
1784 
1785     if (!aSpec.IsEmpty() && aSpec[0] == '#') {
1786       // Looks like a reference instead of a fully-specified URI.
1787       // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
1788       return NS_GetURIWithNewRef(aBaseURI, aSpec, aURI);
1789     }
1790 
1791     rv = aBaseURI->GetScheme(scheme);
1792     if (NS_FAILED(rv)) return rv;
1793   }
1794 
1795   if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) {
1796     return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT,
1797                           aURI);
1798   }
1799   if (scheme.EqualsLiteral("https") || scheme.EqualsLiteral("wss")) {
1800     return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT,
1801                           aURI);
1802   }
1803   if (scheme.EqualsLiteral("ftp")) {
1804     return NewStandardURI(aSpec, aCharset, aBaseURI, 21, aURI);
1805   }
1806   if (scheme.EqualsLiteral("ssh")) {
1807     return NewStandardURI(aSpec, aCharset, aBaseURI, 22, aURI);
1808   }
1809 
1810   if (scheme.EqualsLiteral("file")) {
1811     nsAutoCString buf(aSpec);
1812 #if defined(XP_WIN)
1813     buf.Truncate();
1814     if (!net_NormalizeFileURL(aSpec, buf)) {
1815       buf = aSpec;
1816     }
1817 #endif
1818 
1819     nsCOMPtr<nsIURI> base(aBaseURI);
1820     return NS_MutateURI(new nsStandardURL::Mutator())
1821         .Apply(NS_MutatorMethod(&nsIFileURLMutator::MarkFileURL))
1822         .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
1823                                 nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, buf,
1824                                 aCharset, base, nullptr))
1825         .Finalize(aURI);
1826   }
1827 
1828   if (scheme.EqualsLiteral("data")) {
1829     return nsDataHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
1830   }
1831 
1832   if (scheme.EqualsLiteral("moz-safe-about") ||
1833       scheme.EqualsLiteral("page-icon") || scheme.EqualsLiteral("moz") ||
1834       scheme.EqualsLiteral("moz-anno") ||
1835       scheme.EqualsLiteral("moz-fonttable")) {
1836     return NS_MutateURI(new nsSimpleURI::Mutator())
1837         .SetSpec(aSpec)
1838         .Finalize(aURI);
1839   }
1840 
1841   if (scheme.EqualsLiteral("chrome")) {
1842     return nsChromeProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
1843                                                  aURI);
1844   }
1845 
1846   if (scheme.EqualsLiteral("javascript")) {
1847     return nsJSProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
1848   }
1849 
1850   if (scheme.EqualsLiteral("blob")) {
1851     return BlobURLProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
1852                                                 aURI);
1853   }
1854 
1855   if (scheme.EqualsLiteral("view-source")) {
1856     return nsViewSourceHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
1857   }
1858 
1859   if (scheme.EqualsLiteral("resource")) {
1860     RefPtr<nsResProtocolHandler> handler = nsResProtocolHandler::GetSingleton();
1861     if (!handler) {
1862       return NS_ERROR_NOT_AVAILABLE;
1863     }
1864     return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
1865   }
1866 
1867   if (scheme.EqualsLiteral("indexeddb")) {
1868     nsCOMPtr<nsIURI> base(aBaseURI);
1869     return NS_MutateURI(new nsStandardURL::Mutator())
1870         .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
1871                                 nsIStandardURL::URLTYPE_AUTHORITY, 0,
1872                                 nsCString(aSpec), aCharset, base, nullptr))
1873         .Finalize(aURI);
1874   }
1875 
1876   if (scheme.EqualsLiteral("moz-extension")) {
1877     RefPtr<mozilla::net::ExtensionProtocolHandler> handler =
1878         mozilla::net::ExtensionProtocolHandler::GetSingleton();
1879     if (!handler) {
1880       return NS_ERROR_NOT_AVAILABLE;
1881     }
1882     return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
1883   }
1884 
1885   if (scheme.EqualsLiteral("moz-page-thumb")) {
1886     // The moz-page-thumb service runs JS to resolve a URI to a
1887     // storage location, so this should only ever run on the main
1888     // thread.
1889     if (!NS_IsMainThread()) {
1890       return NS_ERROR_NOT_AVAILABLE;
1891     }
1892 
1893     RefPtr<mozilla::net::PageThumbProtocolHandler> handler =
1894         mozilla::net::PageThumbProtocolHandler::GetSingleton();
1895     if (!handler) {
1896       return NS_ERROR_NOT_AVAILABLE;
1897     }
1898     return handler->NewURI(aSpec, aCharset, aBaseURI, aURI);
1899   }
1900 
1901   if (scheme.EqualsLiteral("about")) {
1902     return nsAboutProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
1903                                                 aURI);
1904   }
1905 
1906   if (scheme.EqualsLiteral("jar")) {
1907     nsCOMPtr<nsIURI> base(aBaseURI);
1908     return NS_MutateURI(new nsJARURI::Mutator())
1909         .Apply(NS_MutatorMethod(&nsIJARURIMutator::SetSpecBaseCharset,
1910                                 nsCString(aSpec), base, aCharset))
1911         .Finalize(aURI);
1912   }
1913 
1914   if (scheme.EqualsLiteral("moz-icon")) {
1915     return NS_MutateURI(new nsMozIconURI::Mutator())
1916         .SetSpec(aSpec)
1917         .Finalize(aURI);
1918   }
1919 
1920 #ifdef MOZ_WIDGET_GTK
1921   if (scheme.EqualsLiteral("smb") || scheme.EqualsLiteral("sftp")) {
1922     nsCOMPtr<nsIURI> base(aBaseURI);
1923     return NS_MutateURI(new nsStandardURL::Mutator())
1924         .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
1925                                 nsIStandardURL::URLTYPE_STANDARD, -1,
1926                                 nsCString(aSpec), aCharset, base, nullptr))
1927         .Finalize(aURI);
1928   }
1929 #endif
1930 
1931   if (scheme.EqualsLiteral("android")) {
1932     nsCOMPtr<nsIURI> base(aBaseURI);
1933     return NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
1934         .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
1935                                 nsIStandardURL::URLTYPE_STANDARD, -1,
1936                                 nsCString(aSpec), aCharset, base, nullptr))
1937         .Finalize(aURI);
1938   }
1939 
1940   // web-extensions can add custom protocol implementations with standard URLs
1941   // that have notion of hostname, authority and relative URLs. Below we
1942   // manually check agains set of known protocols schemes until more general
1943   // solution is in place (See Bug 1569733)
1944   if (!StaticPrefs::network_url_useDefaultURI()) {
1945     if (scheme.EqualsLiteral("dweb") || scheme.EqualsLiteral("dat") ||
1946         scheme.EqualsLiteral("ipfs") || scheme.EqualsLiteral("ipns") ||
1947         scheme.EqualsLiteral("ssb") || scheme.EqualsLiteral("wtp")) {
1948       return NewStandardURI(aSpec, aCharset, aBaseURI, -1, aURI);
1949     }
1950   }
1951 
1952 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
1953   rv = NS_NewMailnewsURI(aURI, aSpec, aCharset, aBaseURI);
1954   if (rv != NS_ERROR_UNKNOWN_PROTOCOL) {
1955     return rv;
1956   }
1957 #endif
1958 
1959   if (aBaseURI) {
1960     nsAutoCString newSpec;
1961     rv = aBaseURI->Resolve(aSpec, newSpec);
1962     NS_ENSURE_SUCCESS(rv, rv);
1963 
1964     nsAutoCString newScheme;
1965     rv = net_ExtractURLScheme(newSpec, newScheme);
1966     if (NS_SUCCEEDED(rv)) {
1967       // The scheme shouldn't really change at this point.
1968       MOZ_DIAGNOSTIC_ASSERT(newScheme == scheme);
1969     }
1970 
1971     if (StaticPrefs::network_url_useDefaultURI()) {
1972       return NS_MutateURI(new DefaultURI::Mutator())
1973           .SetSpec(newSpec)
1974           .Finalize(aURI);
1975     }
1976 
1977     return NS_MutateURI(new nsSimpleURI::Mutator())
1978         .SetSpec(newSpec)
1979         .Finalize(aURI);
1980   }
1981 
1982   if (StaticPrefs::network_url_useDefaultURI()) {
1983     return NS_MutateURI(new DefaultURI::Mutator())
1984         .SetSpec(aSpec)
1985         .Finalize(aURI);
1986   }
1987 
1988   // Falls back to external protocol handler.
1989   return NS_MutateURI(new nsSimpleURI::Mutator()).SetSpec(aSpec).Finalize(aURI);
1990 }
1991 
NS_GetSanitizedURIStringFromURI(nsIURI * aUri,nsAString & aSanitizedSpec)1992 nsresult NS_GetSanitizedURIStringFromURI(nsIURI* aUri,
1993                                          nsAString& aSanitizedSpec) {
1994   aSanitizedSpec.Truncate();
1995 
1996   nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(aUri);
1997   nsAutoCString cSpec;
1998   nsresult rv;
1999   if (safeUri) {
2000     rv = safeUri->GetSensitiveInfoHiddenSpec(cSpec);
2001   } else {
2002     rv = aUri->GetSpec(cSpec);
2003   }
2004 
2005   if (NS_SUCCEEDED(rv)) {
2006     aSanitizedSpec.Assign(NS_ConvertUTF8toUTF16(cSpec));
2007   }
2008   return rv;
2009 }
2010 
NS_LoadPersistentPropertiesFromURISpec(nsIPersistentProperties ** outResult,const nsACString & aSpec)2011 nsresult NS_LoadPersistentPropertiesFromURISpec(
2012     nsIPersistentProperties** outResult, const nsACString& aSpec) {
2013   nsCOMPtr<nsIURI> uri;
2014   nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpec);
2015   NS_ENSURE_SUCCESS(rv, rv);
2016 
2017   nsCOMPtr<nsIChannel> channel;
2018   rv = NS_NewChannel(getter_AddRefs(channel), uri,
2019                      nsContentUtils::GetSystemPrincipal(),
2020                      nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
2021                      nsIContentPolicy::TYPE_OTHER);
2022   NS_ENSURE_SUCCESS(rv, rv);
2023   nsCOMPtr<nsIInputStream> in;
2024   rv = channel->Open(getter_AddRefs(in));
2025   NS_ENSURE_SUCCESS(rv, rv);
2026 
2027   nsCOMPtr<nsIPersistentProperties> properties = new nsPersistentProperties();
2028   rv = properties->Load(in);
2029   NS_ENSURE_SUCCESS(rv, rv);
2030 
2031   properties.swap(*outResult);
2032   return NS_OK;
2033 }
2034 
NS_UsePrivateBrowsing(nsIChannel * channel)2035 bool NS_UsePrivateBrowsing(nsIChannel* channel) {
2036   OriginAttributes attrs;
2037   bool result = StoragePrincipalHelper::GetOriginAttributes(
2038       channel, attrs, StoragePrincipalHelper::eRegularPrincipal);
2039   NS_ENSURE_TRUE(result, result);
2040   return attrs.mPrivateBrowsingId > 0;
2041 }
2042 
NS_HasBeenCrossOrigin(nsIChannel * aChannel,bool aReport)2043 bool NS_HasBeenCrossOrigin(nsIChannel* aChannel, bool aReport) {
2044   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
2045   // TYPE_DOCUMENT loads have a null LoadingPrincipal and can not be cross
2046   // origin.
2047   if (!loadInfo->GetLoadingPrincipal()) {
2048     return false;
2049   }
2050 
2051   // Always treat tainted channels as cross-origin.
2052   if (loadInfo->GetTainting() != LoadTainting::Basic) {
2053     return true;
2054   }
2055 
2056   nsCOMPtr<nsIPrincipal> loadingPrincipal = loadInfo->GetLoadingPrincipal();
2057   uint32_t mode = loadInfo->GetSecurityMode();
2058   bool dataInherits =
2059       mode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT ||
2060       mode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT ||
2061       mode == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
2062 
2063   bool aboutBlankInherits = dataInherits && loadInfo->GetAboutBlankInherits();
2064 
2065   uint64_t innerWindowID = loadInfo->GetInnerWindowID();
2066 
2067   for (nsIRedirectHistoryEntry* redirectHistoryEntry :
2068        loadInfo->RedirectChain()) {
2069     nsCOMPtr<nsIPrincipal> principal;
2070     redirectHistoryEntry->GetPrincipal(getter_AddRefs(principal));
2071     if (!principal) {
2072       return true;
2073     }
2074 
2075     nsCOMPtr<nsIURI> uri;
2076     auto* basePrin = BasePrincipal::Cast(principal);
2077     basePrin->GetURI(getter_AddRefs(uri));
2078     if (!uri) {
2079       return true;
2080     }
2081 
2082     if (aboutBlankInherits && NS_IsAboutBlank(uri)) {
2083       continue;
2084     }
2085 
2086     nsresult res;
2087     if (aReport) {
2088       res = loadingPrincipal->CheckMayLoadWithReporting(uri, dataInherits,
2089                                                         innerWindowID);
2090     } else {
2091       res = loadingPrincipal->CheckMayLoad(uri, dataInherits);
2092     }
2093     if (NS_FAILED(res)) {
2094       return true;
2095     }
2096   }
2097 
2098   nsCOMPtr<nsIURI> uri;
2099   NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
2100   if (!uri) {
2101     return true;
2102   }
2103 
2104   if (aboutBlankInherits && NS_IsAboutBlank(uri)) {
2105     return false;
2106   }
2107 
2108   nsresult res;
2109   if (aReport) {
2110     res = loadingPrincipal->CheckMayLoadWithReporting(uri, dataInherits,
2111                                                       innerWindowID);
2112   } else {
2113     res = loadingPrincipal->CheckMayLoad(uri, dataInherits);
2114   }
2115 
2116   return NS_FAILED(res);
2117 }
2118 
NS_IsSafeMethodNav(nsIChannel * aChannel)2119 bool NS_IsSafeMethodNav(nsIChannel* aChannel) {
2120   RefPtr<HttpBaseChannel> baseChan = do_QueryObject(aChannel);
2121   if (!baseChan) {
2122     return false;
2123   }
2124   nsHttpRequestHead* requestHead = baseChan->GetRequestHead();
2125   if (!requestHead) {
2126     return false;
2127   }
2128   return requestHead->IsSafeMethod();
2129 }
2130 
NS_WrapAuthPrompt(nsIAuthPrompt * aAuthPrompt,nsIAuthPrompt2 ** aAuthPrompt2)2131 void NS_WrapAuthPrompt(nsIAuthPrompt* aAuthPrompt,
2132                        nsIAuthPrompt2** aAuthPrompt2) {
2133   nsCOMPtr<nsIAuthPromptAdapterFactory> factory =
2134       do_GetService(NS_AUTHPROMPT_ADAPTER_FACTORY_CONTRACTID);
2135   if (!factory) return;
2136 
2137   NS_WARNING("Using deprecated nsIAuthPrompt");
2138   factory->CreateAdapter(aAuthPrompt, aAuthPrompt2);
2139 }
2140 
NS_QueryAuthPrompt2(nsIInterfaceRequestor * aCallbacks,nsIAuthPrompt2 ** aAuthPrompt)2141 void NS_QueryAuthPrompt2(nsIInterfaceRequestor* aCallbacks,
2142                          nsIAuthPrompt2** aAuthPrompt) {
2143   CallGetInterface(aCallbacks, aAuthPrompt);
2144   if (*aAuthPrompt) return;
2145 
2146   // Maybe only nsIAuthPrompt is provided and we have to wrap it.
2147   nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks));
2148   if (!prompt) return;
2149 
2150   NS_WrapAuthPrompt(prompt, aAuthPrompt);
2151 }
2152 
NS_QueryAuthPrompt2(nsIChannel * aChannel,nsIAuthPrompt2 ** aAuthPrompt)2153 void NS_QueryAuthPrompt2(nsIChannel* aChannel, nsIAuthPrompt2** aAuthPrompt) {
2154   *aAuthPrompt = nullptr;
2155 
2156   // We want to use any auth prompt we can find on the channel's callbacks,
2157   // and if that fails use the loadgroup's prompt (if any)
2158   // Therefore, we can't just use NS_QueryNotificationCallbacks, because
2159   // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's
2160   // nsIAuthPrompt.
2161   nsCOMPtr<nsIInterfaceRequestor> callbacks;
2162   aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
2163   if (callbacks) {
2164     NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
2165     if (*aAuthPrompt) return;
2166   }
2167 
2168   nsCOMPtr<nsILoadGroup> group;
2169   aChannel->GetLoadGroup(getter_AddRefs(group));
2170   if (!group) return;
2171 
2172   group->GetNotificationCallbacks(getter_AddRefs(callbacks));
2173   if (!callbacks) return;
2174   NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
2175 }
2176 
NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor * callbacks,nsILoadGroup * loadGroup,nsIEventTarget * target,nsIInterfaceRequestor ** result)2177 nsresult NS_NewNotificationCallbacksAggregation(
2178     nsIInterfaceRequestor* callbacks, nsILoadGroup* loadGroup,
2179     nsIEventTarget* target, nsIInterfaceRequestor** result) {
2180   nsCOMPtr<nsIInterfaceRequestor> cbs;
2181   if (loadGroup) loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
2182   return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result);
2183 }
2184 
NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor * callbacks,nsILoadGroup * loadGroup,nsIInterfaceRequestor ** result)2185 nsresult NS_NewNotificationCallbacksAggregation(
2186     nsIInterfaceRequestor* callbacks, nsILoadGroup* loadGroup,
2187     nsIInterfaceRequestor** result) {
2188   return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr,
2189                                                 result);
2190 }
2191 
NS_DoImplGetInnermostURI(nsINestedURI * nestedURI,nsIURI ** result)2192 nsresult NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) {
2193   MOZ_ASSERT(nestedURI, "Must have a nested URI!");
2194   MOZ_ASSERT(!*result, "Must have null *result");
2195 
2196   nsCOMPtr<nsIURI> inner;
2197   nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner));
2198   NS_ENSURE_SUCCESS(rv, rv);
2199 
2200   // We may need to loop here until we reach the innermost
2201   // URI.
2202   nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner));
2203   while (nestedInner) {
2204     rv = nestedInner->GetInnerURI(getter_AddRefs(inner));
2205     NS_ENSURE_SUCCESS(rv, rv);
2206     nestedInner = do_QueryInterface(inner);
2207   }
2208 
2209   // Found the innermost one if we reach here.
2210   inner.swap(*result);
2211 
2212   return rv;
2213 }
2214 
NS_ImplGetInnermostURI(nsINestedURI * nestedURI,nsIURI ** result)2215 nsresult NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) {
2216   // Make it safe to use swap()
2217   *result = nullptr;
2218 
2219   return NS_DoImplGetInnermostURI(nestedURI, result);
2220 }
2221 
NS_GetInnermostURI(nsIURI * aURI)2222 already_AddRefed<nsIURI> NS_GetInnermostURI(nsIURI* aURI) {
2223   MOZ_ASSERT(aURI, "Must have URI");
2224 
2225   nsCOMPtr<nsIURI> uri = aURI;
2226 
2227   nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri));
2228   if (!nestedURI) {
2229     return uri.forget();
2230   }
2231 
2232   nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
2233   if (NS_FAILED(rv)) {
2234     return nullptr;
2235   }
2236 
2237   return uri.forget();
2238 }
2239 
NS_GetFinalChannelURI(nsIChannel * channel,nsIURI ** uri)2240 nsresult NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri) {
2241   *uri = nullptr;
2242 
2243   nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
2244   nsCOMPtr<nsIURI> resultPrincipalURI;
2245   loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
2246   if (resultPrincipalURI) {
2247     resultPrincipalURI.forget(uri);
2248     return NS_OK;
2249   }
2250   return channel->GetOriginalURI(uri);
2251 }
2252 
NS_URIChainHasFlags(nsIURI * uri,uint32_t flags,bool * result)2253 nsresult NS_URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
2254   nsresult rv;
2255   nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
2256   NS_ENSURE_SUCCESS(rv, rv);
2257 
2258   return util->URIChainHasFlags(uri, flags, result);
2259 }
2260 
NS_SecurityHashURI(nsIURI * aURI)2261 uint32_t NS_SecurityHashURI(nsIURI* aURI) {
2262   nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
2263 
2264   nsAutoCString scheme;
2265   uint32_t schemeHash = 0;
2266   if (NS_SUCCEEDED(baseURI->GetScheme(scheme))) {
2267     schemeHash = mozilla::HashString(scheme);
2268   }
2269 
2270   // TODO figure out how to hash file:// URIs
2271   if (scheme.EqualsLiteral("file")) return schemeHash;  // sad face
2272 
2273 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
2274   bool hasFlag;
2275   if (NS_FAILED(NS_URIChainHasFlags(
2276           baseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) ||
2277       hasFlag) {
2278     nsAutoCString spec;
2279     uint32_t specHash;
2280     nsresult res = baseURI->GetSpec(spec);
2281     if (NS_SUCCEEDED(res))
2282       specHash = mozilla::HashString(spec);
2283     else
2284       specHash = static_cast<uint32_t>(res);
2285     return specHash;
2286   }
2287 #endif
2288 
2289   nsAutoCString host;
2290   uint32_t hostHash = 0;
2291   if (NS_SUCCEEDED(baseURI->GetAsciiHost(host))) {
2292     hostHash = mozilla::HashString(host);
2293   }
2294 
2295   return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI));
2296 }
2297 
NS_SecurityCompareURIs(nsIURI * aSourceURI,nsIURI * aTargetURI,bool aStrictFileOriginPolicy)2298 bool NS_SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI,
2299                             bool aStrictFileOriginPolicy) {
2300   nsresult rv;
2301 
2302   // Note that this is not an Equals() test on purpose -- for URIs that don't
2303   // support host/port, we want equality to basically be object identity, for
2304   // security purposes.  Otherwise, for example, two javascript: URIs that
2305   // are otherwise unrelated could end up "same origin", which would be
2306   // unfortunate.
2307   if (aSourceURI && aSourceURI == aTargetURI) {
2308     return true;
2309   }
2310 
2311   if (!aTargetURI || !aSourceURI) {
2312     return false;
2313   }
2314 
2315   // If either URI is a nested URI, get the base URI
2316   nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
2317   nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
2318 
2319 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
2320   // Check if either URI has a special origin.
2321   nsCOMPtr<nsIURI> origin;
2322   nsCOMPtr<nsIURIWithSpecialOrigin> uriWithSpecialOrigin =
2323       do_QueryInterface(sourceBaseURI);
2324   if (uriWithSpecialOrigin) {
2325     rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
2326     if (NS_WARN_IF(NS_FAILED(rv))) {
2327       return false;
2328     }
2329     MOZ_ASSERT(origin);
2330     sourceBaseURI = origin;
2331   }
2332   uriWithSpecialOrigin = do_QueryInterface(targetBaseURI);
2333   if (uriWithSpecialOrigin) {
2334     rv = uriWithSpecialOrigin->GetOrigin(getter_AddRefs(origin));
2335     if (NS_WARN_IF(NS_FAILED(rv))) {
2336       return false;
2337     }
2338     MOZ_ASSERT(origin);
2339     targetBaseURI = origin;
2340   }
2341 #endif
2342 
2343   nsCOMPtr<nsIPrincipal> sourceBlobPrincipal;
2344   if (BlobURLProtocolHandler::GetBlobURLPrincipal(
2345           sourceBaseURI, getter_AddRefs(sourceBlobPrincipal))) {
2346     nsCOMPtr<nsIURI> sourceBlobOwnerURI;
2347     auto* basePrin = BasePrincipal::Cast(sourceBlobPrincipal);
2348     rv = basePrin->GetURI(getter_AddRefs(sourceBlobOwnerURI));
2349     if (NS_SUCCEEDED(rv)) {
2350       sourceBaseURI = sourceBlobOwnerURI;
2351     }
2352   }
2353 
2354   nsCOMPtr<nsIPrincipal> targetBlobPrincipal;
2355   if (BlobURLProtocolHandler::GetBlobURLPrincipal(
2356           targetBaseURI, getter_AddRefs(targetBlobPrincipal))) {
2357     nsCOMPtr<nsIURI> targetBlobOwnerURI;
2358     auto* basePrin = BasePrincipal::Cast(targetBlobPrincipal);
2359     rv = basePrin->GetURI(getter_AddRefs(targetBlobOwnerURI));
2360     if (NS_SUCCEEDED(rv)) {
2361       targetBaseURI = targetBlobOwnerURI;
2362     }
2363   }
2364 
2365   if (!sourceBaseURI || !targetBaseURI) return false;
2366 
2367   // Compare schemes
2368   nsAutoCString targetScheme;
2369   bool sameScheme = false;
2370   if (NS_FAILED(targetBaseURI->GetScheme(targetScheme)) ||
2371       NS_FAILED(sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme)) ||
2372       !sameScheme) {
2373     // Not same-origin if schemes differ
2374     return false;
2375   }
2376 
2377   // For file scheme, reject unless the files are identical. See
2378   // NS_RelaxStrictFileOriginPolicy for enforcing file same-origin checking
2379   if (targetScheme.EqualsLiteral("file")) {
2380     // in traditional unsafe behavior all files are the same origin
2381     if (!aStrictFileOriginPolicy) return true;
2382 
2383     nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
2384     nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
2385 
2386     if (!sourceFileURL || !targetFileURL) return false;
2387 
2388     nsCOMPtr<nsIFile> sourceFile, targetFile;
2389 
2390     sourceFileURL->GetFile(getter_AddRefs(sourceFile));
2391     targetFileURL->GetFile(getter_AddRefs(targetFile));
2392 
2393     if (!sourceFile || !targetFile) return false;
2394 
2395     // Otherwise they had better match
2396     bool filesAreEqual = false;
2397     rv = sourceFile->Equals(targetFile, &filesAreEqual);
2398     return NS_SUCCEEDED(rv) && filesAreEqual;
2399   }
2400 
2401 #if IS_ORIGIN_IS_FULL_SPEC_DEFINED
2402   bool hasFlag;
2403   if (NS_FAILED(NS_URIChainHasFlags(
2404           targetBaseURI, nsIProtocolHandler::ORIGIN_IS_FULL_SPEC, &hasFlag)) ||
2405       hasFlag) {
2406     // URIs with this flag have the whole spec as a distinct trust
2407     // domain; use the whole spec for comparison
2408     nsAutoCString targetSpec;
2409     nsAutoCString sourceSpec;
2410     return (NS_SUCCEEDED(targetBaseURI->GetSpec(targetSpec)) &&
2411             NS_SUCCEEDED(sourceBaseURI->GetSpec(sourceSpec)) &&
2412             targetSpec.Equals(sourceSpec));
2413   }
2414 #endif
2415 
2416   // Compare hosts
2417   nsAutoCString targetHost;
2418   nsAutoCString sourceHost;
2419   if (NS_FAILED(targetBaseURI->GetAsciiHost(targetHost)) ||
2420       NS_FAILED(sourceBaseURI->GetAsciiHost(sourceHost))) {
2421     return false;
2422   }
2423 
2424   nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI));
2425   nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI));
2426   if (!targetURL || !sourceURL) {
2427     return false;
2428   }
2429 
2430   if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator)) {
2431     return false;
2432   }
2433 
2434   return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI);
2435 }
2436 
NS_URIIsLocalFile(nsIURI * aURI)2437 bool NS_URIIsLocalFile(nsIURI* aURI) {
2438   nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
2439 
2440   bool isFile;
2441   return util &&
2442          NS_SUCCEEDED(util->ProtocolHasFlags(
2443              aURI, nsIProtocolHandler::URI_IS_LOCAL_FILE, &isFile)) &&
2444          isFile;
2445 }
2446 
NS_RelaxStrictFileOriginPolicy(nsIURI * aTargetURI,nsIURI * aSourceURI,bool aAllowDirectoryTarget)2447 bool NS_RelaxStrictFileOriginPolicy(nsIURI* aTargetURI, nsIURI* aSourceURI,
2448                                     bool aAllowDirectoryTarget /* = false */) {
2449   if (!NS_URIIsLocalFile(aTargetURI)) {
2450     // This is probably not what the caller intended
2451     MOZ_ASSERT_UNREACHABLE(
2452         "NS_RelaxStrictFileOriginPolicy called with non-file URI");
2453     return false;
2454   }
2455 
2456   if (!NS_URIIsLocalFile(aSourceURI)) {
2457     // If the source is not also a file: uri then forget it
2458     // (don't want resource: principals in a file: doc)
2459     //
2460     // note: we're not de-nesting jar: uris here, we want to
2461     // keep archive content bottled up in its own little island
2462     return false;
2463   }
2464 
2465   //
2466   // pull out the internal files
2467   //
2468   nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(aTargetURI));
2469   nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(aSourceURI));
2470   nsCOMPtr<nsIFile> targetFile;
2471   nsCOMPtr<nsIFile> sourceFile;
2472   bool targetIsDir;
2473 
2474   // Make sure targetFile is not a directory (bug 209234)
2475   // and that it exists w/out unescaping (bug 395343)
2476   if (!sourceFileURL || !targetFileURL ||
2477       NS_FAILED(targetFileURL->GetFile(getter_AddRefs(targetFile))) ||
2478       NS_FAILED(sourceFileURL->GetFile(getter_AddRefs(sourceFile))) ||
2479       !targetFile || !sourceFile || NS_FAILED(targetFile->Normalize()) ||
2480 #ifndef MOZ_WIDGET_ANDROID
2481       NS_FAILED(sourceFile->Normalize()) ||
2482 #endif
2483       (!aAllowDirectoryTarget &&
2484        (NS_FAILED(targetFile->IsDirectory(&targetIsDir)) || targetIsDir))) {
2485     return false;
2486   }
2487 
2488   if (!StaticPrefs::privacy_file_unique_origin()) {
2489     //
2490     // If the file to be loaded is in a subdirectory of the source
2491     // (or same-dir if source is not a directory) then it will
2492     // inherit its source principal and be scriptable by that source.
2493     //
2494     bool sourceIsDir;
2495     bool allowed = false;
2496     nsresult rv = sourceFile->IsDirectory(&sourceIsDir);
2497     if (NS_SUCCEEDED(rv) && sourceIsDir) {
2498       rv = sourceFile->Contains(targetFile, &allowed);
2499     } else {
2500       nsCOMPtr<nsIFile> sourceParent;
2501       rv = sourceFile->GetParent(getter_AddRefs(sourceParent));
2502       if (NS_SUCCEEDED(rv) && sourceParent) {
2503         rv = sourceParent->Equals(targetFile, &allowed);
2504         if (NS_FAILED(rv) || !allowed) {
2505           rv = sourceParent->Contains(targetFile, &allowed);
2506         } else {
2507           MOZ_ASSERT(aAllowDirectoryTarget,
2508                      "sourceFile->Parent == targetFile, but targetFile "
2509                      "should've been disallowed if it is a directory");
2510         }
2511       }
2512     }
2513 
2514     if (NS_SUCCEEDED(rv) && allowed) {
2515       return true;
2516     }
2517   }
2518 
2519   return false;
2520 }
2521 
NS_IsInternalSameURIRedirect(nsIChannel * aOldChannel,nsIChannel * aNewChannel,uint32_t aFlags)2522 bool NS_IsInternalSameURIRedirect(nsIChannel* aOldChannel,
2523                                   nsIChannel* aNewChannel, uint32_t aFlags) {
2524   if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
2525     return false;
2526   }
2527 
2528   nsCOMPtr<nsIURI> oldURI, newURI;
2529   aOldChannel->GetURI(getter_AddRefs(oldURI));
2530   aNewChannel->GetURI(getter_AddRefs(newURI));
2531 
2532   if (!oldURI || !newURI) {
2533     return false;
2534   }
2535 
2536   bool res;
2537   return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
2538 }
2539 
NS_IsHSTSUpgradeRedirect(nsIChannel * aOldChannel,nsIChannel * aNewChannel,uint32_t aFlags)2540 bool NS_IsHSTSUpgradeRedirect(nsIChannel* aOldChannel, nsIChannel* aNewChannel,
2541                               uint32_t aFlags) {
2542   if (!(aFlags & nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
2543     return false;
2544   }
2545 
2546   nsCOMPtr<nsIURI> oldURI, newURI;
2547   aOldChannel->GetURI(getter_AddRefs(oldURI));
2548   aNewChannel->GetURI(getter_AddRefs(newURI));
2549 
2550   if (!oldURI || !newURI) {
2551     return false;
2552   }
2553 
2554   if (!oldURI->SchemeIs("http")) {
2555     return false;
2556   }
2557 
2558   nsCOMPtr<nsIURI> upgradedURI;
2559   nsresult rv = NS_GetSecureUpgradedURI(oldURI, getter_AddRefs(upgradedURI));
2560   if (NS_FAILED(rv)) {
2561     return false;
2562   }
2563 
2564   bool res;
2565   return NS_SUCCEEDED(upgradedURI->Equals(newURI, &res)) && res;
2566 }
2567 
NS_LinkRedirectChannels(uint64_t channelId,nsIParentChannel * parentChannel,nsIChannel ** _result)2568 nsresult NS_LinkRedirectChannels(uint64_t channelId,
2569                                  nsIParentChannel* parentChannel,
2570                                  nsIChannel** _result) {
2571   nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
2572       RedirectChannelRegistrar::GetOrCreate();
2573   MOZ_ASSERT(registrar);
2574 
2575   return registrar->LinkChannels(channelId, parentChannel, _result);
2576 }
2577 
NS_MaybeOpenChannelUsingOpen(nsIChannel * aChannel,nsIInputStream ** aStream)2578 nsresult NS_MaybeOpenChannelUsingOpen(nsIChannel* aChannel,
2579                                       nsIInputStream** aStream) {
2580   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
2581   return aChannel->Open(aStream);
2582 }
2583 
NS_MaybeOpenChannelUsingAsyncOpen(nsIChannel * aChannel,nsIStreamListener * aListener)2584 nsresult NS_MaybeOpenChannelUsingAsyncOpen(nsIChannel* aChannel,
2585                                            nsIStreamListener* aListener) {
2586   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
2587   return aChannel->AsyncOpen(aListener);
2588 }
2589 
2590 nsILoadInfo::CrossOriginEmbedderPolicy
NS_GetCrossOriginEmbedderPolicyFromHeader(const nsACString & aHeader)2591 NS_GetCrossOriginEmbedderPolicyFromHeader(const nsACString& aHeader) {
2592   nsCOMPtr<nsISFVService> sfv = GetSFVService();
2593 
2594   nsCOMPtr<nsISFVItem> item;
2595   nsresult rv = sfv->ParseItem(aHeader, getter_AddRefs(item));
2596   if (NS_FAILED(rv)) {
2597     return nsILoadInfo::EMBEDDER_POLICY_NULL;
2598   }
2599 
2600   nsCOMPtr<nsISFVBareItem> value;
2601   rv = item->GetValue(getter_AddRefs(value));
2602   if (NS_FAILED(rv)) {
2603     return nsILoadInfo::EMBEDDER_POLICY_NULL;
2604   }
2605 
2606   nsCOMPtr<nsISFVToken> token = do_QueryInterface(value);
2607   if (!token) {
2608     return nsILoadInfo::EMBEDDER_POLICY_NULL;
2609   }
2610 
2611   nsAutoCString embedderPolicy;
2612   rv = token->GetValue(embedderPolicy);
2613   if (NS_FAILED(rv)) {
2614     return nsILoadInfo::EMBEDDER_POLICY_NULL;
2615   }
2616 
2617   return embedderPolicy.EqualsLiteral("require-corp")
2618              ? nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP
2619              : nsILoadInfo::EMBEDDER_POLICY_NULL;
2620 }
2621 
2622 /** Given the first (disposition) token from a Content-Disposition header,
2623  * tell whether it indicates the content is inline or attachment
2624  * @param aDispToken the disposition token from the content-disposition header
2625  */
NS_GetContentDispositionFromToken(const nsAString & aDispToken)2626 uint32_t NS_GetContentDispositionFromToken(const nsAString& aDispToken) {
2627   // RFC 2183, section 2.8 says that an unknown disposition
2628   // value should be treated as "attachment"
2629   // If all of these tests eval to false, then we have a content-disposition of
2630   // "attachment" or unknown
2631   if (aDispToken.IsEmpty() || aDispToken.LowerCaseEqualsLiteral("inline") ||
2632       // Broken sites just send
2633       // Content-Disposition: filename="file"
2634       // without a disposition token... screen those out.
2635       StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename")) {
2636     return nsIChannel::DISPOSITION_INLINE;
2637   }
2638 
2639   return nsIChannel::DISPOSITION_ATTACHMENT;
2640 }
2641 
NS_GetContentDispositionFromHeader(const nsACString & aHeader,nsIChannel * aChan)2642 uint32_t NS_GetContentDispositionFromHeader(const nsACString& aHeader,
2643                                             nsIChannel* aChan /* = nullptr */) {
2644   nsresult rv;
2645   nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
2646       do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
2647   if (NS_FAILED(rv)) return nsIChannel::DISPOSITION_ATTACHMENT;
2648 
2649   nsAutoString dispToken;
2650   rv = mimehdrpar->GetParameterHTTP(aHeader, "", ""_ns, true, nullptr,
2651                                     dispToken);
2652 
2653   if (NS_FAILED(rv)) {
2654     // special case (see bug 272541): empty disposition type handled as "inline"
2655     if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY) {
2656       return nsIChannel::DISPOSITION_INLINE;
2657     }
2658     return nsIChannel::DISPOSITION_ATTACHMENT;
2659   }
2660 
2661   return NS_GetContentDispositionFromToken(dispToken);
2662 }
2663 
NS_GetFilenameFromDisposition(nsAString & aFilename,const nsACString & aDisposition)2664 nsresult NS_GetFilenameFromDisposition(nsAString& aFilename,
2665                                        const nsACString& aDisposition) {
2666   aFilename.Truncate();
2667 
2668   nsresult rv;
2669   nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
2670       do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
2671   if (NS_FAILED(rv)) return rv;
2672 
2673   // Get the value of 'filename' parameter
2674   rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename", ""_ns, true,
2675                                     nullptr, aFilename);
2676 
2677   if (NS_FAILED(rv)) {
2678     aFilename.Truncate();
2679     return rv;
2680   }
2681 
2682   if (aFilename.IsEmpty()) return NS_ERROR_NOT_AVAILABLE;
2683 
2684   // Filename may still be percent-encoded. Fix:
2685   if (aFilename.FindChar('%') != -1) {
2686     nsCOMPtr<nsITextToSubURI> textToSubURI =
2687         do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
2688     if (NS_SUCCEEDED(rv)) {
2689       nsAutoString unescaped;
2690       textToSubURI->UnEscapeURIForUI(NS_ConvertUTF16toUTF8(aFilename),
2691                                      unescaped);
2692       aFilename.Assign(unescaped);
2693     }
2694   }
2695 
2696   return NS_OK;
2697 }
2698 
net_EnsurePSMInit()2699 void net_EnsurePSMInit() {
2700   if (XRE_IsSocketProcess()) {
2701     EnsureNSSInitializedChromeOrContent();
2702     return;
2703   }
2704 
2705   MOZ_ASSERT(XRE_IsParentProcess());
2706   MOZ_ASSERT(NS_IsMainThread());
2707 
2708   DebugOnly<bool> rv = EnsureNSSInitializedChromeOrContent();
2709   MOZ_ASSERT(rv);
2710 }
2711 
NS_IsAboutBlank(nsIURI * uri)2712 bool NS_IsAboutBlank(nsIURI* uri) {
2713   // GetSpec can be expensive for some URIs, so check the scheme first.
2714   if (!uri->SchemeIs("about")) {
2715     return false;
2716   }
2717 
2718   return uri->GetSpecOrDefault().EqualsLiteral("about:blank");
2719 }
2720 
NS_GenerateHostPort(const nsCString & host,int32_t port,nsACString & hostLine)2721 nsresult NS_GenerateHostPort(const nsCString& host, int32_t port,
2722                              nsACString& hostLine) {
2723   if (strchr(host.get(), ':')) {
2724     // host is an IPv6 address literal and must be encapsulated in []'s
2725     hostLine.Assign('[');
2726     // scope id is not needed for Host header.
2727     int scopeIdPos = host.FindChar('%');
2728     if (scopeIdPos == -1) {
2729       hostLine.Append(host);
2730     } else if (scopeIdPos > 0) {
2731       hostLine.Append(Substring(host, 0, scopeIdPos));
2732     } else {
2733       return NS_ERROR_MALFORMED_URI;
2734     }
2735     hostLine.Append(']');
2736   } else {
2737     hostLine.Assign(host);
2738   }
2739   if (port != -1) {
2740     hostLine.Append(':');
2741     hostLine.AppendInt(port);
2742   }
2743   return NS_OK;
2744 }
2745 
NS_SniffContent(const char * aSnifferType,nsIRequest * aRequest,const uint8_t * aData,uint32_t aLength,nsACString & aSniffedType)2746 void NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest,
2747                      const uint8_t* aData, uint32_t aLength,
2748                      nsACString& aSniffedType) {
2749   using ContentSnifferCache = nsCategoryCache<nsIContentSniffer>;
2750   extern ContentSnifferCache* gNetSniffers;
2751   extern ContentSnifferCache* gDataSniffers;
2752   extern ContentSnifferCache* gORBSniffers;
2753   extern ContentSnifferCache* gNetAndORBSniffers;
2754   ContentSnifferCache* cache = nullptr;
2755   if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) {
2756     if (!gNetSniffers) {
2757       gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY);
2758     }
2759     cache = gNetSniffers;
2760   } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) {
2761     if (!gDataSniffers) {
2762       gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY);
2763     }
2764     cache = gDataSniffers;
2765   } else if (!strcmp(aSnifferType, NS_ORB_SNIFFER_CATEGORY)) {
2766     if (!gORBSniffers) {
2767       gORBSniffers = new ContentSnifferCache(NS_ORB_SNIFFER_CATEGORY);
2768     }
2769     cache = gORBSniffers;
2770   } else if (!strcmp(aSnifferType, NS_CONTENT_AND_ORB_SNIFFER_CATEGORY)) {
2771     if (!gNetAndORBSniffers) {
2772       gNetAndORBSniffers =
2773           new ContentSnifferCache(NS_CONTENT_AND_ORB_SNIFFER_CATEGORY);
2774     }
2775     cache = gNetAndORBSniffers;
2776   } else {
2777     // Invalid content sniffer type was requested
2778     MOZ_ASSERT(false);
2779     return;
2780   }
2781 
2782   // In case XCTO nosniff was present, we could just skip sniffing here
2783   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
2784   if (channel) {
2785     nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
2786     if (loadInfo->GetSkipContentSniffing()) {
2787       /* Bug 1571742
2788        * We cannot skip snffing if the current MIME-Type might be a JSON.
2789        * The JSON-Viewer relies on its own sniffer to determine, if it can
2790        * render the page, so we need to make an exception if the Server provides
2791        * a application/ mime, as it might be json.
2792        */
2793       nsAutoCString currentContentType;
2794       channel->GetContentType(currentContentType);
2795       if (!StringBeginsWith(currentContentType, "application/"_ns)) {
2796         return;
2797       }
2798     }
2799   }
2800   nsCOMArray<nsIContentSniffer> sniffers;
2801   cache->GetEntries(sniffers);
2802   for (int32_t i = 0; i < sniffers.Count(); ++i) {
2803     nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength,
2804                                                       aSniffedType);
2805     if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
2806       return;
2807     }
2808   }
2809 
2810   aSniffedType.Truncate();
2811 }
2812 
NS_IsSrcdocChannel(nsIChannel * aChannel)2813 bool NS_IsSrcdocChannel(nsIChannel* aChannel) {
2814   bool isSrcdoc;
2815   nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
2816   if (isr) {
2817     isr->GetIsSrcdocChannel(&isSrcdoc);
2818     return isSrcdoc;
2819   }
2820   nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
2821   if (vsc) {
2822     nsresult rv = vsc->GetIsSrcdocChannel(&isSrcdoc);
2823     if (NS_SUCCEEDED(rv)) {
2824       return isSrcdoc;
2825     }
2826   }
2827   return false;
2828 }
2829 
NS_ShouldSecureUpgrade(nsIURI * aURI,nsILoadInfo * aLoadInfo,nsIPrincipal * aChannelResultPrincipal,bool aPrivateBrowsing,bool aAllowSTS,const OriginAttributes & aOriginAttributes,bool & aShouldUpgrade,std::function<void (bool,nsresult)> && aResultCallback,bool & aWillCallback)2830 nsresult NS_ShouldSecureUpgrade(
2831     nsIURI* aURI, nsILoadInfo* aLoadInfo, nsIPrincipal* aChannelResultPrincipal,
2832     bool aPrivateBrowsing, bool aAllowSTS,
2833     const OriginAttributes& aOriginAttributes, bool& aShouldUpgrade,
2834     std::function<void(bool, nsresult)>&& aResultCallback,
2835     bool& aWillCallback) {
2836   MOZ_ASSERT(XRE_IsParentProcess());
2837   if (!XRE_IsParentProcess()) {
2838     return NS_ERROR_NOT_AVAILABLE;
2839   }
2840 
2841   aWillCallback = false;
2842 
2843   // Even if we're in private browsing mode, we still enforce existing STS
2844   // data (it is read-only).
2845   // if the connection is not using SSL and either the exact host matches or
2846   // a superdomain wants to force HTTPS, do it.
2847   bool isHttps = aURI->SchemeIs("https");
2848 
2849   if (!isHttps &&
2850       !nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aURI)) {
2851     if (aLoadInfo) {
2852       // Check if the request can get upgraded with the HTTPS-Only mode
2853       if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, aLoadInfo) ||
2854           nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(aURI, aLoadInfo)) {
2855         aShouldUpgrade = true;
2856         return NS_OK;
2857       }
2858 
2859       // If any of the documents up the chain to the root document makes use of
2860       // the CSP directive 'upgrade-insecure-requests', then it's time to
2861       // fulfill the promise to CSP and mixed content blocking to upgrade the
2862       // channel from http to https.
2863       if (aLoadInfo->GetUpgradeInsecureRequests() ||
2864           aLoadInfo->GetBrowserUpgradeInsecureRequests()) {
2865         // let's log a message to the console that we are upgrading a request
2866         nsAutoCString scheme;
2867         aURI->GetScheme(scheme);
2868         // append the additional 's' for security to the scheme :-)
2869         scheme.AppendLiteral("s");
2870         NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
2871         NS_ConvertUTF8toUTF16 reportScheme(scheme);
2872 
2873         if (aLoadInfo->GetUpgradeInsecureRequests()) {
2874           AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
2875           uint32_t innerWindowId = aLoadInfo->GetInnerWindowID();
2876           CSP_LogLocalizedStr(
2877               "upgradeInsecureRequest", params,
2878               u""_ns,  // aSourceFile
2879               u""_ns,  // aScriptSample
2880               0,       // aLineNumber
2881               0,       // aColumnNumber
2882               nsIScriptError::warningFlag, "upgradeInsecureRequest"_ns,
2883               innerWindowId,
2884               !!aLoadInfo->GetOriginAttributes().mPrivateBrowsingId);
2885           Telemetry::AccumulateCategorical(
2886               Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::CSP);
2887         } else {
2888           AutoTArray<nsString, 2> params = {reportSpec, reportScheme};
2889 
2890           nsAutoString localizedMsg;
2891           nsContentUtils::FormatLocalizedString(
2892               nsContentUtils::eSECURITY_PROPERTIES, "MixedContentAutoUpgrade",
2893               params, localizedMsg);
2894 
2895           // Prepending ixed Content to the outgoing console message
2896           nsString message;
2897           message.AppendLiteral(u"Mixed Content: ");
2898           message.Append(localizedMsg);
2899 
2900           uint32_t innerWindowId = aLoadInfo->GetInnerWindowID();
2901           nsContentUtils::ReportToConsoleByWindowID(
2902               message, nsIScriptError::warningFlag, "Mixed Content Message"_ns,
2903               innerWindowId, aURI);
2904 
2905           // Set this flag so we know we'll upgrade because of
2906           // 'security.mixed_content.upgrade_display_content'.
2907           aLoadInfo->SetBrowserDidUpgradeInsecureRequests(true);
2908           Telemetry::AccumulateCategorical(
2909               Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::BrowserDisplay);
2910         }
2911 
2912         aShouldUpgrade = true;
2913         return NS_OK;
2914       }
2915     }
2916 
2917     // enforce Strict-Transport-Security
2918     nsISiteSecurityService* sss = gHttpHandler->GetSSService();
2919     NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
2920 
2921     bool isStsHost = false;
2922     uint32_t hstsSource = 0;
2923     uint32_t flags =
2924         aPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
2925 
2926     auto handleResultFunc = [aAllowSTS](bool aIsStsHost, uint32_t aHstsSource) {
2927       if (aIsStsHost) {
2928         LOG(("nsHttpChannel::Connect() STS permissions found\n"));
2929         if (aAllowSTS) {
2930           Telemetry::AccumulateCategorical(
2931               Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::STS);
2932           switch (aHstsSource) {
2933             case nsISiteSecurityService::SOURCE_PRELOAD_LIST:
2934               Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 0);
2935               break;
2936             case nsISiteSecurityService::SOURCE_ORGANIC_REQUEST:
2937               Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 1);
2938               break;
2939             case nsISiteSecurityService::SOURCE_UNKNOWN:
2940             default:
2941               // record this as an organic request
2942               Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 1);
2943               break;
2944           }
2945           return true;
2946         }
2947         Telemetry::AccumulateCategorical(
2948             Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::PrefBlockedSTS);
2949       } else {
2950         Telemetry::AccumulateCategorical(
2951             Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::NoReasonToUpgrade);
2952       }
2953       return false;
2954     };
2955 
2956     // Calling |IsSecureURI| before the storage is ready to read will
2957     // block the main thread. Once the storage is ready, we can call it
2958     // from main thread.
2959     static Atomic<bool, Relaxed> storageReady(false);
2960     if (!storageReady && gSocketTransportService && aResultCallback) {
2961       nsCOMPtr<nsIURI> uri = aURI;
2962       nsCOMPtr<nsISiteSecurityService> service = sss;
2963       nsresult rv = gSocketTransportService->Dispatch(
2964           NS_NewRunnableFunction(
2965               "net::NS_ShouldSecureUpgrade",
2966               [service{std::move(service)}, uri{std::move(uri)}, flags(flags),
2967                originAttributes(aOriginAttributes),
2968                handleResultFunc{std::move(handleResultFunc)},
2969                resultCallback{std::move(aResultCallback)}]() mutable {
2970                 uint32_t hstsSource = 0;
2971                 bool isStsHost = false;
2972                 nsresult rv =
2973                     service->IsSecureURI(uri, flags, originAttributes, nullptr,
2974                                          &hstsSource, &isStsHost);
2975 
2976                 // Successfully get the result from |IsSecureURI| implies that
2977                 // the storage is ready to read.
2978                 storageReady = NS_SUCCEEDED(rv);
2979                 bool shouldUpgrade = handleResultFunc(isStsHost, hstsSource);
2980 
2981                 NS_DispatchToMainThread(NS_NewRunnableFunction(
2982                     "net::NS_ShouldSecureUpgrade::ResultCallback",
2983                     [rv, shouldUpgrade,
2984                      resultCallback{std::move(resultCallback)}]() {
2985                       resultCallback(shouldUpgrade, rv);
2986                     }));
2987               }),
2988           NS_DISPATCH_NORMAL);
2989       aWillCallback = NS_SUCCEEDED(rv);
2990       return rv;
2991     }
2992 
2993     nsresult rv = sss->IsSecureURI(aURI, flags, aOriginAttributes, nullptr,
2994                                    &hstsSource, &isStsHost);
2995 
2996     // if the SSS check fails, it's likely because this load is on a
2997     // malformed URI or something else in the setup is wrong, so any error
2998     // should be reported.
2999     NS_ENSURE_SUCCESS(rv, rv);
3000 
3001     aShouldUpgrade = handleResultFunc(isStsHost, hstsSource);
3002     return NS_OK;
3003   }
3004 
3005   Telemetry::AccumulateCategorical(
3006       Telemetry::LABELS_HTTP_SCHEME_UPGRADE_TYPE::AlreadyHTTPS);
3007   aShouldUpgrade = false;
3008   return NS_OK;
3009 }
3010 
NS_GetSecureUpgradedURI(nsIURI * aURI,nsIURI ** aUpgradedURI)3011 nsresult NS_GetSecureUpgradedURI(nsIURI* aURI, nsIURI** aUpgradedURI) {
3012   NS_MutateURI mutator(aURI);
3013   mutator.SetScheme("https"_ns);  // Change the scheme to HTTPS:
3014 
3015   // Change the default port to 443:
3016   nsCOMPtr<nsIStandardURL> stdURL = do_QueryInterface(aURI);
3017   if (stdURL) {
3018     mutator.Apply(
3019         NS_MutatorMethod(&nsIStandardURLMutator::SetDefaultPort, 443, nullptr));
3020   } else {
3021     // If we don't have a nsStandardURL, fall back to using GetPort/SetPort.
3022     // XXXdholbert Is this function even called with a non-nsStandardURL arg,
3023     // in practice?
3024     NS_WARNING("Calling NS_GetSecureUpgradedURI for non nsStandardURL");
3025     int32_t oldPort = -1;
3026     nsresult rv = aURI->GetPort(&oldPort);
3027     if (NS_FAILED(rv)) return rv;
3028 
3029     // Keep any nonstandard ports so only the scheme is changed.
3030     // For example:
3031     //  http://foo.com:80 -> https://foo.com:443
3032     //  http://foo.com:81 -> https://foo.com:81
3033 
3034     if (oldPort == 80 || oldPort == -1) {
3035       mutator.SetPort(-1);
3036     } else {
3037       mutator.SetPort(oldPort);
3038     }
3039   }
3040 
3041   return mutator.Finalize(aUpgradedURI);
3042 }
3043 
NS_CompareLoadInfoAndLoadContext(nsIChannel * aChannel)3044 nsresult NS_CompareLoadInfoAndLoadContext(nsIChannel* aChannel) {
3045   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
3046 
3047   nsCOMPtr<nsILoadContext> loadContext;
3048   NS_QueryNotificationCallbacks(aChannel, loadContext);
3049   if (!loadContext) {
3050     return NS_OK;
3051   }
3052 
3053   // We try to skip about:newtab.
3054   // about:newtab will use SystemPrincipal to download thumbnails through
3055   // https:// and blob URLs.
3056   bool isAboutPage = false;
3057   nsINode* node = loadInfo->LoadingNode();
3058   if (node) {
3059     nsIURI* uri = node->OwnerDoc()->GetDocumentURI();
3060     isAboutPage = uri->SchemeIs("about");
3061   }
3062 
3063   if (isAboutPage) {
3064     return NS_OK;
3065   }
3066 
3067   // We skip the favicon loading here. The favicon loading might be
3068   // triggered by the XUL image. For that case, the loadContext will have
3069   // default originAttributes since the XUL image uses SystemPrincipal, but
3070   // the loadInfo will use originAttributes from the content. Thus, the
3071   // originAttributes between loadInfo and loadContext will be different.
3072   // That's why we have to skip the comparison for the favicon loading.
3073   if (loadInfo->GetLoadingPrincipal() &&
3074       loadInfo->GetLoadingPrincipal()->IsSystemPrincipal() &&
3075       loadInfo->InternalContentPolicyType() ==
3076           nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
3077     return NS_OK;
3078   }
3079 
3080   OriginAttributes originAttrsLoadInfo = loadInfo->GetOriginAttributes();
3081   OriginAttributes originAttrsLoadContext;
3082   loadContext->GetOriginAttributes(originAttrsLoadContext);
3083 
3084   LOG(
3085       ("NS_CompareLoadInfoAndLoadContext - loadInfo: %d, %d; "
3086        "loadContext: %d, %d. [channel=%p]",
3087        originAttrsLoadInfo.mUserContextId,
3088        originAttrsLoadInfo.mPrivateBrowsingId,
3089        originAttrsLoadContext.mUserContextId,
3090        originAttrsLoadContext.mPrivateBrowsingId, aChannel));
3091 
3092   MOZ_ASSERT(originAttrsLoadInfo.mUserContextId ==
3093                  originAttrsLoadContext.mUserContextId,
3094              "The value of mUserContextId in the loadContext and in the "
3095              "loadInfo are not the same!");
3096 
3097   MOZ_ASSERT(originAttrsLoadInfo.mPrivateBrowsingId ==
3098                  originAttrsLoadContext.mPrivateBrowsingId,
3099              "The value of mPrivateBrowsingId in the loadContext and in the "
3100              "loadInfo are not the same!");
3101 
3102   return NS_OK;
3103 }
3104 
NS_SetRequestBlockingReason(nsIChannel * channel,uint32_t reason)3105 nsresult NS_SetRequestBlockingReason(nsIChannel* channel, uint32_t reason) {
3106   NS_ENSURE_ARG(channel);
3107 
3108   nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
3109   return NS_SetRequestBlockingReason(loadInfo, reason);
3110 }
3111 
NS_SetRequestBlockingReason(nsILoadInfo * loadInfo,uint32_t reason)3112 nsresult NS_SetRequestBlockingReason(nsILoadInfo* loadInfo, uint32_t reason) {
3113   NS_ENSURE_ARG(loadInfo);
3114 
3115   return loadInfo->SetRequestBlockingReason(reason);
3116 }
3117 
NS_SetRequestBlockingReasonIfNull(nsILoadInfo * loadInfo,uint32_t reason)3118 nsresult NS_SetRequestBlockingReasonIfNull(nsILoadInfo* loadInfo,
3119                                            uint32_t reason) {
3120   NS_ENSURE_ARG(loadInfo);
3121 
3122   uint32_t existingReason;
3123   if (NS_SUCCEEDED(loadInfo->GetRequestBlockingReason(&existingReason)) &&
3124       existingReason != nsILoadInfo::BLOCKING_REASON_NONE) {
3125     return NS_OK;
3126   }
3127 
3128   return loadInfo->SetRequestBlockingReason(reason);
3129 }
3130 
NS_IsOffline()3131 bool NS_IsOffline() {
3132   bool offline = true;
3133   bool connectivity = true;
3134   nsCOMPtr<nsIIOService> ios = do_GetIOService();
3135   if (ios) {
3136     ios->GetOffline(&offline);
3137     ios->GetConnectivity(&connectivity);
3138   }
3139   return offline || !connectivity;
3140 }
3141 
3142 /**
3143  * This function returns true if this channel should be classified by
3144  * the URL Classifier, false otherwise.
3145  *
3146  * The idea of the algorithm to determine if a channel should be
3147  * classified is based on:
3148  * 1. Channels created by non-privileged code should be classified.
3149  * 2. Top-level document’s channels, if loaded by privileged code
3150  *    (system principal), should be classified.
3151  * 3. Any other channel, created by privileged code, is considered safe.
3152  *
3153  * A bad/hacked/corrupted safebrowsing database, plus a mistakenly
3154  * classified critical channel (this may result from a bug in the exemption
3155  * rules or incorrect information being passed into) can cause serious
3156  * problems. For example, if the updater channel is classified and blocked
3157  * by the Safe Browsing, Firefox can't update itself, and there is no way to
3158  * recover from that.
3159  *
3160  * So two safeguards are added to ensure critical channels are never
3161  * automatically classified either because there is a bug in the algorithm
3162  * or the data in loadinfo is wrong.
3163  * 1. beConservative, this is set by ServiceRequest and we treat
3164  *    channel created for ServiceRequest as critical channels.
3165  * 2. nsIChannel::LOAD_BYPASS_URL_CLASSIFIER, channel's opener can use this
3166  *    flag to enforce bypassing the URL classifier check.
3167  */
NS_ShouldClassifyChannel(nsIChannel * aChannel)3168 bool NS_ShouldClassifyChannel(nsIChannel* aChannel) {
3169   nsLoadFlags loadFlags;
3170   Unused << aChannel->GetLoadFlags(&loadFlags);
3171   //  If our load flags dictate that we must let this channel through without
3172   //  URL classification, obey that here without performing more checks.
3173   if (loadFlags & nsIChannel::LOAD_BYPASS_URL_CLASSIFIER) {
3174     return false;
3175   }
3176 
3177   nsCOMPtr<nsIHttpChannelInternal> httpChannel(do_QueryInterface(aChannel));
3178   if (httpChannel) {
3179     bool beConservative;
3180     nsresult rv = httpChannel->GetBeConservative(&beConservative);
3181 
3182     // beConservative flag, set by ServiceRequest to ensure channels that
3183     // fetch update use conservative TLS setting, are used here to identify
3184     // channels are critical to bypass classification. for channels don't
3185     // support beConservative, continue to apply the exemption rules.
3186     if (NS_SUCCEEDED(rv) && beConservative) {
3187       return false;
3188     }
3189   }
3190 
3191   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
3192   ExtContentPolicyType type = loadInfo->GetExternalContentPolicyType();
3193   // Skip classifying channel triggered by system unless it is a top-level
3194   // load.
3195   return !(loadInfo->TriggeringPrincipal()->IsSystemPrincipal() &&
3196            ExtContentPolicy::TYPE_DOCUMENT != type);
3197 }
3198 
3199 namespace mozilla {
3200 namespace net {
3201 
InScriptableRange(int64_t val)3202 bool InScriptableRange(int64_t val) {
3203   return (val <= kJS_MAX_SAFE_INTEGER) && (val >= kJS_MIN_SAFE_INTEGER);
3204 }
3205 
InScriptableRange(uint64_t val)3206 bool InScriptableRange(uint64_t val) { return val <= kJS_MAX_SAFE_UINTEGER; }
3207 
GetParameterHTTP(const nsACString & aHeaderVal,const char * aParamName,nsAString & aResult)3208 nsresult GetParameterHTTP(const nsACString& aHeaderVal, const char* aParamName,
3209                           nsAString& aResult) {
3210   return nsMIMEHeaderParamImpl::GetParameterHTTP(aHeaderVal, aParamName,
3211                                                  aResult);
3212 }
3213 
ChannelIsPost(nsIChannel * aChannel)3214 bool ChannelIsPost(nsIChannel* aChannel) {
3215   if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
3216     nsAutoCString method;
3217     Unused << httpChannel->GetRequestMethod(method);
3218     return method.EqualsLiteral("POST");
3219   }
3220   return false;
3221 }
3222 
SchemeIsHTTP(nsIURI * aURI)3223 bool SchemeIsHTTP(nsIURI* aURI) {
3224   MOZ_ASSERT(aURI);
3225   return aURI->SchemeIs("http");
3226 }
3227 
SchemeIsHTTPS(nsIURI * aURI)3228 bool SchemeIsHTTPS(nsIURI* aURI) {
3229   MOZ_ASSERT(aURI);
3230   return aURI->SchemeIs("https");
3231 }
3232 
SchemeIsJavascript(nsIURI * aURI)3233 bool SchemeIsJavascript(nsIURI* aURI) {
3234   MOZ_ASSERT(aURI);
3235   return aURI->SchemeIs("javascript");
3236 }
3237 
SchemeIsChrome(nsIURI * aURI)3238 bool SchemeIsChrome(nsIURI* aURI) {
3239   MOZ_ASSERT(aURI);
3240   return aURI->SchemeIs("chrome");
3241 }
3242 
SchemeIsAbout(nsIURI * aURI)3243 bool SchemeIsAbout(nsIURI* aURI) {
3244   MOZ_ASSERT(aURI);
3245   return aURI->SchemeIs("about");
3246 }
3247 
SchemeIsBlob(nsIURI * aURI)3248 bool SchemeIsBlob(nsIURI* aURI) {
3249   MOZ_ASSERT(aURI);
3250   return aURI->SchemeIs("blob");
3251 }
3252 
SchemeIsFile(nsIURI * aURI)3253 bool SchemeIsFile(nsIURI* aURI) {
3254   MOZ_ASSERT(aURI);
3255   return aURI->SchemeIs("file");
3256 }
3257 
SchemeIsData(nsIURI * aURI)3258 bool SchemeIsData(nsIURI* aURI) {
3259   MOZ_ASSERT(aURI);
3260   return aURI->SchemeIs("data");
3261 }
3262 
SchemeIsViewSource(nsIURI * aURI)3263 bool SchemeIsViewSource(nsIURI* aURI) {
3264   MOZ_ASSERT(aURI);
3265   return aURI->SchemeIs("view-source");
3266 }
3267 
SchemeIsResource(nsIURI * aURI)3268 bool SchemeIsResource(nsIURI* aURI) {
3269   MOZ_ASSERT(aURI);
3270   return aURI->SchemeIs("resource");
3271 }
3272 
SchemeIsFTP(nsIURI * aURI)3273 bool SchemeIsFTP(nsIURI* aURI) {
3274   MOZ_ASSERT(aURI);
3275   return aURI->SchemeIs("ftp");
3276 }
3277 
3278 }  // namespace net
3279 }  // namespace mozilla
3280 
NS_HasRootDomain(const nsACString & aInput,const nsACString & aHost,bool * aResult)3281 nsresult NS_HasRootDomain(const nsACString& aInput, const nsACString& aHost,
3282                           bool* aResult) {
3283   if (NS_WARN_IF(!aResult)) {
3284     return NS_ERROR_FAILURE;
3285   }
3286 
3287   *aResult = false;
3288 
3289   // If the strings are the same, we obviously have a match.
3290   if (aInput == aHost) {
3291     *aResult = true;
3292     return NS_OK;
3293   }
3294 
3295   // If aHost is not found, we know we do not have it as a root domain.
3296   int32_t index = nsAutoCString(aInput).Find(aHost.BeginReading());
3297   if (index == kNotFound) {
3298     return NS_OK;
3299   }
3300 
3301   // Otherwise, we have aHost as our root domain iff the index of aHost is
3302   // aHost.length subtracted from our length and (since we do not have an
3303   // exact match) the character before the index is a dot or slash.
3304   *aResult = index > 0 && (uint32_t)index == aInput.Length() - aHost.Length() &&
3305              (aInput[index - 1] == '.' || aInput[index - 1] == '/');
3306   return NS_OK;
3307 }
3308