netwerk/base/public/nsNetUtil.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim:set ts=4 sw=4 sts=4 et cin: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef nsNetUtil_h__
     8 #define nsNetUtil_h__
    10 #include "nsError.h"
    11 #include "nsNetCID.h"
    12 #include "nsStringGlue.h"
    13 #include "nsMemory.h"
    14 #include "nsCOMPtr.h"
    15 #include "prio.h" // for read/write flags, permissions, etc.
    16 #include "nsHashKeys.h"
    18 #include "plstr.h"
    19 #include "nsIURI.h"
    20 #include "nsIStandardURL.h"
    21 #include "nsIURLParser.h"
    22 #include "nsIUUIDGenerator.h"
    23 #include "nsIInputStream.h"
    24 #include "nsIOutputStream.h"
    25 #include "nsISafeOutputStream.h"
    26 #include "nsIStreamListener.h"
    27 #include "nsIRequestObserverProxy.h"
    28 #include "nsISimpleStreamListener.h"
    29 #include "nsILoadGroup.h"
    30 #include "nsIInterfaceRequestor.h"
    31 #include "nsIInterfaceRequestorUtils.h"
    32 #include "nsIIOService.h"
    33 #include "nsIServiceManager.h"
    34 #include "nsIChannel.h"
    35 #include "nsChannelProperties.h"
    36 #include "nsIInputStreamChannel.h"
    37 #include "nsITransport.h"
    38 #include "nsIStreamTransportService.h"
    39 #include "nsIHttpChannel.h"
    40 #include "nsIDownloader.h"
    41 #include "nsIStreamLoader.h"
    42 #include "nsIUnicharStreamLoader.h"
    43 #include "nsIPipe.h"
    44 #include "nsIProtocolHandler.h"
    45 #include "nsIFileProtocolHandler.h"
    46 #include "nsIStringStream.h"
    47 #include "nsIFile.h"
    48 #include "nsIFileStreams.h"
    49 #include "nsIFileURL.h"
    50 #include "nsIProtocolProxyService.h"
    51 #include "nsIProxyInfo.h"
    52 #include "nsIFileStreams.h"
    53 #include "nsIBufferedStreams.h"
    54 #include "nsIInputStreamPump.h"
    55 #include "nsIAsyncStreamCopier.h"
    56 #include "nsIPersistentProperties2.h"
    57 #include "nsISyncStreamListener.h"
    58 #include "nsInterfaceRequestorAgg.h"
    59 #include "nsINetUtil.h"
    60 #include "nsIURIWithPrincipal.h"
    61 #include "nsIAuthPrompt.h"
    62 #include "nsIAuthPrompt2.h"
    63 #include "nsIAuthPromptAdapterFactory.h"
    64 #include "nsComponentManagerUtils.h"
    65 #include "nsServiceManagerUtils.h"
    66 #include "nsINestedURI.h"
    67 #include "nsIMutable.h"
    68 #include "nsIPropertyBag2.h"
    69 #include "nsIWritablePropertyBag2.h"
    70 #include "nsIIDNService.h"
    71 #include "nsIChannelEventSink.h"
    72 #include "nsIChannelPolicy.h"
    73 #include "nsISocketProviderService.h"
    74 #include "nsISocketProvider.h"
    75 #include "nsIRedirectChannelRegistrar.h"
    76 #include "nsIMIMEHeaderParam.h"
    77 #include "nsILoadContext.h"
    78 #include "mozilla/Services.h"
    79 #include "nsIPrivateBrowsingChannel.h"
    80 #include "mozIApplicationClearPrivateDataParams.h"
    81 #include "nsIOfflineCacheUpdate.h"
    82 #include "nsIContentSniffer.h"
    83 #include "nsCategoryCache.h"
    84 #include "nsStringStream.h"
    85 #include "nsIViewSourceChannel.h"
    87 #include <limits>
    89 #ifdef MOZILLA_INTERNAL_API
    91 #include "nsReadableUtils.h"
    93 inline already_AddRefed<nsIIOService>
    94 do_GetIOService(nsresult* error = 0)
    95 {
    96     nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
    97     if (error)
    98         *error = io ? NS_OK : NS_ERROR_FAILURE;
    99     return io.forget();
   100 }
   102 inline already_AddRefed<nsINetUtil>
   103 do_GetNetUtil(nsresult *error = 0) 
   104 {
   105     nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
   106     nsCOMPtr<nsINetUtil> util;
   107     if (io)
   108         util = do_QueryInterface(io);
   110     if (error)
   111         *error = !!util ? NS_OK : NS_ERROR_FAILURE;
   112     return util.forget();
   113 }
   114 #else
   115 // Helper, to simplify getting the I/O service.
   116 inline const nsGetServiceByContractIDWithError
   117 do_GetIOService(nsresult* error = 0)
   118 {
   119     return nsGetServiceByContractIDWithError(NS_IOSERVICE_CONTRACTID, error);
   120 }
   122 // An alias to do_GetIOService
   123 inline const nsGetServiceByContractIDWithError
   124 do_GetNetUtil(nsresult* error = 0)
   125 {
   126     return do_GetIOService(error);
   127 }
   128 #endif
   130 // private little helper function... don't call this directly!
   131 inline nsresult
   132 net_EnsureIOService(nsIIOService **ios, nsCOMPtr<nsIIOService> &grip)
   133 {
   134     nsresult rv = NS_OK;
   135     if (!*ios) {
   136         grip = do_GetIOService(&rv);
   137         *ios = grip;
   138     }
   139     return rv;
   140 }
   142 inline nsresult
   143 NS_NewURI(nsIURI **result, 
   144           const nsACString &spec, 
   145           const char *charset = nullptr,
   146           nsIURI *baseURI = nullptr,
   147           nsIIOService *ioService = nullptr)     // pass in nsIIOService to optimize callers
   148 {
   149     nsresult rv;
   150     nsCOMPtr<nsIIOService> grip;
   151     rv = net_EnsureIOService(&ioService, grip);
   152     if (ioService)
   153         rv = ioService->NewURI(spec, charset, baseURI, result);
   154     return rv; 
   155 }
   157 inline nsresult
   158 NS_NewURI(nsIURI* *result, 
   159           const nsAString& spec, 
   160           const char *charset = nullptr,
   161           nsIURI* baseURI = nullptr,
   162           nsIIOService* ioService = nullptr)     // pass in nsIIOService to optimize callers
   163 {
   164     return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), charset, baseURI, ioService);
   165 }
   167 inline nsresult
   168 NS_NewURI(nsIURI* *result, 
   169           const char *spec,
   170           nsIURI* baseURI = nullptr,
   171           nsIIOService* ioService = nullptr)     // pass in nsIIOService to optimize callers
   172 {
   173     return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI, ioService);
   174 }
   176 inline nsresult
   177 NS_NewFileURI(nsIURI* *result, 
   178               nsIFile* spec, 
   179               nsIIOService* ioService = nullptr)     // pass in nsIIOService to optimize callers
   180 {
   181     nsresult rv;
   182     nsCOMPtr<nsIIOService> grip;
   183     rv = net_EnsureIOService(&ioService, grip);
   184     if (ioService)
   185         rv = ioService->NewFileURI(spec, result);
   186     return rv;
   187 }
   189 inline nsresult
   190 NS_NewChannel(nsIChannel           **result,
   191               nsIURI                *uri,
   192               nsIIOService          *ioService = nullptr,    // pass in nsIIOService to optimize callers
   193               nsILoadGroup          *loadGroup = nullptr,
   194               nsIInterfaceRequestor *callbacks = nullptr,
   195               uint32_t               loadFlags = nsIRequest::LOAD_NORMAL,
   196               nsIChannelPolicy      *channelPolicy = nullptr)
   197 {
   198     nsresult rv;
   199     nsCOMPtr<nsIIOService> grip;
   200     rv = net_EnsureIOService(&ioService, grip);
   201     if (ioService) {
   202         nsCOMPtr<nsIChannel> chan;
   203         rv = ioService->NewChannelFromURI(uri, getter_AddRefs(chan));
   204         if (NS_SUCCEEDED(rv)) {
   205             if (loadGroup) {
   206                 rv = chan->SetLoadGroup(loadGroup);
   207             }
   208             if (callbacks) {
   209                 nsresult tmp = chan->SetNotificationCallbacks(callbacks);
   210                 if (NS_FAILED(tmp)) {
   211                     rv = tmp;
   212                 }
   213             }
   214             if (loadFlags != nsIRequest::LOAD_NORMAL) {
   215                 // Retain the LOAD_REPLACE load flag if set.
   216                 nsLoadFlags normalLoadFlags = 0;
   217                 chan->GetLoadFlags(&normalLoadFlags);
   218                 nsresult tmp = chan->SetLoadFlags(loadFlags |
   219                                                   (normalLoadFlags &
   220                                                    nsIChannel::LOAD_REPLACE));
   221                 if (NS_FAILED(tmp)) {
   222                     rv = tmp;
   223                 }
   224             }
   225             if (channelPolicy) {
   226                 nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(chan);
   227                 if (props) {
   228                     props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
   229                                                   channelPolicy);
   230                 }
   231             }
   232             if (NS_SUCCEEDED(rv))
   233                 chan.forget(result);
   234         }
   235     }
   236     return rv;
   237 }
   239 // Use this function with CAUTION. It creates a stream that blocks when you
   240 // Read() from it and blocking the UI thread is a bad idea. If you don't want
   241 // to implement a full blown asynchronous consumer (via nsIStreamListener) look
   242 // at nsIStreamLoader instead.
   243 inline nsresult
   244 NS_OpenURI(nsIInputStream       **result,
   245            nsIURI                *uri,
   246            nsIIOService          *ioService = nullptr,     // pass in nsIIOService to optimize callers
   247            nsILoadGroup          *loadGroup = nullptr,
   248            nsIInterfaceRequestor *callbacks = nullptr,
   249            uint32_t               loadFlags = nsIRequest::LOAD_NORMAL,
   250            nsIChannel           **channelOut = nullptr)
   251 {
   252     nsresult rv;
   253     nsCOMPtr<nsIChannel> channel;
   254     rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
   255                        loadGroup, callbacks, loadFlags);
   256     if (NS_SUCCEEDED(rv)) {
   257         nsIInputStream *stream;
   258         rv = channel->Open(&stream);
   259         if (NS_SUCCEEDED(rv)) {
   260             *result = stream;
   261             if (channelOut) {
   262                 *channelOut = nullptr;
   263                 channel.swap(*channelOut);
   264             }
   265         }
   266     }
   267     return rv;
   268 }
   270 inline nsresult
   271 NS_OpenURI(nsIStreamListener     *listener, 
   272            nsISupports           *context, 
   273            nsIURI                *uri,
   274            nsIIOService          *ioService = nullptr,     // pass in nsIIOService to optimize callers
   275            nsILoadGroup          *loadGroup = nullptr,
   276            nsIInterfaceRequestor *callbacks = nullptr,
   277            uint32_t               loadFlags = nsIRequest::LOAD_NORMAL)
   278 {
   279     nsresult rv;
   280     nsCOMPtr<nsIChannel> channel;
   281     rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService,
   282                        loadGroup, callbacks, loadFlags);
   283     if (NS_SUCCEEDED(rv))
   284         rv = channel->AsyncOpen(listener, context);
   285     return rv;
   286 }
   288 inline nsresult
   289 NS_MakeAbsoluteURI(nsACString       &result,
   290                    const nsACString &spec, 
   291                    nsIURI           *baseURI)
   292 {
   293     nsresult rv;
   294     if (!baseURI) {
   295         NS_WARNING("It doesn't make sense to not supply a base URI");
   296         result = spec;
   297         rv = NS_OK;
   298     }
   299     else if (spec.IsEmpty())
   300         rv = baseURI->GetSpec(result);
   301     else
   302         rv = baseURI->Resolve(spec, result);
   303     return rv;
   304 }
   306 inline nsresult
   307 NS_MakeAbsoluteURI(char        **result,
   308                    const char   *spec, 
   309                    nsIURI       *baseURI)
   310 {
   311     nsresult rv;
   312     nsAutoCString resultBuf;
   313     rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI);
   314     if (NS_SUCCEEDED(rv)) {
   315         *result = ToNewCString(resultBuf);
   316         if (!*result)
   317             rv = NS_ERROR_OUT_OF_MEMORY;
   318     }
   319     return rv;
   320 }
   322 inline nsresult
   323 NS_MakeAbsoluteURI(nsAString       &result,
   324                    const nsAString &spec, 
   325                    nsIURI          *baseURI)
   326 {
   327     nsresult rv;
   328     if (!baseURI) {
   329         NS_WARNING("It doesn't make sense to not supply a base URI");
   330         result = spec;
   331         rv = NS_OK;
   332     }
   333     else {
   334         nsAutoCString resultBuf;
   335         if (spec.IsEmpty())
   336             rv = baseURI->GetSpec(resultBuf);
   337         else
   338             rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf);
   339         if (NS_SUCCEEDED(rv))
   340             CopyUTF8toUTF16(resultBuf, result);
   341     }
   342     return rv;
   343 }
   345 /**
   346  * This function is a helper function to get a scheme's default port.
   347  */
   348 inline int32_t
   349 NS_GetDefaultPort(const char *scheme,
   350                   nsIIOService* ioService = nullptr)
   351 {
   352   nsresult rv;
   354   nsCOMPtr<nsIIOService> grip;
   355   net_EnsureIOService(&ioService, grip);
   356   if (!ioService)
   357       return -1;
   359   nsCOMPtr<nsIProtocolHandler> handler;
   360   rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
   361   if (NS_FAILED(rv))
   362     return -1;
   363   int32_t port;
   364   rv = handler->GetDefaultPort(&port);
   365   return NS_SUCCEEDED(rv) ? port : -1;
   366 }
   368 /**
   369  * This function is a helper function to apply the ToAscii conversion
   370  * to a string
   371  */
   372 inline bool
   373 NS_StringToACE(const nsACString &idn, nsACString &result)
   374 {
   375   nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
   376   if (!idnSrv)
   377     return false;
   378   nsresult rv = idnSrv->ConvertUTF8toACE(idn, result);
   379   if (NS_FAILED(rv))
   380     return false;
   382   return true;
   383 }
   385 /**
   386  * This function is a helper function to get a protocol's default port if the
   387  * URI does not specify a port explicitly. Returns -1 if this protocol has no
   388  * concept of ports or if there was an error getting the port.
   389  */
   390 inline int32_t
   391 NS_GetRealPort(nsIURI* aURI)
   392 {
   393     int32_t port;
   394     nsresult rv = aURI->GetPort(&port);
   395     if (NS_FAILED(rv))
   396         return -1;
   398     if (port != -1)
   399         return port; // explicitly specified
   401     // Otherwise, we have to get the default port from the protocol handler
   403     // Need the scheme first
   404     nsAutoCString scheme;
   405     rv = aURI->GetScheme(scheme);
   406     if (NS_FAILED(rv))
   407         return -1;
   409     return NS_GetDefaultPort(scheme.get());
   410 }
   412 inline nsresult
   413 NS_NewInputStreamChannel(nsIChannel      **result,
   414                          nsIURI           *uri,
   415                          nsIInputStream   *stream,
   416                          const nsACString &contentType,
   417                          const nsACString *contentCharset)
   418 {
   419     nsresult rv;
   420     nsCOMPtr<nsIInputStreamChannel> isc =
   421         do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
   422     if (NS_FAILED(rv))
   423         return rv;
   424     rv = isc->SetURI(uri);
   425     nsresult tmp = isc->SetContentStream(stream);
   426     if (NS_FAILED(tmp)) {
   427         rv = tmp;
   428     }
   429     if (NS_FAILED(rv))
   430         return rv;
   431     nsCOMPtr<nsIChannel> chan = do_QueryInterface(isc, &rv);
   432     if (NS_FAILED(rv))
   433         return rv;
   434     if (!contentType.IsEmpty())
   435         rv = chan->SetContentType(contentType);
   436     if (contentCharset && !contentCharset->IsEmpty()) {
   437         tmp = chan->SetContentCharset(*contentCharset);
   438         if (NS_FAILED(tmp)) {
   439             rv = tmp;
   440         }
   441     }
   442     if (NS_SUCCEEDED(rv)) {
   443         *result = nullptr;
   444         chan.swap(*result);
   445     }
   446     return rv;
   447 }
   449 inline nsresult
   450 NS_NewInputStreamChannel(nsIChannel      **result,
   451                          nsIURI           *uri,
   452                          nsIInputStream   *stream,
   453                          const nsACString &contentType    = EmptyCString())
   454 {
   455     return NS_NewInputStreamChannel(result, uri, stream, contentType, nullptr);
   456 }
   458 inline nsresult
   459 NS_NewInputStreamChannel(nsIChannel      **result,
   460                          nsIURI           *uri,
   461                          nsIInputStream   *stream,
   462                          const nsACString &contentType,
   463                          const nsACString &contentCharset)
   464 {
   465     return NS_NewInputStreamChannel(result, uri, stream, contentType,
   466                                     &contentCharset);
   467 }
   469 inline nsresult
   470 NS_NewInputStreamChannel(nsIChannel      **result,
   471                          nsIURI           *uri,
   472                          const nsAString  &data,
   473                          const nsACString &contentType,
   474                          bool              isSrcdocChannel = false)
   475 {
   477     nsresult rv;
   479     nsCOMPtr<nsIStringInputStream> stream;
   480     stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
   481     NS_ENSURE_SUCCESS(rv, rv);
   483 #ifdef MOZILLA_INTERNAL_API
   484     uint32_t len;
   485     char* utf8Bytes = ToNewUTF8String(data, &len);
   486     rv = stream->AdoptData(utf8Bytes, len);
   487 #else
   488     char* utf8Bytes = ToNewUTF8String(data);
   489     rv = stream->AdoptData(utf8Bytes, strlen(utf8Bytes));
   490 #endif
   492     nsCOMPtr<nsIChannel> chan;
   494     rv = NS_NewInputStreamChannel(getter_AddRefs(chan), uri, stream,
   495                                   contentType, NS_LITERAL_CSTRING("UTF-8"));
   496     NS_ENSURE_SUCCESS(rv, rv);
   498     if (isSrcdocChannel) {
   499         nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(chan);
   500         NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE);
   501         inStrmChan->SetSrcdocData(data);
   502     }
   504     *result = nullptr;
   505     chan.swap(*result);
   507     return NS_OK;
   508 }
   510 inline nsresult
   511 NS_NewInputStreamPump(nsIInputStreamPump **result,
   512                       nsIInputStream      *stream,
   513                       int64_t              streamPos = int64_t(-1),
   514                       int64_t              streamLen = int64_t(-1),
   515                       uint32_t             segsize = 0,
   516                       uint32_t             segcount = 0,
   517                       bool                 closeWhenDone = false)
   518 {
   519     nsresult rv;
   520     nsCOMPtr<nsIInputStreamPump> pump =
   521         do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
   522     if (NS_SUCCEEDED(rv)) {
   523         rv = pump->Init(stream, streamPos, streamLen,
   524                         segsize, segcount, closeWhenDone);
   525         if (NS_SUCCEEDED(rv)) {
   526             *result = nullptr;
   527             pump.swap(*result);
   528         }
   529     }
   530     return rv;
   531 }
   533 // NOTE: you will need to specify whether or not your streams are buffered
   534 // (i.e., do they implement ReadSegments/WriteSegments).  the default
   535 // assumption of TRUE for both streams might not be right for you!
   536 inline nsresult
   537 NS_NewAsyncStreamCopier(nsIAsyncStreamCopier **result,
   538                         nsIInputStream        *source,
   539                         nsIOutputStream       *sink,
   540                         nsIEventTarget        *target,
   541                         bool                   sourceBuffered = true,
   542                         bool                   sinkBuffered = true,
   543                         uint32_t               chunkSize = 0,
   544                         bool                   closeSource = true,
   545                         bool                   closeSink = true)
   546 {
   547     nsresult rv;
   548     nsCOMPtr<nsIAsyncStreamCopier> copier =
   549         do_CreateInstance(NS_ASYNCSTREAMCOPIER_CONTRACTID, &rv);
   550     if (NS_SUCCEEDED(rv)) {
   551         rv = copier->Init(source, sink, target, sourceBuffered, sinkBuffered,
   552                           chunkSize, closeSource, closeSink);
   553         if (NS_SUCCEEDED(rv)) {
   554             *result = nullptr;
   555             copier.swap(*result);
   556         }
   557     }
   558     return rv;
   559 }
   561 inline nsresult
   562 NS_NewLoadGroup(nsILoadGroup      **result,
   563                 nsIRequestObserver *obs)
   564 {
   565     nsresult rv;
   566     nsCOMPtr<nsILoadGroup> group =
   567         do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv);
   568     if (NS_SUCCEEDED(rv)) {
   569         rv = group->SetGroupObserver(obs);
   570         if (NS_SUCCEEDED(rv)) {
   571             *result = nullptr;
   572             group.swap(*result);
   573         }
   574     }
   575     return rv;
   576 }
   578 inline nsresult
   579 NS_NewDownloader(nsIStreamListener   **result,
   580                  nsIDownloadObserver  *observer,
   581                  nsIFile              *downloadLocation = nullptr)
   582 {
   583     nsresult rv;
   584     nsCOMPtr<nsIDownloader> downloader =
   585         do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv);
   586     if (NS_SUCCEEDED(rv)) {
   587         rv = downloader->Init(observer, downloadLocation);
   588         if (NS_SUCCEEDED(rv))
   589             NS_ADDREF(*result = downloader);
   590     }
   591     return rv;
   592 }
   594 inline nsresult
   595 NS_NewStreamLoader(nsIStreamLoader        **result,
   596                    nsIStreamLoaderObserver *observer)
   597 {
   598     nsresult rv;
   599     nsCOMPtr<nsIStreamLoader> loader =
   600         do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv);
   601     if (NS_SUCCEEDED(rv)) {
   602         rv = loader->Init(observer);
   603         if (NS_SUCCEEDED(rv)) {
   604             *result = nullptr;
   605             loader.swap(*result);
   606         }
   607     }
   608     return rv;
   609 }
   611 inline nsresult
   612 NS_NewStreamLoader(nsIStreamLoader        **result,
   613                    nsIURI                  *uri,
   614                    nsIStreamLoaderObserver *observer,
   615                    nsISupports             *context   = nullptr,
   616                    nsILoadGroup            *loadGroup = nullptr,
   617                    nsIInterfaceRequestor   *callbacks = nullptr,
   618                    uint32_t                 loadFlags = nsIRequest::LOAD_NORMAL,
   619                    nsIURI                  *referrer  = nullptr)
   620 {
   621     nsresult rv;
   622     nsCOMPtr<nsIChannel> channel;
   623     rv = NS_NewChannel(getter_AddRefs(channel),
   624                        uri,
   625                        nullptr,
   626                        loadGroup,
   627                        callbacks,
   628                        loadFlags);
   629     if (NS_SUCCEEDED(rv)) {
   630         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   631         if (httpChannel)
   632             httpChannel->SetReferrer(referrer);
   633         rv = NS_NewStreamLoader(result, observer);
   634         if (NS_SUCCEEDED(rv))
   635           rv = channel->AsyncOpen(*result, context);
   636     }
   637     return rv;
   638 }
   640 inline nsresult
   641 NS_NewUnicharStreamLoader(nsIUnicharStreamLoader        **result,
   642                           nsIUnicharStreamLoaderObserver *observer)
   643 {
   644     nsresult rv;
   645     nsCOMPtr<nsIUnicharStreamLoader> loader =
   646         do_CreateInstance(NS_UNICHARSTREAMLOADER_CONTRACTID, &rv);
   647     if (NS_SUCCEEDED(rv)) {
   648         rv = loader->Init(observer);
   649         if (NS_SUCCEEDED(rv)) {
   650             *result = nullptr;
   651             loader.swap(*result);
   652         }
   653     }
   654     return rv;
   655 }
   657 inline nsresult
   658 NS_NewSyncStreamListener(nsIStreamListener **result,
   659                          nsIInputStream    **stream)
   660 {
   661     nsresult rv;
   662     nsCOMPtr<nsISyncStreamListener> listener =
   663         do_CreateInstance(NS_SYNCSTREAMLISTENER_CONTRACTID, &rv);
   664     if (NS_SUCCEEDED(rv)) {
   665         rv = listener->GetInputStream(stream);
   666         if (NS_SUCCEEDED(rv))
   667             NS_ADDREF(*result = listener);  // cannot use nsCOMPtr::swap
   668     }
   669     return rv;
   670 }
   672 /**
   673  * Implement the nsIChannel::Open(nsIInputStream**) method using the channel's
   674  * AsyncOpen method.
   675  *
   676  * NOTE: Reading from the returned nsIInputStream may spin the current
   677  * thread's event queue, which could result in any event being processed.
   678  */
   679 inline nsresult
   680 NS_ImplementChannelOpen(nsIChannel      *channel,
   681                         nsIInputStream **result)
   682 {
   683     nsCOMPtr<nsIStreamListener> listener;
   684     nsCOMPtr<nsIInputStream> stream;
   685     nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener),
   686                                            getter_AddRefs(stream));
   687     if (NS_SUCCEEDED(rv)) {
   688         rv = channel->AsyncOpen(listener, nullptr);
   689         if (NS_SUCCEEDED(rv)) {
   690             uint64_t n;
   691             // block until the initial response is received or an error occurs.
   692             rv = stream->Available(&n);
   693             if (NS_SUCCEEDED(rv)) {
   694                 *result = nullptr;
   695                 stream.swap(*result);
   696             }
   697         }
   698     }
   699     return rv;
   700 }
   702 inline nsresult
   703 NS_NewRequestObserverProxy(nsIRequestObserver **result,
   704                            nsIRequestObserver  *observer,
   705                            nsISupports         *context)
   706 {
   707     nsresult rv;
   708     nsCOMPtr<nsIRequestObserverProxy> proxy =
   709         do_CreateInstance(NS_REQUESTOBSERVERPROXY_CONTRACTID, &rv);
   710     if (NS_SUCCEEDED(rv)) {
   711         rv = proxy->Init(observer, context);
   712         if (NS_SUCCEEDED(rv))
   713             NS_ADDREF(*result = proxy);  // cannot use nsCOMPtr::swap
   714     }
   715     return rv;
   716 }
   718 inline nsresult
   719 NS_NewSimpleStreamListener(nsIStreamListener **result,
   720                            nsIOutputStream    *sink,
   721                            nsIRequestObserver *observer = nullptr)
   722 {
   723     nsresult rv;
   724     nsCOMPtr<nsISimpleStreamListener> listener = 
   725         do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv);
   726     if (NS_SUCCEEDED(rv)) {
   727         rv = listener->Init(sink, observer);
   728         if (NS_SUCCEEDED(rv))
   729             NS_ADDREF(*result = listener);  // cannot use nsCOMPtr::swap
   730     }
   731     return rv;
   732 }
   734 inline nsresult
   735 NS_CheckPortSafety(int32_t       port,
   736                    const char   *scheme,
   737                    nsIIOService *ioService = nullptr)
   738 {
   739     nsresult rv;
   740     nsCOMPtr<nsIIOService> grip;
   741     rv = net_EnsureIOService(&ioService, grip);
   742     if (ioService) {
   743         bool allow;
   744         rv = ioService->AllowPort(port, scheme, &allow);
   745         if (NS_SUCCEEDED(rv) && !allow) {
   746             NS_WARNING("port blocked");
   747             rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
   748         }
   749     }
   750     return rv;
   751 }
   753 // Determine if this URI is using a safe port.
   754 inline nsresult
   755 NS_CheckPortSafety(nsIURI *uri) {
   756     int32_t port;
   757     nsresult rv = uri->GetPort(&port);
   758     if (NS_FAILED(rv) || port == -1)  // port undefined or default-valued
   759         return NS_OK;
   760     nsAutoCString scheme;
   761     uri->GetScheme(scheme);
   762     return NS_CheckPortSafety(port, scheme.get());
   763 }
   765 inline nsresult
   766 NS_NewProxyInfo(const nsACString &type,
   767                 const nsACString &host,
   768                 int32_t           port,
   769                 uint32_t          flags,
   770                 nsIProxyInfo    **result)
   771 {
   772     nsresult rv;
   773     nsCOMPtr<nsIProtocolProxyService> pps =
   774             do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
   775     if (NS_SUCCEEDED(rv))
   776         rv = pps->NewProxyInfo(type, host, port, flags, UINT32_MAX, nullptr,
   777                                result);
   778     return rv; 
   779 }
   781 inline nsresult
   782 NS_GetFileProtocolHandler(nsIFileProtocolHandler **result,
   783                           nsIIOService            *ioService = nullptr)
   784 {
   785     nsresult rv;
   786     nsCOMPtr<nsIIOService> grip;
   787     rv = net_EnsureIOService(&ioService, grip);
   788     if (ioService) {
   789         nsCOMPtr<nsIProtocolHandler> handler;
   790         rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
   791         if (NS_SUCCEEDED(rv))
   792             rv = CallQueryInterface(handler, result);
   793     }
   794     return rv;
   795 }
   797 inline nsresult
   798 NS_GetFileFromURLSpec(const nsACString  &inURL,
   799                       nsIFile          **result,
   800                       nsIIOService      *ioService = nullptr)
   801 {
   802     nsresult rv;
   803     nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   804     rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   805     if (NS_SUCCEEDED(rv))
   806         rv = fileHandler->GetFileFromURLSpec(inURL, result);
   807     return rv;
   808 }
   810 inline nsresult
   811 NS_GetURLSpecFromFile(nsIFile      *file,
   812                       nsACString   &url,
   813                       nsIIOService *ioService = nullptr)
   814 {
   815     nsresult rv;
   816     nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   817     rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   818     if (NS_SUCCEEDED(rv))
   819         rv = fileHandler->GetURLSpecFromFile(file, url);
   820     return rv;
   821 }
   823 /**
   824  * Converts the nsIFile to the corresponding URL string.
   825  * Should only be called on files which are not directories,
   826  * is otherwise identical to NS_GetURLSpecFromFile, but is
   827  * usually more efficient.
   828  * Warning: this restriction may not be enforced at runtime!
   829  */
   830 inline nsresult
   831 NS_GetURLSpecFromActualFile(nsIFile      *file,
   832                             nsACString   &url,
   833                             nsIIOService *ioService = nullptr)
   834 {
   835     nsresult rv;
   836     nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   837     rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   838     if (NS_SUCCEEDED(rv))
   839         rv = fileHandler->GetURLSpecFromActualFile(file, url);
   840     return rv;
   841 }
   843 /**
   844  * Converts the nsIFile to the corresponding URL string.
   845  * Should only be called on files which are directories,
   846  * is otherwise identical to NS_GetURLSpecFromFile, but is
   847  * usually more efficient.
   848  * Warning: this restriction may not be enforced at runtime!
   849  */
   850 inline nsresult
   851 NS_GetURLSpecFromDir(nsIFile      *file,
   852                      nsACString   &url,
   853                      nsIIOService *ioService = nullptr)
   854 {
   855     nsresult rv;
   856     nsCOMPtr<nsIFileProtocolHandler> fileHandler;
   857     rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService);
   858     if (NS_SUCCEEDED(rv))
   859         rv = fileHandler->GetURLSpecFromDir(file, url);
   860     return rv;
   861 }
   863 /**
   864  * Obtains the referrer for a given channel.  This first tries to obtain the
   865  * referrer from the property docshell.internalReferrer, and if that doesn't
   866  * work and the channel is an nsIHTTPChannel, we check it's referrer property.
   867  *
   868  * @returns NS_ERROR_NOT_AVAILABLE if no referrer is available.
   869  */
   870 inline nsresult
   871 NS_GetReferrerFromChannel(nsIChannel *channel,
   872                           nsIURI **referrer)
   873 {
   874     nsresult rv = NS_ERROR_NOT_AVAILABLE;
   875     *referrer = nullptr;
   877     nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
   878     if (props) {
   879       // We have to check for a property on a property bag because the
   880       // referrer may be empty for security reasons (for example, when loading
   881       // an http page with an https referrer).
   882       rv = props->GetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
   883                                          NS_GET_IID(nsIURI),
   884                                          reinterpret_cast<void **>(referrer));
   885       if (NS_FAILED(rv))
   886         *referrer = nullptr;
   887     }
   889     // if that didn't work, we can still try to get the referrer from the
   890     // nsIHttpChannel (if we can QI to it)
   891     if (!(*referrer)) {
   892       nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
   893       if (chan) {
   894         rv = chan->GetReferrer(referrer);
   895         if (NS_FAILED(rv))
   896           *referrer = nullptr;
   897       }
   898     }
   899     return rv;
   900 }
   902 inline nsresult
   903 NS_ParseContentType(const nsACString &rawContentType,
   904                     nsCString        &contentType,
   905                     nsCString        &contentCharset)
   906 {
   907     // contentCharset is left untouched if not present in rawContentType
   908     nsresult rv;
   909     nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   910     NS_ENSURE_SUCCESS(rv, rv);
   911     nsCString charset;
   912     bool hadCharset;
   913     rv = util->ParseContentType(rawContentType, charset, &hadCharset,
   914                                 contentType);
   915     if (NS_SUCCEEDED(rv) && hadCharset)
   916         contentCharset = charset;
   917     return rv;
   918 }
   920 inline nsresult
   921 NS_ExtractCharsetFromContentType(const nsACString &rawContentType,
   922                                  nsCString        &contentCharset,
   923                                  bool             *hadCharset,
   924                                  int32_t          *charsetStart,
   925                                  int32_t          *charsetEnd)
   926 {
   927     // contentCharset is left untouched if not present in rawContentType
   928     nsresult rv;
   929     nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
   930     NS_ENSURE_SUCCESS(rv, rv);
   932     return util->ExtractCharsetFromContentType(rawContentType,
   933                                                contentCharset,
   934                                                charsetStart,
   935                                                charsetEnd,
   936                                                hadCharset);
   937 }
   939 inline nsresult
   940 NS_NewLocalFileInputStream(nsIInputStream **result,
   941                            nsIFile         *file,
   942                            int32_t          ioFlags       = -1,
   943                            int32_t          perm          = -1,
   944                            int32_t          behaviorFlags = 0)
   945 {
   946     nsresult rv;
   947     nsCOMPtr<nsIFileInputStream> in =
   948         do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv);
   949     if (NS_SUCCEEDED(rv)) {
   950         rv = in->Init(file, ioFlags, perm, behaviorFlags);
   951         if (NS_SUCCEEDED(rv))
   952             in.forget(result);
   953     }
   954     return rv;
   955 }
   957 inline nsresult
   958 NS_NewPartialLocalFileInputStream(nsIInputStream **result,
   959                                   nsIFile         *file,
   960                                   uint64_t         offset,
   961                                   uint64_t         length,
   962                                   int32_t          ioFlags       = -1,
   963                                   int32_t          perm          = -1,
   964                                   int32_t          behaviorFlags = 0)
   965 {
   966     nsresult rv;
   967     nsCOMPtr<nsIPartialFileInputStream> in =
   968         do_CreateInstance(NS_PARTIALLOCALFILEINPUTSTREAM_CONTRACTID, &rv);
   969     if (NS_SUCCEEDED(rv)) {
   970         rv = in->Init(file, offset, length, ioFlags, perm, behaviorFlags);
   971         if (NS_SUCCEEDED(rv))
   972             rv = CallQueryInterface(in, result);
   973     }
   974     return rv;
   975 }
   977 inline nsresult
   978 NS_NewLocalFileOutputStream(nsIOutputStream **result,
   979                             nsIFile          *file,
   980                             int32_t           ioFlags       = -1,
   981                             int32_t           perm          = -1,
   982                             int32_t           behaviorFlags = 0)
   983 {
   984     nsresult rv;
   985     nsCOMPtr<nsIFileOutputStream> out =
   986         do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
   987     if (NS_SUCCEEDED(rv)) {
   988         rv = out->Init(file, ioFlags, perm, behaviorFlags);
   989         if (NS_SUCCEEDED(rv))
   990             out.forget(result);
   991     }
   992     return rv;
   993 }
   995 // returns a file output stream which can be QI'ed to nsISafeOutputStream.
   996 inline nsresult
   997 NS_NewAtomicFileOutputStream(nsIOutputStream **result,
   998                                 nsIFile          *file,
   999                                 int32_t           ioFlags       = -1,
  1000                                 int32_t           perm          = -1,
  1001                                 int32_t           behaviorFlags = 0)
  1003     nsresult rv;
  1004     nsCOMPtr<nsIFileOutputStream> out =
  1005         do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
  1006     if (NS_SUCCEEDED(rv)) {
  1007         rv = out->Init(file, ioFlags, perm, behaviorFlags);
  1008         if (NS_SUCCEEDED(rv))
  1009             out.forget(result);
  1011     return rv;
  1014 // returns a file output stream which can be QI'ed to nsISafeOutputStream.
  1015 inline nsresult
  1016 NS_NewSafeLocalFileOutputStream(nsIOutputStream **result,
  1017                                 nsIFile          *file,
  1018                                 int32_t           ioFlags       = -1,
  1019                                 int32_t           perm          = -1,
  1020                                 int32_t           behaviorFlags = 0)
  1022     nsresult rv;
  1023     nsCOMPtr<nsIFileOutputStream> out =
  1024         do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
  1025     if (NS_SUCCEEDED(rv)) {
  1026         rv = out->Init(file, ioFlags, perm, behaviorFlags);
  1027         if (NS_SUCCEEDED(rv))
  1028             out.forget(result);
  1030     return rv;
  1033 inline nsresult
  1034 NS_NewLocalFileStream(nsIFileStream **result,
  1035                       nsIFile        *file,
  1036                       int32_t         ioFlags       = -1,
  1037                       int32_t         perm          = -1,
  1038                       int32_t         behaviorFlags = 0)
  1040     nsresult rv;
  1041     nsCOMPtr<nsIFileStream> stream =
  1042         do_CreateInstance(NS_LOCALFILESTREAM_CONTRACTID, &rv);
  1043     if (NS_SUCCEEDED(rv)) {
  1044         rv = stream->Init(file, ioFlags, perm, behaviorFlags);
  1045         if (NS_SUCCEEDED(rv))
  1046             stream.forget(result);
  1048     return rv;
  1051 // returns the input end of a pipe.  the output end of the pipe
  1052 // is attached to the original stream.  data from the original
  1053 // stream is read into the pipe on a background thread.
  1054 inline nsresult
  1055 NS_BackgroundInputStream(nsIInputStream **result,
  1056                          nsIInputStream  *stream,
  1057                          uint32_t         segmentSize  = 0,
  1058                          uint32_t         segmentCount = 0)
  1060     nsresult rv;
  1061     nsCOMPtr<nsIStreamTransportService> sts =
  1062         do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
  1063     if (NS_SUCCEEDED(rv)) {
  1064         nsCOMPtr<nsITransport> inTransport;
  1065         rv = sts->CreateInputTransport(stream, int64_t(-1), int64_t(-1),
  1066                                        true, getter_AddRefs(inTransport));
  1067         if (NS_SUCCEEDED(rv))
  1068             rv = inTransport->OpenInputStream(nsITransport::OPEN_BLOCKING,
  1069                                               segmentSize, segmentCount,
  1070                                               result);
  1072     return rv;
  1075 // returns the output end of a pipe.  the input end of the pipe
  1076 // is attached to the original stream.  data written to the pipe
  1077 // is copied to the original stream on a background thread.
  1078 inline nsresult
  1079 NS_BackgroundOutputStream(nsIOutputStream **result,
  1080                           nsIOutputStream  *stream,
  1081                           uint32_t          segmentSize  = 0,
  1082                           uint32_t          segmentCount = 0)
  1084     nsresult rv;
  1085     nsCOMPtr<nsIStreamTransportService> sts =
  1086         do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
  1087     if (NS_SUCCEEDED(rv)) {
  1088         nsCOMPtr<nsITransport> inTransport;
  1089         rv = sts->CreateOutputTransport(stream, int64_t(-1), int64_t(-1),
  1090                                         true, getter_AddRefs(inTransport));
  1091         if (NS_SUCCEEDED(rv))
  1092             rv = inTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
  1093                                                segmentSize, segmentCount,
  1094                                                result);
  1096     return rv;
  1099 MOZ_WARN_UNUSED_RESULT inline nsresult
  1100 NS_NewBufferedInputStream(nsIInputStream **result,
  1101                           nsIInputStream  *str,
  1102                           uint32_t         bufferSize)
  1104     nsresult rv;
  1105     nsCOMPtr<nsIBufferedInputStream> in =
  1106         do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv);
  1107     if (NS_SUCCEEDED(rv)) {
  1108         rv = in->Init(str, bufferSize);
  1109         if (NS_SUCCEEDED(rv))
  1110             NS_ADDREF(*result = in);  // cannot use nsCOMPtr::swap
  1112     return rv;
  1115 // note: the resulting stream can be QI'ed to nsISafeOutputStream iff the
  1116 // provided stream supports it.
  1117 inline nsresult
  1118 NS_NewBufferedOutputStream(nsIOutputStream **result,
  1119                            nsIOutputStream  *str,
  1120                            uint32_t          bufferSize)
  1122     nsresult rv;
  1123     nsCOMPtr<nsIBufferedOutputStream> out =
  1124         do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
  1125     if (NS_SUCCEEDED(rv)) {
  1126         rv = out->Init(str, bufferSize);
  1127         if (NS_SUCCEEDED(rv))
  1128             NS_ADDREF(*result = out);  // cannot use nsCOMPtr::swap
  1130     return rv;
  1133 /**
  1134  * Attempts to buffer a given output stream.  If this fails, it returns the
  1135  * passed-in output stream.
  1137  * @param aOutputStream
  1138  *        The output stream we want to buffer.  This cannot be null.
  1139  * @param aBufferSize
  1140  *        The size of the buffer for the buffered output stream.
  1141  * @returns an nsIOutputStream that is buffered with the specified buffer size,
  1142  *          or is aOutputStream if creating the new buffered stream failed.
  1143  */
  1144 inline already_AddRefed<nsIOutputStream>
  1145 NS_BufferOutputStream(nsIOutputStream *aOutputStream,
  1146                       uint32_t aBufferSize)
  1148     NS_ASSERTION(aOutputStream, "No output stream given!");
  1150     nsCOMPtr<nsIOutputStream> bos;
  1151     nsresult rv = NS_NewBufferedOutputStream(getter_AddRefs(bos), aOutputStream,
  1152                                              aBufferSize);
  1153     if (NS_SUCCEEDED(rv))
  1154         return bos.forget();
  1156     bos = aOutputStream;
  1157     return bos.forget();
  1160 // returns an input stream compatible with nsIUploadChannel::SetUploadStream()
  1161 inline nsresult
  1162 NS_NewPostDataStream(nsIInputStream  **result,
  1163                      bool              isFile,
  1164                      const nsACString &data)
  1166     nsresult rv;
  1168     if (isFile) {
  1169         nsCOMPtr<nsIFile> file;
  1170         nsCOMPtr<nsIInputStream> fileStream;
  1172         rv = NS_NewNativeLocalFile(data, false, getter_AddRefs(file));
  1173         if (NS_SUCCEEDED(rv)) {
  1174             rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
  1175             if (NS_SUCCEEDED(rv)) {
  1176                 // wrap the file stream with a buffered input stream
  1177                 rv = NS_NewBufferedInputStream(result, fileStream, 8192);
  1180         return rv;
  1183     // otherwise, create a string stream for the data (copies)
  1184     nsCOMPtr<nsIStringInputStream> stream
  1185         (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
  1186     if (NS_FAILED(rv))
  1187         return rv;
  1189     rv = stream->SetData(data.BeginReading(), data.Length());
  1190     if (NS_FAILED(rv))
  1191         return rv;
  1193     NS_ADDREF(*result = stream);
  1194     return NS_OK;
  1197 inline nsresult
  1198 NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream, 
  1199                            void** aDest,
  1200                            uint32_t aCount)
  1202     nsresult rv;
  1204     if (!*aDest) {
  1205         *aDest = malloc(aCount);
  1206         if (!*aDest)
  1207             return NS_ERROR_OUT_OF_MEMORY;
  1210     char * p = reinterpret_cast<char*>(*aDest);
  1211     uint32_t bytesRead;
  1212     uint32_t totalRead = 0;
  1213     while (1) {
  1214         rv = aInputStream->Read(p + totalRead, aCount - totalRead, &bytesRead);
  1215         if (!NS_SUCCEEDED(rv)) 
  1216             return rv;
  1217         totalRead += bytesRead;
  1218         if (totalRead == aCount)
  1219             break;
  1220         // if Read reads 0 bytes, we've hit EOF 
  1221         if (bytesRead == 0)
  1222             return NS_ERROR_UNEXPECTED;
  1224     return rv; 
  1227 // external code can't see fallible_t
  1228 #ifdef MOZILLA_INTERNAL_API
  1230 inline nsresult
  1231 NS_ReadInputStreamToString(nsIInputStream *aInputStream, 
  1232                            nsACString &aDest,
  1233                            uint32_t aCount)
  1235     if (!aDest.SetLength(aCount, mozilla::fallible_t()))
  1236         return NS_ERROR_OUT_OF_MEMORY;
  1237     void* dest = aDest.BeginWriting();
  1238     return NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount);
  1241 #endif
  1243 inline nsresult
  1244 NS_LoadPersistentPropertiesFromURI(nsIPersistentProperties **result,
  1245                                    nsIURI                   *uri,
  1246                                    nsIIOService             *ioService = nullptr)
  1248     nsCOMPtr<nsIInputStream> in;
  1249     nsresult rv = NS_OpenURI(getter_AddRefs(in), uri, ioService);
  1250     if (NS_SUCCEEDED(rv)) {
  1251         nsCOMPtr<nsIPersistentProperties> properties = 
  1252             do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID, &rv);
  1253         if (NS_SUCCEEDED(rv)) {
  1254             rv = properties->Load(in);
  1255             if (NS_SUCCEEDED(rv)) {
  1256                 *result = nullptr;
  1257                 properties.swap(*result);
  1261     return rv;
  1264 inline nsresult
  1265 NS_LoadPersistentPropertiesFromURISpec(nsIPersistentProperties **result,
  1266                                        const nsACString        &spec,
  1267                                        const char              *charset = nullptr,
  1268                                        nsIURI                  *baseURI = nullptr,
  1269                                        nsIIOService            *ioService = nullptr)     
  1271     nsCOMPtr<nsIURI> uri;
  1272     nsresult rv = 
  1273         NS_NewURI(getter_AddRefs(uri), spec, charset, baseURI, ioService);
  1275     if (NS_SUCCEEDED(rv))
  1276         rv = NS_LoadPersistentPropertiesFromURI(result, uri, ioService);
  1278     return rv;
  1281 /**
  1282  * NS_QueryNotificationCallbacks implements the canonical algorithm for
  1283  * querying interfaces from a channel's notification callbacks.  It first
  1284  * searches the channel's notificationCallbacks attribute, and if the interface
  1285  * is not found there, then it inspects the notificationCallbacks attribute of
  1286  * the channel's loadGroup.
  1288  * Note: templatized only because nsIWebSocketChannel is currently not an
  1289  * nsIChannel.
  1290  */
  1291 template <class T> inline void
  1292 NS_QueryNotificationCallbacks(T            *channel,
  1293                               const nsIID  &iid,
  1294                               void        **result)
  1296     NS_PRECONDITION(channel, "null channel");
  1297     *result = nullptr;
  1299     nsCOMPtr<nsIInterfaceRequestor> cbs;
  1300     channel->GetNotificationCallbacks(getter_AddRefs(cbs));
  1301     if (cbs)
  1302         cbs->GetInterface(iid, result);
  1303     if (!*result) {
  1304         // try load group's notification callbacks...
  1305         nsCOMPtr<nsILoadGroup> loadGroup;
  1306         channel->GetLoadGroup(getter_AddRefs(loadGroup));
  1307         if (loadGroup) {
  1308             loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
  1309             if (cbs)
  1310                 cbs->GetInterface(iid, result);
  1315 // template helper:
  1316 // Note: "class C" templatized only because nsIWebSocketChannel is currently not
  1317 // an nsIChannel.
  1319 template <class C, class T> inline void
  1320 NS_QueryNotificationCallbacks(C           *channel,
  1321                               nsCOMPtr<T> &result)
  1323     NS_QueryNotificationCallbacks(channel, NS_GET_TEMPLATE_IID(T),
  1324                                   getter_AddRefs(result));
  1327 /**
  1328  * Alternate form of NS_QueryNotificationCallbacks designed for use by
  1329  * nsIChannel implementations.
  1330  */
  1331 inline void
  1332 NS_QueryNotificationCallbacks(nsIInterfaceRequestor  *callbacks,
  1333                               nsILoadGroup           *loadGroup,
  1334                               const nsIID            &iid,
  1335                               void                  **result)
  1337     *result = nullptr;
  1339     if (callbacks)
  1340         callbacks->GetInterface(iid, result);
  1341     if (!*result) {
  1342         // try load group's notification callbacks...
  1343         if (loadGroup) {
  1344             nsCOMPtr<nsIInterfaceRequestor> cbs;
  1345             loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
  1346             if (cbs)
  1347                 cbs->GetInterface(iid, result);
  1352 /**
  1353  * Returns true if channel is using Private Browsing, or false if not.
  1354  * Returns false if channel's callbacks don't implement nsILoadContext.
  1355  */
  1356 inline bool
  1357 NS_UsePrivateBrowsing(nsIChannel *channel)
  1359     bool isPrivate = false;
  1360     bool isOverriden = false;
  1361     nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
  1362     if (pbChannel &&
  1363         NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate, &isOverriden)) &&
  1364         isOverriden) {
  1365         return isPrivate;
  1367     nsCOMPtr<nsILoadContext> loadContext;
  1368     NS_QueryNotificationCallbacks(channel, loadContext);
  1369     return loadContext && loadContext->UsePrivateBrowsing();
  1372 // Constants duplicated from nsIScriptSecurityManager so we avoid having necko
  1373 // know about script security manager.
  1374 #define NECKO_NO_APP_ID 0
  1375 #define NECKO_UNKNOWN_APP_ID UINT32_MAX
  1376 // special app id reserved for separating the safebrowsing cookie
  1377 #define NECKO_SAFEBROWSING_APP_ID UINT32_MAX - 1
  1379 /**
  1380  * Gets AppId and isInBrowserElement from channel's nsILoadContext.
  1381  * Returns false if error or channel's callbacks don't implement nsILoadContext.
  1382  */
  1383 inline bool
  1384 NS_GetAppInfo(nsIChannel *aChannel, uint32_t *aAppID, bool *aIsInBrowserElement)
  1386     nsCOMPtr<nsILoadContext> loadContext;
  1387     NS_QueryNotificationCallbacks(aChannel, loadContext);
  1388     if (!loadContext) {
  1389         return false;
  1392     nsresult rv = loadContext->GetAppId(aAppID);
  1393     NS_ENSURE_SUCCESS(rv, false);
  1395     rv = loadContext->GetIsInBrowserElement(aIsInBrowserElement);
  1396     NS_ENSURE_SUCCESS(rv, false);
  1398     return true;
  1401 /**
  1402  *  Gets appId and browserOnly parameters from the TOPIC_WEB_APP_CLEAR_DATA
  1403  *  nsIObserverService notification.  Used when clearing user data or
  1404  *  uninstalling web apps.
  1405  */
  1406 inline nsresult
  1407 NS_GetAppInfoFromClearDataNotification(nsISupports *aSubject,
  1408                                        uint32_t *aAppID, bool* aBrowserOnly)
  1410     nsresult rv;
  1412     nsCOMPtr<mozIApplicationClearPrivateDataParams>
  1413         clearParams(do_QueryInterface(aSubject));
  1414     MOZ_ASSERT(clearParams);
  1415     if (!clearParams) {
  1416         return NS_ERROR_UNEXPECTED;
  1419     uint32_t appId;
  1420     rv = clearParams->GetAppId(&appId);
  1421     MOZ_ASSERT(NS_SUCCEEDED(rv));
  1422     MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
  1423     NS_ENSURE_SUCCESS(rv, rv);
  1424     if (appId == NECKO_UNKNOWN_APP_ID) {
  1425         return NS_ERROR_UNEXPECTED;
  1428     bool browserOnly = false;
  1429     rv = clearParams->GetBrowserOnly(&browserOnly);
  1430     MOZ_ASSERT(NS_SUCCEEDED(rv));
  1431     NS_ENSURE_SUCCESS(rv, rv);
  1433     *aAppID = appId;
  1434     *aBrowserOnly = browserOnly;
  1435     return NS_OK;
  1438 /**
  1439  * Determines whether appcache should be checked for a given URI.
  1440  */
  1441 inline bool
  1442 NS_ShouldCheckAppCache(nsIURI *aURI, bool usePrivateBrowsing)
  1444     if (usePrivateBrowsing) {
  1445         return false;
  1448     nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
  1449         do_GetService("@mozilla.org/offlinecacheupdate-service;1");
  1450     if (!offlineService) {
  1451         return false;
  1454     bool allowed;
  1455     nsresult rv = offlineService->OfflineAppAllowedForURI(aURI,
  1456                                                           nullptr,
  1457                                                           &allowed);
  1458     return NS_SUCCEEDED(rv) && allowed;
  1461 inline bool
  1462 NS_ShouldCheckAppCache(nsIPrincipal * aPrincipal, bool usePrivateBrowsing)
  1464     if (usePrivateBrowsing) {
  1465         return false;
  1468     nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
  1469         do_GetService("@mozilla.org/offlinecacheupdate-service;1");
  1470     if (!offlineService) {
  1471         return false;
  1474     bool allowed;
  1475     nsresult rv = offlineService->OfflineAppAllowed(aPrincipal,
  1476                                                     nullptr,
  1477                                                     &allowed);
  1478     return NS_SUCCEEDED(rv) && allowed;
  1481 /**
  1482  * Wraps an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. This
  1483  * method is provided mainly for use by other methods in this file.
  1485  * *aAuthPrompt2 should be set to null before calling this function.
  1486  */
  1487 inline void
  1488 NS_WrapAuthPrompt(nsIAuthPrompt *aAuthPrompt, nsIAuthPrompt2** aAuthPrompt2)
  1490     nsCOMPtr<nsIAuthPromptAdapterFactory> factory =
  1491         do_GetService(NS_AUTHPROMPT_ADAPTER_FACTORY_CONTRACTID);
  1492     if (!factory)
  1493         return;
  1495     NS_WARNING("Using deprecated nsIAuthPrompt");
  1496     factory->CreateAdapter(aAuthPrompt, aAuthPrompt2);
  1499 /**
  1500  * Gets an auth prompt from an interface requestor. This takes care of wrapping
  1501  * an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2.
  1502  */
  1503 inline void
  1504 NS_QueryAuthPrompt2(nsIInterfaceRequestor  *aCallbacks,
  1505                     nsIAuthPrompt2        **aAuthPrompt)
  1507     CallGetInterface(aCallbacks, aAuthPrompt);
  1508     if (*aAuthPrompt)
  1509         return;
  1511     // Maybe only nsIAuthPrompt is provided and we have to wrap it.
  1512     nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks));
  1513     if (!prompt)
  1514         return;
  1516     NS_WrapAuthPrompt(prompt, aAuthPrompt);
  1519 /**
  1520  * Gets an nsIAuthPrompt2 from a channel. Use this instead of
  1521  * NS_QueryNotificationCallbacks for better backwards compatibility.
  1522  */
  1523 inline void
  1524 NS_QueryAuthPrompt2(nsIChannel      *aChannel,
  1525                     nsIAuthPrompt2 **aAuthPrompt)
  1527     *aAuthPrompt = nullptr;
  1529     // We want to use any auth prompt we can find on the channel's callbacks,
  1530     // and if that fails use the loadgroup's prompt (if any)
  1531     // Therefore, we can't just use NS_QueryNotificationCallbacks, because
  1532     // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's
  1533     // nsIAuthPrompt.
  1534     nsCOMPtr<nsIInterfaceRequestor> callbacks;
  1535     aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
  1536     if (callbacks) {
  1537         NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
  1538         if (*aAuthPrompt)
  1539             return;
  1542     nsCOMPtr<nsILoadGroup> group;
  1543     aChannel->GetLoadGroup(getter_AddRefs(group));
  1544     if (!group)
  1545         return;
  1547     group->GetNotificationCallbacks(getter_AddRefs(callbacks));
  1548     if (!callbacks)
  1549         return;
  1550     NS_QueryAuthPrompt2(callbacks, aAuthPrompt);
  1553 /* template helper */
  1554 template <class T> inline void
  1555 NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks,
  1556                               nsILoadGroup          *loadGroup,
  1557                               nsCOMPtr<T>           &result)
  1559     NS_QueryNotificationCallbacks(callbacks, loadGroup,
  1560                                   NS_GET_TEMPLATE_IID(T),
  1561                                   getter_AddRefs(result));
  1564 /* template helper */
  1565 template <class T> inline void
  1566 NS_QueryNotificationCallbacks(const nsCOMPtr<nsIInterfaceRequestor> &aCallbacks,
  1567                               const nsCOMPtr<nsILoadGroup>          &aLoadGroup,
  1568                               nsCOMPtr<T>                           &aResult)
  1570     NS_QueryNotificationCallbacks(aCallbacks.get(), aLoadGroup.get(), aResult);
  1573 /* template helper */
  1574 template <class T> inline void
  1575 NS_QueryNotificationCallbacks(const nsCOMPtr<nsIChannel> &aChannel,
  1576                               nsCOMPtr<T>                &aResult)
  1578     NS_QueryNotificationCallbacks(aChannel.get(), aResult);
  1581 /**
  1582  * This function returns a nsIInterfaceRequestor instance that returns the
  1583  * same result as NS_QueryNotificationCallbacks when queried.  It is useful
  1584  * as the value for nsISocketTransport::securityCallbacks.
  1585  */
  1586 inline nsresult
  1587 NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor  *callbacks,
  1588                                        nsILoadGroup           *loadGroup,
  1589                                        nsIEventTarget         *target,
  1590                                        nsIInterfaceRequestor **result)
  1592     nsCOMPtr<nsIInterfaceRequestor> cbs;
  1593     if (loadGroup)
  1594         loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
  1595     return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result);
  1598 inline nsresult
  1599 NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor  *callbacks,
  1600                                        nsILoadGroup           *loadGroup,
  1601                                        nsIInterfaceRequestor **result)
  1603     return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr, result);
  1606 /**
  1607  * Helper function for testing online/offline state of the browser.
  1608  */
  1609 inline bool
  1610 NS_IsOffline()
  1612     bool offline = true;
  1613     nsCOMPtr<nsIIOService> ios = do_GetIOService();
  1614     if (ios)
  1615         ios->GetOffline(&offline);
  1616     return offline;
  1619 /**
  1620  * Helper functions for implementing nsINestedURI::innermostURI.
  1622  * Note that NS_DoImplGetInnermostURI is "private" -- call
  1623  * NS_ImplGetInnermostURI instead.
  1624  */
  1625 inline nsresult
  1626 NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
  1628     NS_PRECONDITION(nestedURI, "Must have a nested URI!");
  1629     NS_PRECONDITION(!*result, "Must have null *result");
  1631     nsCOMPtr<nsIURI> inner;
  1632     nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner));
  1633     NS_ENSURE_SUCCESS(rv, rv);
  1635     // We may need to loop here until we reach the innermost
  1636     // URI.
  1637     nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner));
  1638     while (nestedInner) {
  1639         rv = nestedInner->GetInnerURI(getter_AddRefs(inner));
  1640         NS_ENSURE_SUCCESS(rv, rv);
  1641         nestedInner = do_QueryInterface(inner);
  1644     // Found the innermost one if we reach here.
  1645     inner.swap(*result);
  1647     return rv;
  1650 inline nsresult
  1651 NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result)
  1653     // Make it safe to use swap()
  1654     *result = nullptr;
  1656     return NS_DoImplGetInnermostURI(nestedURI, result);
  1659 /**
  1660  * Helper function that ensures that |result| is a URI that's safe to
  1661  * return.  If |uri| is immutable, just returns it, otherwise returns
  1662  * a clone.  |uri| must not be null.
  1663  */
  1664 inline nsresult
  1665 NS_EnsureSafeToReturn(nsIURI* uri, nsIURI** result)
  1667     NS_PRECONDITION(uri, "Must have a URI");
  1669     // Assume mutable until told otherwise
  1670     bool isMutable = true;
  1671     nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
  1672     if (mutableObj) {
  1673         nsresult rv = mutableObj->GetMutable(&isMutable);
  1674         isMutable = NS_FAILED(rv) || isMutable;
  1677     if (!isMutable) {
  1678         NS_ADDREF(*result = uri);
  1679         return NS_OK;
  1682     nsresult rv = uri->Clone(result);
  1683     if (NS_SUCCEEDED(rv) && !*result) {
  1684         NS_ERROR("nsIURI.clone contract was violated");
  1685         return NS_ERROR_UNEXPECTED;
  1688     return rv;
  1691 /**
  1692  * Helper function that tries to set the argument URI to be immutable
  1693  */  
  1694 inline void
  1695 NS_TryToSetImmutable(nsIURI* uri)
  1697     nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri));
  1698     if (mutableObj) {
  1699         mutableObj->SetMutable(false);
  1703 /**
  1704  * Helper function for calling ToImmutableURI.  If all else fails, returns
  1705  * the input URI.  The optional second arg indicates whether we had to fall
  1706  * back to the input URI.  Passing in a null URI is ok.
  1707  */
  1708 inline already_AddRefed<nsIURI>
  1709 NS_TryToMakeImmutable(nsIURI* uri,
  1710                       nsresult* outRv = nullptr)
  1712     nsresult rv;
  1713     nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
  1715     nsCOMPtr<nsIURI> result;
  1716     if (NS_SUCCEEDED(rv)) {
  1717         NS_ASSERTION(util, "do_GetNetUtil lied");
  1718         rv = util->ToImmutableURI(uri, getter_AddRefs(result));
  1721     if (NS_FAILED(rv)) {
  1722         result = uri;
  1725     if (outRv) {
  1726         *outRv = rv;
  1729     return result.forget();
  1732 /**
  1733  * Helper function for testing whether the given URI, or any of its
  1734  * inner URIs, has all the given protocol flags.
  1735  */
  1736 inline nsresult
  1737 NS_URIChainHasFlags(nsIURI   *uri,
  1738                     uint32_t  flags,
  1739                     bool     *result)
  1741     nsresult rv;
  1742     nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
  1743     NS_ENSURE_SUCCESS(rv, rv);
  1745     return util->URIChainHasFlags(uri, flags, result);
  1748 /**
  1749  * Helper function for getting the innermost URI for a given URI.  The return
  1750  * value could be just the object passed in if it's not a nested URI.
  1751  */
  1752 inline already_AddRefed<nsIURI>
  1753 NS_GetInnermostURI(nsIURI* aURI)
  1755     NS_PRECONDITION(aURI, "Must have URI");
  1757     nsCOMPtr<nsIURI> uri = aURI;
  1759     nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri));
  1760     if (!nestedURI) {
  1761         return uri.forget();
  1764     nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
  1765     if (NS_FAILED(rv)) {
  1766         return nullptr;
  1769     return uri.forget();
  1772 /**
  1773  * Get the "final" URI for a channel.  This is either the same as GetURI or
  1774  * GetOriginalURI, depending on whether this channel has
  1775  * nsIChanel::LOAD_REPLACE set.  For channels without that flag set, the final
  1776  * URI is the original URI, while for ones with the flag the final URI is the
  1777  * channel URI.
  1778  */
  1779 inline nsresult
  1780 NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri)
  1782     *uri = nullptr;
  1783     nsLoadFlags loadFlags = 0;
  1784     nsresult rv = channel->GetLoadFlags(&loadFlags);
  1785     NS_ENSURE_SUCCESS(rv, rv);
  1787     if (loadFlags & nsIChannel::LOAD_REPLACE) {
  1788         return channel->GetURI(uri);
  1791     return channel->GetOriginalURI(uri);
  1794 // NS_SecurityHashURI must return the same hash value for any two URIs that
  1795 // compare equal according to NS_SecurityCompareURIs.  Unfortunately, in the
  1796 // case of files, it's not clear we can do anything better than returning
  1797 // the schemeHash, so hashing files degenerates to storing them in a list.
  1798 inline uint32_t
  1799 NS_SecurityHashURI(nsIURI* aURI)
  1801     nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
  1803     nsAutoCString scheme;
  1804     uint32_t schemeHash = 0;
  1805     if (NS_SUCCEEDED(baseURI->GetScheme(scheme)))
  1806         schemeHash = mozilla::HashString(scheme);
  1808     // TODO figure out how to hash file:// URIs
  1809     if (scheme.EqualsLiteral("file"))
  1810         return schemeHash; // sad face
  1812     if (scheme.EqualsLiteral("imap") ||
  1813         scheme.EqualsLiteral("mailbox") ||
  1814         scheme.EqualsLiteral("news"))
  1816         nsAutoCString spec;
  1817         uint32_t specHash;
  1818         nsresult res = baseURI->GetSpec(spec);
  1819         if (NS_SUCCEEDED(res))
  1820             specHash = mozilla::HashString(spec);
  1821         else
  1822             specHash = static_cast<uint32_t>(res);
  1823         return specHash;
  1826     nsAutoCString host;
  1827     uint32_t hostHash = 0;
  1828     if (NS_SUCCEEDED(baseURI->GetAsciiHost(host)))
  1829         hostHash = mozilla::HashString(host);
  1831     return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI));
  1834 inline bool
  1835 NS_SecurityCompareURIs(nsIURI* aSourceURI,
  1836                        nsIURI* aTargetURI,
  1837                        bool aStrictFileOriginPolicy)
  1839     // Note that this is not an Equals() test on purpose -- for URIs that don't
  1840     // support host/port, we want equality to basically be object identity, for
  1841     // security purposes.  Otherwise, for example, two javascript: URIs that
  1842     // are otherwise unrelated could end up "same origin", which would be
  1843     // unfortunate.
  1844     if (aSourceURI && aSourceURI == aTargetURI)
  1846         return true;
  1849     if (!aTargetURI || !aSourceURI)
  1851         return false;
  1854     // If either URI is a nested URI, get the base URI
  1855     nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
  1856     nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
  1858     // If either uri is an nsIURIWithPrincipal
  1859     nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(sourceBaseURI);
  1860     if (uriPrinc) {
  1861         uriPrinc->GetPrincipalUri(getter_AddRefs(sourceBaseURI));
  1864     uriPrinc = do_QueryInterface(targetBaseURI);
  1865     if (uriPrinc) {
  1866         uriPrinc->GetPrincipalUri(getter_AddRefs(targetBaseURI));
  1869     if (!sourceBaseURI || !targetBaseURI)
  1870         return false;
  1872     // Compare schemes
  1873     nsAutoCString targetScheme;
  1874     bool sameScheme = false;
  1875     if (NS_FAILED( targetBaseURI->GetScheme(targetScheme) ) ||
  1876         NS_FAILED( sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme) ) ||
  1877         !sameScheme)
  1879         // Not same-origin if schemes differ
  1880         return false;
  1883     // For file scheme, reject unless the files are identical. See
  1884     // NS_RelaxStrictFileOriginPolicy for enforcing file same-origin checking
  1885     if (targetScheme.EqualsLiteral("file"))
  1887         // in traditional unsafe behavior all files are the same origin
  1888         if (!aStrictFileOriginPolicy)
  1889             return true;
  1891         nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
  1892         nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
  1894         if (!sourceFileURL || !targetFileURL)
  1895             return false;
  1897         nsCOMPtr<nsIFile> sourceFile, targetFile;
  1899         sourceFileURL->GetFile(getter_AddRefs(sourceFile));
  1900         targetFileURL->GetFile(getter_AddRefs(targetFile));
  1902         if (!sourceFile || !targetFile)
  1903             return false;
  1905         // Otherwise they had better match
  1906         bool filesAreEqual = false;
  1907         nsresult rv = sourceFile->Equals(targetFile, &filesAreEqual);
  1908         return NS_SUCCEEDED(rv) && filesAreEqual;
  1911     // Special handling for mailnews schemes
  1912     if (targetScheme.EqualsLiteral("imap") ||
  1913         targetScheme.EqualsLiteral("mailbox") ||
  1914         targetScheme.EqualsLiteral("news"))
  1916         // Each message is a distinct trust domain; use the
  1917         // whole spec for comparison
  1918         nsAutoCString targetSpec;
  1919         nsAutoCString sourceSpec;
  1920         return ( NS_SUCCEEDED( targetBaseURI->GetSpec(targetSpec) ) &&
  1921                  NS_SUCCEEDED( sourceBaseURI->GetSpec(sourceSpec) ) &&
  1922                  targetSpec.Equals(sourceSpec) );
  1925     // Compare hosts
  1926     nsAutoCString targetHost;
  1927     nsAutoCString sourceHost;
  1928     if (NS_FAILED( targetBaseURI->GetAsciiHost(targetHost) ) ||
  1929         NS_FAILED( sourceBaseURI->GetAsciiHost(sourceHost) ))
  1931         return false;
  1934     nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI));
  1935     nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI));
  1936     if (!targetURL || !sourceURL)
  1938         return false;
  1941 #ifdef MOZILLA_INTERNAL_API
  1942     if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator() ))
  1943 #else
  1944     if (!targetHost.Equals(sourceHost, CaseInsensitiveCompare))
  1945 #endif
  1947         return false;
  1950     return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI);
  1953 inline bool
  1954 NS_URIIsLocalFile(nsIURI *aURI)
  1956   nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
  1958   bool isFile;
  1959   return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
  1960                                 nsIProtocolHandler::URI_IS_LOCAL_FILE,
  1961                                 &isFile)) &&
  1962          isFile;
  1965 // When strict file origin policy is enabled, SecurityCompareURIs will fail for
  1966 // file URIs that do not point to the same local file. This call provides an
  1967 // alternate file-specific origin check that allows target files that are
  1968 // contained in the same directory as the source.
  1969 //
  1970 // https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
  1971 inline bool
  1972 NS_RelaxStrictFileOriginPolicy(nsIURI *aTargetURI,
  1973                                nsIURI *aSourceURI,
  1974                                bool aAllowDirectoryTarget = false)
  1976   if (!NS_URIIsLocalFile(aTargetURI)) {
  1977     // This is probably not what the caller intended
  1978     NS_NOTREACHED("NS_RelaxStrictFileOriginPolicy called with non-file URI");
  1979     return false;
  1982   if (!NS_URIIsLocalFile(aSourceURI)) {
  1983     // If the source is not also a file: uri then forget it
  1984     // (don't want resource: principals in a file: doc)
  1985     //
  1986     // note: we're not de-nesting jar: uris here, we want to
  1987     // keep archive content bottled up in its own little island
  1988     return false;
  1991   //
  1992   // pull out the internal files
  1993   //
  1994   nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(aTargetURI));
  1995   nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(aSourceURI));
  1996   nsCOMPtr<nsIFile> targetFile;
  1997   nsCOMPtr<nsIFile> sourceFile;
  1998   bool targetIsDir;
  2000   // Make sure targetFile is not a directory (bug 209234)
  2001   // and that it exists w/out unescaping (bug 395343)
  2002   if (!sourceFileURL || !targetFileURL ||
  2003       NS_FAILED(targetFileURL->GetFile(getter_AddRefs(targetFile))) ||
  2004       NS_FAILED(sourceFileURL->GetFile(getter_AddRefs(sourceFile))) ||
  2005       !targetFile || !sourceFile ||
  2006       NS_FAILED(targetFile->Normalize()) ||
  2007 #ifndef MOZ_WIDGET_ANDROID
  2008       NS_FAILED(sourceFile->Normalize()) ||
  2009 #endif
  2010       (!aAllowDirectoryTarget &&
  2011        (NS_FAILED(targetFile->IsDirectory(&targetIsDir)) || targetIsDir))) {
  2012     return false;
  2015   //
  2016   // If the file to be loaded is in a subdirectory of the source
  2017   // (or same-dir if source is not a directory) then it will
  2018   // inherit its source principal and be scriptable by that source.
  2019   //
  2020   bool sourceIsDir;
  2021   bool allowed = false;
  2022   nsresult rv = sourceFile->IsDirectory(&sourceIsDir);
  2023   if (NS_SUCCEEDED(rv) && sourceIsDir) {
  2024     rv = sourceFile->Contains(targetFile, true, &allowed);
  2025   } else {
  2026     nsCOMPtr<nsIFile> sourceParent;
  2027     rv = sourceFile->GetParent(getter_AddRefs(sourceParent));
  2028     if (NS_SUCCEEDED(rv) && sourceParent) {
  2029       rv = sourceParent->Equals(targetFile, &allowed);
  2030       if (NS_FAILED(rv) || !allowed) {
  2031         rv = sourceParent->Contains(targetFile, true, &allowed);
  2032       } else {
  2033         MOZ_ASSERT(aAllowDirectoryTarget,
  2034                    "sourceFile->Parent == targetFile, but targetFile "
  2035                    "should've been disallowed if it is a directory");
  2040   if (NS_SUCCEEDED(rv) && allowed) {
  2041     return true;
  2044   return false;
  2047 inline bool
  2048 NS_IsInternalSameURIRedirect(nsIChannel *aOldChannel,
  2049                              nsIChannel *aNewChannel,
  2050                              uint32_t aFlags)
  2052   if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
  2053     return false;
  2056   nsCOMPtr<nsIURI> oldURI, newURI;
  2057   aOldChannel->GetURI(getter_AddRefs(oldURI));
  2058   aNewChannel->GetURI(getter_AddRefs(newURI));
  2060   if (!oldURI || !newURI) {
  2061     return false;
  2064   bool res;
  2065   return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
  2068 inline nsresult
  2069 NS_LinkRedirectChannels(uint32_t channelId,
  2070                         nsIParentChannel *parentChannel,
  2071                         nsIChannel** _result)
  2073   nsresult rv;
  2075   nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
  2076       do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
  2077   NS_ENSURE_SUCCESS(rv, rv);
  2079   return registrar->LinkChannels(channelId,
  2080                                  parentChannel,
  2081                                  _result);
  2084 /**
  2085  * Helper function to create a random URL string that's properly formed
  2086  * but guaranteed to be invalid.
  2087  */  
  2088 #define NS_FAKE_SCHEME "http://"
  2089 #define NS_FAKE_TLD ".invalid"
  2090 inline nsresult
  2091 NS_MakeRandomInvalidURLString(nsCString& result)
  2093   nsresult rv;
  2094   nsCOMPtr<nsIUUIDGenerator> uuidgen =
  2095     do_GetService("@mozilla.org/uuid-generator;1", &rv);
  2096   NS_ENSURE_SUCCESS(rv, rv);
  2098   nsID idee;
  2099   rv = uuidgen->GenerateUUIDInPlace(&idee);
  2100   NS_ENSURE_SUCCESS(rv, rv);
  2102   char chars[NSID_LENGTH];
  2103   idee.ToProvidedString(chars);
  2105   result.AssignLiteral(NS_FAKE_SCHEME);
  2106   // Strip off the '{' and '}' at the beginning and end of the UUID
  2107   result.Append(chars + 1, NSID_LENGTH - 3);
  2108   result.AppendLiteral(NS_FAKE_TLD);
  2110   return NS_OK;
  2112 #undef NS_FAKE_SCHEME
  2113 #undef NS_FAKE_TLD
  2115 /**
  2116  * Helper function to determine whether urlString is Java-compatible --
  2117  * whether it can be passed to the Java URL(String) constructor without the
  2118  * latter throwing a MalformedURLException, or without Java otherwise
  2119  * mishandling it.  This function (in effect) implements a scheme whitelist
  2120  * for Java.
  2121  */  
  2122 inline nsresult
  2123 NS_CheckIsJavaCompatibleURLString(nsCString& urlString, bool *result)
  2125   *result = false; // Default to "no"
  2127   nsresult rv = NS_OK;
  2128   nsCOMPtr<nsIURLParser> urlParser =
  2129     do_GetService(NS_STDURLPARSER_CONTRACTID, &rv);
  2130   if (NS_FAILED(rv) || !urlParser)
  2131     return NS_ERROR_FAILURE;
  2133   bool compatible = true;
  2134   uint32_t schemePos = 0;
  2135   int32_t schemeLen = 0;
  2136   urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen,
  2137                       nullptr, nullptr, nullptr, nullptr);
  2138   if (schemeLen != -1) {
  2139     nsCString scheme;
  2140     scheme.Assign(urlString.get() + schemePos, schemeLen);
  2141     // By default Java only understands a small number of URL schemes, and of
  2142     // these only some can legitimately represent a browser page's "origin"
  2143     // (and be something we can legitimately expect Java to handle ... or not
  2144     // to mishandle).
  2145     //
  2146     // Besides those listed below, the OJI plugin understands the "jar",
  2147     // "mailto", "netdoc", "javascript" and "rmi" schemes, and Java Plugin2
  2148     // also understands the "about" scheme.  We actually pass "about" URLs
  2149     // to Java ("about:blank" when processing a javascript: URL (one that
  2150     // calls Java) from the location bar of a blank page, and (in FF4 and up)
  2151     // "about:home" when processing a javascript: URL from the home page).
  2152     // And Java doesn't appear to mishandle them (for example it doesn't allow
  2153     // connections to "about" URLs).  But it doesn't make any sense to do
  2154     // same-origin checks on "about" URLs, so we don't include them in our
  2155     // scheme whitelist.
  2156     //
  2157     // The OJI plugin doesn't understand "chrome" URLs (only Java Plugin2
  2158     // does) -- so we mustn't pass them to the OJI plugin.  But we do need to
  2159     // pass "chrome" URLs to Java Plugin2:  Java Plugin2 grants additional
  2160     // privileges to chrome "origins", and some extensions take advantage of
  2161     // this.  For more information see bug 620773.
  2162     //
  2163     // As of FF4, we no longer support the OJI plugin.
  2164     if (PL_strcasecmp(scheme.get(), "http") &&
  2165         PL_strcasecmp(scheme.get(), "https") &&
  2166         PL_strcasecmp(scheme.get(), "file") &&
  2167         PL_strcasecmp(scheme.get(), "ftp") &&
  2168         PL_strcasecmp(scheme.get(), "gopher") &&
  2169         PL_strcasecmp(scheme.get(), "chrome"))
  2170       compatible = false;
  2171   } else {
  2172     compatible = false;
  2175   *result = compatible;
  2177   return NS_OK;
  2180 /** Given the first (disposition) token from a Content-Disposition header,
  2181  * tell whether it indicates the content is inline or attachment
  2182  * @param aDispToken the disposition token from the content-disposition header
  2183  */
  2184 inline uint32_t
  2185 NS_GetContentDispositionFromToken(const nsAString& aDispToken)
  2187   // RFC 2183, section 2.8 says that an unknown disposition
  2188   // value should be treated as "attachment"
  2189   // If all of these tests eval to false, then we have a content-disposition of
  2190   // "attachment" or unknown
  2191   if (aDispToken.IsEmpty() ||
  2192       aDispToken.LowerCaseEqualsLiteral("inline") ||
  2193       // Broken sites just send
  2194       // Content-Disposition: filename="file"
  2195       // without a disposition token... screen those out.
  2196       StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename"))
  2197     return nsIChannel::DISPOSITION_INLINE;
  2199   return nsIChannel::DISPOSITION_ATTACHMENT;
  2202 /** Determine the disposition (inline/attachment) of the content based on the
  2203  * Content-Disposition header
  2204  * @param aHeader the content-disposition header (full value)
  2205  * @param aChan the channel the header came from
  2206  */
  2207 inline uint32_t
  2208 NS_GetContentDispositionFromHeader(const nsACString& aHeader, nsIChannel *aChan = nullptr)
  2210   nsresult rv;
  2211   nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
  2212   if (NS_FAILED(rv))
  2213     return nsIChannel::DISPOSITION_ATTACHMENT;
  2215   nsAutoCString fallbackCharset;
  2216   if (aChan) {
  2217     nsCOMPtr<nsIURI> uri;
  2218     aChan->GetURI(getter_AddRefs(uri));
  2219     if (uri)
  2220       uri->GetOriginCharset(fallbackCharset);
  2223   nsAutoString dispToken;
  2224   rv = mimehdrpar->GetParameterHTTP(aHeader, "", fallbackCharset, true, nullptr,
  2225                                     dispToken);
  2227   if (NS_FAILED(rv)) {
  2228     // special case (see bug 272541): empty disposition type handled as "inline"
  2229     if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY)
  2230         return nsIChannel::DISPOSITION_INLINE;
  2231     return nsIChannel::DISPOSITION_ATTACHMENT;
  2234   return NS_GetContentDispositionFromToken(dispToken);
  2237 /** Extracts the filename out of a content-disposition header
  2238  * @param aFilename [out] The filename. Can be empty on error.
  2239  * @param aDisposition Value of a Content-Disposition header
  2240  * @param aURI Optional. Will be used to get a fallback charset for the
  2241  *        filename, if it is QI'able to nsIURL
  2242  */
  2243 inline nsresult
  2244 NS_GetFilenameFromDisposition(nsAString& aFilename,
  2245                               const nsACString& aDisposition,
  2246                               nsIURI* aURI = nullptr)
  2248   aFilename.Truncate();
  2250   nsresult rv;
  2251   nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
  2252       do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
  2253   if (NS_FAILED(rv))
  2254     return rv;
  2256   nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
  2258   nsAutoCString fallbackCharset;
  2259   if (url)
  2260     url->GetOriginCharset(fallbackCharset);
  2261   // Get the value of 'filename' parameter
  2262   rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename",
  2263                                     fallbackCharset, true, nullptr,
  2264                                     aFilename);
  2266   if (NS_FAILED(rv)) {
  2267     aFilename.Truncate();
  2268     return rv;
  2271   if (aFilename.IsEmpty())
  2272     return NS_ERROR_NOT_AVAILABLE;
  2274   return NS_OK;
  2277 /**
  2278  * Make sure Personal Security Manager is initialized
  2279  */
  2280 inline void
  2281 net_EnsurePSMInit()
  2283     nsCOMPtr<nsISocketProviderService> spserv =
  2284             do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
  2285     if (spserv) {
  2286         nsCOMPtr<nsISocketProvider> provider;
  2287         spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
  2291 /**
  2292  * Test whether a URI is "about:blank".  |uri| must not be null
  2293  */
  2294 inline bool
  2295 NS_IsAboutBlank(nsIURI *uri)
  2297     // GetSpec can be expensive for some URIs, so check the scheme first.
  2298     bool isAbout = false;
  2299     if (NS_FAILED(uri->SchemeIs("about", &isAbout)) || !isAbout) {
  2300         return false;
  2303     nsAutoCString str;
  2304     uri->GetSpec(str);
  2305     return str.EqualsLiteral("about:blank");
  2309 inline nsresult
  2310 NS_GenerateHostPort(const nsCString& host, int32_t port,
  2311                     nsCString& hostLine)
  2313     if (strchr(host.get(), ':')) {
  2314         // host is an IPv6 address literal and must be encapsulated in []'s
  2315         hostLine.Assign('[');
  2316         // scope id is not needed for Host header.
  2317         int scopeIdPos = host.FindChar('%');
  2318         if (scopeIdPos == -1)
  2319             hostLine.Append(host);
  2320         else if (scopeIdPos > 0)
  2321             hostLine.Append(Substring(host, 0, scopeIdPos));
  2322         else
  2323           return NS_ERROR_MALFORMED_URI;
  2324         hostLine.Append(']');
  2326     else
  2327         hostLine.Assign(host);
  2328     if (port != -1) {
  2329         hostLine.Append(':');
  2330         hostLine.AppendInt(port);
  2332     return NS_OK;
  2335 /**
  2336  * Sniff the content type for a given request or a given buffer.
  2338  * aSnifferType can be either NS_CONTENT_SNIFFER_CATEGORY or
  2339  * NS_DATA_SNIFFER_CATEGORY.  The function returns the sniffed content type
  2340  * in the aSniffedType argument.  This argument will not be modified if the
  2341  * content type could not be sniffed.
  2342  */
  2343 inline void
  2344 NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest,
  2345                 const uint8_t* aData, uint32_t aLength,
  2346                 nsACString& aSniffedType)
  2348   typedef nsCategoryCache<nsIContentSniffer> ContentSnifferCache;
  2349   extern NS_HIDDEN_(ContentSnifferCache*) gNetSniffers;
  2350   extern NS_HIDDEN_(ContentSnifferCache*) gDataSniffers;
  2351   ContentSnifferCache* cache = nullptr;
  2352   if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) {
  2353     if (!gNetSniffers) {
  2354       gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY);
  2356     cache = gNetSniffers;
  2357   } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) {
  2358     if (!gDataSniffers) {
  2359       gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY);
  2361     cache = gDataSniffers;
  2362   } else {
  2363     // Invalid content sniffer type was requested
  2364     MOZ_ASSERT(false);
  2365     return;
  2368   nsCOMArray<nsIContentSniffer> sniffers;
  2369   cache->GetEntries(sniffers);
  2370   for (int32_t i = 0; i < sniffers.Count(); ++i) {
  2371     nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength, aSniffedType);
  2372     if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
  2373       return;
  2377   aSniffedType.Truncate();
  2380 /**
  2381  * Whether the channel was created to load a srcdoc document.
  2382  * Note that view-source:about:srcdoc is classified as a srcdoc document by 
  2383  * this function, which may not be applicable everywhere.
  2384  */
  2385 inline bool
  2386 NS_IsSrcdocChannel(nsIChannel *aChannel)
  2388   bool isSrcdoc;
  2389   nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
  2390   if (isr) {
  2391     isr->GetIsSrcdocChannel(&isSrcdoc);
  2392     return isSrcdoc;
  2394   nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
  2395   if (vsc) {
  2396     vsc->GetIsSrcdocChannel(&isSrcdoc);
  2397     return isSrcdoc;
  2399   return false;
  2402 #endif // !nsNetUtil_h__

mercurial