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