Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=4 sw=2 sts=2 et cin: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
// HttpLog.h should generally be included first
#include "DecoderDoctorDiagnostics.h"
#include "HttpLog.h"
#include "nsNetUtil.h"
#include "mozilla/Atomics.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Components.h"
#include "mozilla/Encoding.h"
#include "mozilla/LoadContext.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "nsAboutProtocolUtils.h"
#include "nsBufferedStreams.h"
#include "nsCategoryCache.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsEscape.h"
#include "nsFileStreams.h"
#include "nsHashKeys.h"
#include "nsHttp.h"
#include "nsMimeTypes.h"
#include "nsIAuthPrompt.h"
#include "nsIAuthPrompt2.h"
#include "nsIAuthPromptAdapterFactory.h"
#include "nsIBufferedStreams.h"
#include "nsBufferedStreams.h"
#include "nsIChannelEventSink.h"
#include "nsIContentSniffer.h"
#include "mozilla/dom/Document.h"
#include "nsIDownloader.h"
#include "nsIFileProtocolHandler.h"
#include "nsIFileStreams.h"
#include "nsIFileURL.h"
#include "nsIIDNService.h"
#include "nsIInputStreamChannel.h"
#include "nsIInputStreamPump.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsIMIMEHeaderParam.h"
#include "nsINode.h"
#include "nsIObjectLoadingContent.h"
#include "nsPersistentProperties.h"
#include "nsIPrivateBrowsingChannel.h"
#include "nsIPropertyBag2.h"
#include "nsIProtocolProxyService.h"
#include "mozilla/net/RedirectChannelRegistrar.h"
#include "nsRequestObserverProxy.h"
#include "nsISensitiveInfoHiddenURI.h"
#include "nsISimpleStreamListener.h"
#include "nsISocketProvider.h"
#include "nsIStandardURL.h"
#include "nsIStreamLoader.h"
#include "nsIIncrementalStreamLoader.h"
#include "nsStringStream.h"
#include "nsSyncStreamListener.h"
#include "nsITextToSubURI.h"
#include "nsIURIWithSpecialOrigin.h"
#include "nsIViewSourceChannel.h"
#include "nsInterfaceRequestorAgg.h"
#include "nsINestedURI.h"
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/nsHTTPSOnlyUtils.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/net/HttpBaseChannel.h"
#include "nsIScriptError.h"
#include "nsISiteSecurityService.h"
#include "nsHttpHandler.h"
#include "nsNSSComponent.h"
#include "nsIRedirectHistoryEntry.h"
#include "nsICertStorage.h"
#include "nsICertOverrideService.h"
#include "nsQueryObject.h"
#include "mozIThirdPartyUtil.h"
#include "../mime/nsMIMEHeaderParamImpl.h"
#include "nsStandardURL.h"
#include "DefaultURI.h"
#include "nsChromeProtocolHandler.h"
#include "nsJSProtocolHandler.h"
#include "nsDataHandler.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "nsStreamUtils.h"
#include "nsSocketTransportService2.h"
#include "nsViewSourceHandler.h"
#include "nsJARURI.h"
#ifndef XP_IOS
# include "nsIconURI.h"
#endif
#include "nsAboutProtocolHandler.h"
#include "nsResProtocolHandler.h"
#include "mozilla/net/ExtensionProtocolHandler.h"
#include "mozilla/net/PageThumbProtocolHandler.h"
#include "mozilla/net/SFVService.h"
#include <limits>
#include "nsIXPConnect.h"
#include "nsParserConstants.h"
#include "nsCRT.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/MediaList.h"
#include "MediaContainerType.h"
#include "DecoderTraits.h"
#include "imgLoader.h"
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
# include "nsNewMailnewsURI.h"
#endif
using namespace mozilla;
using namespace mozilla::net;
using mozilla::dom::BlobURLProtocolHandler;
using mozilla::dom::ClientInfo;
using mozilla::dom::PerformanceStorage;
using mozilla::dom::ServiceWorkerDescriptor;
#define MAX_RECURSION_COUNT 50
already_AddRefed<nsIIOService> do_GetIOService(nsresult* error /* = 0 */) {
nsCOMPtr<nsIIOService> io;
io = mozilla::components::IO::Service();
if (error) *error = io ? NS_OK : NS_ERROR_FAILURE;
return io.forget();
}
nsresult NS_NewLocalFileInputStream(nsIInputStream** result, nsIFile* file,
int32_t ioFlags /* = -1 */,
int32_t perm /* = -1 */,
int32_t behaviorFlags /* = 0 */) {
nsresult rv;
nsCOMPtr<nsIFileInputStream> in =
do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = in->Init(file, ioFlags, perm, behaviorFlags);
if (NS_SUCCEEDED(rv)) in.forget(result);
}
return rv;
}
Result<nsCOMPtr<nsIInputStream>, nsresult> NS_NewLocalFileInputStream(
nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
int32_t behaviorFlags /* = 0 */) {
nsCOMPtr<nsIInputStream> stream;
const nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file,
ioFlags, perm, behaviorFlags);
if (NS_SUCCEEDED(rv)) {
return stream;
}
return Err(rv);
}
nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file,
int32_t ioFlags /* = -1 */,
int32_t perm /* = -1 */,
int32_t behaviorFlags /* = 0 */) {
nsresult rv;
nsCOMPtr<nsIFileOutputStream> out =
do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = out->Init(file, ioFlags, perm, behaviorFlags);
if (NS_SUCCEEDED(rv)) out.forget(result);
}
return rv;
}
Result<nsCOMPtr<nsIOutputStream>, nsresult> NS_NewLocalFileOutputStream(
nsIFile* file, int32_t ioFlags /* = -1 */, int32_t perm /* = -1 */,
int32_t behaviorFlags /* = 0 */) {
nsCOMPtr<nsIOutputStream> stream;
const nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), file,
ioFlags, perm, behaviorFlags);
if (NS_SUCCEEDED(rv)) {
return stream;
}
return Err(rv);
}
nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result,
const mozilla::ipc::FileDescriptor& fd) {
nsCOMPtr<nsIFileOutputStream> out;
nsFileOutputStream::Create(NS_GET_IID(nsIFileOutputStream),
getter_AddRefs(out));
nsresult rv =
static_cast<nsFileOutputStream*>(out.get())->InitWithFileDescriptor(fd);
if (NS_FAILED(rv)) {
return rv;
}
out.forget(result);
return NS_OK;
}
nsresult net_EnsureIOService(nsIIOService** ios, nsCOMPtr<nsIIOService>& grip) {
nsresult rv = NS_OK;
if (!*ios) {
grip = do_GetIOService(&rv);
*ios = grip;
}
return rv;
}
nsresult NS_NewFileURI(
nsIURI** result, nsIFile* spec,
nsIIOService*
ioService /* = nullptr */) // pass in nsIIOService to optimize callers
{
nsresult rv;
nsCOMPtr<nsIIOService> grip;
rv = net_EnsureIOService(&ioService, grip);
if (ioService) rv = ioService->NewFileURI(spec, result);
return rv;
}
nsresult NS_GetURIWithNewRef(nsIURI* aInput, const nsACString& aRef,
nsIURI** aOutput) {
MOZ_DIAGNOSTIC_ASSERT(aRef.IsEmpty() || aRef[0] == '#');
if (NS_WARN_IF(!aInput || !aOutput)) {
return NS_ERROR_INVALID_ARG;
}
bool hasRef;
nsresult rv = aInput->GetHasRef(&hasRef);
nsAutoCString ref;
if (NS_SUCCEEDED(rv)) {
rv = aInput->GetRef(ref);
}
// If the ref is already equal to the new ref, we do not need to do anything.
// Also, if the GetRef failed (it could return NS_ERROR_NOT_IMPLEMENTED)
// we can assume SetRef would fail as well, so returning the original
// URI is OK.
//
// Note that aRef contains the hash, but ref doesn't, so need to account for
// that in the equality check.
if (NS_FAILED(rv) || (!hasRef && aRef.IsEmpty()) ||
(!aRef.IsEmpty() && hasRef &&
Substring(aRef.Data() + 1, aRef.Length() - 1) == ref)) {
nsCOMPtr<nsIURI> uri = aInput;
uri.forget(aOutput);
return NS_OK;
}
return NS_MutateURI(aInput).SetRef(aRef).Finalize(aOutput);
}
nsresult NS_GetURIWithoutRef(nsIURI* aInput, nsIURI** aOutput) {
return NS_GetURIWithNewRef(aInput, ""_ns, aOutput);
}
nsresult NS_NewChannelInternal(
nsIChannel** outChannel, nsIURI* aUri, nsILoadInfo* aLoadInfo,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */) {
// NS_NewChannelInternal is mostly called for channel redirects. We should
// allow the creation of a channel even if the original channel did not have a
// loadinfo attached.
NS_ENSURE_ARG_POINTER(outChannel);
nsCOMPtr<nsIIOService> grip;
nsresult rv = net_EnsureIOService(&aIoService, grip);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> channel;
rv = aIoService->NewChannelFromURIWithLoadInfo(aUri, aLoadInfo,
getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, rv);
if (aLoadGroup) {
rv = channel->SetLoadGroup(aLoadGroup);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aCallbacks) {
rv = channel->SetNotificationCallbacks(aCallbacks);
NS_ENSURE_SUCCESS(rv, rv);
}
#ifdef DEBUG
nsLoadFlags channelLoadFlags = 0;
channel->GetLoadFlags(&channelLoadFlags);
// Will be removed when we remove LOAD_REPLACE altogether
// This check is trying to catch protocol handlers that still
// try to set the LOAD_REPLACE flag.
MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
#endif
if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
rv = channel->SetLoadFlags(aLoadFlags);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aPerformanceStorage) {
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
loadInfo->SetPerformanceStorage(aPerformanceStorage);
}
channel.forget(outChannel);
return NS_OK;
}
namespace {
void AssertLoadingPrincipalAndClientInfoMatch(
nsIPrincipal* aLoadingPrincipal, const ClientInfo& aLoadingClientInfo,
nsContentPolicyType aType) {
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
// Verify that the provided loading ClientInfo matches the loading
// principal. Unfortunately we can't just use nsIPrincipal::Equals() here
// because of some corner cases:
//
// 1. Worker debugger scripts want to use a system loading principal for
// worker scripts with a content principal. We exempt these from this
// check.
// 2. Null principals currently require exact object identity for
// nsIPrincipal::Equals() to return true. This doesn't work here because
// ClientInfo::GetPrincipal() uses PrincipalInfoToPrincipal() to allocate
// a new object. To work around this we compare the principal origin
// Equals().
// Allow worker debugger to load with a system principal.
if (aLoadingPrincipal->IsSystemPrincipal() &&
(aType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
aType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
aType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER ||
aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS ||
aType == nsIContentPolicy::TYPE_INTERNAL_WORKER_STATIC_MODULE)) {
return;
}
// Perform a fast comparison for most principal checks.
auto clientPrincipalOrErr(aLoadingClientInfo.GetPrincipal());
if (clientPrincipalOrErr.isOk()) {
nsCOMPtr<nsIPrincipal> clientPrincipal = clientPrincipalOrErr.unwrap();
if (aLoadingPrincipal->Equals(clientPrincipal)) {
return;
}
// Fall back to a slower origin equality test to support null principals.
nsAutoCString loadingOriginNoSuffix;
MOZ_ALWAYS_SUCCEEDS(
aLoadingPrincipal->GetOriginNoSuffix(loadingOriginNoSuffix));
nsAutoCString clientOriginNoSuffix;
MOZ_ALWAYS_SUCCEEDS(
clientPrincipal->GetOriginNoSuffix(clientOriginNoSuffix));
// The client principal will have the partitionKey set if it's in a third
// party context, but the loading principal won't. So, we ignore he
// partitionKey when doing the verification here.
MOZ_DIAGNOSTIC_ASSERT(loadingOriginNoSuffix == clientOriginNoSuffix);
MOZ_DIAGNOSTIC_ASSERT(
aLoadingPrincipal->OriginAttributesRef().EqualsIgnoringPartitionKey(
clientPrincipal->OriginAttributesRef()));
}
#endif
}
} // namespace
nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
nsIPrincipal* aLoadingPrincipal,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */,
uint32_t aSandboxFlags /* = 0 */,
bool aSkipCheckForBrokenURLOrZeroSized /* = false */) {
return NS_NewChannelInternal(
outChannel, aUri,
nullptr, // aLoadingNode,
aLoadingPrincipal,
nullptr, // aTriggeringPrincipal
Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
aContentPolicyType, aCookieJarSettings, aPerformanceStorage, aLoadGroup,
aCallbacks, aLoadFlags, aIoService, aSandboxFlags,
aSkipCheckForBrokenURLOrZeroSized);
}
nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
nsIPrincipal* aLoadingPrincipal,
const ClientInfo& aLoadingClientInfo,
const Maybe<ServiceWorkerDescriptor>& aController,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */,
uint32_t aSandboxFlags /* = 0 */,
bool aSkipCheckForBrokenURLOrZeroSized /* = false */) {
AssertLoadingPrincipalAndClientInfoMatch(
aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
Maybe<ClientInfo> loadingClientInfo;
loadingClientInfo.emplace(aLoadingClientInfo);
return NS_NewChannelInternal(
outChannel, aUri,
nullptr, // aLoadingNode,
aLoadingPrincipal,
nullptr, // aTriggeringPrincipal
loadingClientInfo, aController, aSecurityFlags, aContentPolicyType,
aCookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks,
aLoadFlags, aIoService, aSandboxFlags, aSkipCheckForBrokenURLOrZeroSized);
}
nsresult 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 /* = nullptr */,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */, uint32_t aSandboxFlags /* = 0 */,
bool aSkipCheckForBrokenURLOrZeroSized /* = false */) {
NS_ENSURE_ARG_POINTER(outChannel);
nsCOMPtr<nsIIOService> grip;
nsresult rv = net_EnsureIOService(&aIoService, grip);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> channel;
rv = aIoService->NewChannelFromURIWithClientAndController(
aUri, aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal,
aLoadingClientInfo, aController, aSecurityFlags, aContentPolicyType,
aSandboxFlags, aSkipCheckForBrokenURLOrZeroSized,
getter_AddRefs(channel));
if (NS_FAILED(rv)) {
return rv;
}
if (aLoadGroup) {
rv = channel->SetLoadGroup(aLoadGroup);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aCallbacks) {
rv = channel->SetNotificationCallbacks(aCallbacks);
NS_ENSURE_SUCCESS(rv, rv);
}
#ifdef DEBUG
nsLoadFlags channelLoadFlags = 0;
channel->GetLoadFlags(&channelLoadFlags);
// Will be removed when we remove LOAD_REPLACE altogether
// This check is trying to catch protocol handlers that still
// try to set the LOAD_REPLACE flag.
MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
#endif
if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
rv = channel->SetLoadFlags(aLoadFlags);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aPerformanceStorage || aCookieJarSettings) {
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
if (aPerformanceStorage) {
loadInfo->SetPerformanceStorage(aPerformanceStorage);
}
if (aCookieJarSettings) {
loadInfo->SetCookieJarSettings(aCookieJarSettings);
}
}
channel.forget(outChannel);
return NS_OK;
}
nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
NS_NewChannelWithTriggeringPrincipal(
nsIChannel** outChannel, nsIURI* aUri, nsINode* aLoadingNode,
nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */) {
MOZ_ASSERT(aLoadingNode);
NS_ASSERTION(aTriggeringPrincipal,
"Can not create channel without a triggering Principal!");
return NS_NewChannelInternal(
outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
aTriggeringPrincipal, Maybe<ClientInfo>(),
Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
aLoadingNode->OwnerDoc()->CookieJarSettings(), aPerformanceStorage,
aLoadGroup, aCallbacks, aLoadFlags, aIoService);
}
// See NS_NewChannelInternal for usage and argument description
nsresult NS_NewChannelWithTriggeringPrincipal(
nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */) {
NS_ASSERTION(aLoadingPrincipal,
"Can not create channel without a loading Principal!");
return NS_NewChannelInternal(
outChannel, aUri,
nullptr, // aLoadingNode
aLoadingPrincipal, aTriggeringPrincipal, Maybe<ClientInfo>(),
Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType,
aCookieJarSettings, aPerformanceStorage, aLoadGroup, aCallbacks,
aLoadFlags, aIoService);
}
// See NS_NewChannelInternal for usage and argument description
nsresult NS_NewChannelWithTriggeringPrincipal(
nsIChannel** outChannel, nsIURI* aUri, nsIPrincipal* aLoadingPrincipal,
nsIPrincipal* aTriggeringPrincipal, const ClientInfo& aLoadingClientInfo,
const Maybe<ServiceWorkerDescriptor>& aController,
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
nsICookieJarSettings* aCookieJarSettings /* = nullptr */,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */) {
AssertLoadingPrincipalAndClientInfoMatch(
aLoadingPrincipal, aLoadingClientInfo, aContentPolicyType);
Maybe<ClientInfo> loadingClientInfo;
loadingClientInfo.emplace(aLoadingClientInfo);
return NS_NewChannelInternal(
outChannel, aUri,
nullptr, // aLoadingNode
aLoadingPrincipal, aTriggeringPrincipal, loadingClientInfo, aController,
aSecurityFlags, aContentPolicyType, aCookieJarSettings,
aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService);
}
nsresult NS_NewChannel(nsIChannel** outChannel, nsIURI* aUri,
nsINode* aLoadingNode, nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
PerformanceStorage* aPerformanceStorage /* = nullptr */,
nsILoadGroup* aLoadGroup /* = nullptr */,
nsIInterfaceRequestor* aCallbacks /* = nullptr */,
nsLoadFlags aLoadFlags /* = nsIRequest::LOAD_NORMAL */,
nsIIOService* aIoService /* = nullptr */,
uint32_t aSandboxFlags /* = 0 */,
bool aSkipCheckForBrokenURLOrZeroSized /* = false */) {
NS_ASSERTION(aLoadingNode, "Can not create channel without a loading Node!");
return NS_NewChannelInternal(
outChannel, aUri, aLoadingNode, aLoadingNode->NodePrincipal(),
nullptr, // aTriggeringPrincipal
Maybe<ClientInfo>(), Maybe<ServiceWorkerDescriptor>(), aSecurityFlags,
aContentPolicyType, aLoadingNode->OwnerDoc()->CookieJarSettings(),
aPerformanceStorage, aLoadGroup, aCallbacks, aLoadFlags, aIoService,
aSandboxFlags, aSkipCheckForBrokenURLOrZeroSized);
}
nsresult NS_GetIsDocumentChannel(nsIChannel* aChannel, bool* aIsDocument) {
// Check if this channel is going to be used to create a document. If it has
// LOAD_DOCUMENT_URI set it is trivially creating a document. If
// LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a
// document, depending on its MIME type.
if (!aChannel || !aIsDocument) {
return NS_ERROR_NULL_POINTER;
}
*aIsDocument = false;
nsLoadFlags loadFlags;
nsresult rv = aChannel->GetLoadFlags(&loadFlags);
if (NS_FAILED(rv)) {
return rv;
}
if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
*aIsDocument = true;
return NS_OK;
}
if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) {
*aIsDocument = false;
return NS_OK;
}
nsAutoCString mimeType;
rv = aChannel->GetContentType(mimeType);
if (NS_FAILED(rv)) {
return rv;
}
if (nsContentUtils::HtmlObjectContentTypeForMIMEType(mimeType) ==
nsIObjectLoadingContent::TYPE_DOCUMENT) {
*aIsDocument = true;
return NS_OK;
}
*aIsDocument = false;
return NS_OK;
}
nsresult NS_MakeAbsoluteURI(nsACString& result, const nsACString& spec,
nsIURI* baseURI) {
nsresult rv;
if (!baseURI) {
NS_WARNING("It doesn't make sense to not supply a base URI");
result = spec;
rv = NS_OK;
} else if (spec.IsEmpty()) {
rv = baseURI->GetSpec(result);
} else {
rv = baseURI->Resolve(spec, result);
}
return rv;
}
nsresult NS_MakeAbsoluteURI(char** result, const char* spec, nsIURI* baseURI) {
nsresult rv;
nsAutoCString resultBuf;
rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
if (NS_SUCCEEDED(rv)) {
*result = ToNewCString(resultBuf, mozilla::fallible);
if (!*result) rv = NS_ERROR_OUT_OF_MEMORY;
}
return rv;
}
nsresult NS_MakeAbsoluteURI(nsAString& result, const nsAString& spec,
nsIURI* baseURI) {
nsresult rv;
if (!baseURI) {
NS_WARNING("It doesn't make sense to not supply a base URI");
result = spec;
rv = NS_OK;
} else {
nsAutoCString resultBuf;
if (spec.IsEmpty()) {
rv = baseURI->GetSpec(resultBuf);
} else {
rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
}
if (NS_SUCCEEDED(rv)) CopyUTF8toUTF16(resultBuf, result);
}
return rv;
}
int32_t NS_GetDefaultPort(const char* scheme,
nsIIOService* ioService /* = nullptr */) {
nsresult rv;
// Getting the default port through the protocol handler previously had a lot
// of XPCOM overhead involved. We optimize the protocols that matter for Web
// pages (HTTP and HTTPS) by hardcoding their default ports here.
//
// XXX: This might not be necessary for performance anymore.
if (strncmp(scheme, "http", 4) == 0) {
if (scheme[4] == 's' && scheme[5] == '\0') {
return 443;
}
if (scheme[4] == '\0') {
return 80;
}
}
nsCOMPtr<nsIIOService> grip;
net_EnsureIOService(&ioService, grip);
if (!ioService) return -1;
int32_t port;
rv = ioService->GetDefaultPort(scheme, &port);
return NS_SUCCEEDED(rv) ? port : -1;
}
int32_t NS_GetRealPort(nsIURI* aURI) {
int32_t port;
nsresult rv = aURI->GetPort(&port);
if (NS_FAILED(rv)) return -1;
if (port != -1) return port; // explicitly specified
// Otherwise, we have to get the default port from the protocol handler
// Need the scheme first
nsAutoCString scheme;
rv = aURI->GetScheme(scheme);
if (NS_FAILED(rv)) return -1;
return NS_GetDefaultPort(scheme.get());
}
nsresult NS_NewInputStreamChannelInternal(
nsIChannel** outChannel, nsIURI* aUri,
already_AddRefed<nsIInputStream> aStream, const nsACString& aContentType,
const nsACString& aContentCharset, nsILoadInfo* aLoadInfo) {
nsresult rv;
nsCOMPtr<nsIInputStreamChannel> isc =
do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = isc->SetURI(aUri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
rv = isc->SetContentStream(stream);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> channel = do_QueryInterface(isc, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (!aContentType.IsEmpty()) {
rv = channel->SetContentType(aContentType);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!aContentCharset.IsEmpty()) {
rv = channel->SetContentCharset(aContentCharset);
NS_ENSURE_SUCCESS(rv, rv);
}
MOZ_ASSERT(aLoadInfo, "need a loadinfo to create a inputstreamchannel");
channel->SetLoadInfo(aLoadInfo);
// If we're sandboxed, make sure to clear any owner the channel
// might already have.
if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) {
channel->SetOwner(nullptr);
}
channel.forget(outChannel);
return NS_OK;
}
nsresult 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) {
nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
aContentPolicyType);
if (!loadInfo) {
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
aContentType, aContentCharset,
loadInfo);
}
nsresult NS_NewInputStreamChannel(
nsIChannel** outChannel, nsIURI* aUri,
already_AddRefed<nsIInputStream> aStream, nsIPrincipal* aLoadingPrincipal,
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
const nsACString& aContentType /* = ""_ns */,
const nsACString& aContentCharset /* = ""_ns */) {
nsCOMPtr<nsIInputStream> stream = aStream;
return NS_NewInputStreamChannelInternal(outChannel, aUri, stream.forget(),
aContentType, aContentCharset,
nullptr, // aLoadingNode
aLoadingPrincipal,
nullptr, // aTriggeringPrincipal
aSecurityFlags, aContentPolicyType);
}
nsresult NS_NewInputStreamChannelInternal(nsIChannel** outChannel, nsIURI* aUri,
const nsAString& aData,
const nsACString& aContentType,
nsILoadInfo* aLoadInfo,
bool aIsSrcdocChannel /* = false */) {
nsresult rv;
nsCOMPtr<nsIStringInputStream> stream;
stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t len;
char* utf8Bytes = ToNewUTF8String(aData, &len);
rv = stream->AdoptData(utf8Bytes, len);
nsCOMPtr<nsIChannel> channel;
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aUri,
stream.forget(), aContentType,
"UTF-8"_ns, aLoadInfo);
NS_ENSURE_SUCCESS(rv, rv);
if (aIsSrcdocChannel) {
nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(channel);
NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
inStrmChan->SetSrcdocData(aData);
}
channel.forget(outChannel);
return NS_OK;
}
nsresult NS_NewInputStreamChannelInternal(
nsIChannel** outChannel, nsIURI* aUri, const nsAString& aData,
const nsACString& aContentType, nsINode* aLoadingNode,
nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal,
nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType,
bool aIsSrcdocChannel /* = false */) {
nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::net::LoadInfo(
aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
aContentPolicyType);
return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
loadInfo, aIsSrcdocChannel);
}
nsresult NS_NewInputStreamChannel(nsIChannel** outChannel, nsIURI* aUri,
const nsAString& aData,
const nsACString& aContentType,
nsIPrincipal* aLoadingPrincipal,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
bool aIsSrcdocChannel /* = false */) {
return NS_NewInputStreamChannelInternal(outChannel, aUri, aData, aContentType,
nullptr, // aLoadingNode
aLoadingPrincipal,
nullptr, // aTriggeringPrincipal
aSecurityFlags, aContentPolicyType,
aIsSrcdocChannel);
}
nsresult NS_NewInputStreamPump(
nsIInputStreamPump** aResult, already_AddRefed<nsIInputStream> aStream,
uint32_t aSegsize /* = 0 */, uint32_t aSegcount /* = 0 */,
bool aCloseWhenDone /* = false */,
nsISerialEventTarget* aMainThreadTarget /* = nullptr */) {
nsCOMPtr<nsIInputStream> stream = std::move(aStream);
nsresult rv;
nsCOMPtr<nsIInputStreamPump> pump =
do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = pump->Init(stream, aSegsize, aSegcount, aCloseWhenDone,
aMainThreadTarget);
if (NS_SUCCEEDED(rv)) {
*aResult = nullptr;
pump.swap(*aResult);
}
}
return rv;
}
nsresult NS_NewLoadGroup(nsILoadGroup** result, nsIRequestObserver* obs) {
nsresult rv;
nsCOMPtr<nsILoadGroup> group =
do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = group->SetGroupObserver(obs);
if (NS_SUCCEEDED(rv)) {
*result = nullptr;
group.swap(*result);
}
}
return rv;
}
bool NS_IsReasonableHTTPHeaderValue(const nsACString& aValue) {
return mozilla::net::nsHttp::IsReasonableHeaderValue(aValue);
}
bool NS_IsValidHTTPToken(const nsACString& aToken) {
return mozilla::net::nsHttp::IsValidToken(aToken);
}
void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) {
mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest);
}
nsresult NS_NewLoadGroup(nsILoadGroup** aResult, nsIPrincipal* aPrincipal) {
using mozilla::LoadContext;
nsresult rv;
nsCOMPtr<nsILoadGroup> group =
do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<LoadContext> loadContext = new LoadContext(aPrincipal);
rv = group->SetNotificationCallbacks(loadContext);
NS_ENSURE_SUCCESS(rv, rv);
group.forget(aResult);