From 4ebc72410aba95c6dabc0caedd368c30551b39a0 Mon Sep 17 00:00:00 2001 From: Fedor Date: Sat, 1 Jun 2024 19:22:47 +0300 Subject: [PATCH] 68.14.2 - network --- netwerk/base/AutoClose.h | 2 +- netwerk/base/BackgroundFileSaver.cpp | 50 +- netwerk/base/BackgroundFileSaver.h | 3 +- netwerk/base/EventTokenBucket.cpp | 2 +- netwerk/base/FuzzySecurityInfo.cpp | 19 +- netwerk/base/LoadInfo.cpp | 67 +- netwerk/base/LoadInfo.h | 2 + netwerk/base/NetworkConnectivityService.cpp | 21 +- netwerk/base/NetworkConnectivityService.h | 2 + netwerk/base/RequestContextService.cpp | 8 +- netwerk/base/SSLTokensCache.cpp | 177 ++- netwerk/base/SSLTokensCache.h | 34 +- netwerk/base/TLSServerSocket.cpp | 9 +- netwerk/base/TLSServerSocket.h | 1 - netwerk/base/Tickler.h | 1 - netwerk/base/moz.build | 1 + netwerk/base/nsAsyncRedirectVerifyHelper.h | 1 - netwerk/base/nsBaseChannel.cpp | 17 +- netwerk/base/nsBaseChannel.h | 4 +- netwerk/base/nsBufferedStreams.cpp | 53 +- netwerk/base/nsBufferedStreams.h | 2 +- netwerk/base/nsFileStreams.cpp | 2 +- netwerk/base/nsFileStreams.h | 4 +- netwerk/base/nsIBackgroundFileSaver.idl | 9 +- netwerk/base/nsILoadInfo.idl | 39 +- .../base/nsINetworkConnectivityService.idl | 4 + netwerk/base/nsIOService.cpp | 2 +- netwerk/base/nsIProgressEventSink.idl | 8 - netwerk/base/nsIncrementalDownload.cpp | 6 +- netwerk/base/nsInputStreamChannel.cpp | 2 +- netwerk/base/nsLoadGroup.cpp | 4 +- netwerk/base/nsMIMEInputStream.cpp | 17 +- netwerk/base/nsNetUtil.cpp | 11 +- netwerk/base/nsNetUtil.h | 6 +- netwerk/base/nsPACMan.cpp | 24 +- netwerk/base/nsPACMan.h | 9 +- netwerk/base/nsProtocolProxyService.cpp | 96 +- netwerk/base/nsProtocolProxyService.h | 3 +- netwerk/base/nsRequestObserverProxy.cpp | 1 - netwerk/base/nsSerializationHelper.cpp | 1 - netwerk/base/nsServerSocket.cpp | 1 - netwerk/base/nsSocketTransport2.cpp | 43 +- netwerk/base/nsSocketTransport2.h | 3 +- netwerk/base/nsStandardURL.cpp | 1 - netwerk/base/nsStreamTransportService.cpp | 13 +- netwerk/base/nsSyncStreamListener.cpp | 2 +- netwerk/base/nsTransportUtils.cpp | 7 +- netwerk/base/nsUDPSocket.cpp | 1 - netwerk/base/nsUDPSocket.h | 1 - netwerk/base/nsURIHashKey.h | 13 +- netwerk/cache/nsApplicationCacheService.cpp | 5 +- netwerk/cache/nsCacheEntry.cpp | 2 +- netwerk/cache/nsCacheEntry.h | 1 - netwerk/cache/nsCacheService.cpp | 61 +- netwerk/cache/nsCacheSession.cpp | 6 +- netwerk/cache/nsDeleteDir.cpp | 19 +- netwerk/cache/nsDiskCacheDeviceSQL.cpp | 7 +- netwerk/cache/nsDiskCacheDeviceSQL.h | 1 - netwerk/cache2/CacheEntry.cpp | 7 - netwerk/cache2/CacheEntry.h | 4 - netwerk/cache2/CacheFile.cpp | 191 +-- netwerk/cache2/CacheFile.h | 9 +- netwerk/cache2/CacheFileChunk.cpp | 9 +- netwerk/cache2/CacheFileChunk.h | 8 +- netwerk/cache2/CacheFileContextEvictor.cpp | 64 +- netwerk/cache2/CacheFileContextEvictor.h | 12 +- netwerk/cache2/CacheFileIOManager.cpp | 108 +- netwerk/cache2/CacheFileIOManager.h | 20 +- netwerk/cache2/CacheFileInputStream.cpp | 11 +- netwerk/cache2/CacheFileInputStream.h | 3 +- netwerk/cache2/CacheFileMetadata.cpp | 63 +- netwerk/cache2/CacheFileMetadata.h | 29 +- netwerk/cache2/CacheFileOutputStream.h | 1 - netwerk/cache2/CacheFileUtils.cpp | 65 -- netwerk/cache2/CacheFileUtils.h | 17 - netwerk/cache2/CacheIOThread.h | 1 - netwerk/cache2/CacheIndex.cpp | 147 +-- netwerk/cache2/CacheIndex.h | 54 +- netwerk/cache2/CacheIndexIterator.h | 1 - netwerk/cache2/CacheObserver.cpp | 30 - netwerk/cache2/CacheObserver.h | 4 - netwerk/cache2/OldWrappers.cpp | 14 +- netwerk/cache2/OldWrappers.h | 3 - netwerk/cache2/nsICacheEntry.idl | 6 - netwerk/cookie/CookieServiceChild.cpp | 5 +- netwerk/cookie/nsCookie.cpp | 35 +- netwerk/cookie/nsCookie.h | 2 + netwerk/cookie/nsCookieService.cpp | 219 ++-- netwerk/cookie/nsCookieService.h | 20 +- netwerk/cookie/nsICookieManager.idl | 52 +- netwerk/cookie/nsICookieService.idl | 17 +- .../test/browser/browser_originattributes.js | 4 +- netwerk/cookie/test/unit/test_bug1155169.js | 2 +- netwerk/cookie/test/unit/test_bug1321912.js | 4 +- netwerk/cookie/test/unit/test_bug643051.js | 4 +- netwerk/cookie/test/unit/test_eviction.js | 2 +- netwerk/cookie/test/unit/test_parser_0001.js | 2 +- netwerk/cookie/test/unit/test_parser_0019.js | 2 +- netwerk/dns/DNSRequestChild.cpp | 3 +- netwerk/dns/GetAddrInfo.cpp | 1 - netwerk/dns/TRR.cpp | 48 +- netwerk/dns/TRRService.cpp | 234 ++-- netwerk/dns/TRRService.h | 16 +- netwerk/dns/nsDNSService2.cpp | 4 +- netwerk/dns/nsDNSService2.h | 1 - netwerk/dns/nsHostResolver.cpp | 103 +- netwerk/dns/nsHostResolver.h | 6 +- netwerk/ipc/ChannelEventQueue.cpp | 2 +- netwerk/ipc/ChannelEventQueue.h | 57 +- netwerk/ipc/NeckoChannelParams.ipdlh | 4 + .../protocol/about/nsAboutProtocolHandler.cpp | 1 - netwerk/protocol/file/nsFileChannel.cpp | 1 - netwerk/protocol/ftp/nsFtpConnectionThread.h | 1 - netwerk/protocol/ftp/nsFtpControlConnection.h | 1 - netwerk/protocol/http/AlternateServices.cpp | 29 +- .../protocol/http/ClassifierDummyChannel.cpp | 4 +- netwerk/protocol/http/Http2Session.cpp | 4 +- netwerk/protocol/http/Http2Stream.h | 2 +- .../http/HttpBackgroundChannelChild.cpp | 56 - .../http/HttpBackgroundChannelChild.h | 5 - .../http/HttpBackgroundChannelParent.cpp | 52 - .../http/HttpBackgroundChannelParent.h | 6 - netwerk/protocol/http/HttpBaseChannel.cpp | 271 ++--- netwerk/protocol/http/HttpBaseChannel.h | 94 +- netwerk/protocol/http/HttpChannelChild.cpp | 876 +++++--------- netwerk/protocol/http/HttpChannelChild.h | 32 +- netwerk/protocol/http/HttpChannelParent.cpp | 98 +- netwerk/protocol/http/HttpChannelParent.h | 5 +- netwerk/protocol/http/InterceptedChannel.cpp | 14 +- netwerk/protocol/http/InterceptedChannel.h | 5 +- .../protocol/http/InterceptedHttpChannel.cpp | 24 +- netwerk/protocol/http/NullHttpChannel.cpp | 8 +- .../protocol/http/PHttpBackgroundChannel.ipdl | 4 - netwerk/protocol/http/PHttpChannel.ipdl | 7 +- netwerk/protocol/http/PSpdyPush.h | 1 - netwerk/protocol/http/TunnelUtils.cpp | 114 +- netwerk/protocol/http/TunnelUtils.h | 2 + .../http/WellKnownOpportunisticUtils.jsm | 11 +- netwerk/protocol/http/nsCORSListenerProxy.cpp | 25 +- netwerk/protocol/http/nsCORSListenerProxy.h | 6 +- netwerk/protocol/http/nsHttp.cpp | 3 +- netwerk/protocol/http/nsHttp.h | 1 - .../http/nsHttpActivityDistributor.cpp | 1 - netwerk/protocol/http/nsHttpAuthCache.cpp | 6 +- netwerk/protocol/http/nsHttpAuthCache.h | 2 +- netwerk/protocol/http/nsHttpAuthManager.cpp | 6 +- netwerk/protocol/http/nsHttpChannel.cpp | 331 ++++-- netwerk/protocol/http/nsHttpChannel.h | 44 +- .../http/nsHttpChannelAuthProvider.cpp | 19 +- .../protocol/http/nsHttpChunkedDecoder.cpp | 2 +- netwerk/protocol/http/nsHttpChunkedDecoder.h | 5 +- netwerk/protocol/http/nsHttpConnection.cpp | 22 +- netwerk/protocol/http/nsHttpConnection.h | 1 - netwerk/protocol/http/nsHttpConnectionMgr.cpp | 69 +- netwerk/protocol/http/nsHttpConnectionMgr.h | 14 +- netwerk/protocol/http/nsHttpHandler.cpp | 139 +-- netwerk/protocol/http/nsHttpHandler.h | 13 +- netwerk/protocol/http/nsHttpNTLMAuth.cpp | 21 +- netwerk/protocol/http/nsHttpRequestHead.cpp | 37 +- netwerk/protocol/http/nsHttpRequestHead.h | 3 + netwerk/protocol/http/nsHttpResponseHead.cpp | 43 +- netwerk/protocol/http/nsHttpResponseHead.h | 11 +- netwerk/protocol/http/nsHttpTransaction.cpp | 66 +- netwerk/protocol/http/nsHttpTransaction.h | 6 +- netwerk/protocol/http/nsIHttpChannel.idl | 6 + .../protocol/http/nsIHttpChannelInternal.idl | 10 +- .../http/nsIWellKnownOpportunisticUtils.idl | 5 +- .../viewsource/nsViewSourceChannel.cpp | 22 +- .../websocket/BaseWebSocketChannel.cpp | 12 +- .../protocol/websocket/WebSocketChannel.cpp | 265 ++--- netwerk/protocol/websocket/WebSocketChannel.h | 4 +- .../websocket/WebSocketChannelChild.cpp | 12 +- .../websocket/WebSocketEventService.h | 1 - netwerk/protocol/websocket/WebSocketFrame.h | 1 - netwerk/sctp/datachannel/DataChannel.cpp | 1031 +++++++++-------- netwerk/sctp/datachannel/DataChannel.h | 103 +- netwerk/sctp/datachannel/DataChannelLog.h | 15 +- .../sctp/datachannel/DataChannelProtocol.h | 3 - netwerk/sctp/datachannel/moz.build | 1 + netwerk/socket/nsISSLSocketControl.idl | 9 +- netwerk/socket/nsITransportSecurityInfo.idl | 7 +- netwerk/socket/nsNamedPipeIOLayer.cpp | 11 +- netwerk/socket/nsNamedPipeIOLayer.h | 1 + .../streamconv/converters/ParseFTPList.cpp | 3 +- .../converters/mozTXTToHTMLConv.cpp | 6 +- .../converters/nsDirIndexParser.cpp | 35 +- .../streamconv/converters/nsDirIndexParser.h | 4 +- .../converters/nsFTPDirListingConv.cpp | 6 +- .../converters/nsHTTPCompressConv.cpp | 2 +- .../converters/nsHTTPCompressConv.h | 3 +- .../converters/nsMultiMixedConv.cpp | 8 +- .../streamconv/converters/nsMultiMixedConv.h | 6 +- .../streamconv/nsStreamConverterService.cpp | 11 +- netwerk/system/win32/nsNotifyAddrListener.cpp | 1 - netwerk/test/TestCookie.cpp | 75 +- netwerk/test/httpserver/httpd.js | 93 ++ netwerk/test/mochitests/file_chromecommon.js | 2 +- ...file_documentcookie_maxage_chromescript.js | 2 +- .../file_testloadflags_chromescript.js | 4 +- .../test/mochitests/test_accept_header.html | 2 +- netwerk/test/unit/head_cookies.js | 26 +- netwerk/test/unit/test_altsvc.js | 7 +- netwerk/test/unit/test_bug1177909.js | 48 +- netwerk/test/unit/test_bug248970_cache.js | 3 + netwerk/test/unit/test_bug411952.js | 2 +- netwerk/test/unit/test_bug526789.js | 59 +- netwerk/test/unit/test_bug528292.js | 2 +- netwerk/test/unit/test_bug650995.js | 1 + netwerk/test/unit/test_bug667818.js | 8 +- netwerk/test/unit/test_bug767025.js | 1 + .../unit/test_cacheForOfflineUse_no-store.js | 6 + netwerk/test/unit/test_cache_204_response.js | 61 + netwerk/test/unit/test_cookie_blacklist.js | 5 - netwerk/test/unit/test_cookie_header.js | 2 +- .../test/unit/test_cookies_async_failure.js | 26 +- .../test/unit/test_cookies_privatebrowsing.js | 8 +- .../test/unit/test_cookies_profile_close.js | 22 +- netwerk/test/unit/test_cookies_read.js | 6 +- .../test/unit/test_cookies_sync_failure.js | 4 +- netwerk/test/unit/test_domain_eviction.js | 14 +- netwerk/test/unit/test_eviction.js | 8 +- .../test_fallback_no-cache-entry_canceled.js | 3 +- .../test_fallback_no-cache-entry_passing.js | 3 +- ...k_redirect-to-different-origin_canceled.js | 3 +- ...ck_redirect-to-different-origin_passing.js | 3 +- .../test_fallback_request-error_canceled.js | 3 +- .../test_fallback_request-error_passing.js | 3 +- .../test_fallback_response-error_canceled.js | 3 +- .../test_fallback_response-error_passing.js | 3 +- netwerk/test/unit/test_file_protocol.js | 26 +- netwerk/test/unit/test_http2-proxy.js | 194 +++- netwerk/test/unit/test_http2.js | 14 +- netwerk/test/unit/test_node_execute.js | 88 ++ .../test_offlinecache_custom-directory.js | 1 + netwerk/test/unit/test_pinned_app_cache.js | 1 + netwerk/test/unit/test_post.js | 13 +- .../test/unit/test_private_cookie_changed.js | 4 +- netwerk/test/unit/test_progress.js | 28 +- netwerk/test/unit/test_schema_2_migration.js | 8 +- netwerk/test/unit/test_schema_3_migration.js | 12 +- .../test/unit/test_signature_extraction.js | 32 +- .../unit/test_stale-while-revalidate_loop.js | 46 + .../test_stale-while-revalidate_positive.js | 4 - .../test/unit/test_synthesized_response.js | 12 +- netwerk/test/unit/test_trr.js | 534 ++++++++- netwerk/test/unit/xpcshell.ini | 7 +- .../url-classifier/UrlClassifierCommon.cpp | 2 +- netwerk/wifi/nsIWifiListener.idl | 2 +- netwerk/wifi/nsWifiMonitor.cpp | 61 +- netwerk/wifi/nsWifiMonitor.h | 3 +- netwerk/wifi/nsWifiScannerMac.cpp | 1 - netwerk/wifi/nsWifiScannerWin.cpp | 3 +- netwerk/wifi/osx_corewlan.mm | 1 - netwerk/wifi/win_wifiScanner.cpp | 6 +- netwerk/wifi/win_wifiScanner.h | 4 +- netwerk/wifi/win_wlanLibrary.h | 6 +- 256 files changed, 4531 insertions(+), 3972 deletions(-) create mode 100644 netwerk/test/unit/test_cache_204_response.js create mode 100644 netwerk/test/unit/test_node_execute.js create mode 100644 netwerk/test/unit/test_stale-while-revalidate_loop.js diff --git a/netwerk/base/AutoClose.h b/netwerk/base/AutoClose.h index 13d8ffd739..3360f5c043 100644 --- a/netwerk/base/AutoClose.h +++ b/netwerk/base/AutoClose.h @@ -11,7 +11,7 @@ namespace mozilla { namespace net { -// Like an nsAutoPtr for XPCOM streams (e.g. nsIAsyncInputStream) and other +// A container for XPCOM streams (e.g. nsIAsyncInputStream) and other // refcounted classes that need to have the Close() method called explicitly // before they are destroyed. template diff --git a/netwerk/base/BackgroundFileSaver.cpp b/netwerk/base/BackgroundFileSaver.cpp index 8be2492ee9..94c1f25297 100644 --- a/netwerk/base/BackgroundFileSaver.cpp +++ b/netwerk/base/BackgroundFileSaver.cpp @@ -15,9 +15,6 @@ #include "nsIFile.h" #include "nsIMutableArray.h" #include "nsIPipe.h" -#include "nsIX509Cert.h" -#include "nsIX509CertDB.h" -#include "nsIX509CertList.h" #include "nsNetUtil.h" #include "nsThreadUtils.h" #include "pk11pub.h" @@ -249,19 +246,17 @@ BackgroundFileSaver::EnableSignatureInfo() { } NS_IMETHODIMP -BackgroundFileSaver::GetSignatureInfo(nsIArray** aSignatureInfo) { +BackgroundFileSaver::GetSignatureInfo( + nsTArray>>& aSignatureInfo) { MOZ_ASSERT(NS_IsMainThread(), "Can't inspect signature off the main thread"); // We acquire a lock because mSignatureInfo is written on the worker thread. MutexAutoLock lock(mLock); if (!mComplete || !mSignatureInfoEnabled) { return NS_ERROR_NOT_AVAILABLE; } - nsCOMPtr sigArray = do_CreateInstance(NS_ARRAY_CONTRACTID); - for (int i = 0; i < mSignatureInfo.Count(); ++i) { - sigArray->AppendElement(mSignatureInfo[i]); + for (const auto& signatureChain : mSignatureInfo) { + aSignatureInfo.AppendElement(signatureChain); } - *aSignatureInfo = sigArray; - NS_IF_ADDREF(*aSignatureInfo); return NS_OK; } @@ -760,9 +755,6 @@ nsresult BackgroundFileSaver::ExtractSignatureInfo(const nsAString& filePath) { return NS_OK; } } - nsresult rv; - nsCOMPtr certDB = do_GetService(NS_X509CERTDB_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); #ifdef XP_WIN // Setup the file to check. WINTRUST_FILE_INFO fileToCheck = {0}; @@ -819,11 +811,8 @@ nsresult BackgroundFileSaver::ExtractSignatureInfo(const nsAString& filePath) { if (!certSimpleChain) { break; } - nsCOMPtr nssCertList = - do_CreateInstance(NS_X509CERTLIST_CONTRACTID); - if (!nssCertList) { - break; - } + + nsTArray> certList; bool extractionSuccess = true; for (DWORD k = 0; k < certSimpleChain->cElement; ++k) { CERT_CHAIN_ELEMENT* certChainElement = certSimpleChain->rgpElement[k]; @@ -831,30 +820,13 @@ nsresult BackgroundFileSaver::ExtractSignatureInfo(const nsAString& filePath) { X509_ASN_ENCODING) { continue; } - nsCOMPtr nssCert = nullptr; - nsDependentCSubstring certDER( - reinterpret_cast( - certChainElement->pCertContext->pbCertEncoded), - certChainElement->pCertContext->cbCertEncoded); - rv = certDB->ConstructX509(certDER, getter_AddRefs(nssCert)); - if (!nssCert) { - extractionSuccess = false; - LOG(("Couldn't create NSS cert [this = %p]", this)); - break; - } - rv = nssCertList->AddCert(nssCert); - if (NS_FAILED(rv)) { - extractionSuccess = false; - LOG(("Couldn't add NSS cert to cert list [this = %p]", this)); - break; - } - nsString subjectName; - nssCert->GetSubjectName(subjectName); - LOG(("Adding cert %s [this = %p]", - NS_ConvertUTF16toUTF8(subjectName).get(), this)); + nsTArray cert; + cert.AppendElements(certChainElement->pCertContext->pbCertEncoded, + certChainElement->pCertContext->cbCertEncoded); + certList.AppendElement(cert); } if (extractionSuccess) { - mSignatureInfo.AppendObject(nssCertList); + mSignatureInfo.AppendElement(std::move(certList)); } } } diff --git a/netwerk/base/BackgroundFileSaver.h b/netwerk/base/BackgroundFileSaver.h index 466badef31..bc67867b09 100644 --- a/netwerk/base/BackgroundFileSaver.h +++ b/netwerk/base/BackgroundFileSaver.h @@ -22,7 +22,6 @@ class nsIAsyncInputStream; class nsIThread; -class nsIX509CertList; namespace mozilla { namespace net { @@ -201,7 +200,7 @@ class BackgroundFileSaver : public nsIBackgroundFileSaver { /** * Store the signature info. */ - nsCOMArray mSignatureInfo; + nsTArray>> mSignatureInfo; /** * Whether or not to extract the signature. Must be set on the main thread diff --git a/netwerk/base/EventTokenBucket.cpp b/netwerk/base/EventTokenBucket.cpp index 192f265b6b..67bc9a819b 100644 --- a/netwerk/base/EventTokenBucket.cpp +++ b/netwerk/base/EventTokenBucket.cpp @@ -214,7 +214,7 @@ nsresult EventTokenBucket::SubmitEvent(ATokenBucketEvent* event, // When this function exits the cancelEvent needs 2 references, one for the // mEvents queue and one for the caller of SubmitEvent() - NS_ADDREF(*cancelable = cancelEvent.get()); + *cancelable = do_AddRef(cancelEvent).take(); if (mPaused || !TryImmediateDispatch(cancelEvent.get())) { // queue it diff --git a/netwerk/base/FuzzySecurityInfo.cpp b/netwerk/base/FuzzySecurityInfo.cpp index e72103b003..a695530cbd 100644 --- a/netwerk/base/FuzzySecurityInfo.cpp +++ b/netwerk/base/FuzzySecurityInfo.cpp @@ -36,7 +36,8 @@ FuzzySecurityInfo::GetErrorCodeString(nsAString& aErrorString) { } NS_IMETHODIMP -FuzzySecurityInfo::GetFailedCertChain(nsIX509CertList** _result) { +FuzzySecurityInfo::GetFailedCertChain( + nsTArray>& aFailedCertChain) { MOZ_CRASH("Unused"); return NS_OK; } @@ -52,8 +53,8 @@ FuzzySecurityInfo::GetServerCert(nsIX509Cert** aServerCert) { } NS_IMETHODIMP -FuzzySecurityInfo::GetSucceededCertChain(nsIX509CertList** _result) { - NS_ENSURE_ARG_POINTER(_result); +FuzzySecurityInfo::GetSucceededCertChain( + nsTArray>& aSucceededCertChain) { MOZ_CRASH("Unused"); return NS_OK; } @@ -315,12 +316,6 @@ FuzzySecurityInfo::SetEsniTxt(const nsACString& aEsniTxt) { return NS_OK; } -NS_IMETHODIMP -FuzzySecurityInfo::GetServerRootCertIsBuiltInRoot(bool* aIsBuiltInRoot) { - *aIsBuiltInRoot = true; - return NS_OK; -} - void FuzzySecurityInfo::SerializeToIPC(IPC::Message* aMsg) { MOZ_CRASH("Unused"); } @@ -331,5 +326,11 @@ bool FuzzySecurityInfo::DeserializeFromIPC(const IPC::Message* aMsg, return false; } +NS_IMETHODIMP +FuzzySecurityInfo::GetPeerId(nsACString& aResult) { + aResult.Assign(EmptyCString()); + return NS_OK; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 2bdc6d14d5..6d21a4300e 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -9,6 +9,7 @@ #include "mozilla/ExpandedPrincipal.h" #include "mozilla/dom/ClientIPCTypes.h" #include "mozilla/dom/ClientSource.h" +#include "mozilla/dom/Performance.h" #include "mozilla/dom/PerformanceStorage.h" #include "mozilla/dom/BrowserChild.h" #include "mozilla/dom/ToJSValue.h" @@ -34,7 +35,6 @@ #include "nsQueryObject.h" #include "nsRedirectHistoryEntry.h" #include "nsSandboxFlags.h" -#include "LoadInfo.h" using namespace mozilla::dom; @@ -95,6 +95,7 @@ LoadInfo::LoadInfo( mServiceWorkerTaintingSynthesized(false), mDocumentHasUserInteracted(false), mDocumentHasLoaded(false), + mAllowListFutureDocumentsCreatedFromThisRedirectChain(false), mIsFromProcessingFrameAttributes(false) { MOZ_ASSERT(mLoadingPrincipal); MOZ_ASSERT(mTriggeringPrincipal); @@ -346,6 +347,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow, mServiceWorkerTaintingSynthesized(false), mDocumentHasUserInteracted(false), mDocumentHasLoaded(false), + mAllowListFutureDocumentsCreatedFromThisRedirectChain(false), mIsFromProcessingFrameAttributes(false) { // Top-level loads are never third-party // Grab the information we can out of the window. @@ -461,6 +463,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) mServiceWorkerTaintingSynthesized(false), mDocumentHasUserInteracted(rhs.mDocumentHasUserInteracted), mDocumentHasLoaded(rhs.mDocumentHasLoaded), + mAllowListFutureDocumentsCreatedFromThisRedirectChain( + rhs.mAllowListFutureDocumentsCreatedFromThisRedirectChain), mCspNonce(rhs.mCspNonce), mIsFromProcessingFrameAttributes(rhs.mIsFromProcessingFrameAttributes) {} @@ -494,8 +498,9 @@ LoadInfo::LoadInfo( const nsTArray& aCorsUnsafeHeaders, bool aForcePreflight, bool aIsPreflight, bool aLoadTriggeredFromExternal, bool aServiceWorkerTaintingSynthesized, bool aDocumentHasUserInteracted, - bool aDocumentHasLoaded, const nsAString& aCspNonce, - uint32_t aRequestBlockingReason) + bool aDocumentHasLoaded, + bool aAllowListFutureDocumentsCreatedFromThisRedirectChain, + const nsAString& aCspNonce, uint32_t aRequestBlockingReason) : mLoadingPrincipal(aLoadingPrincipal), mTriggeringPrincipal(aTriggeringPrincipal), mPrincipalToInherit(aPrincipalToInherit), @@ -544,6 +549,8 @@ LoadInfo::LoadInfo( mServiceWorkerTaintingSynthesized(aServiceWorkerTaintingSynthesized), mDocumentHasUserInteracted(aDocumentHasUserInteracted), mDocumentHasLoaded(aDocumentHasLoaded), + mAllowListFutureDocumentsCreatedFromThisRedirectChain( + aAllowListFutureDocumentsCreatedFromThisRedirectChain), mCspNonce(aCspNonce), mIsFromProcessingFrameAttributes(false) { // Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal @@ -604,11 +611,13 @@ LoadInfo::GetLoadingPrincipal(nsIPrincipal** aLoadingPrincipal) { return NS_OK; } -nsIPrincipal* LoadInfo::LoadingPrincipal() { return mLoadingPrincipal; } +nsIPrincipal* LoadInfo::VirtualGetLoadingPrincipal() { + return mLoadingPrincipal; +} NS_IMETHODIMP LoadInfo::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal) { - NS_ADDREF(*aTriggeringPrincipal = mTriggeringPrincipal); + *aTriggeringPrincipal = do_AddRef(mTriggeringPrincipal).take(); return NS_OK; } @@ -1282,6 +1291,20 @@ LoadInfo::SetDocumentHasLoaded(bool aDocumentHasLoaded) { return NS_OK; } +NS_IMETHODIMP +LoadInfo::GetAllowListFutureDocumentsCreatedFromThisRedirectChain( + bool* aValue) { + MOZ_ASSERT(aValue); + *aValue = mAllowListFutureDocumentsCreatedFromThisRedirectChain; + return NS_OK; +} + +NS_IMETHODIMP +LoadInfo::SetAllowListFutureDocumentsCreatedFromThisRedirectChain(bool aValue) { + mAllowListFutureDocumentsCreatedFromThisRedirectChain = aValue; + return NS_OK; +} + NS_IMETHODIMP LoadInfo::GetCspNonce(nsAString& aCspNonce) { aCspNonce = mCspNonce; @@ -1415,7 +1438,39 @@ void LoadInfo::SetPerformanceStorage(PerformanceStorage* aPerformanceStorage) { } PerformanceStorage* LoadInfo::GetPerformanceStorage() { - return mPerformanceStorage; + if (mPerformanceStorage) { + return mPerformanceStorage; + } + + RefPtr loadingDocument; + GetLoadingDocument(getter_AddRefs(loadingDocument)); + if (!loadingDocument) { + return nullptr; + } + + if (!TriggeringPrincipal()->Equals(loadingDocument->NodePrincipal())) { + return nullptr; + } + + if (nsILoadInfo::GetExternalContentPolicyType() == + nsIContentPolicy::TYPE_SUBDOCUMENT && + !GetIsFromProcessingFrameAttributes()) { + // We only report loads caused by processing the attributes of the + // browsing context container. + return nullptr; + } + + nsCOMPtr innerWindow = loadingDocument->GetInnerWindow(); + if (!innerWindow) { + return nullptr; + } + + mozilla::dom::Performance* performance = innerWindow->GetPerformance(); + if (!performance) { + return nullptr; + } + + return performance->AsPerformanceStorage(); } NS_IMETHODIMP diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index c26a781794..4a0689eff8 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -150,6 +150,7 @@ class LoadInfo final : public nsILoadInfo { bool aIsPreflight, bool aLoadTriggeredFromExternal, bool aServiceWorkerTaintingSynthesized, bool aDocumentHasUserInteracted, bool aDocumentHasLoaded, + bool aAllowListFutureDocumentsCreatedFromThisRedirectChain, const nsAString& aCspNonce, uint32_t aRequestBlockingReason); LoadInfo(const LoadInfo& rhs); @@ -230,6 +231,7 @@ class LoadInfo final : public nsILoadInfo { bool mServiceWorkerTaintingSynthesized; bool mDocumentHasUserInteracted; bool mDocumentHasLoaded; + bool mAllowListFutureDocumentsCreatedFromThisRedirectChain; nsString mCspNonce; // Is true if this load was triggered by processing the attributes of the diff --git a/netwerk/base/NetworkConnectivityService.cpp b/netwerk/base/NetworkConnectivityService.cpp index 3d7dbe4ed3..9b8f27cf90 100644 --- a/netwerk/base/NetworkConnectivityService.cpp +++ b/netwerk/base/NetworkConnectivityService.cpp @@ -128,15 +128,17 @@ NetworkConnectivityService::RecheckDNS() { nsAutoCString host; Preferences::GetCString("network.connectivity-service.DNSv4.domain", host); - rv = dns->AsyncResolveNative(host, nsIDNSService::RESOLVE_DISABLE_IPV6, this, - NS_GetCurrentThread(), attrs, - getter_AddRefs(mDNSv4Request)); + rv = dns->AsyncResolveNative( + host, + nsIDNSService::RESOLVE_DISABLE_IPV6 | nsIDNSService::RESOLVE_DISABLE_TRR, + this, NS_GetCurrentThread(), attrs, getter_AddRefs(mDNSv4Request)); NS_ENSURE_SUCCESS(rv, rv); Preferences::GetCString("network.connectivity-service.DNSv6.domain", host); - rv = dns->AsyncResolveNative(host, nsIDNSService::RESOLVE_DISABLE_IPV4, this, - NS_GetCurrentThread(), attrs, - getter_AddRefs(mDNSv6Request)); + rv = dns->AsyncResolveNative( + host, + nsIDNSService::RESOLVE_DISABLE_IPV4 | nsIDNSService::RESOLVE_DISABLE_TRR, + this, NS_GetCurrentThread(), attrs, getter_AddRefs(mDNSv6Request)); return rv; } @@ -194,9 +196,10 @@ static inline already_AddRefed SetupIPCheckChannel(bool ipv4) { nullptr, // aPerformanceStorage nullptr, // aLoadGroup nullptr, - nsIRequest::LOAD_BYPASS_CACHE | // don't read from the cache - nsIRequest::INHIBIT_CACHING | // don't write the response to cache - nsIRequest::LOAD_ANONYMOUS); // prevent privacy leaks + nsIRequest::LOAD_BYPASS_CACHE | // don't read from the cache + nsIRequest::INHIBIT_CACHING | // don't write the response to cache + nsIRequest::LOAD_DISABLE_TRR | // check network capabilities not TRR + nsIRequest::LOAD_ANONYMOUS); // prevent privacy leaks NS_ENSURE_SUCCESS(rv, nullptr); diff --git a/netwerk/base/NetworkConnectivityService.h b/netwerk/base/NetworkConnectivityService.h index 9ac36c199d..968fbc36b9 100644 --- a/netwerk/base/NetworkConnectivityService.h +++ b/netwerk/base/NetworkConnectivityService.h @@ -6,7 +6,9 @@ #define NetworkConnectivityService_h_ #include "nsINetworkConnectivityService.h" +#include "nsIObserver.h" #include "nsIDNSListener.h" +#include "nsIStreamListener.h" namespace mozilla { namespace net { diff --git a/netwerk/base/RequestContextService.cpp b/netwerk/base/RequestContextService.cpp index 36305d0119..137340956f 100644 --- a/netwerk/base/RequestContextService.cpp +++ b/netwerk/base/RequestContextService.cpp @@ -2,9 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsAutoPtr.h" #include "nsIDocShell.h" #include "mozilla/dom/Document.h" +#include "nsComponentManagerUtils.h" #include "nsIDocumentLoader.h" #include "nsIObserverService.h" #include "nsIXULRuntime.h" @@ -57,7 +57,7 @@ class RequestContext final : public nsIRequestContext, public nsITimerCallback { uint64_t mID; Atomic mBlockingTransactionCount; - nsAutoPtr mSpdyCache; + UniquePtr mSpdyCache; nsCString mUserAgentOverride; typedef nsCOMPtr PendingTailRequest; @@ -177,10 +177,10 @@ RequestContext::RemoveBlockingTransaction(uint32_t* outval) { return NS_OK; } -SpdyPushCache* RequestContext::GetSpdyPushCache() { return mSpdyCache; } +SpdyPushCache* RequestContext::GetSpdyPushCache() { return mSpdyCache.get(); } void RequestContext::SetSpdyPushCache(SpdyPushCache* aSpdyPushCache) { - mSpdyCache = aSpdyPushCache; + mSpdyCache = WrapUnique(aSpdyPushCache); } uint64_t RequestContext::GetID() { return mID; } diff --git a/netwerk/base/SSLTokensCache.cpp b/netwerk/base/SSLTokensCache.cpp index acec48a25a..9bd2638aa8 100644 --- a/netwerk/base/SSLTokensCache.cpp +++ b/netwerk/base/SSLTokensCache.cpp @@ -5,6 +5,8 @@ #include "SSLTokensCache.h" #include "mozilla/Preferences.h" #include "mozilla/Logging.h" +#include "nsNSSIOLayer.h" +#include "TransportSecurityInfo.h" #include "ssl.h" #include "sslexp.h" @@ -23,12 +25,12 @@ static LazyLogModule gSSLTokensCacheLog("SSLTokensCache"); class ExpirationComparator { public: - bool Equals(SSLTokensCache::HostRecord* a, - SSLTokensCache::HostRecord* b) const { + bool Equals(SSLTokensCache::TokenCacheRecord* a, + SSLTokensCache::TokenCacheRecord* b) const { return a->mExpirationTime == b->mExpirationTime; } - bool LessThan(SSLTokensCache::HostRecord* a, - SSLTokensCache::HostRecord* b) const { + bool LessThan(SSLTokensCache::TokenCacheRecord* a, + SSLTokensCache::TokenCacheRecord* b) const { return a->mExpirationTime < b->mExpirationTime; } }; @@ -36,6 +38,28 @@ class ExpirationComparator { StaticRefPtr SSLTokensCache::gInstance; StaticMutex SSLTokensCache::sLock; +uint32_t SSLTokensCache::TokenCacheRecord::Size() const { + uint32_t size = mToken.Length() + sizeof(mSessionCacheInfo.mEVStatus) + + sizeof(mSessionCacheInfo.mCertificateTransparencyStatus) + + mSessionCacheInfo.mServerCertBytes.Length(); + if (mSessionCacheInfo.mSucceededCertChainBytes) { + for (const auto& cert : mSessionCacheInfo.mSucceededCertChainBytes.ref()) { + size += cert.Length(); + } + } + return size; +} + +void SSLTokensCache::TokenCacheRecord::Reset() { + mToken.Clear(); + mExpirationTime = 0; + mSessionCacheInfo.mEVStatus = psm::EVStatus::NotEV; + mSessionCacheInfo.mCertificateTransparencyStatus = + nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE; + mSessionCacheInfo.mServerCertBytes.Clear(); + mSessionCacheInfo.mSucceededCertChainBytes.reset(); +} + NS_IMPL_ISUPPORTS(SSLTokensCache, nsIMemoryReporter) // static @@ -78,18 +102,23 @@ SSLTokensCache::SSLTokensCache() : mCacheSize(0) { SSLTokensCache::~SSLTokensCache() { LOG(("SSLTokensCache::~SSLTokensCache")); } // static -nsresult SSLTokensCache::Put(const nsACString& aHost, const uint8_t* aToken, - uint32_t aTokenLen) { +nsresult SSLTokensCache::Put(const nsACString& aKey, const uint8_t* aToken, + uint32_t aTokenLen, + nsITransportSecurityInfo* aSecInfo) { StaticMutexAutoLock lock(sLock); - LOG(("SSLTokensCache::Put [host=%s, tokenLen=%u]", - PromiseFlatCString(aHost).get(), aTokenLen)); + LOG(("SSLTokensCache::Put [key=%s, tokenLen=%u]", + PromiseFlatCString(aKey).get(), aTokenLen)); if (!gInstance) { LOG((" service not initialized")); return NS_ERROR_NOT_INITIALIZED; } + if (!aSecInfo) { + return NS_ERROR_FAILURE; + } + PRUint32 expirationTime; SSLResumptionTokenInfo tokenInfo; if (SSL_GetResumptionTokenInfo(aToken, aTokenLen, &tokenInfo, @@ -101,22 +130,79 @@ nsresult SSLTokensCache::Put(const nsACString& aHost, const uint8_t* aToken, expirationTime = tokenInfo.expirationTime; SSL_DestroyResumptionTokenInfo(&tokenInfo); - HostRecord* rec = nullptr; + nsCOMPtr cert; + aSecInfo->GetServerCert(getter_AddRefs(cert)); + if (!cert) { + return NS_ERROR_FAILURE; + } + + nsTArray certBytes; + nsresult rv = cert->GetRawDER(certBytes); + if (NS_FAILED(rv)) { + return rv; + } + + Maybe>> succeededCertChainBytes; + nsTArray> succeededCertArray; + rv = aSecInfo->GetSucceededCertChain(succeededCertArray); + if (NS_FAILED(rv)) { + return rv; + } + + if (!succeededCertArray.IsEmpty()) { + succeededCertChainBytes.emplace(); + for (const auto& cert : succeededCertArray) { + nsTArray rawCert; + nsresult rv = cert->GetRawDER(rawCert); + if (NS_FAILED(rv)) { + return rv; + } + succeededCertChainBytes->AppendElement(std::move(rawCert)); + } + } + + bool isEV; + rv = aSecInfo->GetIsExtendedValidation(&isEV); + if (NS_FAILED(rv)) { + return rv; + } + + uint16_t certificateTransparencyStatus; + rv = aSecInfo->GetCertificateTransparencyStatus( + &certificateTransparencyStatus); + if (NS_FAILED(rv)) { + return rv; + } - if (!gInstance->mHostRecs.Get(aHost, &rec)) { - rec = new HostRecord(); - rec->mHost = aHost; - gInstance->mHostRecs.Put(aHost, rec); + TokenCacheRecord* rec = nullptr; + + if (!gInstance->mTokenCacheRecords.Get(aKey, &rec)) { + rec = new TokenCacheRecord(); + rec->mKey = aKey; + gInstance->mTokenCacheRecords.Put(aKey, rec); gInstance->mExpirationArray.AppendElement(rec); } else { - gInstance->mCacheSize -= rec->mToken.Length(); - rec->mToken.Clear(); + gInstance->mCacheSize -= rec->Size(); + rec->Reset(); } rec->mExpirationTime = expirationTime; MOZ_ASSERT(rec->mToken.IsEmpty()); rec->mToken.AppendElements(aToken, aTokenLen); - gInstance->mCacheSize += rec->mToken.Length(); + + rec->mSessionCacheInfo.mServerCertBytes = std::move(certBytes); + + rec->mSessionCacheInfo.mSucceededCertChainBytes = + std::move(succeededCertChainBytes); + + if (isEV) { + rec->mSessionCacheInfo.mEVStatus = psm::EVStatus::EV; + } + + rec->mSessionCacheInfo.mCertificateTransparencyStatus = + certificateTransparencyStatus; + + gInstance->mCacheSize += rec->Size(); gInstance->LogStats(); @@ -126,20 +212,20 @@ nsresult SSLTokensCache::Put(const nsACString& aHost, const uint8_t* aToken, } // static -nsresult SSLTokensCache::Get(const nsACString& aHost, +nsresult SSLTokensCache::Get(const nsACString& aKey, nsTArray& aToken) { StaticMutexAutoLock lock(sLock); - LOG(("SSLTokensCache::Get [host=%s]", PromiseFlatCString(aHost).get())); + LOG(("SSLTokensCache::Get [key=%s]", PromiseFlatCString(aKey).get())); if (!gInstance) { LOG((" service not initialized")); return NS_ERROR_NOT_INITIALIZED; } - HostRecord* rec = nullptr; + TokenCacheRecord* rec = nullptr; - if (gInstance->mHostRecs.Get(aHost, &rec)) { + if (gInstance->mTokenCacheRecords.Get(aKey, &rec)) { if (rec->mToken.Length()) { aToken = rec->mToken; return NS_OK; @@ -151,33 +237,57 @@ nsresult SSLTokensCache::Get(const nsACString& aHost, } // static -nsresult SSLTokensCache::Remove(const nsACString& aHost) { +bool SSLTokensCache::GetSessionCacheInfo(const nsACString& aKey, + SessionCacheInfo& aResult) { + StaticMutexAutoLock lock(sLock); + + LOG(("SSLTokensCache::GetSessionCacheInfo [key=%s]", + PromiseFlatCString(aKey).get())); + + if (!gInstance) { + LOG((" service not initialized")); + return false; + } + + TokenCacheRecord* rec = nullptr; + + if (gInstance->mTokenCacheRecords.Get(aKey, &rec)) { + aResult = rec->mSessionCacheInfo; + return true; + } + + LOG((" token not found")); + return false; +} + +// static +nsresult SSLTokensCache::Remove(const nsACString& aKey) { StaticMutexAutoLock lock(sLock); - LOG(("SSLTokensCache::Remove [host=%s]", PromiseFlatCString(aHost).get())); + LOG(("SSLTokensCache::Remove [key=%s]", PromiseFlatCString(aKey).get())); if (!gInstance) { LOG((" service not initialized")); return NS_ERROR_NOT_INITIALIZED; } - return gInstance->RemoveLocked(aHost); + return gInstance->RemoveLocked(aKey); } -nsresult SSLTokensCache::RemoveLocked(const nsACString& aHost) { +nsresult SSLTokensCache::RemoveLocked(const nsACString& aKey) { sLock.AssertCurrentThreadOwns(); - LOG(("SSLTokensCache::RemoveLocked [host=%s]", - PromiseFlatCString(aHost).get())); + LOG(("SSLTokensCache::RemoveLocked [key=%s]", + PromiseFlatCString(aKey).get())); - UniquePtr rec; + UniquePtr rec; - if (!mHostRecs.Remove(aHost, &rec)) { + if (!mTokenCacheRecords.Remove(aKey, &rec)) { LOG((" token not found")); return NS_ERROR_NOT_AVAILABLE; } - mCacheSize -= rec->mToken.Length(); + mCacheSize -= rec->Size(); if (!mExpirationArray.RemoveElement(rec.get())) { MOZ_ASSERT(false, "token not found in mExpirationArray"); @@ -206,8 +316,9 @@ void SSLTokensCache::EvictIfNecessary() { mExpirationArray.Sort(ExpirationComparator()); while (mCacheSize > capacity && mExpirationArray.Length() > 0) { - if (NS_FAILED(RemoveLocked(mExpirationArray[0]->mHost))) { - MOZ_ASSERT(false, "mExpirationArray and mHostRecs are out of sync!"); + if (NS_FAILED(RemoveLocked(mExpirationArray[0]->mKey))) { + MOZ_ASSERT(false, + "mExpirationArray and mTokenCacheRecords are out of sync!"); mExpirationArray.RemoveElementAt(0); } } @@ -222,12 +333,12 @@ size_t SSLTokensCache::SizeOfIncludingThis( mozilla::MallocSizeOf mallocSizeOf) const { size_t n = mallocSizeOf(this); - n += mHostRecs.ShallowSizeOfExcludingThis(mallocSizeOf); + n += mTokenCacheRecords.ShallowSizeOfExcludingThis(mallocSizeOf); n += mExpirationArray.ShallowSizeOfExcludingThis(mallocSizeOf); for (uint32_t i = 0; i < mExpirationArray.Length(); ++i) { n += mallocSizeOf(mExpirationArray[i]); - n += mExpirationArray[i]->mHost.SizeOfExcludingThisIfUnshared(mallocSizeOf); + n += mExpirationArray[i]->mKey.SizeOfExcludingThisIfUnshared(mallocSizeOf); n += mExpirationArray[i]->mToken.ShallowSizeOfExcludingThis(mallocSizeOf); } diff --git a/netwerk/base/SSLTokensCache.h b/netwerk/base/SSLTokensCache.h index 3b86fefea7..4cd9d859c0 100644 --- a/netwerk/base/SSLTokensCache.h +++ b/netwerk/base/SSLTokensCache.h @@ -8,13 +8,23 @@ #include "nsIMemoryReporter.h" #include "nsClassHashtable.h" #include "nsTArray.h" +#include "mozilla/Maybe.h" #include "mozilla/StaticMutex.h" #include "mozilla/StaticPtr.h" #include "nsXULAppAPI.h" +#include "TransportSecurityInfo.h" // For EVStatus namespace mozilla { namespace net { +struct SessionCacheInfo { + psm::EVStatus mEVStatus = psm::EVStatus::NotEV; + uint16_t mCertificateTransparencyStatus = + nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE; + nsTArray mServerCertBytes; + Maybe>> mSucceededCertChainBytes; +}; + class SSLTokensCache : public nsIMemoryReporter { public: NS_DECL_THREADSAFE_ISUPPORTS @@ -27,16 +37,18 @@ class SSLTokensCache : public nsIMemoryReporter { static bool IsEnabled() { return sEnabled; } - static nsresult Put(const nsACString& aHost, const uint8_t* aToken, - uint32_t aTokenLen); - static nsresult Get(const nsACString& aHost, nsTArray& aToken); - static nsresult Remove(const nsACString& aHost); + static nsresult Put(const nsACString& aKey, const uint8_t* aToken, + uint32_t aTokenLen, nsITransportSecurityInfo* aSecInfo); + static nsresult Get(const nsACString& aKey, nsTArray& aToken); + static bool GetSessionCacheInfo(const nsACString& aKey, + SessionCacheInfo& aResult); + static nsresult Remove(const nsACString& aKey); private: SSLTokensCache(); virtual ~SSLTokensCache(); - nsresult RemoveLocked(const nsACString& aHost); + nsresult RemoveLocked(const nsACString& aKey); void InitPrefs(); void EvictIfNecessary(); @@ -53,15 +65,19 @@ class SSLTokensCache : public nsIMemoryReporter { uint32_t mCacheSize; // Actual cache size in bytes - class HostRecord { + class TokenCacheRecord { public: - nsCString mHost; + uint32_t Size() const; + void Reset(); + + nsCString mKey; PRUint32 mExpirationTime; nsTArray mToken; + SessionCacheInfo mSessionCacheInfo; }; - nsClassHashtable mHostRecs; - nsTArray mExpirationArray; + nsClassHashtable mTokenCacheRecords; + nsTArray mExpirationArray; }; } // namespace net diff --git a/netwerk/base/TLSServerSocket.cpp b/netwerk/base/TLSServerSocket.cpp index 3f5a21f850..c21d2733fc 100644 --- a/netwerk/base/TLSServerSocket.cpp +++ b/netwerk/base/TLSServerSocket.cpp @@ -5,7 +5,6 @@ #include "TLSServerSocket.h" #include "mozilla/net/DNS.h" -#include "nsAutoPtr.h" #include "nsComponentManagerUtils.h" #include "nsDependentSubstring.h" #include "nsIServerSocket.h" @@ -416,10 +415,10 @@ nsresult TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD) { } nsCOMPtr clientCertPSM; - nsDependentCSubstring certDER( - reinterpret_cast(clientCert->derCert.data), - clientCert->derCert.len); - rv = certDB->ConstructX509(certDER, getter_AddRefs(clientCertPSM)); + nsTArray clientCertBytes; + clientCertBytes.AppendElements(clientCert->derCert.data, + clientCert->derCert.len); + rv = certDB->ConstructX509(clientCertBytes, getter_AddRefs(clientCertPSM)); if (NS_FAILED(rv)) { return rv; } diff --git a/netwerk/base/TLSServerSocket.h b/netwerk/base/TLSServerSocket.h index 70279e442e..8d16dc0dcb 100644 --- a/netwerk/base/TLSServerSocket.h +++ b/netwerk/base/TLSServerSocket.h @@ -5,7 +5,6 @@ #ifndef mozilla_net_TLSServerSocket_h #define mozilla_net_TLSServerSocket_h -#include "nsAutoPtr.h" #include "nsITLSServerSocket.h" #include "nsServerSocket.h" #include "nsString.h" diff --git a/netwerk/base/Tickler.h b/netwerk/base/Tickler.h index 01746a4c7c..1a6308c0e9 100644 --- a/netwerk/base/Tickler.h +++ b/netwerk/base/Tickler.h @@ -37,7 +37,6 @@ #ifdef MOZ_USE_WIFI_TICKLER # include "mozilla/Mutex.h" # include "mozilla/TimeStamp.h" -# include "nsAutoPtr.h" # include "nsISupports.h" # include "nsIThread.h" # include "nsITimer.h" diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index d8428150de..3c6bac367a 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -319,6 +319,7 @@ LOCAL_INCLUDES += [ '/netwerk/protocol/http', '/netwerk/socket', '/netwerk/url-classifier', + '/security/manager/ssl', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': diff --git a/netwerk/base/nsAsyncRedirectVerifyHelper.h b/netwerk/base/nsAsyncRedirectVerifyHelper.h index 0bc4adbb6c..20190fccbf 100644 --- a/netwerk/base/nsAsyncRedirectVerifyHelper.h +++ b/netwerk/base/nsAsyncRedirectVerifyHelper.h @@ -9,7 +9,6 @@ #include "nsIChannelEventSink.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" #include "mozilla/Attributes.h" diff --git a/netwerk/base/nsBaseChannel.cpp b/netwerk/base/nsBaseChannel.cpp index b43428d648..b014aef01f 100644 --- a/netwerk/base/nsBaseChannel.cpp +++ b/netwerk/base/nsBaseChannel.cpp @@ -442,8 +442,8 @@ nsBaseChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) { NS_IMETHODIMP nsBaseChannel::GetOriginalURI(nsIURI** aURI) { - *aURI = OriginalURI(); - NS_ADDREF(*aURI); + RefPtr uri = OriginalURI(); + uri.forget(aURI); return NS_OK; } @@ -574,7 +574,8 @@ nsBaseChannel::GetContentDispositionFilename( NS_IMETHODIMP nsBaseChannel::SetContentDispositionFilename( const nsAString& aContentDispositionFilename) { - mContentDispositionFilename = new nsString(aContentDispositionFilename); + mContentDispositionFilename = + MakeUnique(aContentDispositionFilename); return NS_OK; } @@ -637,12 +638,12 @@ nsBaseChannel::AsyncOpen(nsIStreamListener* aListener) { } MOZ_ASSERT( - !mLoadInfo || mLoadInfo->GetSecurityMode() == 0 || + mLoadInfo->GetSecurityMode() == 0 || mLoadInfo->GetInitialSecurityCheckDone() || (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL && - mLoadInfo->LoadingPrincipal() && - mLoadInfo->LoadingPrincipal()->IsSystemPrincipal()), + mLoadInfo->GetLoadingPrincipal() && + mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()), "security flags in loadInfo but doContentSecurityCheck() not called"); NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED); @@ -727,12 +728,12 @@ nsBaseChannel::OnTransportStatus(nsITransport* transport, nsresult status, if (!HasLoadFlag(LOAD_BACKGROUND)) { nsAutoString statusArg; if (GetStatusArg(status, statusArg)) { - mProgressSink->OnStatus(this, nullptr, status, statusArg.get()); + mProgressSink->OnStatus(this, status, statusArg.get()); } } if (progress) { - mProgressSink->OnProgress(this, nullptr, progress, progressMax); + mProgressSink->OnProgress(this, progress, progressMax); } return NS_OK; diff --git a/netwerk/base/nsBaseChannel.h b/netwerk/base/nsBaseChannel.h index 34100ccf76..b6aab3962c 100644 --- a/netwerk/base/nsBaseChannel.h +++ b/netwerk/base/nsBaseChannel.h @@ -7,8 +7,8 @@ #include "mozilla/net/NeckoTargetHolder.h" #include "mozilla/MozPromise.h" +#include "mozilla/UniquePtr.h" #include "nsString.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsHashPropertyBag.h" #include "nsInputStreamPump.h" @@ -293,7 +293,7 @@ class nsBaseChannel nsCOMPtr mListener; nsresult mStatus; uint32_t mContentDispositionHint; - nsAutoPtr mContentDispositionFilename; + mozilla::UniquePtr mContentDispositionFilename; int64_t mContentLength; bool mWasOpened; diff --git a/netwerk/base/nsBufferedStreams.cpp b/netwerk/base/nsBufferedStreams.cpp index cb2389d1ff..ca2dc559ce 100644 --- a/netwerk/base/nsBufferedStreams.cpp +++ b/netwerk/base/nsBufferedStreams.cpp @@ -76,7 +76,7 @@ nsresult nsBufferedStream::Init(nsISupports* aStream, uint32_t bufferSize) { return NS_OK; } -nsresult nsBufferedStream::Close() { +void nsBufferedStream::Close() { // Drop the reference from nsBufferedStream::Init() mStream = nullptr; if (mBuffer) { @@ -114,7 +114,6 @@ nsresult nsBufferedStream::Close() { } } #endif - return NS_OK; } NS_IMETHODIMP @@ -130,9 +129,7 @@ nsBufferedStream::Seek(int32_t whence, int64_t offset) { nsresult rv; nsCOMPtr ras = do_QueryInterface(mStream, &rv); if (NS_FAILED(rv)) { -#ifdef DEBUG NS_WARNING("mStream doesn't QI to nsISeekableStream"); -#endif return rv; } @@ -373,32 +370,18 @@ already_AddRefed nsBufferedInputStream::GetInputStream() { NS_IMETHODIMP nsBufferedInputStream::Close() { - nsresult rv1 = NS_OK, rv2; + nsresult rv = NS_OK; if (mStream) { - rv1 = Source()->Close(); -#ifdef DEBUG - if (NS_FAILED(rv1)) { + rv = Source()->Close(); + if (NS_FAILED(rv)) { NS_WARNING( - "(debug) Error: Source()->Close() returned error (rv1) in " + "(debug) Error: Source()->Close() returned error in " "bsBuffedInputStream::Close()."); - }; -#endif + } } - rv2 = nsBufferedStream::Close(); - -#ifdef DEBUG - if (NS_FAILED(rv2)) { - NS_WARNING( - "(debug) Error: nsBufferedStream::Close() returned error (rv2) within " - "nsBufferedInputStream::Close()."); - }; -#endif - - if (NS_FAILED(rv1)) { - return rv1; - } - return rv2; + nsBufferedStream::Close(); + return rv; } NS_IMETHODIMP @@ -875,7 +858,7 @@ nsBufferedOutputStream::Init(nsIOutputStream* stream, uint32_t bufferSize) { NS_IMETHODIMP nsBufferedOutputStream::Close() { - nsresult rv1, rv2 = NS_OK, rv3; + nsresult rv1, rv2 = NS_OK; rv1 = Flush(); @@ -900,15 +883,7 @@ nsBufferedOutputStream::Close() { } #endif } - rv3 = nsBufferedStream::Close(); - -#ifdef DEBUG - if (NS_FAILED(rv3)) { - NS_WARNING( - "(debug) nsBufferedStream:Close() inside " - "nsBufferedOutputStream::Close() returned error (rv3)."); - } -#endif + nsBufferedStream::Close(); if (NS_FAILED(rv1)) { return rv1; @@ -916,7 +891,7 @@ nsBufferedOutputStream::Close() { if (NS_FAILED(rv2)) { return rv2; } - return rv3; + return NS_OK; } NS_IMETHODIMP @@ -1001,7 +976,7 @@ NS_IMETHODIMP nsBufferedOutputStream::Finish() { // flush the stream, to write out any buffered data... nsresult rv1 = nsBufferedOutputStream::Flush(); - nsresult rv2 = NS_OK, rv3; + nsresult rv2 = NS_OK; if (NS_FAILED(rv1)) { NS_WARNING( @@ -1025,7 +1000,7 @@ nsBufferedOutputStream::Finish() { // ... and close the buffered stream, so any further attempts to flush/close // the buffered stream won't cause errors. - rv3 = nsBufferedStream::Close(); + nsBufferedStream::Close(); // We want to return the errors precisely from Finish() // and mimick the existing error handling in @@ -1037,7 +1012,7 @@ nsBufferedOutputStream::Finish() { if (NS_FAILED(rv2)) { return rv2; } - return rv3; + return NS_OK; } static nsresult nsReadFromInputStream(nsIOutputStream* outStr, void* closure, diff --git a/netwerk/base/nsBufferedStreams.h b/netwerk/base/nsBufferedStreams.h index b35f783c50..8906571491 100644 --- a/netwerk/base/nsBufferedStreams.h +++ b/netwerk/base/nsBufferedStreams.h @@ -28,7 +28,7 @@ class nsBufferedStream : public nsISeekableStream { nsBufferedStream(); - nsresult Close(); + void Close(); protected: virtual ~nsBufferedStream(); diff --git a/netwerk/base/nsFileStreams.cpp b/netwerk/base/nsFileStreams.cpp index dbb2adb661..fd16d1af14 100644 --- a/netwerk/base/nsFileStreams.cpp +++ b/netwerk/base/nsFileStreams.cpp @@ -483,7 +483,7 @@ nsFileInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* _retval) { NS_IMETHODIMP nsFileInputStream::ReadLine(nsACString& aLine, bool* aResult) { if (!mLineBuffer) { - mLineBuffer = new nsLineBuffer; + mLineBuffer = MakeUnique>(); } return NS_ReadLine(this, mLineBuffer.get(), aLine, aResult); } diff --git a/netwerk/base/nsFileStreams.h b/netwerk/base/nsFileStreams.h index 8968d952c9..032baaa4fa 100644 --- a/netwerk/base/nsFileStreams.h +++ b/netwerk/base/nsFileStreams.h @@ -5,7 +5,7 @@ #ifndef nsFileStreams_h__ #define nsFileStreams_h__ -#include "nsAutoPtr.h" +#include "mozilla/UniquePtr.h" #include "nsIFileStreams.h" #include "nsIFile.h" #include "nsICloneableInputStream.h" @@ -155,7 +155,7 @@ class nsFileInputStream : public nsFileStreamBase, nsresult SeekInternal(int32_t aWhence, int64_t aOffset, bool aClearBuf = true); - nsAutoPtr > mLineBuffer; + mozilla::UniquePtr> mLineBuffer; /** * The file being opened. diff --git a/netwerk/base/nsIBackgroundFileSaver.idl b/netwerk/base/nsIBackgroundFileSaver.idl index bc3ea8399e..99ec8557d3 100644 --- a/netwerk/base/nsIBackgroundFileSaver.idl +++ b/netwerk/base/nsIBackgroundFileSaver.idl @@ -51,16 +51,17 @@ interface nsIBackgroundFileSaver : nsISupports attribute nsIBackgroundFileSaverObserver observer; /** - * An nsIArray of nsIX509CertList, representing a chain of X.509 signatures on - * the downloaded file. Each list may belong to a different signer and contain - * certificates all the way up to the root. + * An Array of Array of Array of bytes, representing a chain of + * X.509 certificates, the last of which signed the downloaded file. + * Each list may belong to a different signer and contain certificates + * all the way up to the root. * * @throws NS_ERROR_NOT_AVAILABLE * In case this is called before the onSaveComplete method has been * called to notify success, or enableSignatureInfo has not been * called. */ - readonly attribute nsIArray signatureInfo; + readonly attribute Array > > signatureInfo; /** * The SHA-256 hash, in raw bytes, associated with the data that was saved. diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index 177afbf498..f7072976be 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -263,10 +263,19 @@ interface nsILoadInfo : nsISupports readonly attribute nsIPrincipal loadingPrincipal; /** - * A C++-friendly version of loadingPrincipal. + * A C++-friendly version of triggeringPrincipal. + * + * This is a bit awkward because we can't use + * binaryname(GetLoadingPrincipal). */ - [noscript, notxpcom, nostdcall, binaryname(LoadingPrincipal)] - nsIPrincipal binaryLoadingPrincipal(); + [noscript, notxpcom, nostdcall] + nsIPrincipal virtualGetLoadingPrincipal(); + +%{C++ + nsIPrincipal* GetLoadingPrincipal() { + return VirtualGetLoadingPrincipal(); + } +%} /** * This is the principal which caused the network load to start. I.e. @@ -1015,13 +1024,19 @@ interface nsILoadInfo : nsISupports /** * Set a custom performance storage. This is meant to be executed only for * workers. If a PerformanceStorage is not set, the loadingDocument->Window - * Performance object will be used instead. + * Performance object will be returned instead. */ [noscript, nostdcall, notxpcom] void SetPerformanceStorage(in PerformanceStoragePtr aPerformanceStorage); /** - * Get the PerformanceStorage. + * Get the custom PerformanceStorage if set by SetPerformanceStorage. + * Otherwise the loadingDocument->Window Performance object will be returned + * instead if all the following conditions are met: + * - the triggeringPrincipal is the same as the loadingDocument's principal. + * - if the external content policy type is TYPE_SUBDOCUMENT then loading + * wasn't caused by processing the attributes of the browsing context + * container. */ [noscript, nostdcall, notxpcom] PerformanceStoragePtr GetPerformanceStorage(); @@ -1090,6 +1105,16 @@ interface nsILoadInfo : nsISupports */ [infallible] attribute boolean documentHasLoaded; + /** + * During a top-level document channel redirect from tracking to + * non-tracking resources, our anti-tracking heuristic, grants the storage + * access permission for a short amount of seconds (See + * privacy.restrict3rdpartystorage.expiration_redirect pref). + * We use this flag to remember this decision even if this channel is part + * of a chain of redirects. + */ + [infallible] attribute boolean allowListFutureDocumentsCreatedFromThisRedirectChain; + /** * A snapshot of the nonce at load start time which is used for CSP * checks and only set for: @@ -1134,6 +1159,10 @@ interface nsILoadInfo : nsISupports const uint32_t BLOCKING_REASON_CONTENT_POLICY_DATA_DOCUMENT = 4004; const uint32_t BLOCKING_REASON_CONTENT_POLICY_WEB_BROWSER = 4005; const uint32_t BLOCKING_REASON_CONTENT_POLICY_PRELOAD = 4006; + // The reason used when SEC_REQUIRE_SAME_ORIGIN_* is set and not satisifed. + const uint32_t BLOCKING_REASON_NOT_SAME_ORIGIN = 5000; + // The reason used when an extension cancels the request via the WebRequest api. + const uint32_t BLOCKING_REASON_EXTENSION_WEBREQUEST = 6000; /** * If the request associated with this load info was blocked by some of diff --git a/netwerk/base/nsINetworkConnectivityService.idl b/netwerk/base/nsINetworkConnectivityService.idl index bddc6dc425..d8575a73e3 100644 --- a/netwerk/base/nsINetworkConnectivityService.idl +++ b/netwerk/base/nsINetworkConnectivityService.idl @@ -21,11 +21,15 @@ interface nsINetworkConnectivityService : nsISupports }; /* If DNS v4/v6 queries actually work on the current network */ + [infallible] readonly attribute nsINetworkConnectivityService_ConnectivityState DNSv4; + [infallible] readonly attribute nsINetworkConnectivityService_ConnectivityState DNSv6; /* If connecting to IPv4/v6 works on the current network */ + [infallible] readonly attribute nsINetworkConnectivityService_ConnectivityState IPv4; + [infallible] readonly attribute nsINetworkConnectivityService_ConnectivityState IPv6; /* Starts the DNS request to check for DNS v4/v6 availability */ diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index e032ffb045..9917abb602 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -1700,7 +1700,7 @@ IOServiceProxyCallback::OnProxyAvailable(nsICancelable* request, if (!speculativeHandler) return NS_OK; nsCOMPtr loadInfo = channel->LoadInfo(); - nsCOMPtr principal = loadInfo->LoadingPrincipal(); + nsCOMPtr principal = loadInfo->GetLoadingPrincipal(); nsLoadFlags loadFlags = 0; channel->GetLoadFlags(&loadFlags); diff --git a/netwerk/base/nsIProgressEventSink.idl b/netwerk/base/nsIProgressEventSink.idl index f55d3ab732..fdf386f668 100644 --- a/netwerk/base/nsIProgressEventSink.idl +++ b/netwerk/base/nsIProgressEventSink.idl @@ -35,9 +35,6 @@ interface nsIProgressEventSink : nsISupports * * @param aRequest * the request being observed (may QI to nsIChannel). - * @param aContext - * if aRequest is a channel, then this parameter is the listener - * context passed to nsIChannel::asyncOpen. * @param aProgress * numeric value in the range 0 to aProgressMax indicating the * number of bytes transfered thus far. @@ -46,7 +43,6 @@ interface nsIProgressEventSink : nsISupports * transfered (or -1 if total is unknown). */ void onProgress(in nsIRequest aRequest, - in nsISupports aContext, in long long aProgress, in long long aProgressMax); @@ -56,9 +52,6 @@ interface nsIProgressEventSink : nsISupports * * @param aRequest * the request being observed (may QI to nsIChannel). - * @param aContext - * if aRequest is a channel, then this parameter is the listener - * context passed to nsIChannel::asyncOpen. * @param aStatus * status code (not necessarily an error code) indicating the * state of the channel (usually the state of the underlying @@ -72,7 +65,6 @@ interface nsIProgressEventSink : nsISupports * indicates the host:port associated with the status code. */ void onStatus(in nsIRequest aRequest, - in nsISupports aContext, in nsresult aStatus, in wstring aStatusArg); diff --git a/netwerk/base/nsIncrementalDownload.cpp b/netwerk/base/nsIncrementalDownload.cpp index ff3fb47065..5e4b2f99a2 100644 --- a/netwerk/base/nsIncrementalDownload.cpp +++ b/netwerk/base/nsIncrementalDownload.cpp @@ -113,7 +113,6 @@ class nsIncrementalDownload final : public nsIIncrementalDownload, nsresult ClearRequestHeader(nsIHttpChannel* channel); nsCOMPtr mObserver; - nsCOMPtr mObserverContext; nsCOMPtr mProgressSink; nsCOMPtr mURI; nsCOMPtr mFinalURI; @@ -172,8 +171,7 @@ void nsIncrementalDownload::UpdateProgress() { mLastProgressUpdate = PR_Now(); if (mProgressSink) - mProgressSink->OnProgress(this, mObserverContext, mCurrentSize + mChunkLen, - mTotalSize); + mProgressSink->OnProgress(this, mCurrentSize + mChunkLen, mTotalSize); } nsresult nsIncrementalDownload::CallOnStartRequest() { @@ -194,7 +192,6 @@ void nsIncrementalDownload::CallOnStopRequest() { mObserver->OnStopRequest(this, mStatus); mObserver = nullptr; - mObserverContext = nullptr; } nsresult nsIncrementalDownload::StartTimer(int32_t interval) { @@ -456,7 +453,6 @@ nsIncrementalDownload::Start(nsIRequestObserver* observer, if (NS_FAILED(rv)) return rv; mObserver = observer; - mObserverContext = context; mProgressSink = do_QueryInterface(observer); // ok if null mIsPending = true; diff --git a/netwerk/base/nsInputStreamChannel.cpp b/netwerk/base/nsInputStreamChannel.cpp index 9aafd4f38f..07762d3fdb 100644 --- a/netwerk/base/nsInputStreamChannel.cpp +++ b/netwerk/base/nsInputStreamChannel.cpp @@ -32,7 +32,7 @@ nsresult nsInputStreamChannel::OpenContentStream(bool async, EnableSynthesizedProgressEvents(true); - NS_ADDREF(*result = mContentStream); + *result = do_AddRef(mContentStream).take(); return NS_OK; } diff --git a/netwerk/base/nsLoadGroup.cpp b/netwerk/base/nsLoadGroup.cpp index 1af11823a2..884e85e442 100644 --- a/netwerk/base/nsLoadGroup.cpp +++ b/netwerk/base/nsLoadGroup.cpp @@ -653,7 +653,7 @@ nsLoadGroup::SetParentLoadGroup(nsILoadGroup* aParentLoadGroup) { NS_IMETHODIMP nsLoadGroup::GetChildLoadGroup(nsILoadGroup** aChildLoadGroup) { - NS_ADDREF(*aChildLoadGroup = this); + *aChildLoadGroup = do_AddRef(this).take(); return NS_OK; } @@ -668,7 +668,7 @@ nsLoadGroup::GetRootLoadGroup(nsILoadGroup** aRootLoadGroup) { if (ancestor) return ancestor->GetRootLoadGroup(aRootLoadGroup); // finally just return this - NS_ADDREF(*aRootLoadGroup = this); + *aRootLoadGroup = do_AddRef(this).take(); return NS_OK; } diff --git a/netwerk/base/nsMIMEInputStream.cpp b/netwerk/base/nsMIMEInputStream.cpp index 2bf059987f..a8ebfffdfc 100644 --- a/netwerk/base/nsMIMEInputStream.cpp +++ b/netwerk/base/nsMIMEInputStream.cpp @@ -7,22 +7,23 @@ * automatic creation of the content-length header. */ -#include "ipc/IPCMessageUtils.h" +#include "nsMIMEInputStream.h" +#include + +#include "ipc/IPCMessageUtils.h" +#include "mozilla/Mutex.h" +#include "mozilla/ipc/InputStreamUtils.h" #include "nsCOMPtr.h" #include "nsComponentManagerUtils.h" #include "nsIAsyncInputStream.h" -#include "nsIInputStreamLength.h" +#include "nsIClassInfoImpl.h" #include "nsIHttpHeaderVisitor.h" +#include "nsIIPCSerializableInputStream.h" +#include "nsIInputStreamLength.h" #include "nsIMIMEInputStream.h" #include "nsISeekableStream.h" #include "nsString.h" -#include "nsMIMEInputStream.h" -#include "nsIClassInfoImpl.h" -#include "nsIIPCSerializableInputStream.h" -#include "mozilla/Move.h" -#include "mozilla/Mutex.h" -#include "mozilla/ipc/InputStreamUtils.h" using namespace mozilla::ipc; using mozilla::Maybe; diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index acb3fcf41e..90e26e043b 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -1934,7 +1934,7 @@ bool NS_HasBeenCrossOrigin(nsIChannel* aChannel, bool aReport) { nsCOMPtr loadInfo = aChannel->LoadInfo(); // TYPE_DOCUMENT loads have a null LoadingPrincipal and can not be cross // origin. - if (!loadInfo->LoadingPrincipal()) { + if (!loadInfo->GetLoadingPrincipal()) { return false; } @@ -1943,7 +1943,7 @@ bool NS_HasBeenCrossOrigin(nsIChannel* aChannel, bool aReport) { return true; } - nsCOMPtr loadingPrincipal = loadInfo->LoadingPrincipal(); + nsCOMPtr loadingPrincipal = loadInfo->GetLoadingPrincipal(); uint32_t mode = loadInfo->GetSecurityMode(); bool dataInherits = mode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS || @@ -2598,8 +2598,7 @@ uint32_t NS_GetContentDispositionFromHeader(const nsACString& aHeader, } nsresult NS_GetFilenameFromDisposition(nsAString& aFilename, - const nsACString& aDisposition, - nsIURI* aURI /* = nullptr */) { + const nsACString& aDisposition) { aFilename.Truncate(); nsresult rv; @@ -2962,8 +2961,8 @@ nsresult NS_CompareLoadInfoAndLoadContext(nsIChannel* aChannel) { // the loadInfo will use originAttributes from the content. Thus, the // originAttributes between loadInfo and loadContext will be different. // That's why we have to skip the comparison for the favicon loading. - if (loadInfo->LoadingPrincipal() && - loadInfo->LoadingPrincipal()->IsSystemPrincipal() && + if (loadInfo->GetLoadingPrincipal() && + loadInfo->GetLoadingPrincipal()->IsSystemPrincipal() && loadInfo->InternalContentPolicyType() == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) { return NS_OK; diff --git a/netwerk/base/nsNetUtil.h b/netwerk/base/nsNetUtil.h index b55e48ba9d..59e5b29b45 100644 --- a/netwerk/base/nsNetUtil.h +++ b/netwerk/base/nsNetUtil.h @@ -814,12 +814,10 @@ uint32_t NS_GetContentDispositionFromHeader(const nsACString& aHeader, /** Extracts the filename out of a content-disposition header * @param aFilename [out] The filename. Can be empty on error. * @param aDisposition Value of a Content-Disposition header - * @param aURI Optional. Will be used to get a fallback charset for the - * filename, if it is QI'able to nsIURL + */ nsresult NS_GetFilenameFromDisposition(nsAString& aFilename, - const nsACString& aDisposition, - nsIURI* aURI = nullptr); + const nsACString& aDisposition); /** * Make sure Personal Security Manager is initialized diff --git a/netwerk/base/nsPACMan.cpp b/netwerk/base/nsPACMan.cpp index acdf3f8b2e..b43c91f065 100644 --- a/netwerk/base/nsPACMan.cpp +++ b/netwerk/base/nsPACMan.cpp @@ -6,6 +6,7 @@ #include "mozilla/Preferences.h" #include "nsContentUtils.h" +#include "nsComponentManagerUtils.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsIAuthPrompt.h" #include "nsIDHCPClient.h" @@ -31,6 +32,10 @@ LazyLogModule gProxyLog("proxy"); #define MOZ_WPAD_URL "http://wpad/wpad.dat" #define MOZ_DHCP_WPAD_OPTION 252 +// These pointers are declared in nsProtocolProxyService.cpp +extern const char kProxyType_HTTPS[]; +extern const char kProxyType_DIRECT[]; + // The PAC thread does evaluations of both PAC files and // nsISystemProxySettings because they can both block the calling thread and we // don't want that on the main thread @@ -298,10 +303,11 @@ class ExecutePACThreadAction final : public Runnable { //----------------------------------------------------------------------------- PendingPACQuery::PendingPACQuery(nsPACMan* pacMan, nsIURI* uri, - nsPACManCallback* callback, + nsPACManCallback* callback, uint32_t flags, bool mainThreadResponse) : Runnable("net::PendingPACQuery"), mPort(0), + mFlags(flags), mPACMan(pacMan), mCallback(callback), mOnMainThreadOnly(mainThreadResponse) { @@ -425,6 +431,7 @@ nsresult nsPACMan::DispatchToPAC(already_AddRefed aEvent, } nsresult nsPACMan::AsyncGetProxyForURI(nsIURI* uri, nsPACManCallback* callback, + uint32_t flags, bool mainThreadResponse) { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); if (mShutdown) return NS_ERROR_NOT_AVAILABLE; @@ -438,7 +445,7 @@ nsresult nsPACMan::AsyncGetProxyForURI(nsIURI* uri, nsPACManCallback* callback, } RefPtr query = - new PendingPACQuery(this, uri, callback, mainThreadResponse); + new PendingPACQuery(this, uri, callback, flags, mainThreadResponse); if (IsPACURI(uri)) { // deal with this directly instead of queueing it @@ -763,6 +770,19 @@ bool nsPACMan::ProcessPending() { NS_SUCCEEDED(mSystemProxySettings->GetProxyForURI( query->mSpec, query->mScheme, query->mHost, query->mPort, pacString))) { + if (query->mFlags & nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY && + query->mFlags & nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY) { + const nsCaseInsensitiveUTF8StringComparator comp; + if (StringBeginsWith(pacString, nsDependentCString(kProxyType_DIRECT), + comp)) { + // DIRECT indicates that system proxy settings are not configured to use + // SOCKS proxy. Try https proxy as a secondary preferrable proxy. This + // is mainly for websocket whose precedence is SOCKS > HTTPS > DIRECT. + NS_SUCCEEDED(mSystemProxySettings->GetProxyForURI( + query->mSpec, nsDependentCString(kProxyType_HTTPS), query->mHost, + query->mPort, pacString)); + } + } LOG(("Use proxy from system settings: %s\n", pacString.get())); query->Complete(NS_OK, pacString); completed = true; diff --git a/netwerk/base/nsPACMan.h b/netwerk/base/nsPACMan.h index 9f5280fe3c..2a1785a2ce 100644 --- a/netwerk/base/nsPACMan.h +++ b/netwerk/base/nsPACMan.h @@ -11,7 +11,6 @@ #include "mozilla/Logging.h" #include "mozilla/net/NeckoTargetHolder.h" #include "mozilla/TimeStamp.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsIChannelEventSink.h" #include "nsIInterfaceRequestor.h" @@ -57,7 +56,7 @@ class PendingPACQuery final : public Runnable, public LinkedListElement { public: PendingPACQuery(nsPACMan* pacMan, nsIURI* uri, nsPACManCallback* callback, - bool mainThreadResponse); + uint32_t flags, bool mainThreadResponse); // can be called from either thread void Complete(nsresult status, const nsACString& pacString); @@ -67,6 +66,7 @@ class PendingPACQuery final : public Runnable, nsCString mScheme; nsCString mHost; int32_t mPort; + uint32_t mFlags; NS_IMETHOD Run(void) override; /* Runnable */ @@ -109,11 +109,14 @@ class nsPACMan final : public nsIStreamLoaderObserver, * The URI to query. * @param callback * The callback to run once the PAC result is available. + * @param flags + * A bit-wise combination of the RESOLVE_ flags defined above. Pass + * 0 to specify the default behavior. * @param mustCallbackOnMainThread * If set to false the callback can be made from the PAC thread */ nsresult AsyncGetProxyForURI(nsIURI* uri, nsPACManCallback* callback, - bool mustCallbackOnMainThread); + uint32_t flags, bool mustCallbackOnMainThread); /** * This method may be called to reload the PAC file. While we are loading diff --git a/netwerk/base/nsProtocolProxyService.cpp b/netwerk/base/nsProtocolProxyService.cpp index 22c11fce5c..cf5b2f83d8 100644 --- a/netwerk/base/nsProtocolProxyService.cpp +++ b/netwerk/base/nsProtocolProxyService.cpp @@ -385,7 +385,8 @@ class nsAsyncResolveRequest final : public nsIRunnable, // now that the load is triggered, we can resubmit the query RefPtr newRequest = new nsAsyncResolveRequest(mPPS, mChannel, mResolveFlags, mCallback); - rv = mPPS->mPACMan->AsyncGetProxyForURI(proxyURI, newRequest, true); + rv = mPPS->mPACMan->AsyncGetProxyForURI(proxyURI, newRequest, + mResolveFlags, true); } if (NS_FAILED(rv)) @@ -539,6 +540,13 @@ nsAsyncResolveRequest::AsyncApplyFilters::OnProxyFilterResult( } mFilterCalledBack = true; + + if (!mRequest) { + // We got canceled + LOG((" canceled")); + return NS_OK; + } + mProxyInfo = aProxyInfo; if (mProcessingInLoop) { @@ -548,12 +556,6 @@ nsAsyncResolveRequest::AsyncApplyFilters::OnProxyFilterResult( return NS_OK; } - if (!mRequest) { - // We got canceled - LOG((" canceled")); - return NS_OK; - } - if (mNextFilterIndex == mFiltersCopy.Length()) { // We are done, all filters have been called on! Finish(); @@ -680,22 +682,22 @@ static void proxy_MaskIPv6Addr(PRIPv6Addr& addr, uint16_t mask_len) { if (mask_len > 96) { addr.pr_s6_addr32[3] = - PR_htonl(PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len))); + PR_htonl(PR_ntohl(addr.pr_s6_addr32[3]) & (~0uL << (128 - mask_len))); } else if (mask_len > 64) { addr.pr_s6_addr32[3] = 0; addr.pr_s6_addr32[2] = - PR_htonl(PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len))); + PR_htonl(PR_ntohl(addr.pr_s6_addr32[2]) & (~0uL << (96 - mask_len))); } else if (mask_len > 32) { addr.pr_s6_addr32[3] = 0; addr.pr_s6_addr32[2] = 0; addr.pr_s6_addr32[1] = - PR_htonl(PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len))); + PR_htonl(PR_ntohl(addr.pr_s6_addr32[1]) & (~0uL << (64 - mask_len))); } else { addr.pr_s6_addr32[3] = 0; addr.pr_s6_addr32[2] = 0; addr.pr_s6_addr32[1] = 0; addr.pr_s6_addr32[0] = - PR_htonl(PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len))); + PR_htonl(PR_ntohl(addr.pr_s6_addr32[0]) & (~0uL << (32 - mask_len))); } } @@ -1102,7 +1104,7 @@ bool nsProtocolProxyService::CanUseProxy(nsIURI* aURI, int32_t defaultPort) { int32_t index = -1; while (++index < int32_t(mHostFiltersArray.Length())) { - HostInfo* hinfo = mHostFiltersArray[index]; + const auto& hinfo = mHostFiltersArray[index]; if (is_ipaddr != hinfo->is_ipaddr) continue; if (hinfo->port && hinfo->port != port) continue; @@ -1190,7 +1192,7 @@ const char* nsProtocolProxyService::ExtractProxyInfo(const char* start, const char* type = nullptr; switch (len) { case 4: - if (PL_strncasecmp(start, kProxyType_HTTP, 5) == 0) { + if (PL_strncasecmp(start, kProxyType_HTTP, 4) == 0) { type = kProxyType_HTTP; } break; @@ -1215,7 +1217,6 @@ const char* nsProtocolProxyService::ExtractProxyInfo(const char* start, break; } if (type) { - const char *host = nullptr, *hostEnd = nullptr; int32_t port = -1; // If it's a SOCKS5 proxy, do name resolution on the server side. @@ -1237,7 +1238,7 @@ const char* nsProtocolProxyService::ExtractProxyInfo(const char* start, port = 1080; } - nsProxyInfo* pi = new nsProxyInfo(); + RefPtr pi = new nsProxyInfo(); pi->mType = type; pi->mFlags = flags; pi->mResolveFlags = aResolveFlags; @@ -1248,10 +1249,18 @@ const char* nsProtocolProxyService::ExtractProxyInfo(const char* start, nsCOMPtr pacURI; nsAutoCString urlHost; - if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) && - NS_SUCCEEDED(pacURI->GetAsciiHost(urlHost)) && !urlHost.IsEmpty()) { - // http://www.example.com:8080 + // First assume the scheme is present, e.g. http://www.example.com:8080 + if (NS_FAILED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) || + NS_FAILED(pacURI->GetAsciiHost(urlHost)) || urlHost.IsEmpty()) { + // It isn't, assume www.example.com:8080 + maybeURL.Insert("http://", 0); + + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL))) { + pacURI->GetAsciiHost(urlHost); + } + } + if (!urlHost.IsEmpty()) { pi->mHost = urlHost; int32_t tPort; @@ -1259,25 +1268,9 @@ const char* nsProtocolProxyService::ExtractProxyInfo(const char* start, port = tPort; } pi->mPort = port; - } else { - // www.example.com:8080 - if (start < end) { - host = start; - hostEnd = strchr(host, ':'); - if (!hostEnd || hostEnd > end) { - hostEnd = end; - // no port, so assume default - } else { - port = atoi(hostEnd + 1); - } - } - // YES, it is ok to specify a null proxy host. - if (host) { - pi->mHost.Assign(host, hostEnd - host); - pi->mPort = port; - } } - NS_ADDREF(*result = pi); + + pi.forget(result); } while (*end == ';' || *end == ' ' || *end == '\t') ++end; @@ -1562,8 +1555,7 @@ nsresult nsProtocolProxyService::AsyncResolveInternal( } // else kick off a PAC thread query - - rv = mPACMan->AsyncGetProxyForURI(uri, ctx, true); + rv = mPACMan->AsyncGetProxyForURI(uri, ctx, flags, true); if (NS_SUCCEEDED(rv)) ctx.forget(result); return rv; } @@ -1682,7 +1674,7 @@ nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo* aProxy, nsIURI* aURI, LOG(("PAC failover from %s %s:%d to %s %s:%d\n", pi->mType, pi->mHost.get(), pi->mPort, pi->mNext->mType, pi->mNext->mHost.get(), pi->mNext->mPort)); - NS_ADDREF(*aResult = pi->mNext); + *aResult = do_AddRef(pi->mNext).take(); return NS_OK; } @@ -2011,8 +2003,7 @@ nsresult nsProtocolProxyService::NewProxyInfo_Internal( NS_ENSURE_ARG(failover); } - nsProxyInfo* proxyInfo = new nsProxyInfo(); - if (!proxyInfo) return NS_ERROR_OUT_OF_MEMORY; + RefPtr proxyInfo = new nsProxyInfo(); proxyInfo->mType = aType; proxyInfo->mHost = aHost; @@ -2027,7 +2018,7 @@ nsresult nsProtocolProxyService::NewProxyInfo_Internal( proxyInfo->mConnectionIsolationKey = aConnectionIsolationKey; failover.swap(proxyInfo->mNext); - NS_ADDREF(*aResult = proxyInfo); + proxyInfo.forget(aResult); return NS_OK; } @@ -2115,7 +2106,26 @@ nsresult nsProtocolProxyService::Resolve_Internal(nsIChannel* channel, // now try the system proxy settings for this particular url if (NS_SUCCEEDED(mSystemProxySettings->GetProxyForURI(spec, scheme, host, port, pacString))) { - ProcessPACString(pacString, 0, result); + nsCOMPtr pi; + ProcessPACString(pacString, 0, getter_AddRefs(pi)); + + if (flags & RESOLVE_PREFER_SOCKS_PROXY && + flags & RESOLVE_PREFER_HTTPS_PROXY) { + nsAutoCString type; + pi->GetType(type); + // DIRECT from ProcessPACString indicates that system proxy settings + // are not configured to use SOCKS proxy. Try https proxy as a + // secondary preferrable proxy. This is mainly for websocket whose + // proxy precedence is SOCKS > HTTPS > DIRECT. + if (type.EqualsLiteral(kProxyType_DIRECT)) { + scheme.AssignLiteral(kProxyType_HTTPS); + if (NS_SUCCEEDED(mSystemProxySettings->GetProxyForURI( + spec, scheme, host, port, pacString))) { + ProcessPACString(pacString, 0, getter_AddRefs(pi)); + } + } + } + pi.forget(result); return NS_OK; } } diff --git a/netwerk/base/nsProtocolProxyService.h b/netwerk/base/nsProtocolProxyService.h index 05768186dc..4668646394 100644 --- a/netwerk/base/nsProtocolProxyService.h +++ b/netwerk/base/nsProtocolProxyService.h @@ -7,7 +7,6 @@ #include "nsString.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "nsTArray.h" #include "nsIProtocolProxyService2.h" #include "nsIProtocolProxyFilter.h" @@ -363,7 +362,7 @@ class nsProtocolProxyService final : public nsIProtocolProxyService2, bool mFilterLocalHosts; // Holds an array of HostInfo objects - nsTArray> mHostFiltersArray; + nsTArray> mHostFiltersArray; // Filters, always sorted by the position. nsTArray> mFilters; diff --git a/netwerk/base/nsRequestObserverProxy.cpp b/netwerk/base/nsRequestObserverProxy.cpp index 9947197f6d..d78e71e58c 100644 --- a/netwerk/base/nsRequestObserverProxy.cpp +++ b/netwerk/base/nsRequestObserverProxy.cpp @@ -7,7 +7,6 @@ #include "nscore.h" #include "nsRequestObserverProxy.h" #include "nsIRequest.h" -#include "nsAutoPtr.h" #include "mozilla/Logging.h" #include "mozilla/IntegerPrintfMacros.h" diff --git a/netwerk/base/nsSerializationHelper.cpp b/netwerk/base/nsSerializationHelper.cpp index 56bd0ec728..6e2efb7c57 100644 --- a/netwerk/base/nsSerializationHelper.cpp +++ b/netwerk/base/nsSerializationHelper.cpp @@ -10,7 +10,6 @@ #include "nsIObjectInputStream.h" #include "nsString.h" #include "nsBase64Encoder.h" -#include "nsAutoPtr.h" #include "nsComponentManagerUtils.h" #include "nsStringStream.h" diff --git a/netwerk/base/nsServerSocket.cpp b/netwerk/base/nsServerSocket.cpp index fa5bb3b7ae..bc112281bc 100644 --- a/netwerk/base/nsServerSocket.cpp +++ b/netwerk/base/nsServerSocket.cpp @@ -5,7 +5,6 @@ #include "nsSocketTransport2.h" #include "nsServerSocket.h" #include "nsProxyRelease.h" -#include "nsAutoPtr.h" #include "nsError.h" #include "nsNetCID.h" #include "prnetdb.h" diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index e5cfef4ec5..489f77b163 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -14,7 +14,6 @@ #include "nsProxyInfo.h" #include "nsNetCID.h" #include "nsNetUtil.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "plstr.h" #include "prerr.h" @@ -1238,8 +1237,22 @@ SECStatus nsSocketTransport::StoreResumptionToken( return SECFailure; } - SSLTokensCache::Put(static_cast(ctx)->mHost, - resumptionToken, len); + nsCOMPtr secCtrl = + do_QueryInterface(static_cast(ctx)->mSecInfo); + if (!secCtrl) { + return SECFailure; + } + nsAutoCString peerId; + secCtrl->GetPeerId(peerId); + + nsCOMPtr secInfo = do_QueryInterface(secCtrl); + if (!secInfo) { + return SECFailure; + } + + if (NS_FAILED(SSLTokensCache::Put(peerId, resumptionToken, len, secInfo))) { + return SECFailure; + } return SECSuccess; } @@ -1533,19 +1546,22 @@ nsresult nsSocketTransport::InitiateSocket() { } } - if (usingSSL && SSLTokensCache::IsEnabled()) { + nsCOMPtr secCtrl = do_QueryInterface(mSecInfo); + if (usingSSL && secCtrl && SSLTokensCache::IsEnabled()) { PRIntn val; // If SSL_NO_CACHE option was set, we must not use the cache if (SSL_OptionGet(fd, SSL_NO_CACHE, &val) == SECSuccess && val == 0) { nsTArray token; - nsresult rv2 = SSLTokensCache::Get(mHost, token); + nsAutoCString peerId; + secCtrl->GetPeerId(peerId); + nsresult rv2 = SSLTokensCache::Get(peerId, token); if (NS_SUCCEEDED(rv2) && token.Length() != 0) { SECStatus srv = SSL_SetResumptionToken(fd, token.Elements(), token.Length()); if (srv == SECFailure) { - SOCKET_LOG(("Setting token failed with NSS error %d [host=%s]", - PORT_GetError(), PromiseFlatCString(mHost).get())); - SSLTokensCache::Remove(mHost); + SOCKET_LOG(("Setting token failed with NSS error %d [id=%s]", + PORT_GetError(), PromiseFlatCString(peerId).get())); + SSLTokensCache::Remove(peerId); } } } @@ -1687,7 +1703,7 @@ nsresult nsSocketTransport::InitiateSocket() { // else { if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() && - connectStarted && connectStarted) { + connectStarted && connectCalled) { SendPRBlockingTelemetry( connectStarted, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_NORMAL, Telemetry::PRCONNECT_FAIL_BLOCKING_TIME_SHUTDOWN, @@ -2759,7 +2775,7 @@ nsSocketTransport::Bind(NetAddr* aLocalAddr) { return NS_ERROR_FAILURE; } - mBindAddr = new NetAddr(); + mBindAddr = MakeUnique(); memcpy(mBindAddr.get(), aLocalAddr, sizeof(NetAddr)); return NS_OK; @@ -2773,8 +2789,8 @@ nsSocketTransport::GetScriptablePeerAddr(nsINetAddr** addr) { rv = GetPeerAddr(&rawAddr); if (NS_FAILED(rv)) return rv; - NS_ADDREF(*addr = new nsNetAddr(&rawAddr)); - + RefPtr netaddr = new nsNetAddr(&rawAddr); + netaddr.forget(addr); return NS_OK; } @@ -2786,7 +2802,8 @@ nsSocketTransport::GetScriptableSelfAddr(nsINetAddr** addr) { rv = GetSelfAddr(&rawAddr); if (NS_FAILED(rv)) return rv; - NS_ADDREF(*addr = new nsNetAddr(&rawAddr)); + RefPtr netaddr = new nsNetAddr(&rawAddr); + netaddr.forget(addr); return NS_OK; } diff --git a/netwerk/base/nsSocketTransport2.h b/netwerk/base/nsSocketTransport2.h index 5d1c42a686..1bf7188c8d 100644 --- a/netwerk/base/nsSocketTransport2.h +++ b/netwerk/base/nsSocketTransport2.h @@ -26,7 +26,6 @@ #include "mozilla/Telemetry.h" #include "prerror.h" -#include "nsAutoPtr.h" #include "ssl.h" class nsICancelable; @@ -347,7 +346,7 @@ class nsSocketTransport final : public nsASocketHandler, Atomic mNetAddrIsSet; Atomic mSelfAddrIsSet; - nsAutoPtr mBindAddr; + UniquePtr mBindAddr; // socket methods (these can only be called on the socket thread): diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index e5f22fdc81..cdb5f70dc4 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -13,7 +13,6 @@ #include "nsIObjectOutputStream.h" #include "nsIIDNService.h" #include "mozilla/Logging.h" -#include "nsAutoPtr.h" #include "nsIURLParser.h" #include "nsNetCID.h" #include "mozilla/MemoryReporting.h" diff --git a/netwerk/base/nsStreamTransportService.cpp b/netwerk/base/nsStreamTransportService.cpp index 962ed236dd..677c4d0705 100644 --- a/netwerk/base/nsStreamTransportService.cpp +++ b/netwerk/base/nsStreamTransportService.cpp @@ -91,9 +91,11 @@ nsInputStreamTransport::OpenInputStream(uint32_t flags, uint32_t segsize, // startup async copy process... rv = NS_AsyncCopy(this, pipeOut, target, NS_ASYNCCOPY_VIA_WRITESEGMENTS, segsize); - if (NS_SUCCEEDED(rv)) NS_ADDREF(*result = mPipeIn); - - return rv; + if (NS_FAILED(rv)) { + return rv; + } + *result = do_AddRef(mPipeIn).take(); + return NS_OK; } NS_IMETHODIMP @@ -251,10 +253,9 @@ NS_IMETHODIMP nsStreamTransportService::CreateInputTransport(nsIInputStream* stream, bool closeWhenDone, nsITransport** result) { - nsInputStreamTransport* trans = + RefPtr trans = new nsInputStreamTransport(stream, closeWhenDone); - if (!trans) return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(*result = trans); + trans.forget(result); return NS_OK; } diff --git a/netwerk/base/nsSyncStreamListener.cpp b/netwerk/base/nsSyncStreamListener.cpp index 10d2696f40..0e167872d1 100644 --- a/netwerk/base/nsSyncStreamListener.cpp +++ b/netwerk/base/nsSyncStreamListener.cpp @@ -50,7 +50,7 @@ NS_IMPL_ISUPPORTS(nsSyncStreamListener, nsIStreamListener, nsIRequestObserver, NS_IMETHODIMP nsSyncStreamListener::GetInputStream(nsIInputStream** result) { - NS_ADDREF(*result = this); + *result = do_AddRef(this).take(); return NS_OK; } diff --git a/netwerk/base/nsTransportUtils.cpp b/netwerk/base/nsTransportUtils.cpp index 629cf0a3b3..4b965a4fdb 100644 --- a/netwerk/base/nsTransportUtils.cpp +++ b/netwerk/base/nsTransportUtils.cpp @@ -7,7 +7,6 @@ #include "nsITransport.h" #include "nsProxyRelease.h" #include "nsThreadUtils.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" using namespace mozilla; @@ -120,8 +119,8 @@ nsTransportEventSinkProxy::OnTransportStatus(nsITransport* transport, nsresult net_NewTransportEventSinkProxy(nsITransportEventSink** result, nsITransportEventSink* sink, nsIEventTarget* target) { - *result = new nsTransportEventSinkProxy(sink, target); - if (!*result) return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(*result); + RefPtr res = + new nsTransportEventSinkProxy(sink, target); + res.forget(result); return NS_OK; } diff --git a/netwerk/base/nsUDPSocket.cpp b/netwerk/base/nsUDPSocket.cpp index dcb30849ae..b011bc6c66 100644 --- a/netwerk/base/nsUDPSocket.cpp +++ b/netwerk/base/nsUDPSocket.cpp @@ -11,7 +11,6 @@ #include "nsSocketTransport2.h" #include "nsUDPSocket.h" #include "nsProxyRelease.h" -#include "nsAutoPtr.h" #include "nsError.h" #include "nsNetCID.h" #include "nsNetUtil.h" diff --git a/netwerk/base/nsUDPSocket.h b/netwerk/base/nsUDPSocket.h index b15b8b16dc..caf49123b5 100644 --- a/netwerk/base/nsUDPSocket.h +++ b/netwerk/base/nsUDPSocket.h @@ -9,7 +9,6 @@ #include "mozilla/Mutex.h" #include "mozilla/net/DNS.h" #include "nsIOutputStream.h" -#include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" //----------------------------------------------------------------------------- diff --git a/netwerk/base/nsURIHashKey.h b/netwerk/base/nsURIHashKey.h index d4d2f1a765..fd7baa030d 100644 --- a/netwerk/base/nsURIHashKey.h +++ b/netwerk/base/nsURIHashKey.h @@ -4,12 +4,13 @@ #ifndef nsURIHashKey_h__ #define nsURIHashKey_h__ +#include + #include "PLDHashTable.h" +#include "mozilla/Unused.h" #include "nsCOMPtr.h" -#include "nsIURI.h" #include "nsHashKeys.h" -#include "mozilla/Move.h" -#include "mozilla/Unused.h" +#include "nsIURI.h" /** * Hashtable key class to use with nsTHashtable/nsBaseHashtable @@ -19,6 +20,7 @@ class nsURIHashKey : public PLDHashEntryHdr { typedef nsIURI* KeyType; typedef const nsIURI* KeyTypePointer; + nsURIHashKey() { MOZ_COUNT_CTOR(nsURIHashKey); } explicit nsURIHashKey(const nsIURI* aKey) : mKey(const_cast(aKey)) { MOZ_COUNT_CTOR(nsURIHashKey); } @@ -28,6 +30,11 @@ class nsURIHashKey : public PLDHashEntryHdr { } MOZ_COUNTED_DTOR(nsURIHashKey) + nsURIHashKey& operator=(const nsURIHashKey& aOther) { + mKey = aOther.mKey; + return *this; + } + nsIURI* GetKey() const { return mKey; } bool KeyEquals(const nsIURI* aKey) const { diff --git a/netwerk/cache/nsApplicationCacheService.cpp b/netwerk/cache/nsApplicationCacheService.cpp index 70075af925..32a41c2246 100644 --- a/netwerk/cache/nsApplicationCacheService.cpp +++ b/netwerk/cache/nsApplicationCacheService.cpp @@ -122,7 +122,10 @@ nsApplicationCacheService::ChooseApplicationCache( RefPtr device; nsresult rv = mCacheService->GetOfflineDevice(getter_AddRefs(device)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_FAILED(rv)) { + // Silently fail and provide no appcache to the caller. + return NS_OK; + } return device->ChooseApplicationCache(key, aLoadContextInfo, out); } diff --git a/netwerk/cache/nsCacheEntry.cpp b/netwerk/cache/nsCacheEntry.cpp index a1dbddcec2..0ef45a040a 100644 --- a/netwerk/cache/nsCacheEntry.cpp +++ b/netwerk/cache/nsCacheEntry.cpp @@ -160,7 +160,7 @@ nsresult nsCacheEntry::CreateDescriptor(nsCacheRequest* request, CACHE_LOG_DEBUG((" descriptor %p created for request %p on entry %p\n", descriptor, request, this)); - NS_ADDREF(*result = descriptor); + *result = do_AddRef(descriptor).take(); return NS_OK; } diff --git a/netwerk/cache/nsCacheEntry.h b/netwerk/cache/nsCacheEntry.h index 1e89a52365..6e549548c3 100644 --- a/netwerk/cache/nsCacheEntry.h +++ b/netwerk/cache/nsCacheEntry.h @@ -11,7 +11,6 @@ #include "nspr.h" #include "PLDHashTable.h" -#include "nsAutoPtr.h" #include "nscore.h" #include "nsCOMPtr.h" #include "nsString.h" diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index 091a8341a9..36808b4cbc 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -33,6 +33,7 @@ #include "nsNetCID.h" #include // for log() #include "mozilla/Services.h" +#include "mozilla/StaticPrefs_browser.h" #include "mozilla/net/NeckoCommon.h" #include @@ -43,7 +44,6 @@ using namespace mozilla::net; /****************************************************************************** * nsCacheProfilePrefObserver *****************************************************************************/ -#define OFFLINE_CACHE_ENABLE_PREF "browser.cache.offline.enable" #define OFFLINE_CACHE_DIR_PREF "browser.cache.offline.parent_directory" #define OFFLINE_CACHE_CAPACITY_PREF "browser.cache.offline.capacity" #define OFFLINE_CACHE_CAPACITY 512000 @@ -55,13 +55,6 @@ static const char* observerList[] = { NS_XPCOM_SHUTDOWN_OBSERVER_ID, "last-pb-context-exited", "suspend_process_notification", "resume_process_notification"}; -static const char* prefList[] = { - OFFLINE_CACHE_ENABLE_PREF, - OFFLINE_CACHE_CAPACITY_PREF, - OFFLINE_CACHE_DIR_PREF, - nullptr, -}; - class nsCacheProfilePrefObserver : public nsIObserver { virtual ~nsCacheProfilePrefObserver() = default; @@ -72,6 +65,7 @@ class nsCacheProfilePrefObserver : public nsIObserver { nsCacheProfilePrefObserver() : mHaveProfile(false), mOfflineCacheEnabled(false), + mOfflineStorageCacheEnabled(false), mOfflineCacheCapacity(0), mCacheCompressionLevel(CACHE_COMPRESSION_LEVEL), mSanitizeOnShutdown(false), @@ -95,14 +89,13 @@ class nsCacheProfilePrefObserver : public nsIObserver { return mSanitizeOnShutdown && mClearCacheOnShutdown; } - void PrefChanged(const char* aPref); - private: bool mHaveProfile; nsCOMPtr mDiskCacheParentDirectory; bool mOfflineCacheEnabled; + bool mOfflineStorageCacheEnabled; int32_t mOfflineCacheCapacity; // in kilobytes nsCOMPtr mOfflineCacheParentDirectory; @@ -143,10 +136,6 @@ nsresult nsCacheProfilePrefObserver::Install() { nsCOMPtr branch = do_GetService(NS_PREFSERVICE_CONTRACTID); if (!branch) return NS_ERROR_FAILURE; - Preferences::RegisterCallbacks( - PREF_CHANGE_METHOD(nsCacheProfilePrefObserver::PrefChanged), prefList, - this); - // Determine if we have a profile already // Install() is called *after* the profile-after-change notification // when there is only a single profile, or it is specified on the @@ -173,13 +162,6 @@ void nsCacheProfilePrefObserver::Remove() { obs->RemoveObserver(this, observer); } } - - // remove Pref Service observers - nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); - if (!prefs) return; - Preferences::UnregisterCallbacks( - PREF_CHANGE_METHOD(nsCacheProfilePrefObserver::PrefChanged), prefList, - this); } NS_IMETHODIMP @@ -226,32 +208,6 @@ nsCacheProfilePrefObserver::Observe(nsISupports* subject, const char* topic, return NS_OK; } -void nsCacheProfilePrefObserver::PrefChanged(const char* aPref) { - // ignore pref changes until we're done switch profiles - if (!mHaveProfile) return; - // which preference changed? - nsresult rv; - if (!strcmp(OFFLINE_CACHE_ENABLE_PREF, aPref)) { - rv = Preferences::GetBool(OFFLINE_CACHE_ENABLE_PREF, &mOfflineCacheEnabled); - if (NS_FAILED(rv)) return; - nsCacheService::SetOfflineCacheEnabled(OfflineCacheEnabled()); - - } else if (!strcmp(OFFLINE_CACHE_CAPACITY_PREF, aPref)) { - int32_t capacity = 0; - rv = Preferences::GetInt(OFFLINE_CACHE_CAPACITY_PREF, &capacity); - if (NS_FAILED(rv)) return; - mOfflineCacheCapacity = std::max(0, capacity); - nsCacheService::SetOfflineCacheCapacity(mOfflineCacheCapacity); -#if 0 - } else if (!strcmp(OFFLINE_CACHE_DIR_PREF, aPref)) { - // XXX We probaby don't want to respond to this pref except after - // XXX profile changes. Ideally, there should be some kind of user - // XXX notification that the pref change won't take effect until - // XXX the next time the profile changes (browser launch) -#endif - } -} - nsresult nsCacheProfilePrefObserver::ReadPrefs(nsIPrefBranch* branch) { nsresult rv = NS_OK; @@ -285,8 +241,9 @@ nsresult nsCacheProfilePrefObserver::ReadPrefs(nsIPrefBranch* branch) { } // read offline cache device prefs - mOfflineCacheEnabled = true; // presume offline cache is enabled - (void)branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF, &mOfflineCacheEnabled); + mOfflineCacheEnabled = StaticPrefs::browser_cache_offline_enable(); + mOfflineStorageCacheEnabled = + StaticPrefs::browser_cache_offline_storage_enable(); mOfflineCacheCapacity = OFFLINE_CACHE_CAPACITY; (void)branch->GetIntPref(OFFLINE_CACHE_CAPACITY_PREF, &mOfflineCacheCapacity); @@ -362,7 +319,7 @@ bool nsCacheProfilePrefObserver::OfflineCacheEnabled() { if ((mOfflineCacheCapacity == 0) || (!mOfflineCacheParentDirectory)) return false; - return mOfflineCacheEnabled; + return mOfflineCacheEnabled && mOfflineStorageCacheEnabled; } int32_t nsCacheProfilePrefObserver::CacheCompressionLevel() { @@ -823,7 +780,7 @@ NS_IMETHODIMP nsCacheService::GetCacheIOTarget( nsresult rv; if (mCacheIOThread) { - NS_ADDREF(*aCacheIOTarget = mCacheIOThread); + *aCacheIOTarget = do_AddRef(mCacheIOThread).take(); rv = NS_OK; } else { *aCacheIOTarget = nullptr; @@ -859,7 +816,7 @@ nsresult nsCacheService::GetOfflineDevice(nsOfflineCacheDevice** aDevice) { NS_ENSURE_SUCCESS(rv, rv); } - NS_ADDREF(*aDevice = mOfflineDevice); + *aDevice = do_AddRef(mOfflineDevice).take(); return NS_OK; } diff --git a/netwerk/cache/nsCacheSession.cpp b/netwerk/cache/nsCacheSession.cpp index c771dff9b4..a48246f17b 100644 --- a/netwerk/cache/nsCacheSession.cpp +++ b/netwerk/cache/nsCacheSession.cpp @@ -50,11 +50,7 @@ NS_IMETHODIMP nsCacheSession::SetProfileDirectory(nsIFile* profileDir) { } NS_IMETHODIMP nsCacheSession::GetProfileDirectory(nsIFile** profileDir) { - if (mProfileDir) - NS_ADDREF(*profileDir = mProfileDir); - else - *profileDir = nullptr; - + *profileDir = do_AddRef(mProfileDir).take(); return NS_OK; } diff --git a/netwerk/cache/nsDeleteDir.cpp b/netwerk/cache/nsDeleteDir.cpp index 964971d00e..673b23e3b7 100644 --- a/netwerk/cache/nsDeleteDir.cpp +++ b/netwerk/cache/nsDeleteDir.cpp @@ -7,7 +7,6 @@ #include "nsString.h" #include "mozilla/Telemetry.h" #include "nsITimer.h" -#include "nsAutoPtr.h" #include "nsThreadUtils.h" #include "nsISupportsPriority.h" #include "nsCacheUtils.h" @@ -144,8 +143,8 @@ void nsDeleteDir::TimerCallback(nsITimer* aTimer, void* arg) { gInstance->mTimers.RemoveObjectAt(idx); } - nsAutoPtr > dirList; - dirList = static_cast*>(arg); + UniquePtr> dirList; + dirList.reset(static_cast*>(arg)); bool shuttingDown = false; @@ -224,13 +223,13 @@ nsresult nsDeleteDir::DeleteDir(nsIFile* dirIn, bool moveToTrash, trash.swap(dir); } - nsAutoPtr > arg(new nsCOMArray); + UniquePtr> arg(new nsCOMArray); arg->AppendObject(trash); - rv = gInstance->PostTimer(arg, delay); + rv = gInstance->PostTimer(arg.get(), delay); if (NS_FAILED(rv)) return rv; - arg.forget(); + Unused << arg.release(); return NS_OK; } @@ -288,7 +287,7 @@ nsresult nsDeleteDir::RemoveOldTrashes(nsIFile* cacheDir) { rv = parent->GetDirectoryEntries(getter_AddRefs(iter)); if (NS_FAILED(rv)) return rv; - nsAutoPtr > dirList; + UniquePtr> dirList; nsCOMPtr file; while (NS_SUCCEEDED(iter->GetNextFile(getter_AddRefs(file))) && file) { @@ -298,16 +297,16 @@ nsresult nsDeleteDir::RemoveOldTrashes(nsIFile* cacheDir) { // match all names that begin with the trash name (i.e. "Cache.Trash") if (Substring(leafName, 0, trashName.Length()).Equals(trashName)) { - if (!dirList) dirList = new nsCOMArray; + if (!dirList) dirList = MakeUnique>(); dirList->AppendObject(file); } } if (dirList) { - rv = gInstance->PostTimer(dirList, 90000); + rv = gInstance->PostTimer(dirList.get(), 90000); if (NS_FAILED(rv)) return rv; - dirList.forget(); + Unused << dirList.release(); } return NS_OK; diff --git a/netwerk/cache/nsDiskCacheDeviceSQL.cpp b/netwerk/cache/nsDiskCacheDeviceSQL.cpp index 75287eb268..7b9004db3c 100644 --- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp +++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp @@ -19,7 +19,6 @@ #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsIURI.h" -#include "nsAutoPtr.h" #include "nsEscape.h" #include "nsIPrefBranch.h" #include "nsString.h" @@ -680,11 +679,7 @@ nsApplicationCache::GetClientID(nsACString& out) { NS_IMETHODIMP nsApplicationCache::GetProfileDirectory(nsIFile** out) { - if (mDevice->BaseDirectory()) - NS_ADDREF(*out = mDevice->BaseDirectory()); - else - *out = nullptr; - + *out = do_AddRef(mDevice->BaseDirectory()).take(); return NS_OK; } diff --git a/netwerk/cache/nsDiskCacheDeviceSQL.h b/netwerk/cache/nsDiskCacheDeviceSQL.h index 7204bee245..2aa6a6096f 100644 --- a/netwerk/cache/nsDiskCacheDeviceSQL.h +++ b/netwerk/cache/nsDiskCacheDeviceSQL.h @@ -10,7 +10,6 @@ #include "mozIStorageConnection.h" #include "mozIStorageFunction.h" #include "nsIFile.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsCOMArray.h" #include "nsInterfaceHashtable.h" diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp index 9316e42251..d74e148b93 100644 --- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -1091,13 +1091,6 @@ nsresult CacheEntry::SetContentType(uint8_t aContentType) { return NS_ERROR_NOT_AVAILABLE; } -nsresult CacheEntry::AddBaseDomainAccess(uint32_t aSiteID) { - if (NS_SUCCEEDED(mFileStatus)) { - return mFile->AddBaseDomainAccess(aSiteID); - } - return NS_ERROR_NOT_AVAILABLE; -} - nsresult CacheEntry::GetIsForcedValid(bool* aIsForcedValid) { NS_ENSURE_ARG(aIsForcedValid); diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h index 06b3be486c..ce93bbb105 100644 --- a/netwerk/cache2/CacheEntry.h +++ b/netwerk/cache2/CacheEntry.h @@ -73,7 +73,6 @@ class CacheEntry final : public nsIRunnable, public CacheFileListener { nsresult GetOnStopTime(uint64_t* aOnStopTime); nsresult SetNetworkTimes(uint64_t onStartTime, uint64_t onStopTime); nsresult SetContentType(uint8_t aContentType); - nsresult AddBaseDomainAccess(uint32_t aSiteID); nsresult ForceValidFor(uint32_t aSecondsToTheFuture); nsresult GetIsForcedValid(bool* aIsForcedValid); nsresult OpenInputStream(int64_t offset, nsIInputStream** _retval); @@ -468,9 +467,6 @@ class CacheEntryHandle final : public nsICacheEntry { NS_IMETHOD SetContentType(uint8_t contentType) override { return mEntry->SetContentType(contentType); } - NS_IMETHOD AddBaseDomainAccess(uint32_t aSiteID) override { - return mEntry->AddBaseDomainAccess(aSiteID); - } NS_IMETHOD ForceValidFor(uint32_t aSecondsToTheFuture) override { return mEntry->ForceValidFor(aSecondsToTheFuture); } diff --git a/netwerk/cache2/CacheFile.cpp b/netwerk/cache2/CacheFile.cpp index 6db14646f8..b0d46e1580 100644 --- a/netwerk/cache2/CacheFile.cpp +++ b/netwerk/cache2/CacheFile.cpp @@ -2,19 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "CacheLog.h" #include "CacheFile.h" +#include +#include + #include "CacheFileChunk.h" #include "CacheFileInputStream.h" #include "CacheFileOutputStream.h" -#include "nsThreadUtils.h" +#include "CacheLog.h" #include "mozilla/DebugOnly.h" -#include "mozilla/Move.h" -#include +#include "mozilla/Telemetry.h" #include "nsComponentManagerUtils.h" #include "nsProxyRelease.h" -#include "mozilla/Telemetry.h" +#include "nsThreadUtils.h" // When CACHE_CHUNKS is defined we always cache unused chunks in mCacheChunks. // When it is not defined, we always release the chunks ASAP, i.e. we cache @@ -437,8 +438,6 @@ nsresult CacheFile::OnChunkUpdated(CacheFileChunk* aChunk) { } nsresult CacheFile::OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) { - nsresult rv; - // Using an 'auto' class to perform doom or fail the listener // outside the CacheFile's lock. class AutoFailDoomListener { @@ -582,13 +581,7 @@ nsresult CacheFile::OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) { MOZ_ASSERT(mListener); mMetadata = new CacheFileMetadata(mHandle, mKey); - - rv = mMetadata->ReadMetadata(this); - if (NS_FAILED(rv)) { - mListener.swap(listener); - listener->OnFileReady(rv, false); - } - + mMetadata->ReadMetadata(this); return NS_OK; } @@ -753,7 +746,7 @@ nsresult CacheFile::OpenInputStream(nsICacheEntry* aEntryHandle, NS_ADDREF(input); mDataAccessed = true; - NS_ADDREF(*_retval = input); + *_retval = do_AddRef(input).take(); return NS_OK; } @@ -821,7 +814,8 @@ nsresult CacheFile::OpenAlternativeInputStream(nsICacheEntry* aEntryHandle, NS_ADDREF(input); mDataAccessed = true; - NS_ADDREF(*_retval = input); + *_retval = do_AddRef(input).take(); + return NS_OK; } @@ -896,7 +890,7 @@ nsresult CacheFile::OpenOutputStream(CacheOutputCloseListener* aCloseListener, mOutput, this)); mDataAccessed = true; - NS_ADDREF(*_retval = mOutput); + *_retval = do_AddRef(mOutput).take(); return NS_OK; } @@ -986,11 +980,13 @@ nsresult CacheFile::OpenAlternativeOutputStream( mDataAccessed = true; mAltDataType = aAltDataType; - NS_ADDREF(*_retval = mOutput); + *_retval = do_AddRef(mOutput).take(); return NS_OK; } nsresult CacheFile::SetMemoryOnly() { + CacheFileAutoLock lock(this); + LOG(("CacheFile::SetMemoryOnly() mMemoryOnly=%d [this=%p]", mMemoryOnly, this)); @@ -1126,7 +1122,8 @@ nsresult CacheFile::VisitMetaData(nsICacheEntryMetaDataVisitor* aVisitor) { MOZ_ASSERT(mReady); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); - return mMetadata->Visit(aVisitor); + mMetadata->Visit(aVisitor); + return NS_OK; } nsresult CacheFile::ElementsSize(uint32_t* _retval) { @@ -1148,8 +1145,8 @@ nsresult CacheFile::SetExpirationTime(uint32_t aExpirationTime) { NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); PostWriteTimer(); - - return mMetadata->SetExpirationTime(aExpirationTime); + mMetadata->SetExpirationTime(aExpirationTime); + return NS_OK; } nsresult CacheFile::GetExpirationTime(uint32_t* _retval) { @@ -1157,7 +1154,8 @@ nsresult CacheFile::GetExpirationTime(uint32_t* _retval) { MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); - return mMetadata->GetExpirationTime(_retval); + *_retval = mMetadata->GetExpirationTime(); + return NS_OK; } nsresult CacheFile::SetFrecency(uint32_t aFrecency) { @@ -1172,17 +1170,18 @@ nsresult CacheFile::SetFrecency(uint32_t aFrecency) { if (mHandle && !mHandle->IsDoomed()) CacheFileIOManager::UpdateIndexEntry(mHandle, &aFrecency, nullptr, nullptr, - nullptr, nullptr, nullptr, 0); + nullptr, nullptr); - return mMetadata->SetFrecency(aFrecency); + mMetadata->SetFrecency(aFrecency); + return NS_OK; } nsresult CacheFile::GetFrecency(uint32_t* _retval) { CacheFileAutoLock lock(this); MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); - - return mMetadata->GetFrecency(_retval); + *_retval = mMetadata->GetFrecency(); + return NS_OK; } nsresult CacheFile::SetNetworkTimes(uint64_t aOnStartTime, @@ -1221,8 +1220,7 @@ nsresult CacheFile::SetNetworkTimes(uint64_t aOnStartTime, if (mHandle && !mHandle->IsDoomed()) { CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, nullptr, - &onStartTime16, &onStopTime16, nullptr, - nullptr, 0); + &onStartTime16, &onStopTime16, nullptr); } return NS_OK; } @@ -1277,54 +1275,7 @@ nsresult CacheFile::SetContentType(uint8_t aContentType) { if (mHandle && !mHandle->IsDoomed()) { CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, nullptr, nullptr, - nullptr, &aContentType, nullptr, 0); - } - return NS_OK; -} - -nsresult CacheFile::AddBaseDomainAccess(uint32_t aSiteID) { - CacheFileAutoLock lock(this); - - nsresult rv; - - LOG(("CacheFile::AddBaseDomainAccess() this=%p, siteID=%u", this, aSiteID)); - - MOZ_ASSERT(mMetadata); - NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); - - uint32_t trID = CacheObserver::TelemetryReportID(); - uint16_t siteIDCount = 0; - bool siteIDFound = false; - const char* elem = mMetadata->GetElement("eTLD1Access"); - if (elem) { - rv = CacheFileUtils::ParseBaseDomainAccessInfo(elem, trID, &aSiteID, - &siteIDFound, &siteIDCount); - if (NS_FAILED(rv)) { - // Ignore existing element, it's not valid anymore. - elem = nullptr; - } else if (siteIDFound) { - // Access from this site is already logged, nothing to do here. - return NS_OK; - } - } - - PostWriteTimer(); - - // This site accessed this element for the first time within this telemetry - // report ID. Add it and update count of accessing site in the index. - ++siteIDCount; - - nsAutoCString newElem; - CacheFileUtils::BuildOrAppendBaseDomainAccessInfo(elem, trID, aSiteID, - newElem); - rv = mMetadata->SetElement("eTLD1Access", newElem.get()); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (mHandle && !mHandle->IsDoomed()) { - CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, nullptr, nullptr, - nullptr, nullptr, &siteIDCount, trID); + nullptr, &aContentType); } return NS_OK; } @@ -1341,7 +1292,8 @@ nsresult CacheFile::SetAltMetadata(const char* aAltMetadata) { nsresult rv = mMetadata->SetElement(CacheFileUtils::kAltDataKey, aAltMetadata); - bool hasAltData = aAltMetadata ? true : false; + + bool hasAltData = !!aAltMetadata; if (NS_FAILED(rv)) { // Removing element shouldn't fail because it doesn't allocate memory. @@ -1354,7 +1306,7 @@ nsresult CacheFile::SetAltMetadata(const char* aAltMetadata) { if (mHandle && !mHandle->IsDoomed()) { CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, &hasAltData, nullptr, - nullptr, nullptr, nullptr, 0); + nullptr, nullptr); } return rv; } @@ -1364,7 +1316,8 @@ nsresult CacheFile::GetLastModified(uint32_t* _retval) { MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); - return mMetadata->GetLastModified(_retval); + *_retval = mMetadata->GetLastModified(); + return NS_OK; } nsresult CacheFile::GetLastFetched(uint32_t* _retval) { @@ -1372,15 +1325,16 @@ nsresult CacheFile::GetLastFetched(uint32_t* _retval) { MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); - return mMetadata->GetLastFetched(_retval); + *_retval = mMetadata->GetLastFetched(); + return NS_OK; } nsresult CacheFile::GetFetchCount(uint32_t* _retval) { CacheFileAutoLock lock(this); MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); - - return mMetadata->GetFetchCount(_retval); + *_retval = mMetadata->GetFetchCount(); + return NS_OK; } nsresult CacheFile::GetDiskStorageSizeInKB(uint32_t* aDiskStorageSize) { @@ -1402,7 +1356,8 @@ nsresult CacheFile::OnFetched() { PostWriteTimer(); - return mMetadata->OnFetched(); + mMetadata->OnFetched(); + return NS_OK; } void CacheFile::Lock() { mLock.Lock(); } @@ -1467,8 +1422,7 @@ nsresult CacheFile::GetChunkLocked(uint32_t aIndex, ECallerType aCaller, if (chunk->IsReady() || aCaller == WRITER) { chunk.swap(*_retval); } else { - rv = QueueChunkListener(aIndex, aCallback); - NS_ENSURE_SUCCESS(rv, rv); + QueueChunkListener(aIndex, aCallback); } if (preload) { @@ -1540,8 +1494,7 @@ nsresult CacheFile::GetChunkLocked(uint32_t aIndex, ECallerType aCaller, if (aCaller == WRITER) { chunk.swap(*_retval); } else if (aCaller != PRELOADER) { - rv = QueueChunkListener(aIndex, aCallback); - NS_ENSURE_SUCCESS(rv, rv); + QueueChunkListener(aIndex, aCallback); } if (preload) { @@ -1629,8 +1582,7 @@ nsresult CacheFile::GetChunkLocked(uint32_t aIndex, ECallerType aCaller, if (mOutput) { // the chunk doesn't exist but mOutput may create it - rv = QueueChunkListener(aIndex, aCallback); - NS_ENSURE_SUCCESS(rv, rv); + QueueChunkListener(aIndex, aCallback); } else { return NS_ERROR_NOT_AVAILABLE; } @@ -2066,10 +2018,7 @@ nsresult CacheFile::Truncate(int64_t aOffset) { return rv; } - rv = chunk->Truncate(bytesInNewLastChunk); - if (NS_FAILED(rv)) { - return rv; - } + chunk->Truncate(bytesInNewLastChunk); // If the chunk is ready set the new hash now. If it's still being loaded // CacheChunk::Truncate() made the chunk dirty and the hash will be updated @@ -2117,9 +2066,8 @@ static uint32_t StatusToTelemetryEnum(nsresult aStatus) { MOZ_ASSERT_UNREACHABLE("We should never get here"); } -nsresult CacheFile::RemoveInput(CacheFileInputStream* aInput, - nsresult aStatus) { - CacheFileAutoLock lock(this); +void CacheFile::RemoveInput(CacheFileInputStream* aInput, nsresult aStatus) { + AssertOwnsLock(); LOG(("CacheFile::RemoveInput() [this=%p, input=%p, status=0x%08" PRIx32 "]", this, aInput, static_cast(aStatus))); @@ -2139,12 +2087,9 @@ nsresult CacheFile::RemoveInput(CacheFileInputStream* aInput, Telemetry::Accumulate(Telemetry::NETWORK_CACHE_V2_INPUT_STREAM_STATUS, StatusToTelemetryEnum(aStatus)); - - return NS_OK; } -nsresult CacheFile::RemoveOutput(CacheFileOutputStream* aOutput, - nsresult aStatus) { +void CacheFile::RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus) { AssertOwnsLock(); nsresult rv; @@ -2157,7 +2102,7 @@ nsresult CacheFile::RemoveOutput(CacheFileOutputStream* aOutput, ("CacheFile::RemoveOutput() - This output was already removed, ignoring" " call [this=%p]", this)); - return NS_OK; + return; } mOutput = nullptr; @@ -2209,8 +2154,6 @@ nsresult CacheFile::RemoveOutput(CacheFileOutputStream* aOutput, Telemetry::Accumulate(Telemetry::NETWORK_CACHE_V2_OUTPUT_STREAM_STATUS, StatusToTelemetryEnum(aStatus)); - - return NS_OK; } nsresult CacheFile::NotifyChunkListener(CacheFileChunkListener* aCallback, @@ -2223,20 +2166,16 @@ nsresult CacheFile::NotifyChunkListener(CacheFileChunkListener* aCallback, this, aCallback, aTarget, static_cast(aResult), aChunkIdx, aChunk)); - nsresult rv; RefPtr ev; ev = new NotifyChunkListenerEvent(aCallback, aResult, aChunkIdx, aChunk); - if (aTarget) - rv = aTarget->Dispatch(ev, NS_DISPATCH_NORMAL); - else - rv = NS_DispatchToCurrentThread(ev); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; + if (aTarget) { + return aTarget->Dispatch(ev, NS_DISPATCH_NORMAL); + } + return NS_DispatchToCurrentThread(ev); } -nsresult CacheFile::QueueChunkListener(uint32_t aIndex, - CacheFileChunkListener* aCallback) { +void CacheFile::QueueChunkListener(uint32_t aIndex, + CacheFileChunkListener* aCallback) { LOG(("CacheFile::QueueChunkListener() [this=%p, idx=%u, listener=%p]", this, aIndex, aCallback)); @@ -2261,7 +2200,6 @@ nsresult CacheFile::QueueChunkListener(uint32_t aIndex, } listeners->mItems.AppendElement(item); - return NS_OK; } nsresult CacheFile::NotifyChunkListeners(uint32_t aIndex, nsresult aResult, @@ -2317,7 +2255,11 @@ void CacheFile::NotifyListenersAboutOutputRemoval() { RefPtr chunk; mChunks.Get(idx, getter_AddRefs(chunk)); if (chunk) { - MOZ_ASSERT(!chunk->IsReady()); + // Skip these listeners because the chunk is being read. We don't have + // assertion here to check its state because it might be already in READY + // state while CacheFile::OnChunkRead() is waiting on Cache I/O thread for + // a lock so the listeners hasn't been notified yet. In any case, the + // listeners will be notified from CacheFile::OnChunkRead(). continue; } @@ -2395,9 +2337,7 @@ bool CacheFile::IsDoomed() { } bool CacheFile::IsWriteInProgress() { - // Returns true when there is a potentially unfinished write operation. - // Not using lock for performance reasons. mMetadata is never released - // during life time of CacheFile. + CacheFileAutoLock lock(this); bool result = false; @@ -2413,6 +2353,8 @@ bool CacheFile::IsWriteInProgress() { bool CacheFile::EntryWouldExceedLimit(int64_t aOffset, int64_t aSize, bool aIsAltData) { + CacheFileAutoLock lock(this); + if (mSkipSizeCheck || aSize < 0) { return false; } @@ -2566,8 +2508,7 @@ nsresult CacheFile::InitIndexEntry() { mMetadata->IsAnonymous(), mPinned); NS_ENSURE_SUCCESS(rv, rv); - uint32_t frecency; - mMetadata->GetFrecency(&frecency); + uint32_t frecency = mMetadata->GetFrecency(); bool hasAltData = mMetadata->GetElement(CacheFileUtils::kAltDataKey) ? true : false; @@ -2600,17 +2541,9 @@ nsresult CacheFile::InitIndexEntry() { contentType = n64; } - uint32_t trID = CacheObserver::TelemetryReportID(); - const char* siteIDInfo = mMetadata->GetElement("eTLD1Access"); - uint16_t siteIDCount = 0; - if (siteIDInfo) { - CacheFileUtils::ParseBaseDomainAccessInfo(siteIDInfo, trID, nullptr, - nullptr, &siteIDCount); - } - rv = CacheFileIOManager::UpdateIndexEntry(mHandle, &frecency, &hasAltData, &onStartTime, &onStopTime, - &contentType, &siteIDCount, trID); + &contentType); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; diff --git a/netwerk/cache2/CacheFile.h b/netwerk/cache2/CacheFile.h index f5a9dd8f91..9b33c5dcd4 100644 --- a/netwerk/cache2/CacheFile.h +++ b/netwerk/cache2/CacheFile.h @@ -102,7 +102,6 @@ class CacheFile final : public CacheFileChunkListener, nsresult GetFrecency(uint32_t* _retval); nsresult SetNetworkTimes(uint64_t aOnStartTime, uint64_t aOnStopTime); nsresult SetContentType(uint8_t aContentType); - nsresult AddBaseDomainAccess(uint32_t aSiteID); nsresult GetOnStartTime(uint64_t* _retval); nsresult GetOnStopTime(uint64_t* _retval); nsresult GetLastModified(uint32_t* _retval); @@ -117,6 +116,7 @@ class CacheFile final : public CacheFileChunkListener, void Key(nsACString& aKey) { aKey = mKey; } bool IsDoomed(); bool IsPinned() const { return mPinned; } + // Returns true when there is a potentially unfinished write operation. bool IsWriteInProgress(); bool EntryWouldExceedLimit(int64_t aOffset, int64_t aSize, bool aIsAltData); @@ -162,13 +162,12 @@ class CacheFile final : public CacheFileChunkListener, int64_t BytesFromChunk(uint32_t aIndex, bool aAlternativeData); nsresult Truncate(int64_t aOffset); - nsresult RemoveInput(CacheFileInputStream* aInput, nsresult aStatus); - nsresult RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus); + void RemoveInput(CacheFileInputStream* aInput, nsresult aStatus); + void RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus); nsresult NotifyChunkListener(CacheFileChunkListener* aCallback, nsIEventTarget* aTarget, nsresult aResult, uint32_t aChunkIdx, CacheFileChunk* aChunk); - nsresult QueueChunkListener(uint32_t aIndex, - CacheFileChunkListener* aCallback); + void QueueChunkListener(uint32_t aIndex, CacheFileChunkListener* aCallback); nsresult NotifyChunkListeners(uint32_t aIndex, nsresult aResult, CacheFileChunk* aChunk); bool HaveChunkListeners(uint32_t aIndex); diff --git a/netwerk/cache2/CacheFileChunk.cpp b/netwerk/cache2/CacheFileChunk.cpp index d10d41c822..da301298c3 100644 --- a/netwerk/cache2/CacheFileChunk.cpp +++ b/netwerk/cache2/CacheFileChunk.cpp @@ -395,7 +395,7 @@ nsresult CacheFileChunk::Write(CacheFileHandle* aHandle, nsresult rv; mState = WRITING; - mWritingStateHandle = new CacheFileChunkReadHandle(mBuf); + mWritingStateHandle = MakeUnique(mBuf); rv = CacheFileIOManager::Write( aHandle, mIndex * kChunkSize, mWritingStateHandle->Buf(), @@ -441,7 +441,7 @@ void CacheFileChunk::WaitForUpdate(CacheFileChunkListener* aCallback) { mUpdateListeners.AppendElement(item); } -nsresult CacheFileChunk::CancelWait(CacheFileChunkListener* aCallback) { +void CacheFileChunk::CancelWait(CacheFileChunkListener* aCallback) { AssertOwnsLock(); LOG(("CacheFileChunk::CancelWait() [this=%p, listener=%p]", this, aCallback)); @@ -464,8 +464,6 @@ nsresult CacheFileChunk::CancelWait(CacheFileChunkListener* aCallback) { MOZ_ASSERT(mUpdateListeners[i]->mCallback != aCallback); } #endif - - return NS_OK; } nsresult CacheFileChunk::NotifyUpdateListeners() { @@ -550,7 +548,7 @@ void CacheFileChunk::UpdateDataSize(uint32_t aOffset, uint32_t aLen) { mValidityMap.Log(); } -nsresult CacheFileChunk::Truncate(uint32_t aOffset) { +void CacheFileChunk::Truncate(uint32_t aOffset) { MOZ_RELEASE_ASSERT(mState == READY || mState == WRITING || mState == READING); if (mState == READING) { @@ -558,7 +556,6 @@ nsresult CacheFileChunk::Truncate(uint32_t aOffset) { } mBuf->SetDataSize(aOffset); - return NS_OK; } nsresult CacheFileChunk::OnFileOpened(CacheFileHandle* aHandle, diff --git a/netwerk/cache2/CacheFileChunk.h b/netwerk/cache2/CacheFileChunk.h index e1986344a1..e89cdd4102 100644 --- a/netwerk/cache2/CacheFileChunk.h +++ b/netwerk/cache2/CacheFileChunk.h @@ -9,8 +9,8 @@ #include "CacheStorageService.h" #include "CacheHashUtils.h" #include "CacheFileUtils.h" -#include "nsAutoPtr.h" #include "mozilla/Mutex.h" +#include "mozilla/UniquePtr.h" namespace mozilla { namespace net { @@ -140,7 +140,7 @@ class CacheFileChunk final : public CacheFileIOListener, CacheHash::Hash16_t aHash, CacheFileChunkListener* aCallback); nsresult Write(CacheFileHandle* aHandle, CacheFileChunkListener* aCallback); void WaitForUpdate(CacheFileChunkListener* aCallback); - nsresult CancelWait(CacheFileChunkListener* aCallback); + void CancelWait(CacheFileChunkListener* aCallback); nsresult NotifyUpdateListeners(); uint32_t Index() const; @@ -182,7 +182,7 @@ class CacheFileChunk final : public CacheFileIOListener, void AssertOwnsLock() const; void UpdateDataSize(uint32_t aOffset, uint32_t aLen); - nsresult Truncate(uint32_t aOffset); + void Truncate(uint32_t aOffset); bool CanAllocate(uint32_t aSize) const; void BuffersAllocationChanged(uint32_t aFreed, uint32_t aAllocated); @@ -217,7 +217,7 @@ class CacheFileChunk final : public CacheFileIOListener, nsTArray> mOldBufs; // Read handle that is used during writing the chunk to the disk. - nsAutoPtr mWritingStateHandle; + UniquePtr mWritingStateHandle; // Buffer that is used to read the chunk from the disk. It is allowed to write // a new data to chunk while we wait for the data from the disk. In this case diff --git a/netwerk/cache2/CacheFileContextEvictor.cpp b/netwerk/cache2/CacheFileContextEvictor.cpp index 5ed811291a..84027296a1 100644 --- a/netwerk/cache2/CacheFileContextEvictor.cpp +++ b/netwerk/cache2/CacheFileContextEvictor.cpp @@ -99,7 +99,7 @@ nsresult CacheFileContextEvictor::AddContext( if (mEntries[i]->mInfo && mEntries[i]->mInfo->Equals(aLoadContextInfo) && mEntries[i]->mPinned == aPinned && mEntries[i]->mOrigin.Equals(aOrigin)) { - entry = mEntries[i]; + entry = mEntries[i].get(); break; } } @@ -122,7 +122,7 @@ nsresult CacheFileContextEvictor::AddContext( entry->mInfo = aLoadContextInfo; entry->mPinned = aPinned; entry->mOrigin = aOrigin; - mEntries.AppendElement(entry); + mEntries.AppendElement(WrapUnique(entry)); } entry->mTimeStamp = PR_Now() / PR_USEC_PER_MSEC; @@ -157,7 +157,7 @@ nsresult CacheFileContextEvictor::AddContext( return NS_OK; } -nsresult CacheFileContextEvictor::CacheIndexStateChanged() { +void CacheFileContextEvictor::CacheIndexStateChanged() { LOG(("CacheFileContextEvictor::CacheIndexStateChanged() [this=%p]", this)); MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); @@ -167,18 +167,18 @@ nsresult CacheFileContextEvictor::CacheIndexStateChanged() { if (mEntries.Length() == 0) { // Just save the state and exit, since there is nothing to do mIndexIsUpToDate = isUpToDate; - return NS_OK; + return; } if (!isUpToDate && !mIndexIsUpToDate) { // Index is outdated and status has not changed, nothing to do. - return NS_OK; + return; } if (isUpToDate && mIndexIsUpToDate) { // Status has not changed, but make sure the eviction is running. if (mEvicting) { - return NS_OK; + return; } // We're not evicting, but we should be evicting?! @@ -196,19 +196,14 @@ nsresult CacheFileContextEvictor::CacheIndexStateChanged() { } else { CloseIterators(); } - - return NS_OK; } -nsresult CacheFileContextEvictor::WasEvicted(const nsACString& aKey, - nsIFile* aFile, - bool* aEvictedAsPinned, - bool* aEvictedAsNonPinned) { +void CacheFileContextEvictor::WasEvicted(const nsACString& aKey, nsIFile* aFile, + bool* aEvictedAsPinned, + bool* aEvictedAsNonPinned) { LOG(("CacheFileContextEvictor::WasEvicted() [key=%s]", PromiseFlatCString(aKey).get())); - nsresult rv; - *aEvictedAsPinned = false; *aEvictedAsNonPinned = false; @@ -218,24 +213,22 @@ nsresult CacheFileContextEvictor::WasEvicted(const nsACString& aKey, MOZ_ASSERT(info); if (!info) { LOG(("CacheFileContextEvictor::WasEvicted() - Cannot parse key!")); - return NS_OK; + return; } for (uint32_t i = 0; i < mEntries.Length(); ++i) { - CacheFileContextEvictorEntry* entry = mEntries[i]; + const auto& entry = mEntries[i]; if (entry->mInfo && !info->Equals(entry->mInfo)) { continue; } PRTime lastModifiedTime; - rv = aFile->GetLastModifiedTime(&lastModifiedTime); - if (NS_FAILED(rv)) { + if (NS_FAILED(aFile->GetLastModifiedTime(&lastModifiedTime))) { LOG( ("CacheFileContextEvictor::WasEvicted() - Cannot get last modified " - "time" - ", returning false.")); - return NS_OK; + "time, returning.")); + return; } if (lastModifiedTime > entry->mTimeStamp) { @@ -254,8 +247,6 @@ nsresult CacheFileContextEvictor::WasEvicted(const nsACString& aKey, *aEvictedAsNonPinned = true; } } - - return NS_OK; } nsresult CacheFileContextEvictor::PersistEvictionInfoToDisk( @@ -405,7 +396,7 @@ nsresult CacheFileContextEvictor::LoadEvictInfoFromDisk() { nsAutoCString origin; if (decoded.Contains('\t')) { auto split = decoded.Split('\t'); - MOZ_ASSERT(decoded.CountChar('\t') == 2); + MOZ_ASSERT(decoded.CountChar('\t') == 1); origin = split.Get(0); decoded = split.Get(1); @@ -542,9 +533,9 @@ void CacheFileContextEvictor::StartEvicting() { return; } - nsCOMPtr ev; - ev = NewRunnableMethod("net::CacheFileContextEvictor::EvictEntries", this, - &CacheFileContextEvictor::EvictEntries); + nsCOMPtr ev = + NewRunnableMethod("net::CacheFileContextEvictor::EvictEntries", this, + &CacheFileContextEvictor::EvictEntries); RefPtr ioThread = CacheFileIOManager::IOThread(); @@ -559,7 +550,7 @@ void CacheFileContextEvictor::StartEvicting() { mEvicting = true; } -nsresult CacheFileContextEvictor::EvictEntries() { +void CacheFileContextEvictor::EvictEntries() { LOG(("CacheFileContextEvictor::EvictEntries()")); nsresult rv; @@ -572,7 +563,7 @@ nsresult CacheFileContextEvictor::EvictEntries() { LOG( ("CacheFileContextEvictor::EvictEntries() - Stopping evicting due to " "outdated index.")); - return NS_OK; + return; } while (true) { @@ -583,7 +574,7 @@ nsresult CacheFileContextEvictor::EvictEntries() { mEvicting = true; // We don't want to start eviction again during shutdown // process. Setting this flag to true ensures it. - return NS_OK; + return; } if (CacheIOThread::YieldAndRerun()) { @@ -591,7 +582,7 @@ nsresult CacheFileContextEvictor::EvictEntries() { ("CacheFileContextEvictor::EvictEntries() - Breaking loop for higher " "level events.")); mEvicting = true; - return NS_OK; + return; } if (mEntries.Length() == 0) { @@ -602,7 +593,7 @@ nsresult CacheFileContextEvictor::EvictEntries() { // Allow index to notify AsyncGetDiskConsumption callbacks. The size is // actual again. CacheIndex::OnAsyncEviction(false); - return NS_OK; + return; } SHA1Sum::Hash hash; @@ -676,13 +667,9 @@ nsresult CacheFileContextEvictor::EvictEntries() { } // Now get the context + enhance id + URL from the key. - nsAutoCString key; - metadata->GetKey(key); - nsAutoCString uriSpec; - RefPtr info = - CacheFileUtils::ParseKey(key, nullptr, &uriSpec); + CacheFileUtils::ParseKey(metadata->GetKey(), nullptr, &uriSpec); MOZ_ASSERT(info); if (!info) { continue; @@ -700,7 +687,7 @@ nsresult CacheFileContextEvictor::EvictEntries() { nsAutoCString urlOrigin; url->Origin(urlOrigin); - if (urlOrigin.Equals(NS_ConvertUTF16toUTF8(mEntries[0]->mOrigin))) { + if (!urlOrigin.Equals(NS_ConvertUTF16toUTF8(mEntries[0]->mOrigin))) { LOG( ("CacheFileContextEvictor::EvictEntries() - Skipping entry since " "origin " @@ -742,7 +729,6 @@ nsresult CacheFileContextEvictor::EvictEntries() { } MOZ_ASSERT_UNREACHABLE("We should never get here"); - return NS_OK; } } // namespace net diff --git a/netwerk/cache2/CacheFileContextEvictor.h b/netwerk/cache2/CacheFileContextEvictor.h index becacef152..3637cc37e6 100644 --- a/netwerk/cache2/CacheFileContextEvictor.h +++ b/netwerk/cache2/CacheFileContextEvictor.h @@ -5,9 +5,9 @@ #ifndef CacheFileContextEvictor__h__ #define CacheFileContextEvictor__h__ +#include "mozilla/UniquePtr.h" #include "nsTArray.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" class nsIFile; class nsILoadContextInfo; @@ -46,14 +46,14 @@ class CacheFileContextEvictor { // CacheFileIOManager calls this method when CacheIndex's state changes. We // check whether the index is up to date and start or stop evicting according // to index's state. - nsresult CacheIndexStateChanged(); + void CacheIndexStateChanged(); // CacheFileIOManager calls this method to check whether an entry file should // be considered as evicted. It returns true when there is a matching context // info to the given key and the last modified time of the entry file is // earlier than the time stamp of the time when the context was added to the // evictor. - nsresult WasEvicted(const nsACString& aKey, nsIFile* aFile, - bool* aEvictedAsPinned, bool* aEvictedAsNonPinned); + void WasEvicted(const nsACString& aKey, nsIFile* aFile, + bool* aEvictedAsPinned, bool* aEvictedAsNonPinned); private: // Writes information about eviction of the given context to the disk. This is @@ -75,7 +75,7 @@ class CacheFileContextEvictor { void CreateIterators(); void CloseIterators(); void StartEvicting(); - nsresult EvictEntries(); + void EvictEntries(); // Whether eviction is in progress bool mEvicting; @@ -88,7 +88,7 @@ class CacheFileContextEvictor { // startup. static bool sDiskAlreadySearched; // Array of contexts being evicted. - nsTArray > mEntries; + nsTArray> mEntries; nsCOMPtr mCacheDirectory; nsCOMPtr mEntriesDir; }; diff --git a/netwerk/cache2/CacheFileIOManager.cpp b/netwerk/cache2/CacheFileIOManager.cpp index 294129ae03..f2b7cdf76f 100644 --- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -385,9 +385,9 @@ nsresult CacheFileHandles::GetHandle(const SHA1Sum::Hash* aHash, return NS_OK; } -nsresult CacheFileHandles::NewHandle(const SHA1Sum::Hash* aHash, bool aPriority, - CacheFileHandle::PinningStatus aPinning, - CacheFileHandle** _retval) { +already_AddRefed CacheFileHandles::NewHandle( + const SHA1Sum::Hash* aHash, bool aPriority, + CacheFileHandle::PinningStatus aPinning) { MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); MOZ_ASSERT(aHash); @@ -415,9 +415,7 @@ nsresult CacheFileHandles::NewHandle(const SHA1Sum::Hash* aHash, bool aPriority, ("CacheFileHandles::NewHandle() hash=%08x%08x%08x%08x%08x " "created new handle %p, entry=%p", LOGSHA1(aHash), handle.get(), entry)); - - handle.forget(_retval); - return NS_OK; + return handle.forget(); } void CacheFileHandles::RemoveHandle(CacheFileHandle* aHandle) { @@ -974,7 +972,7 @@ class InitIndexEntryEvent : public Runnable { // if there is no write to the file. uint32_t sizeInK = mHandle->FileSizeInK(); CacheIndex::UpdateEntry(mHandle->Hash(), nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, 0, &sizeInK); + nullptr, &sizeInK); return NS_OK; } @@ -991,9 +989,7 @@ class UpdateIndexEntryEvent : public Runnable { UpdateIndexEntryEvent(CacheFileHandle* aHandle, const uint32_t* aFrecency, const bool* aHasAltData, const uint16_t* aOnStartTime, const uint16_t* aOnStopTime, - const uint8_t* aContentType, - const uint16_t* aBaseDomainAccessCount, - const uint32_t aTelemetryReportID) + const uint8_t* aContentType) : Runnable("net::UpdateIndexEntryEvent"), mHandle(aHandle), mHasFrecency(false), @@ -1001,14 +997,11 @@ class UpdateIndexEntryEvent : public Runnable { mHasOnStartTime(false), mHasOnStopTime(false), mHasContentType(false), - mHasBaseDomainAccessCount(false), mFrecency(0), mHasAltData(false), mOnStartTime(0), mOnStopTime(0), - mContentType(nsICacheEntry::CONTENT_TYPE_UNKNOWN), - mBaseDomainAccessCount(0), - mTelemetryReportID(aTelemetryReportID) { + mContentType(nsICacheEntry::CONTENT_TYPE_UNKNOWN) { if (aFrecency) { mHasFrecency = true; mFrecency = *aFrecency; @@ -1029,10 +1022,6 @@ class UpdateIndexEntryEvent : public Runnable { mHasContentType = true; mContentType = *aContentType; } - if (aBaseDomainAccessCount) { - mHasBaseDomainAccessCount = true; - mBaseDomainAccessCount = *aBaseDomainAccessCount; - } } protected: @@ -1050,8 +1039,7 @@ class UpdateIndexEntryEvent : public Runnable { mHasOnStartTime ? &mOnStartTime : nullptr, mHasOnStopTime ? &mOnStopTime : nullptr, mHasContentType ? &mContentType : nullptr, - mHasBaseDomainAccessCount ? &mBaseDomainAccessCount : nullptr, - mTelemetryReportID, nullptr); + nullptr); return NS_OK; } @@ -1063,15 +1051,12 @@ class UpdateIndexEntryEvent : public Runnable { bool mHasOnStartTime; bool mHasOnStopTime; bool mHasContentType; - bool mHasBaseDomainAccessCount; uint32_t mFrecency; bool mHasAltData; uint16_t mOnStartTime; uint16_t mOnStopTime; uint8_t mContentType; - uint16_t mBaseDomainAccessCount; - uint32_t mTelemetryReportID; }; class MetadataWriteScheduleEvent : public Runnable { @@ -1205,7 +1190,7 @@ nsresult CacheFileIOManager::Shutdown() { return NS_OK; } -nsresult CacheFileIOManager::ShutdownInternal() { +void CacheFileIOManager::ShutdownInternal() { LOG(("CacheFileIOManager::ShutdownInternal() [this=%p]", this)); MOZ_ASSERT(mIOThread->IsCurrentThread()); @@ -1273,8 +1258,6 @@ nsresult CacheFileIOManager::ShutdownInternal() { mContextEvictor->Shutdown(); mContextEvictor = nullptr; } - - return NS_OK; } // static @@ -1457,7 +1440,7 @@ nsresult CacheFileIOManager::UnscheduleMetadataWrite(CacheFile* aFile) { return target->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); } -nsresult CacheFileIOManager::UnscheduleMetadataWriteInternal(CacheFile* aFile) { +void CacheFileIOManager::UnscheduleMetadataWriteInternal(CacheFile* aFile) { MOZ_ASSERT(IsOnIOThreadOrCeased()); mScheduledMetadataWrites.RemoveElement(aFile); @@ -1466,8 +1449,6 @@ nsresult CacheFileIOManager::UnscheduleMetadataWriteInternal(CacheFile* aFile) { mMetadataWritesTimer->Cancel(); mMetadataWritesTimer = nullptr; } - - return NS_OK; } // static @@ -1482,7 +1463,7 @@ nsresult CacheFileIOManager::ShutdownMetadataWriteScheduling() { return target->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); } -nsresult CacheFileIOManager::ShutdownMetadataWriteSchedulingInternal() { +void CacheFileIOManager::ShutdownMetadataWriteSchedulingInternal() { MOZ_ASSERT(IsOnIOThreadOrCeased()); nsTArray > files; @@ -1496,8 +1477,6 @@ nsresult CacheFileIOManager::ShutdownMetadataWriteSchedulingInternal() { mMetadataWritesTimer->Cancel(); mMetadataWritesTimer = nullptr; } - - return NS_OK; } NS_IMETHODIMP @@ -1588,9 +1567,7 @@ nsresult CacheFileIOManager::OpenFileInternal(const SHA1Sum::Hash* aHash, handle = nullptr; } - rv = mHandles.NewHandle(aHash, aFlags & PRIORITY, pinning, - getter_AddRefs(handle)); - NS_ENSURE_SUCCESS(rv, rv); + handle = mHandles.NewHandle(aHash, aFlags & PRIORITY, pinning); bool exists; rv = file->Exists(&exists); @@ -1645,10 +1622,7 @@ nsresult CacheFileIOManager::OpenFileInternal(const SHA1Sum::Hash* aHash, pinning = CacheFileHandle::PinningStatus::UNKNOWN; } - rv = mHandles.NewHandle(aHash, aFlags & PRIORITY, pinning, - getter_AddRefs(handle)); - NS_ENSURE_SUCCESS(rv, rv); - + handle = mHandles.NewHandle(aHash, aFlags & PRIORITY, pinning); if (exists) { // If this file has been found evicted through the context file evictor // above for any of pinned or non-pinned state, these calls ensure we doom @@ -1775,9 +1749,8 @@ nsresult CacheFileIOManager::OpenSpecialFileInternal( return NS_OK; } -nsresult CacheFileIOManager::CloseHandleInternal(CacheFileHandle* aHandle) { +void CacheFileIOManager::CloseHandleInternal(CacheFileHandle* aHandle) { nsresult rv; - LOG(("CacheFileIOManager::CloseHandleInternal() [handle=%p]", aHandle)); MOZ_ASSERT(!aHandle->IsClosed()); @@ -1821,8 +1794,6 @@ nsresult CacheFileIOManager::CloseHandleInternal(CacheFileHandle* aHandle) { mHandles.RemoveHandle(aHandle); } } - - return NS_OK; } // static @@ -2064,7 +2035,7 @@ nsresult CacheFileIOManager::WriteInternal(CacheFileHandle* aHandle, if (oldSizeInK != newSizeInK && !aHandle->IsDoomed() && !aHandle->IsSpecialFile()) { CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, 0, &newSizeInK); + nullptr, nullptr, &newSizeInK); if (oldSizeInK < newSizeInK) { EvictIfOverLimitInternal(); @@ -2473,11 +2444,8 @@ nsresult CacheFileIOManager::GetEntryInfo( } // Now get the context + enhance id + URL from the key. - nsAutoCString key; - metadata->GetKey(key); - RefPtr info = - CacheFileUtils::ParseKey(key, &enhanceId, &uriSpec); + CacheFileUtils::ParseKey(metadata->GetKey(), &enhanceId, &uriSpec); MOZ_ASSERT(info); if (!info) { return NS_OK; @@ -2485,18 +2453,9 @@ nsresult CacheFileIOManager::GetEntryInfo( // Pick all data to pass to the callback. int64_t dataSize = metadata->Offset(); - uint32_t fetchCount; - if (NS_FAILED(metadata->GetFetchCount(&fetchCount))) { - fetchCount = 0; - } - uint32_t expirationTime; - if (NS_FAILED(metadata->GetExpirationTime(&expirationTime))) { - expirationTime = 0; - } - uint32_t lastModified; - if (NS_FAILED(metadata->GetLastModified(&lastModified))) { - lastModified = 0; - } + uint32_t fetchCount = metadata->GetFetchCount(); + uint32_t expirationTime = metadata->GetExpirationTime(); + uint32_t lastModified = metadata->GetLastModified(); // Call directly on the callback. aCallback->OnEntryInfo(uriSpec, enhanceId, dataSize, fetchCount, lastModified, @@ -2592,7 +2551,7 @@ nsresult CacheFileIOManager::TruncateSeekSetEOFInternal( if (oldSizeInK != newSizeInK && !aHandle->IsDoomed() && !aHandle->IsSpecialFile()) { CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, 0, &newSizeInK); + nullptr, &newSizeInK); if (oldSizeInK < newSizeInK) { EvictIfOverLimitInternal(); @@ -2906,7 +2865,7 @@ nsresult CacheFileIOManager::OverLimitEvictionInternal() { // failing on one entry forever. uint32_t frecency = 0; rv = CacheIndex::UpdateEntry(&hash, &frecency, nullptr, nullptr, nullptr, - nullptr, nullptr, 0, nullptr); + nullptr, nullptr); NS_ENSURE_SUCCESS(rv, rv); consecutiveFailures++; @@ -3193,8 +3152,7 @@ nsresult CacheFileIOManager::CacheIndexStateChanged() { // We have to re-distatch even if we are on IO thread to prevent reentering // the lock in CacheIndex - nsCOMPtr ev; - ev = NewRunnableMethod( + nsCOMPtr ev = NewRunnableMethod( "net::CacheFileIOManager::CacheIndexStateChangedInternal", gInstance.get(), &CacheFileIOManager::CacheIndexStateChangedInternal); @@ -3209,18 +3167,17 @@ nsresult CacheFileIOManager::CacheIndexStateChanged() { return NS_OK; } -nsresult CacheFileIOManager::CacheIndexStateChangedInternal() { +void CacheFileIOManager::CacheIndexStateChangedInternal() { if (mShuttingDown) { // ignore notification during shutdown - return NS_OK; + return; } if (!mContextEvictor) { - return NS_OK; + return; } mContextEvictor->CacheIndexStateChanged(); - return NS_OK; } nsresult CacheFileIOManager::TrashDirectory(nsIFile* aFile) { @@ -3563,21 +3520,15 @@ nsresult CacheFileIOManager::InitIndexEntry(CacheFileHandle* aHandle, nsresult CacheFileIOManager::UpdateIndexEntry( CacheFileHandle* aHandle, const uint32_t* aFrecency, const bool* aHasAltData, const uint16_t* aOnStartTime, - const uint16_t* aOnStopTime, const uint8_t* aContentType, - const uint16_t* aBaseDomainAccessCount, const uint32_t aTelemetryReportID) { + const uint16_t* aOnStopTime, const uint8_t* aContentType) { LOG( ("CacheFileIOManager::UpdateIndexEntry() [handle=%p, frecency=%s, " - "hasAltData=%s, onStartTime=%s, onStopTime=%s, contentType=%s, " - "baseDomainAccessCount=%s, telemetryReportID=%u]", + "hasAltData=%s, onStartTime=%s, onStopTime=%s, contentType=%s]", aHandle, aFrecency ? nsPrintfCString("%u", *aFrecency).get() : "", aHasAltData ? (*aHasAltData ? "true" : "false") : "", aOnStartTime ? nsPrintfCString("%u", *aOnStartTime).get() : "", aOnStopTime ? nsPrintfCString("%u", *aOnStopTime).get() : "", - aContentType ? nsPrintfCString("%u", *aContentType).get() : "", - aBaseDomainAccessCount - ? nsPrintfCString("%u", *aBaseDomainAccessCount).get() - : "", - aTelemetryReportID)); + aContentType ? nsPrintfCString("%u", *aContentType).get() : "")); nsresult rv; RefPtr ioMan = gInstance; @@ -3591,8 +3542,7 @@ nsresult CacheFileIOManager::UpdateIndexEntry( } RefPtr ev = new UpdateIndexEntryEvent( - aHandle, aFrecency, aHasAltData, aOnStartTime, aOnStopTime, aContentType, - aBaseDomainAccessCount, aTelemetryReportID); + aHandle, aFrecency, aHasAltData, aOnStartTime, aOnStopTime, aContentType); rv = ioMan->mIOThread->Dispatch(ev, aHandle->mPriority ? CacheIOThread::WRITE_PRIORITY : CacheIOThread::WRITE); diff --git a/netwerk/cache2/CacheFileIOManager.h b/netwerk/cache2/CacheFileIOManager.h index 1c830492e5..6e81cc613f 100644 --- a/netwerk/cache2/CacheFileIOManager.h +++ b/netwerk/cache2/CacheFileIOManager.h @@ -133,9 +133,9 @@ class CacheFileHandles { ~CacheFileHandles(); nsresult GetHandle(const SHA1Sum::Hash* aHash, CacheFileHandle** _retval); - nsresult NewHandle(const SHA1Sum::Hash* aHash, bool aPriority, - CacheFileHandle::PinningStatus aPinning, - CacheFileHandle** _retval); + already_AddRefed NewHandle(const SHA1Sum::Hash*, + bool aPriority, + CacheFileHandle::PinningStatus); void RemoveHandle(CacheFileHandle* aHandlle); void GetAllHandles(nsTArray >* _retval); void GetActiveHandles(nsTArray >* _retval); @@ -323,9 +323,7 @@ class CacheFileIOManager final : public nsITimerCallback, public nsINamed { const bool* aHasAltData, const uint16_t* aOnStartTime, const uint16_t* aOnStopTime, - const uint8_t* aContentType, - const uint16_t* aBaseDomainAccessCount, - const uint32_t aTelemetryReportID); + const uint8_t* aContentType); static nsresult UpdateIndexEntry(); @@ -369,13 +367,13 @@ class CacheFileIOManager final : public nsITimerCallback, public nsINamed { virtual ~CacheFileIOManager(); nsresult InitInternal(); - nsresult ShutdownInternal(); + void ShutdownInternal(); nsresult OpenFileInternal(const SHA1Sum::Hash* aHash, const nsACString& aKey, uint32_t aFlags, CacheFileHandle** _retval); nsresult OpenSpecialFileInternal(const nsACString& aKey, uint32_t aFlags, CacheFileHandle** _retval); - nsresult CloseHandleInternal(CacheFileHandle* aHandle); + void CloseHandleInternal(CacheFileHandle* aHandle); nsresult ReadInternal(CacheFileHandle* aHandle, int64_t aOffset, char* aBuf, int32_t aCount); nsresult WriteInternal(CacheFileHandle* aHandle, int64_t aOffset, @@ -421,11 +419,11 @@ class CacheFileIOManager final : public nsITimerCallback, public nsINamed { void SyncRemoveAllCacheFiles(); nsresult ScheduleMetadataWriteInternal(CacheFile* aFile); - nsresult UnscheduleMetadataWriteInternal(CacheFile* aFile); - nsresult ShutdownMetadataWriteSchedulingInternal(); + void UnscheduleMetadataWriteInternal(CacheFile* aFile); + void ShutdownMetadataWriteSchedulingInternal(); static nsresult CacheIndexStateChanged(); - nsresult CacheIndexStateChangedInternal(); + void CacheIndexStateChangedInternal(); // Smart size calculation. UpdateSmartCacheSize() must be called on IO thread. // It is called in EvictIfOverLimitInternal() just before we decide whether to diff --git a/netwerk/cache2/CacheFileInputStream.cpp b/netwerk/cache2/CacheFileInputStream.cpp index 978781afb9..dc6d0208e6 100644 --- a/netwerk/cache2/CacheFileInputStream.cpp +++ b/netwerk/cache2/CacheFileInputStream.cpp @@ -27,6 +27,7 @@ CacheFileInputStream::Release() { } if (count == 1) { + CacheFileAutoLock lock(mFile); mFile->RemoveInput(this, mStatus); } @@ -251,10 +252,11 @@ CacheFileInputStream::CloseWithStatus(nsresult aStatus) { "]", this, static_cast(aStatus))); - return CloseWithStatusLocked(aStatus); + CloseWithStatusLocked(aStatus); + return NS_OK; } -nsresult CacheFileInputStream::CloseWithStatusLocked(nsresult aStatus) { +void CacheFileInputStream::CloseWithStatusLocked(nsresult aStatus) { LOG( ("CacheFileInputStream::CloseWithStatusLocked() [this=%p, " "aStatus=0x%08" PRIx32 "]", @@ -266,8 +268,7 @@ nsresult CacheFileInputStream::CloseWithStatusLocked(nsresult aStatus) { // step out from ReadSegments. So if the stream is already closed the // following assertion must be true. MOZ_ASSERT(!mCallback || mInReadSegments); - - return NS_OK; + return; } mClosed = true; @@ -276,8 +277,6 @@ nsresult CacheFileInputStream::CloseWithStatusLocked(nsresult aStatus) { if (!mInReadSegments) { CleanUp(); } - - return NS_OK; } void CacheFileInputStream::CleanUp() { diff --git a/netwerk/cache2/CacheFileInputStream.h b/netwerk/cache2/CacheFileInputStream.h index cbfb553cf9..8280f9d224 100644 --- a/netwerk/cache2/CacheFileInputStream.h +++ b/netwerk/cache2/CacheFileInputStream.h @@ -8,7 +8,6 @@ #include "nsIAsyncInputStream.h" #include "nsISeekableStream.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "CacheFileChunk.h" namespace mozilla { @@ -47,7 +46,7 @@ class CacheFileInputStream : public nsIAsyncInputStream, private: virtual ~CacheFileInputStream(); - nsresult CloseWithStatusLocked(nsresult aStatus); + void CloseWithStatusLocked(nsresult aStatus); void CleanUp(); void ReleaseChunk(); void EnsureCorrectChunk(bool aReleaseOnly); diff --git a/netwerk/cache2/CacheFileMetadata.cpp b/netwerk/cache2/CacheFileMetadata.cpp index aa87846244..738a1e9f49 100644 --- a/netwerk/cache2/CacheFileMetadata.cpp +++ b/netwerk/cache2/CacheFileMetadata.cpp @@ -147,12 +147,7 @@ void CacheFileMetadata::SetHandle(CacheFileHandle* aHandle) { mHandle = aHandle; } -nsresult CacheFileMetadata::GetKey(nsACString& _retval) { - _retval = mKey; - return NS_OK; -} - -nsresult CacheFileMetadata::ReadMetadata(CacheFileMetadataListener* aListener) { +void CacheFileMetadata::ReadMetadata(CacheFileMetadataListener* aListener) { LOG(("CacheFileMetadata::ReadMetadata() [this=%p, listener=%p]", this, aListener)); @@ -175,7 +170,7 @@ nsresult CacheFileMetadata::ReadMetadata(CacheFileMetadataListener* aListener) { InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); - return NS_OK; + return; } if (size < int64_t(sizeof(CacheFileMetadataHeader) + 2 * sizeof(uint32_t))) { @@ -187,7 +182,7 @@ nsresult CacheFileMetadata::ReadMetadata(CacheFileMetadataListener* aListener) { InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); - return NS_OK; + return; } // Set offset so that we read at least kMinMetadataRead if the file is big @@ -225,10 +220,7 @@ nsresult CacheFileMetadata::ReadMetadata(CacheFileMetadataListener* aListener) { mListener = nullptr; InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); - return NS_OK; } - - return NS_OK; } uint32_t CacheFileMetadata::CalcMetadataSize(uint32_t aElementsSize, @@ -478,7 +470,7 @@ nsresult CacheFileMetadata::SetElement(const char* aKey, const char* aValue) { return NS_OK; } -nsresult CacheFileMetadata::Visit(nsICacheEntryMetaDataVisitor* aVisitor) { +void CacheFileMetadata::Visit(nsICacheEntryMetaDataVisitor* aVisitor) { const char* data = mBuf; const char* limit = mBuf + mElementsSize; @@ -494,8 +486,6 @@ nsresult CacheFileMetadata::Visit(nsICacheEntryMetaDataVisitor* aVisitor) { } MOZ_ASSERT(data == limit, "Metadata elements corrupted"); - - return NS_OK; } CacheHash::Hash16_t CacheFileMetadata::GetHash(uint32_t aIndex) { @@ -551,72 +541,37 @@ nsresult CacheFileMetadata::RemoveHash(uint32_t aIndex) { return NS_OK; } -nsresult CacheFileMetadata::AddFlags(uint32_t aFlags) { +void CacheFileMetadata::AddFlags(uint32_t aFlags) { MarkDirty(false); mMetaHdr.mFlags |= aFlags; - return NS_OK; } -nsresult CacheFileMetadata::RemoveFlags(uint32_t aFlags) { +void CacheFileMetadata::RemoveFlags(uint32_t aFlags) { MarkDirty(false); mMetaHdr.mFlags &= ~aFlags; - return NS_OK; -} - -nsresult CacheFileMetadata::GetFlags(uint32_t* _retval) { - *_retval = mMetaHdr.mFlags; - return NS_OK; } -nsresult CacheFileMetadata::SetExpirationTime(uint32_t aExpirationTime) { +void CacheFileMetadata::SetExpirationTime(uint32_t aExpirationTime) { LOG(("CacheFileMetadata::SetExpirationTime() [this=%p, expirationTime=%d]", this, aExpirationTime)); MarkDirty(false); mMetaHdr.mExpirationTime = aExpirationTime; - return NS_OK; } -nsresult CacheFileMetadata::GetExpirationTime(uint32_t* _retval) { - *_retval = mMetaHdr.mExpirationTime; - return NS_OK; -} - -nsresult CacheFileMetadata::SetFrecency(uint32_t aFrecency) { +void CacheFileMetadata::SetFrecency(uint32_t aFrecency) { LOG(("CacheFileMetadata::SetFrecency() [this=%p, frecency=%f]", this, (double)aFrecency)); MarkDirty(false); mMetaHdr.mFrecency = aFrecency; - return NS_OK; -} - -nsresult CacheFileMetadata::GetFrecency(uint32_t* _retval) { - *_retval = mMetaHdr.mFrecency; - return NS_OK; -} - -nsresult CacheFileMetadata::GetLastModified(uint32_t* _retval) { - *_retval = mMetaHdr.mLastModified; - return NS_OK; -} - -nsresult CacheFileMetadata::GetLastFetched(uint32_t* _retval) { - *_retval = mMetaHdr.mLastFetched; - return NS_OK; } -nsresult CacheFileMetadata::GetFetchCount(uint32_t* _retval) { - *_retval = mMetaHdr.mFetchCount; - return NS_OK; -} - -nsresult CacheFileMetadata::OnFetched() { +void CacheFileMetadata::OnFetched() { MarkDirty(false); mMetaHdr.mLastFetched = NOW_SECONDS(); ++mMetaHdr.mFetchCount; - return NS_OK; } void CacheFileMetadata::MarkDirty(bool aUpdateLastModified) { diff --git a/netwerk/cache2/CacheFileMetadata.h b/netwerk/cache2/CacheFileMetadata.h index 5dff9326f4..32ac9ef0f9 100644 --- a/netwerk/cache2/CacheFileMetadata.h +++ b/netwerk/cache2/CacheFileMetadata.h @@ -11,7 +11,6 @@ #include "CacheObserver.h" #include "mozilla/EndianUtils.h" #include "mozilla/BasePrincipal.h" -#include "nsAutoPtr.h" #include "nsString.h" class nsICacheEntryMetaDataVisitor; @@ -141,9 +140,9 @@ class CacheFileMetadata final : public CacheFileIOListener, void SetHandle(CacheFileHandle* aHandle); - nsresult GetKey(nsACString& _retval); + const nsACString& GetKey() const { return mKey; } - nsresult ReadMetadata(CacheFileMetadataListener* aListener); + void ReadMetadata(CacheFileMetadataListener* aListener); uint32_t CalcMetadataSize(uint32_t aElementsSize, uint32_t aHashCount); nsresult WriteMetadata(uint32_t aOffset, CacheFileMetadataListener* aListener); @@ -157,25 +156,25 @@ class CacheFileMetadata final : public CacheFileIOListener, const char* GetElement(const char* aKey); nsresult SetElement(const char* aKey, const char* aValue); - nsresult Visit(nsICacheEntryMetaDataVisitor* aVisitor); + void Visit(nsICacheEntryMetaDataVisitor* aVisitor); CacheHash::Hash16_t GetHash(uint32_t aIndex); nsresult SetHash(uint32_t aIndex, CacheHash::Hash16_t aHash); nsresult RemoveHash(uint32_t aIndex); - nsresult AddFlags(uint32_t aFlags); - nsresult RemoveFlags(uint32_t aFlags); - nsresult GetFlags(uint32_t* _retval); - nsresult SetExpirationTime(uint32_t aExpirationTime); - nsresult GetExpirationTime(uint32_t* _retval); - nsresult SetFrecency(uint32_t aFrecency); - nsresult GetFrecency(uint32_t* _retval); - nsresult GetLastModified(uint32_t* _retval); - nsresult GetLastFetched(uint32_t* _retval); - nsresult GetFetchCount(uint32_t* _retval); + void AddFlags(uint32_t aFlags); + void RemoveFlags(uint32_t aFlags); + uint32_t GetFlags() const { return mMetaHdr.mFlags; } + void SetExpirationTime(uint32_t aExpirationTime); + uint32_t GetExpirationTime() const { return mMetaHdr.mExpirationTime; } + void SetFrecency(uint32_t aFrecency); + uint32_t GetFrecency() const { return mMetaHdr.mFrecency; } + uint32_t GetLastModified() const { return mMetaHdr.mLastModified; } + uint32_t GetLastFetched() const { return mMetaHdr.mLastFetched; } + uint32_t GetFetchCount() const { return mMetaHdr.mFetchCount; } // Called by upper layers to indicate the entry this metadata belongs // with has been fetched, i.e. delivered to the consumer. - nsresult OnFetched(); + void OnFetched(); int64_t Offset() { return mOffset; } uint32_t ElementsSize() { return mElementsSize; } diff --git a/netwerk/cache2/CacheFileOutputStream.h b/netwerk/cache2/CacheFileOutputStream.h index 0650515079..4d1fc5e4b7 100644 --- a/netwerk/cache2/CacheFileOutputStream.h +++ b/netwerk/cache2/CacheFileOutputStream.h @@ -8,7 +8,6 @@ #include "nsIAsyncOutputStream.h" #include "nsISeekableStream.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "CacheFileChunk.h" namespace mozilla { diff --git a/netwerk/cache2/CacheFileUtils.cpp b/netwerk/cache2/CacheFileUtils.cpp index 116181d2d8..6d635797f5 100644 --- a/netwerk/cache2/CacheFileUtils.cpp +++ b/netwerk/cache2/CacheFileUtils.cpp @@ -9,7 +9,6 @@ #include "mozilla/Tokenizer.h" #include "mozilla/Telemetry.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "nsString.h" #include #include "mozilla/Unused.h" @@ -23,8 +22,6 @@ namespace CacheFileUtils { static uint32_t const kAltDataVersion = 1; const char* kAltDataKey = "alt-data"; -static uint32_t const kBaseDomainAccessInfoVersion = 1; - namespace { /** @@ -662,68 +659,6 @@ void BuildAlternativeDataInfo(const char* aInfo, int64_t aOffset, _retval.Append(aInfo); } -nsresult ParseBaseDomainAccessInfo(const char* aInfo, uint32_t aTrID, - const uint32_t* aSearchSiteID, bool* _found, - uint16_t* _count) { - // The format is: "1;12;339456,490536687,1964820," - // ;;,, - mozilla::Tokenizer p(aInfo); - uint32_t i = 0; - uint16_t siteIDCnt = 0; - - // Check version and telemetry report ID - if (!p.ReadInteger(&i) || i != kBaseDomainAccessInfoVersion || - !p.CheckChar(';') || !p.ReadInteger(&i) || i != aTrID || - !p.CheckChar(';')) { - LOG( - ("ParseBaseDomainAccessInfo() - cannot parse info [info=%s, version=%u," - " trID=%u]", - aInfo, kBaseDomainAccessInfoVersion, aTrID)); - return NS_ERROR_NOT_AVAILABLE; - } - - do { - if (!p.ReadInteger(&i) || !p.CheckChar(',')) { - LOG( - ("ParseBaseDomainAccessInfo() - cannot parse site ID [info=%s, " - "siteIDCnt=%d]", - aInfo, siteIDCnt)); - return NS_ERROR_NOT_AVAILABLE; - } - - // If aSearchSiteID was provided, we don't need the total count of IDs. - // Just return true and don't process the rest of data. - if (aSearchSiteID && *aSearchSiteID == i) { - *_found = true; - return NS_OK; - } - - ++siteIDCnt; - } while (!p.CheckEOF()); - - if (_count) { - *_count = siteIDCnt; - } - - return NS_OK; -} - -void BuildOrAppendBaseDomainAccessInfo(const char* aOldInfo, uint32_t aTrID, - uint32_t aSiteID, nsACString& _retval) { - if (aOldInfo) { - _retval.Assign(aOldInfo); - } else { - _retval.Truncate(); - _retval.AppendInt(kBaseDomainAccessInfoVersion); - _retval.Append(';'); - _retval.AppendInt(aTrID); - _retval.Append(';'); - } - - _retval.AppendInt(aSiteID); - _retval.Append(','); -} - } // namespace CacheFileUtils } // namespace net } // namespace mozilla diff --git a/netwerk/cache2/CacheFileUtils.h b/netwerk/cache2/CacheFileUtils.h index f72d9f8704..57e251cf14 100644 --- a/netwerk/cache2/CacheFileUtils.h +++ b/netwerk/cache2/CacheFileUtils.h @@ -217,23 +217,6 @@ nsresult ParseAlternativeDataInfo(const char* aInfo, int64_t* _offset, void BuildAlternativeDataInfo(const char* aInfo, int64_t aOffset, nsACString& _retval); -// Parses base domain access info. If the info cannot be parsed (e.g. it's -// corrupted or it's invalid because aTrID has changed) an error is thrown. -// If aSearchSiteID is null, then the whole string is parsed and number of sites -// in the info is returned in _count. -// If aSearchSiteID is passed, then _count argument is ignored. It only searches -// siteID in the info and returns the result in _found. -nsresult ParseBaseDomainAccessInfo(const char* aInfo, uint32_t aTrID, - const uint32_t* aSearchSiteID, bool* _found, - uint16_t* _count); - -// If aOldInfo is null then new base domain access info containing aSiteID is -// built. If an old base domain access info is passed in aOldInfo, then only -// aSiteID is appended to it. Note that this function doesn't parse the old base -// domain info, i.e. it assumes that it's valid and it doesn't contain aSiteID. -void BuildOrAppendBaseDomainAccessInfo(const char* aOldInfo, uint32_t aTrID, - uint32_t aSiteID, nsACString& _retval); - } // namespace CacheFileUtils } // namespace net } // namespace mozilla diff --git a/netwerk/cache2/CacheIOThread.h b/netwerk/cache2/CacheIOThread.h index d899c48ff7..a7b0a1cb6e 100644 --- a/netwerk/cache2/CacheIOThread.h +++ b/netwerk/cache2/CacheIOThread.h @@ -9,7 +9,6 @@ #include "nsISupportsImpl.h" #include "prthread.h" #include "nsTArray.h" -#include "nsAutoPtr.h" #include "mozilla/Monitor2.h" #include "mozilla/DebugOnly.h" #include "mozilla/Atomics.h" diff --git a/netwerk/cache2/CacheIndex.cpp b/netwerk/cache2/CacheIndex.cpp index d85be84ade..cbab46b65d 100644 --- a/netwerk/cache2/CacheIndex.cpp +++ b/netwerk/cache2/CacheIndex.cpp @@ -24,7 +24,7 @@ #define kMinUnwrittenChanges 300 #define kMinDumpInterval 20000 // in milliseconds #define kMaxBufSize 16384 -#define kIndexVersion 0x00000008 +#define kIndexVersion 0x00000009 #define kUpdateIndexStartDelay 50000 // in milliseconds #define kTelemetryReportBytesLimit (2U * 1024U * 1024U * 1024U) // 2GB @@ -87,7 +87,7 @@ class CacheIndexEntryAutoManage { const CacheIndexEntry* entry = FindEntry(); mIndex->mIndexStats.BeforeChange(entry); if (entry && entry->IsInitialized() && !entry->IsRemoved()) { - mOldRecord = entry->mRec; + mOldRecord = entry->mRec.get(); mOldFrecency = entry->mRec->mFrecency; } } @@ -102,28 +102,29 @@ class CacheIndexEntryAutoManage { } if (entry && !mOldRecord) { - mIndex->mFrecencyArray.AppendRecord(entry->mRec); - mIndex->AddRecordToIterators(entry->mRec); + mIndex->mFrecencyArray.AppendRecord(entry->mRec.get()); + mIndex->AddRecordToIterators(entry->mRec.get()); } else if (!entry && mOldRecord) { mIndex->mFrecencyArray.RemoveRecord(mOldRecord); mIndex->RemoveRecordFromIterators(mOldRecord); } else if (entry && mOldRecord) { - if (entry->mRec != mOldRecord) { + auto rec = entry->mRec.get(); + if (rec != mOldRecord) { // record has a different address, we have to replace it - mIndex->ReplaceRecordInIterators(mOldRecord, entry->mRec); + mIndex->ReplaceRecordInIterators(mOldRecord, rec); if (entry->mRec->mFrecency == mOldFrecency) { // If frecency hasn't changed simply replace the pointer - mIndex->mFrecencyArray.ReplaceRecord(mOldRecord, entry->mRec); + mIndex->mFrecencyArray.ReplaceRecord(mOldRecord, rec); } else { // Remove old pointer and insert the new one at the end of the array mIndex->mFrecencyArray.RemoveRecord(mOldRecord); - mIndex->mFrecencyArray.AppendRecord(entry->mRec); + mIndex->mFrecencyArray.AppendRecord(rec); } } else if (entry->mRec->mFrecency != mOldFrecency) { // Move the element at the end of the array - mIndex->mFrecencyArray.RemoveRecord(entry->mRec); - mIndex->mFrecencyArray.AppendRecord(entry->mRec); + mIndex->mFrecencyArray.RemoveRecord(rec); + mIndex->mFrecencyArray.AppendRecord(rec); } } else { // both entries were removed or not initialized, do nothing @@ -929,22 +930,17 @@ nsresult CacheIndex::UpdateEntry( const SHA1Sum::Hash* aHash, const uint32_t* aFrecency, const bool* aHasAltData, const uint16_t* aOnStartTime, const uint16_t* aOnStopTime, const uint8_t* aContentType, - const uint16_t* aBaseDomainAccessCount, const uint32_t aTelemetryReportID, const uint32_t* aSize) { LOG( ("CacheIndex::UpdateEntry() [hash=%08x%08x%08x%08x%08x, " "frecency=%s, hasAltData=%s, onStartTime=%s, onStopTime=%s, " - "contentType=%s, baseDomainAccessCount=%s, telemetryReportID=%u, " - "size=%s]", + "contentType=%s, size=%s]", LOGSHA1(aHash), aFrecency ? nsPrintfCString("%u", *aFrecency).get() : "", aHasAltData ? (*aHasAltData ? "true" : "false") : "", aOnStartTime ? nsPrintfCString("%u", *aOnStartTime).get() : "", aOnStopTime ? nsPrintfCString("%u", *aOnStopTime).get() : "", aContentType ? nsPrintfCString("%u", *aContentType).get() : "", - aBaseDomainAccessCount - ? nsPrintfCString("%u", *aBaseDomainAccessCount).get() - : "", - aTelemetryReportID, aSize ? nsPrintfCString("%u", *aSize).get() : "")); + aSize ? nsPrintfCString("%u", *aSize).get() : "")); MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); @@ -965,19 +961,6 @@ nsresult CacheIndex::UpdateEntry( CacheIndexEntry* entry = index->mIndex.GetEntry(*aHash); - uint16_t baseDomainAccessCount = 0; - if (aBaseDomainAccessCount) { - if (aTelemetryReportID != CacheObserver::TelemetryReportID()) { - // Telemetry report ID has changed and the value is no longer valid. - // Reset the count to 0. - LOG( - ("CacheIndex::UpdateEntry() - Telemetry report ID has changed, " - "setting baseDomainAccessCount to 0.")); - } else { - baseDomainAccessCount = *aBaseDomainAccessCount; - } - } - if (entry && entry->IsRemoved()) { entry = nullptr; } @@ -996,9 +979,7 @@ nsresult CacheIndex::UpdateEntry( if (!HasEntryChanged( entry, aFrecency, aHasAltData, aOnStartTime, aOnStopTime, - aContentType, - aBaseDomainAccessCount ? &baseDomainAccessCount : nullptr, - aSize)) { + aContentType, aSize)) { return NS_OK; } @@ -1026,10 +1007,6 @@ nsresult CacheIndex::UpdateEntry( entry->SetContentType(*aContentType); } - if (aBaseDomainAccessCount) { - entry->SetBaseDomainAccessCount(baseDomainAccessCount); - } - if (aSize) { entry->SetFileSize(*aSize); } @@ -1080,10 +1057,6 @@ nsresult CacheIndex::UpdateEntry( updated->SetContentType(*aContentType); } - if (aBaseDomainAccessCount) { - updated->SetBaseDomainAccessCount(baseDomainAccessCount); - } - if (aSize) { updated->SetFileSize(*aSize); } @@ -1302,7 +1275,7 @@ nsresult CacheIndex::GetEntryForEviction(bool aIgnoreEmptyEntries, continue; } - if (aIgnoreEmptyEntries && !CacheIndexEntry::GetFileSize(rec)) { + if (aIgnoreEmptyEntries && !CacheIndexEntry::GetFileSize(*rec)) { continue; } @@ -1403,7 +1376,7 @@ nsresult CacheIndex::GetCacheStats(nsILoadContextInfo* aInfo, uint32_t* aSize, if (aInfo && !CacheIndexEntry::RecordMatchesLoadContextInfo(record, aInfo)) continue; - *aSize += CacheIndexEntry::GetFileSize(record); + *aSize += CacheIndexEntry::GetFileSize(*record); ++*aCount; } @@ -1569,8 +1542,7 @@ bool CacheIndex::IsCollision(CacheIndexEntry* aEntry, bool CacheIndex::HasEntryChanged( CacheIndexEntry* aEntry, const uint32_t* aFrecency, const bool* aHasAltData, const uint16_t* aOnStartTime, const uint16_t* aOnStopTime, - const uint8_t* aContentType, const uint16_t* aBaseDomainAccessCount, - const uint32_t* aSize) { + const uint8_t* aContentType, const uint32_t* aSize) { if (aFrecency && *aFrecency != aEntry->GetFrecency()) { return true; } @@ -1591,11 +1563,6 @@ bool CacheIndex::HasEntryChanged( return true; } - if (aBaseDomainAccessCount && - *aBaseDomainAccessCount != aEntry->GetBaseDomainAccessCount()) { - return true; - } - if (aSize && (*aSize & CacheIndexEntry::kFileSizeMask) != aEntry->GetFileSize()) { return true; @@ -2673,9 +2640,7 @@ nsresult CacheIndex::InitEntryFromDiskData(CacheIndexEntry* aEntry, aEntry->Init(GetOriginAttrsHash(aMetaData->OriginAttributes()), aMetaData->IsAnonymous(), aMetaData->Pinned()); - uint32_t frecency; - aMetaData->GetFrecency(&frecency); - aEntry->SetFrecency(frecency); + aEntry->SetFrecency(aMetaData->GetFrecency()); const char* altData = aMetaData->GetElement(CacheFileUtils::kAltDataKey); bool hasAltData = altData ? true : false; @@ -2712,15 +2677,6 @@ nsresult CacheIndex::InitEntryFromDiskData(CacheIndexEntry* aEntry, } aEntry->SetContentType(contentType); - uint32_t trID = CacheObserver::TelemetryReportID(); - const char* siteIDInfo = aMetaData->GetElement("eTLD1Access"); - uint16_t siteIDCount = 0; - if (siteIDInfo) { - CacheFileUtils::ParseBaseDomainAccessInfo(siteIDInfo, trID, nullptr, - nullptr, &siteIDCount); - } - aEntry->SetBaseDomainAccessCount(siteIDCount); - aEntry->SetFileSize(static_cast(std::min( static_cast(PR_UINT32_MAX), (aFileSize + 0x3FF) >> 10))); return NS_OK; @@ -3506,14 +3462,13 @@ nsresult CacheIndex::Run() { return NS_OK; } -nsresult CacheIndex::OnFileOpenedInternal(FileOpenHelper* aOpener, - CacheFileHandle* aHandle, - nsresult aResult) { +void CacheIndex::OnFileOpenedInternal(FileOpenHelper* aOpener, + CacheFileHandle* aHandle, + nsresult aResult) { LOG( ("CacheIndex::OnFileOpenedInternal() [opener=%p, handle=%p, " "result=0x%08" PRIx32 "]", aOpener, aHandle, static_cast(aResult))); - MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); nsresult rv; @@ -3523,7 +3478,7 @@ nsresult CacheIndex::OnFileOpenedInternal(FileOpenHelper* aOpener, MOZ_RELEASE_ASSERT(IsIndexUsable()); if (mState == READY && mShuttingDown) { - return NS_OK; + return; } switch (mState) { @@ -3610,8 +3565,6 @@ nsresult CacheIndex::OnFileOpenedInternal(FileOpenHelper* aOpener, default: MOZ_ASSERT(false, "Unexpected state!"); } - - return NS_OK; } nsresult CacheIndex::OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) { @@ -3942,84 +3895,32 @@ void CacheIndex::DoTelemetryReport() { // size in kB of all entries uint32_t size = 0; - // increase of size in kB that would be caused by first party isolation - uint32_t sizeInc = 0; // count of all entries uint32_t count = 0; - // increase of count that would be caused by first party isolation - uint32_t countInc = 0; // the same stats as above split by content type uint32_t sizeByType[nsICacheEntry::CONTENT_TYPE_LAST]; - uint32_t sizeIncByType[nsICacheEntry::CONTENT_TYPE_LAST]; uint32_t countByType[nsICacheEntry::CONTENT_TYPE_LAST]; - uint32_t countIncByType[nsICacheEntry::CONTENT_TYPE_LAST]; memset(&sizeByType, 0, sizeof(sizeByType)); - memset(&sizeIncByType, 0, sizeof(sizeIncByType)); memset(&countByType, 0, sizeof(countByType)); - memset(&countIncByType, 0, sizeof(countIncByType)); for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) { CacheIndexEntry* entry = iter.Get(); if (entry->IsRemoved() || !entry->IsInitialized() || entry->IsFileEmpty()) { - entry->SetBaseDomainAccessCount(0); continue; } uint32_t entrySize = entry->GetFileSize(); - uint32_t accessCnt = entry->GetBaseDomainAccessCount(); uint8_t contentType = entry->GetContentType(); - entry->SetBaseDomainAccessCount(0); ++count; ++countByType[contentType]; size += entrySize; sizeByType[contentType] += entrySize; - - if (accessCnt > 1) { - countInc += accessCnt - 1; - countIncByType[contentType] += accessCnt - 1; - sizeInc += (accessCnt - 1) * entrySize; - sizeIncByType[contentType] += (accessCnt - 1) * entrySize; - } - - Telemetry::Accumulate( - Telemetry::NETWORK_CACHE_ISOLATION_UNIQUE_SITE_ACCESS_COUNT, - contentTypeNames[contentType], accessCnt); - } - - if (size > 0) { - Telemetry::Accumulate(Telemetry::NETWORK_CACHE_ISOLATION_SIZE_INCREASE, - NS_LITERAL_CSTRING("ALL"), - round(static_cast(sizeInc) * 100.0 / - static_cast(size))); - } - - if (count > 0) { - Telemetry::Accumulate( - Telemetry::NETWORK_CACHE_ISOLATION_ENTRY_COUNT_INCREASE, - NS_LITERAL_CSTRING("ALL"), - round(static_cast(countInc) * 100.0 / - static_cast(count))); } for (uint32_t i = 0; i < nsICacheEntry::CONTENT_TYPE_LAST; ++i) { - if (sizeByType[i] > 0) { - Telemetry::Accumulate(Telemetry::NETWORK_CACHE_ISOLATION_SIZE_INCREASE, - contentTypeNames[i], - round(static_cast(sizeIncByType[i]) * - 100.0 / static_cast(sizeByType[i]))); - } - - if (countByType[i] > 0) { - Telemetry::Accumulate( - Telemetry::NETWORK_CACHE_ISOLATION_ENTRY_COUNT_INCREASE, - contentTypeNames[i], - round(static_cast(countIncByType[i]) * 100.0 / - static_cast(countByType[i]))); - } - if (size > 0) { Telemetry::Accumulate(Telemetry::NETWORK_CACHE_SIZE_SHARE, contentTypeNames[i], @@ -4043,10 +3944,6 @@ void CacheIndex::DoTelemetryReport() { } Telemetry::Accumulate(Telemetry::NETWORK_CACHE_ENTRY_COUNT, probeKey, count); Telemetry::Accumulate(Telemetry::NETWORK_CACHE_SIZE, probeKey, size >> 10); - - // Change telemetry report ID. This will invalidate eTLD+1 access data stored - // in all cache entries. - CacheObserver::SetTelemetryReportID(CacheObserver::TelemetryReportID() + 1); } // static diff --git a/netwerk/cache2/CacheIndex.h b/netwerk/cache2/CacheIndex.h index 2bb8ee7535..c4eac9ea0f 100644 --- a/netwerk/cache2/CacheIndex.h +++ b/netwerk/cache2/CacheIndex.h @@ -21,6 +21,7 @@ #include "mozilla/StaticPtr.h" #include "mozilla/EndianUtils.h" #include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" class nsIFile; class nsIDirectoryEnumerator; @@ -73,7 +74,6 @@ struct CacheIndexRecord { uint16_t mOnStartTime; uint16_t mOnStopTime; uint8_t mContentType; - uint16_t mBaseDomainAccessCount; /* * 1000 0000 0000 0000 0000 0000 0000 0000 : initialized @@ -94,7 +94,6 @@ struct CacheIndexRecord { mOnStartTime(kIndexTimeNotAvailable), mOnStopTime(kIndexTimeNotAvailable), mContentType(nsICacheEntry::CONTENT_TYPE_UNKNOWN), - mBaseDomainAccessCount(0), mFlags(0) {} }; #pragma pack(pop) @@ -105,7 +104,6 @@ static_assert(sizeof(CacheIndexRecord::mHash) + sizeof(CacheIndexRecord::mOnStartTime) + sizeof(CacheIndexRecord::mOnStopTime) + sizeof(CacheIndexRecord::mContentType) + - sizeof(CacheIndexRecord::mBaseDomainAccessCount) + sizeof(CacheIndexRecord::mFlags) == sizeof(CacheIndexRecord), "Unexpected sizeof(CacheIndexRecord)!"); @@ -117,7 +115,7 @@ class CacheIndexEntry : public PLDHashEntryHdr { explicit CacheIndexEntry(KeyTypePointer aKey) { MOZ_COUNT_CTOR(CacheIndexEntry); - mRec = new CacheIndexRecord(); + mRec = MakeUnique(); LOG(("CacheIndexEntry::CacheIndexEntry() - Created record [rec=%p]", mRec.get())); memcpy(&mRec->mHash, aKey, sizeof(SHA1Sum::Hash)); @@ -160,7 +158,6 @@ class CacheIndexEntry : public PLDHashEntryHdr { mRec->mOnStartTime = aOther.mRec->mOnStartTime; mRec->mOnStopTime = aOther.mRec->mOnStopTime; mRec->mContentType = aOther.mRec->mContentType; - mRec->mBaseDomainAccessCount = aOther.mRec->mBaseDomainAccessCount; mRec->mFlags = aOther.mRec->mFlags; return *this; } @@ -171,7 +168,6 @@ class CacheIndexEntry : public PLDHashEntryHdr { mRec->mOnStartTime = kIndexTimeNotAvailable; mRec->mOnStopTime = kIndexTimeNotAvailable; mRec->mContentType = nsICacheEntry::CONTENT_TYPE_UNKNOWN; - mRec->mBaseDomainAccessCount = 0; mRec->mFlags = 0; } @@ -181,7 +177,6 @@ class CacheIndexEntry : public PLDHashEntryHdr { MOZ_ASSERT(mRec->mOnStartTime == kIndexTimeNotAvailable); MOZ_ASSERT(mRec->mOnStopTime == kIndexTimeNotAvailable); MOZ_ASSERT(mRec->mContentType == nsICacheEntry::CONTENT_TYPE_UNKNOWN); - MOZ_ASSERT(mRec->mBaseDomainAccessCount == 0); // When we init the entry it must be fresh and may be dirty MOZ_ASSERT((mRec->mFlags & ~kDirtyMask) == kFreshMask); @@ -235,13 +230,6 @@ class CacheIndexEntry : public PLDHashEntryHdr { void SetContentType(uint8_t aType) { mRec->mContentType = aType; } uint8_t GetContentType() const { return mRec->mContentType; } - void SetBaseDomainAccessCount(uint16_t aCount) { - mRec->mBaseDomainAccessCount = aCount; - } - uint8_t GetBaseDomainAccessCount() const { - return mRec->mBaseDomainAccessCount; - } - // Sets filesize in kilobytes. void SetFileSize(uint32_t aFileSize) { if (aFileSize > kFileSizeMask) { @@ -255,9 +243,9 @@ class CacheIndexEntry : public PLDHashEntryHdr { mRec->mFlags |= aFileSize; } // Returns filesize in kilobytes. - uint32_t GetFileSize() const { return GetFileSize(mRec); } - static uint32_t GetFileSize(CacheIndexRecord* aRec) { - return aRec->mFlags & kFileSizeMask; + uint32_t GetFileSize() const { return GetFileSize(*mRec); } + static uint32_t GetFileSize(const CacheIndexRecord& aRec) { + return aRec.mFlags & kFileSizeMask; } static uint32_t IsPinned(CacheIndexRecord* aRec) { return aRec->mFlags & kPinnedMask; @@ -278,8 +266,6 @@ class CacheIndexEntry : public PLDHashEntryHdr { ptr += sizeof(uint16_t); *ptr = mRec->mContentType; ptr += sizeof(uint8_t); - NetworkEndian::writeUint16(ptr, mRec->mBaseDomainAccessCount); - ptr += sizeof(uint16_t); // Dirty and fresh flags should never go to disk, since they make sense only // during current session. NetworkEndian::writeUint32(ptr, mRec->mFlags & ~(kDirtyMask | kFreshMask)); @@ -299,8 +285,6 @@ class CacheIndexEntry : public PLDHashEntryHdr { ptr += sizeof(uint16_t); mRec->mContentType = *ptr; ptr += sizeof(uint8_t); - mRec->mBaseDomainAccessCount = NetworkEndian::readUint16(ptr); - ptr += sizeof(uint16_t); mRec->mFlags = NetworkEndian::readUint32(ptr); } @@ -309,12 +293,11 @@ class CacheIndexEntry : public PLDHashEntryHdr { ("CacheIndexEntry::Log() [this=%p, hash=%08x%08x%08x%08x%08x, fresh=%u," " initialized=%u, removed=%u, dirty=%u, anonymous=%u, " "originAttrsHash=%" PRIx64 ", frecency=%u, hasAltData=%u, " - "onStartTime=%u, onStopTime=%u, contentType=%u, " - "baseDomainAccessCount=%u, size=%u]", + "onStartTime=%u, onStopTime=%u, contentType=%u, size=%u]", this, LOGSHA1(mRec->mHash), IsFresh(), IsInitialized(), IsRemoved(), IsDirty(), Anonymous(), OriginAttrsHash(), GetFrecency(), GetHasAltData(), GetOnStartTime(), GetOnStopTime(), GetContentType(), - GetBaseDomainAccessCount(), GetFileSize())); + GetFileSize())); } static bool RecordMatchesLoadContextInfo(CacheIndexRecord* aRec, @@ -371,7 +354,7 @@ class CacheIndexEntry : public PLDHashEntryHdr { // FileSize in kilobytes static const uint32_t kFileSizeMask = 0x00FFFFFF; - nsAutoPtr mRec; + UniquePtr mRec; }; class CacheIndexEntryUpdate : public CacheIndexEntry { @@ -426,11 +409,6 @@ class CacheIndexEntryUpdate : public CacheIndexEntry { CacheIndexEntry::SetContentType(aType); } - void SetBaseDomainAccessCount(uint16_t aCount) { - mUpdateFlags |= kBaseDomainAccessCountUpdatedMask; - CacheIndexEntry::SetBaseDomainAccessCount(aCount); - } - void SetFileSize(uint32_t aFileSize) { mUpdateFlags |= kFileSizeUpdatedMask; CacheIndexEntry::SetFileSize(aFileSize); @@ -452,9 +430,6 @@ class CacheIndexEntryUpdate : public CacheIndexEntry { if (mUpdateFlags & kContentTypeUpdatedMask) { aDst->mRec->mContentType = mRec->mContentType; } - if (mUpdateFlags & kBaseDomainAccessCountUpdatedMask) { - aDst->mRec->mBaseDomainAccessCount = mRec->mBaseDomainAccessCount; - } if (mUpdateFlags & kHasAltDataUpdatedMask && ((aDst->mRec->mFlags ^ mRec->mFlags) & kHasAltDataMask)) { // Toggle the bit if we need to. @@ -478,7 +453,6 @@ class CacheIndexEntryUpdate : public CacheIndexEntry { static const uint32_t kHasAltDataUpdatedMask = 0x00000008; static const uint32_t kOnStartTimeUpdatedMask = 0x00000010; static const uint32_t kOnStopTimeUpdatedMask = 0x00000020; - static const uint32_t kBaseDomainAccessCountUpdatedMask = 0x00000040; uint32_t mUpdateFlags; }; @@ -713,7 +687,6 @@ class CacheIndex final : public CacheFileIOListener, public nsIRunnable { const SHA1Sum::Hash* aHash, const uint32_t* aFrecency, const bool* aHasAltData, const uint16_t* aOnStartTime, const uint16_t* aOnStopTime, const uint8_t* aContentType, - const uint16_t* aBaseDomainAccessCount, const uint32_t aTelemetryReportID, const uint32_t* aSize); // Remove all entries from the index. Called when clearing the whole cache. @@ -793,8 +766,8 @@ class CacheIndex final : public CacheFileIOListener, public nsIRunnable { virtual ~CacheIndex(); NS_IMETHOD OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) override; - nsresult OnFileOpenedInternal(FileOpenHelper* aOpener, - CacheFileHandle* aHandle, nsresult aResult); + void OnFileOpenedInternal(FileOpenHelper* aOpener, CacheFileHandle* aHandle, + nsresult aResult); NS_IMETHOD OnDataWritten(CacheFileHandle* aHandle, const char* aBuf, nsresult aResult) override; NS_IMETHOD OnDataRead(CacheFileHandle* aHandle, char* aBuf, @@ -821,7 +794,7 @@ class CacheIndex final : public CacheFileIOListener, public nsIRunnable { CacheIndexEntry* aEntry, const uint32_t* aFrecency, const bool* aHasAltData, const uint16_t* aOnStartTime, const uint16_t* aOnStopTime, const uint8_t* aContentType, - const uint16_t* aBaseDomainAccessCount, const uint32_t* aSize); + const uint32_t* aSize); // Merge all pending operations from mPendingUpdates into mIndex. void ProcessPendingOperations(); @@ -1014,9 +987,8 @@ class CacheIndex final : public CacheFileIOListener, public nsIRunnable { void ReportHashStats(); - // Reports telemetry about cache, i.e. size, entry count, content type stats - // and first party cache isolation stats. Clears first party cache isolation - // counters stored in the index entries and bumps a telemetry report ID. + // Reports telemetry about cache, i.e. size, entry count and content type + // stats. void DoTelemetryReport(); static mozilla::StaticRefPtr gInstance; diff --git a/netwerk/cache2/CacheIndexIterator.h b/netwerk/cache2/CacheIndexIterator.h index 306aa93b5a..8b952f190a 100644 --- a/netwerk/cache2/CacheIndexIterator.h +++ b/netwerk/cache2/CacheIndexIterator.h @@ -7,7 +7,6 @@ #include "nsTArray.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "mozilla/SHA1.h" namespace mozilla { diff --git a/netwerk/cache2/CacheObserver.cpp b/netwerk/cache2/CacheObserver.cpp index 16c29e722a..282785653a 100644 --- a/netwerk/cache2/CacheObserver.cpp +++ b/netwerk/cache2/CacheObserver.cpp @@ -42,10 +42,6 @@ bool CacheObserver::sHashStatsReported = kDefaultHashStatsReported; Atomic CacheObserver::sShutdownDemandedTime( PR_INTERVAL_NO_TIMEOUT); -static uint32_t const kDefaultTelemetryReportID = 0; -Atomic CacheObserver::sTelemetryReportID( - kDefaultTelemetryReportID); - static uint32_t const kDefaultCacheAmountWritten = 0; Atomic CacheObserver::sCacheAmountWritten( kDefaultCacheAmountWritten); @@ -104,9 +100,6 @@ void CacheObserver::AttachToPreferences() { 0.01F, std::min(1440.0F, mozilla::Preferences::GetFloat( "browser.cache.frecency_half_life_hours", kDefaultHalfLifeHours))); - mozilla::Preferences::AddAtomicUintVarCache( - &sTelemetryReportID, "browser.cache.disk.telemetry_report_ID", - kDefaultTelemetryReportID); mozilla::Preferences::AddAtomicUintVarCache( &sCacheAmountWritten, "browser.cache.disk.amount_written", @@ -216,29 +209,6 @@ void CacheObserver::StoreHashStatsReported() { sHashStatsReported); } -// static -void CacheObserver::SetTelemetryReportID(uint32_t aTelemetryReportID) { - sTelemetryReportID = aTelemetryReportID; - - if (!sSelf) { - return; - } - - if (NS_IsMainThread()) { - sSelf->StoreTelemetryReportID(); - } else { - nsCOMPtr event = - NewRunnableMethod("net::CacheObserver::StoreTelemetryReportID", - sSelf.get(), &CacheObserver::StoreTelemetryReportID); - NS_DispatchToMainThread(event); - } -} - -void CacheObserver::StoreTelemetryReportID() { - mozilla::Preferences::SetInt("browser.cache.disk.telemetry_report_ID", - sTelemetryReportID); -} - // static void CacheObserver::SetCacheAmountWritten(uint32_t aCacheAmountWritten) { sCacheAmountWritten = aCacheAmountWritten; diff --git a/netwerk/cache2/CacheObserver.h b/netwerk/cache2/CacheObserver.h index ff6a0a950c..c25259bdaf 100644 --- a/netwerk/cache2/CacheObserver.h +++ b/netwerk/cache2/CacheObserver.h @@ -82,8 +82,6 @@ class CacheObserver : public nsIObserver, public nsSupportsWeakReference { static void SetCacheFSReported(); static bool HashStatsReported() { return sHashStatsReported; } static void SetHashStatsReported(); - static uint32_t TelemetryReportID() { return sTelemetryReportID; } - static void SetTelemetryReportID(uint32_t); static uint32_t CacheAmountWritten() // result in kilobytes { return sCacheAmountWritten; @@ -108,7 +106,6 @@ class CacheObserver : public nsIObserver, public nsSupportsWeakReference { void StoreDiskCacheCapacity(); void StoreCacheFSReported(); void StoreHashStatsReported(); - void StoreTelemetryReportID(); void StoreCacheAmountWritten(); void AttachToPreferences(); @@ -118,7 +115,6 @@ class CacheObserver : public nsIObserver, public nsSupportsWeakReference { static bool sCacheFSReported; static bool sHashStatsReported; static Atomic sShutdownDemandedTime; - static Atomic sTelemetryReportID; static Atomic sCacheAmountWritten; // Non static properties, accessible via sSelf diff --git a/netwerk/cache2/OldWrappers.cpp b/netwerk/cache2/OldWrappers.cpp index d9d3a5d423..4cd6517c65 100644 --- a/netwerk/cache2/OldWrappers.cpp +++ b/netwerk/cache2/OldWrappers.cpp @@ -475,10 +475,11 @@ NS_IMETHODIMP _OldCacheEntryWrapper::VisitMetaData( namespace { -nsresult GetCacheSessionNameForStoragePolicy( - const nsACString& scheme, nsCacheStoragePolicy storagePolicy, - bool isPrivate, OriginAttributes const* originAttribs, - nsACString& sessionName) { +void GetCacheSessionNameForStoragePolicy(const nsACString& scheme, + nsCacheStoragePolicy storagePolicy, + bool isPrivate, + OriginAttributes const* originAttribs, + nsACString& sessionName) { MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY); // HTTP @@ -523,8 +524,6 @@ nsresult GetCacheSessionNameForStoragePolicy( nsAutoCString suffix; originAttribs->CreateSuffix(suffix); sessionName.Append(suffix); - - return NS_OK; } nsresult GetCacheSession(const nsACString& aScheme, bool aWriteToDisk, @@ -545,10 +544,9 @@ nsresult GetCacheSession(const nsACString& aScheme, bool aWriteToDisk, if (aAppCache) { aAppCache->GetClientID(clientId); } else { - rv = GetCacheSessionNameForStoragePolicy( + GetCacheSessionNameForStoragePolicy( aScheme, storagePolicy, aLoadInfo->IsPrivate(), aLoadInfo->OriginAttributesPtr(), clientId); - NS_ENSURE_SUCCESS(rv, rv); } LOG((" GetCacheSession for client=%s, policy=%d", clientId.get(), diff --git a/netwerk/cache2/OldWrappers.h b/netwerk/cache2/OldWrappers.h index cd51541580..30575c2476 100644 --- a/netwerk/cache2/OldWrappers.h +++ b/netwerk/cache2/OldWrappers.h @@ -126,9 +126,6 @@ class _OldCacheEntryWrapper : public nsICacheEntry { NS_IMETHOD SetContentType(uint8_t aContentType) override { return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD AddBaseDomainAccess(uint32_t aSiteID) override { - return NS_ERROR_NOT_IMPLEMENTED; - } NS_IMETHOD GetLoadContextInfo(nsILoadContextInfo** aInfo) override { return NS_ERROR_NOT_IMPLEMENTED; } diff --git a/netwerk/cache2/nsICacheEntry.idl b/netwerk/cache2/nsICacheEntry.idl index 4b3764e5aa..c9732496b1 100644 --- a/netwerk/cache2/nsICacheEntry.idl +++ b/netwerk/cache2/nsICacheEntry.idl @@ -101,12 +101,6 @@ interface nsICacheEntry : nsISupports */ void setContentType(in uint8_t contentType); - /** - * Stores information about an access from site identified by unique siteID. - * It's used for first party cache isolation telemetry. - */ - void addBaseDomainAccess(in uint32_t siteID); - /** * This method is intended to override the per-spec cache validation * decisions for a duration specified in seconds. The current state can diff --git a/netwerk/cookie/CookieServiceChild.cpp b/netwerk/cookie/CookieServiceChild.cpp index 7c0e417e65..bbe008cf0b 100644 --- a/netwerk/cookie/CookieServiceChild.cpp +++ b/netwerk/cookie/CookieServiceChild.cpp @@ -289,7 +289,7 @@ void CookieServiceChild::GetCookieStringFromCookieHashTable( nsAutoCString hostFromURI, pathFromURI; aHostURI->GetAsciiHost(hostFromURI); - aHostURI->GetPathQueryRef(pathFromURI); + aHostURI->GetFilePath(pathFromURI); bool isSecure = aHostURI->SchemeIs("https"); int64_t currentTimeInUsec = PR_Now(); int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC; @@ -656,7 +656,7 @@ CookieServiceChild::GetCookieStringFromHttp(nsIURI* aHostURI, nsIURI* aFirstURI, } NS_IMETHODIMP -CookieServiceChild::SetCookieString(nsIURI* aHostURI, nsIPrompt* aPrompt, +CookieServiceChild::SetCookieString(nsIURI* aHostURI, const nsACString& aCookieString, nsIChannel* aChannel) { return SetCookieStringInternal(aHostURI, aChannel, aCookieString, @@ -665,7 +665,6 @@ CookieServiceChild::SetCookieString(nsIURI* aHostURI, nsIPrompt* aPrompt, NS_IMETHODIMP CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI, nsIURI* aFirstURI, - nsIPrompt* aPrompt, const nsACString& aCookieString, const nsACString& aServerTime, nsIChannel* aChannel) { diff --git a/netwerk/cookie/nsCookie.cpp b/netwerk/cookie/nsCookie.cpp index 9ec91380aa..3094ef9ee2 100644 --- a/netwerk/cookie/nsCookie.cpp +++ b/netwerk/cookie/nsCookie.cpp @@ -5,8 +5,9 @@ #include "mozilla/Encoding.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/StaticPrefs_network.h" -#include "nsAutoPtr.h" #include "nsCookie.h" +#include "nsIURLParser.h" +#include "nsURLHelper.h" #include /****************************************************************************** @@ -80,7 +81,8 @@ size_t nsCookie::SizeOfIncludingThis( mData.name().SizeOfExcludingThisIfUnshared(MallocSizeOf) + mData.value().SizeOfExcludingThisIfUnshared(MallocSizeOf) + mData.host().SizeOfExcludingThisIfUnshared(MallocSizeOf) + - mData.path().SizeOfExcludingThisIfUnshared(MallocSizeOf); + mData.path().SizeOfExcludingThisIfUnshared(MallocSizeOf) + + mFilePathCache.SizeOfExcludingThisIfUnshared(MallocSizeOf); } bool nsCookie::IsStale() const { @@ -159,6 +161,35 @@ nsCookie::GetOriginAttributes(JSContext* aCx, return NS_OK; } +const nsCString& nsCookie::GetFilePath() { + MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); + + if (Path().IsEmpty()) { + // If we don't have a path, just return the (empty) file path cache. + return mFilePathCache; + } + if (!mFilePathCache.IsEmpty()) { + // If we've computed the answer before, just return it. + return mFilePathCache; + } + + nsIURLParser* parser = net_GetStdURLParser(); + NS_ENSURE_TRUE(parser, mFilePathCache); + + int32_t pathLen = Path().Length(), filepathLen = 0; + uint32_t filepathPos = 0; + + nsresult rv = parser->ParsePath(PromiseFlatCString(Path()).get(), pathLen, + &filepathPos, &filepathLen, nullptr, + nullptr, // don't care about query + nullptr, nullptr); // don't care about ref + NS_ENSURE_SUCCESS(rv, mFilePathCache); + + mFilePathCache = Substring(Path(), filepathPos, filepathLen); + + return mFilePathCache; +} + // compatibility method, for use with the legacy nsICookie interface. // here, expires == 0 denotes a session cookie. NS_IMETHODIMP diff --git a/netwerk/cookie/nsCookie.h b/netwerk/cookie/nsCookie.h index b958fba2fe..60c2b28929 100644 --- a/netwerk/cookie/nsCookie.h +++ b/netwerk/cookie/nsCookie.h @@ -65,6 +65,7 @@ class nsCookie final : public nsICookie { return nsDependentCSubstring(mData.host(), IsDomain() ? 1 : 0); } inline const nsCString& Path() const { return mData.path(); } + const nsCString& GetFilePath(); inline int64_t Expiry() const { return mData.expiry(); } // in seconds inline int64_t LastAccessed() const { return mData.lastAccessed(); @@ -102,6 +103,7 @@ class nsCookie final : public nsICookie { // Please update SizeOfIncludingThis if this strategy changes. mozilla::net::CookieStruct mData; mozilla::OriginAttributes mOriginAttributes; + nsCString mFilePathCache; }; // Comparator class for sorting cookies before sending to a server. diff --git a/netwerk/cookie/nsCookieService.cpp b/netwerk/cookie/nsCookieService.cpp index 071a808533..1a06cba8d7 100644 --- a/netwerk/cookie/nsCookieService.cpp +++ b/netwerk/cookie/nsCookieService.cpp @@ -16,6 +16,7 @@ #include "mozilla/net/NeckoCommon.h" #include "nsCookieService.h" +#include "nsComponentManagerUtils.h" #include "nsContentUtils.h" #include "nsIWebProgressListener.h" #include "nsIHttpChannel.h" @@ -38,18 +39,15 @@ #include "nsTArray.h" #include "nsCOMArray.h" #include "nsIMutableArray.h" -#include "nsArrayEnumerator.h" -#include "nsEnumeratorUtils.h" -#include "nsAutoPtr.h" #include "nsReadableUtils.h" #include "nsCRT.h" #include "prprf.h" #include "nsNetUtil.h" #include "nsNetCID.h" -#include "nsISimpleEnumerator.h" #include "nsIInputStream.h" #include "nsAppDirectoryServiceDefs.h" #include "nsNetCID.h" +#include "mozilla/dom/Promise.h" #include "mozilla/storage.h" #include "mozilla/AutoRestore.h" #include "mozilla/FileUtils.h" @@ -63,6 +61,7 @@ #include "nsVariant.h" using namespace mozilla; +using namespace mozilla::dom; using namespace mozilla::net; // Create key from baseDomain that will access the default cookie namespace. @@ -2006,41 +2005,18 @@ already_AddRefed nsCookieService::GetCookieSettings( } NS_IMETHODIMP -nsCookieService::SetCookieString(nsIURI* aHostURI, nsIPrompt* aPrompt, +nsCookieService::SetCookieString(nsIURI* aHostURI, const nsACString& aCookieHeader, nsIChannel* aChannel) { - // The aPrompt argument is deprecated and unused. Avoid introducing new - // code that uses this argument by warning if the value is non-null. - MOZ_ASSERT(!aPrompt); - if (aPrompt) { - nsCOMPtr aConsoleService = - do_GetService("@mozilla.org/consoleservice;1"); - if (aConsoleService) { - aConsoleService->LogStringMessage( - u"Non-null prompt ignored by nsCookieService."); - } - } return SetCookieStringCommon(aHostURI, aCookieHeader, VoidCString(), aChannel, false); } NS_IMETHODIMP nsCookieService::SetCookieStringFromHttp(nsIURI* aHostURI, nsIURI* aFirstURI, - nsIPrompt* aPrompt, const nsACString& aCookieHeader, const nsACString& aServerTime, nsIChannel* aChannel) { - // The aPrompt argument is deprecated and unused. Avoid introducing new - // code that uses this argument by warning if the value is non-null. - MOZ_ASSERT(!aPrompt); - if (aPrompt) { - nsCOMPtr aConsoleService = - do_GetService("@mozilla.org/consoleservice;1"); - if (aConsoleService) { - aConsoleService->LogStringMessage( - u"Non-null prompt ignored by nsCookieService."); - } - } return SetCookieStringCommon(aHostURI, aCookieHeader, aServerTime, aChannel, true); } @@ -2049,8 +2025,7 @@ int64_t nsCookieService::ParseServerTime(const nsACString& aServerTime) { // parse server local time. this is not just done here for efficiency // reasons - if there's an error parsing it, and we need to default it // to the current time, we must do it here since the current time in - // SetCookieInternal() will change for each cookie processed (e.g. if the - // user is prompted). + // SetCookieInternal() will change for each cookie processed. PRTime tempServerTime; int64_t serverTime; PRStatus result = @@ -2365,7 +2340,7 @@ nsCookieService::RemoveAll() { } NS_IMETHODIMP -nsCookieService::GetEnumerator(nsISimpleEnumerator** aEnumerator) { +nsCookieService::GetCookies(nsTArray>& aCookies) { if (!mDBState) { NS_WARNING("No DBState! Profile already closed?"); return NS_ERROR_NOT_AVAILABLE; @@ -2373,19 +2348,19 @@ nsCookieService::GetEnumerator(nsISimpleEnumerator** aEnumerator) { EnsureReadComplete(true); - nsCOMArray cookieList(mDBState->cookieCount); + aCookies.SetCapacity(mDBState->cookieCount); for (auto iter = mDBState->hostTable.Iter(); !iter.Done(); iter.Next()) { const nsCookieEntry::ArrayType& cookies = iter.Get()->GetCookies(); for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) { - cookieList.AppendObject(cookies[i]); + aCookies.AppendElement(cookies[i]); } } - return NS_NewArrayEnumerator(aEnumerator, cookieList, NS_GET_IID(nsICookie)); + return NS_OK; } NS_IMETHODIMP -nsCookieService::GetSessionEnumerator(nsISimpleEnumerator** aEnumerator) { +nsCookieService::GetSessionCookies(nsTArray>& aCookies) { if (!mDBState) { NS_WARNING("No DBState! Profile already closed?"); return NS_ERROR_NOT_AVAILABLE; @@ -2393,19 +2368,19 @@ nsCookieService::GetSessionEnumerator(nsISimpleEnumerator** aEnumerator) { EnsureReadComplete(true); - nsCOMArray cookieList(mDBState->cookieCount); + aCookies.SetCapacity(mDBState->cookieCount); for (auto iter = mDBState->hostTable.Iter(); !iter.Done(); iter.Next()) { const nsCookieEntry::ArrayType& cookies = iter.Get()->GetCookies(); for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) { nsCookie* cookie = cookies[i]; // Filter out non-session cookies. if (cookie->IsSession()) { - cookieList.AppendObject(cookie); + aCookies.AppendElement(cookie); } } } - return NS_NewArrayEnumerator(aEnumerator, cookieList, NS_GET_IID(nsICookie)); + return NS_OK; } NS_IMETHODIMP @@ -2492,8 +2467,10 @@ nsresult nsCookieService::Remove(const nsACString& aHost, NS_ENSURE_SUCCESS(rv, rv); nsAutoCString baseDomain; - rv = GetBaseDomainFromHost(mTLDService, host, baseDomain); - NS_ENSURE_SUCCESS(rv, rv); + if (!host.IsEmpty()) { + rv = GetBaseDomainFromHost(mTLDService, host, baseDomain); + NS_ENSURE_SUCCESS(rv, rv); + } nsListIter matchIter; RefPtr cookie; @@ -2869,11 +2846,6 @@ nsCookieService::ImportCookies(nsIFile* aCookieFile) { * private GetCookie/SetCookie helpers ******************************************************************************/ -// helper function for GetCookieList -static inline bool ispathdelimiter(char c) { - return c == '/' || c == '?' || c == '#' || c == ';'; -} - bool nsCookieService::DomainMatches(nsCookie* aCookie, const nsACString& aHost) { // first, check for an exact host or domain cookie match, e.g. "google.com" @@ -2884,33 +2856,28 @@ bool nsCookieService::DomainMatches(nsCookie* aCookie, } bool nsCookieService::PathMatches(nsCookie* aCookie, const nsACString& aPath) { - // calculate cookie path length, excluding trailing '/' - uint32_t cookiePathLen = aCookie->Path().Length(); - if (cookiePathLen > 0 && aCookie->Path().Last() == '/') --cookiePathLen; + nsCString cookiePath(aCookie->GetFilePath()); - // if the given path is shorter than the cookie path, it doesn't match - // if the given path doesn't start with the cookie path, it doesn't match. - if (!StringBeginsWith(aPath, Substring(aCookie->Path(), 0, cookiePathLen))) - return false; + // if our cookie path is empty we can't really perform our prefix check, and + // also we can't check the last character of the cookie path, so we would + // never return a successful match. + if (cookiePath.IsEmpty()) return false; - // if the given path is longer than the cookie path, and the first char after - // the cookie path is not a path delimiter, it doesn't match. - if (aPath.Length() > cookiePathLen && - !ispathdelimiter(aPath.CharAt(cookiePathLen))) { - /* - * |ispathdelimiter| tests four cases: '/', '?', '#', and ';'. - * '/' is the "standard" case; the '?' test allows a site at host/abc?def - * to receive a cookie that has a path attribute of abc. this seems - * strange but at least one major site (citibank, bug 156725) depends - * on it. The test for # and ; are put in to proactively avoid problems - * with other sites - these are the only other chars allowed in the path. - */ - return false; - } + // if the cookie path and the request path are identical, they match. + if (cookiePath.Equals(aPath)) return true; - // either the paths match exactly, or the cookie path is a prefix of - // the given path. - return true; + // if the cookie path is a prefix of the request path, and the last character + // of the cookie path is %x2F ("/"), they match. + bool isPrefix = StringBeginsWith(aPath, cookiePath); + if (isPrefix && cookiePath.Last() == '/') return true; + + // if the cookie path is a prefix of the request path, and the first character + // of the request path that is not included in the cookie path is a %x2F ("/") + // character, they match. + uint32_t cookiePathLen = cookiePath.Length(); + if (isPrefix && aPath[cookiePathLen] == '/') return true; + + return false; } void nsCookieService::GetCookiesForURI( @@ -2942,7 +2909,7 @@ void nsCookieService::GetCookiesForURI( nsresult rv = GetBaseDomain(mTLDService, aHostURI, baseDomain, requireHostMatch); if (NS_SUCCEEDED(rv)) rv = aHostURI->GetAsciiHost(hostFromURI); - if (NS_SUCCEEDED(rv)) rv = aHostURI->GetPathQueryRef(pathFromURI); + if (NS_SUCCEEDED(rv)) rv = aHostURI->GetFilePath(pathFromURI); if (NS_FAILED(rv)) { COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, VoidCString(), "invalid host/path from URI"); @@ -2966,7 +2933,10 @@ void nsCookieService::GetCookiesForURI( // (but not if there was an error) switch (cookieStatus) { case STATUS_REJECTED: - NotifyRejected(aHostURI, aChannel, rejectedReason, OPERATION_READ); + // If we don't have any cookies from this host, fail silently. + if (priorCookieCount) { + NotifyRejected(aHostURI, aChannel, rejectedReason, OPERATION_READ); + } return; default: break; @@ -4524,7 +4494,9 @@ NS_IMETHODIMP nsCookieService::GetCookiesFromHost(const nsACString& aHost, JS::HandleValue aOriginAttributes, JSContext* aCx, - nsISimpleEnumerator** aEnumerator) { + nsTArray>& aResult) { + aResult.Clear(); + if (!mDBState) { NS_WARNING("No DBState! Profile already closed?"); return NS_ERROR_NOT_AVAILABLE; @@ -4552,21 +4524,21 @@ nsCookieService::GetCookiesFromHost(const nsACString& aHost, nsCookieKey key = nsCookieKey(baseDomain, attrs); nsCookieEntry* entry = mDBState->hostTable.GetEntry(key); - if (!entry) return NS_NewEmptyEnumerator(aEnumerator); + if (!entry) return NS_OK; - nsCOMArray cookieList(mMaxCookiesPerHost); + aResult.SetCapacity(mMaxCookiesPerHost); const nsCookieEntry::ArrayType& cookies = entry->GetCookies(); for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) { - cookieList.AppendObject(cookies[i]); + aResult.AppendElement(cookies[i]); } - return NS_NewArrayEnumerator(aEnumerator, cookieList, NS_GET_IID(nsICookie)); + return NS_OK; } NS_IMETHODIMP nsCookieService::GetCookiesWithOriginAttributes( const nsAString& aPattern, const nsACString& aHost, - nsISimpleEnumerator** aEnumerator) { + nsTArray>& aResult) { mozilla::OriginAttributesPattern pattern; if (!pattern.Init(aPattern)) { return NS_ERROR_INVALID_ARG; @@ -4580,12 +4552,12 @@ nsCookieService::GetCookiesWithOriginAttributes( rv = GetBaseDomainFromHost(mTLDService, host, baseDomain); NS_ENSURE_SUCCESS(rv, rv); - return GetCookiesWithOriginAttributes(pattern, baseDomain, aEnumerator); + return GetCookiesWithOriginAttributes(pattern, baseDomain, aResult); } nsresult nsCookieService::GetCookiesWithOriginAttributes( const mozilla::OriginAttributesPattern& aPattern, - const nsCString& aBaseDomain, nsISimpleEnumerator** aEnumerator) { + const nsCString& aBaseDomain, nsTArray>& aResult) { if (!mDBState) { NS_WARNING("No DBState! Profile already closed?"); return NS_ERROR_NOT_AVAILABLE; @@ -4598,7 +4570,6 @@ nsresult nsCookieService::GetCookiesWithOriginAttributes( ? mPrivateDBState : mDefaultDBState; - nsCOMArray cookies; for (auto iter = mDBState->hostTable.Iter(); !iter.Done(); iter.Next()) { nsCookieEntry* entry = iter.Get(); @@ -4613,11 +4584,11 @@ nsresult nsCookieService::GetCookiesWithOriginAttributes( const nsCookieEntry::ArrayType& entryCookies = entry->GetCookies(); for (nsCookieEntry::IndexType i = 0; i < entryCookies.Length(); ++i) { - cookies.AppendObject(entryCookies[i]); + aResult.AppendElement(entryCookies[i]); } } - return NS_NewArrayEnumerator(aEnumerator, cookies, NS_GET_IID(nsICookie)); + return NS_OK; } NS_IMETHODIMP @@ -4764,6 +4735,88 @@ nsresult nsCookieService::RemoveCookiesFromExactHost( return NS_OK; } +namespace { + +class RemoveAllSinceRunnable : public Runnable { + public: + typedef nsTArray> CookieArray; + RemoveAllSinceRunnable(Promise* aPromise, nsCookieService* aSelf, + CookieArray&& aCookieArray, int64_t aSinceWhen) + : Runnable("RemoveAllSinceRunnable"), + mPromise(aPromise), + mSelf(aSelf), + mList(std::move(aCookieArray)), + mIndex(0), + mSinceWhen(aSinceWhen) {} + + NS_IMETHODIMP Run() { + RemoveSome(); + + if (mIndex < mList.Length()) { + return NS_DispatchToCurrentThread(this); + } else { + mPromise->MaybeResolveWithUndefined(); + } + return NS_OK; + } + + private: + void RemoveSome() { + for (CookieArray::size_type iter = 0; + iter < kYieldPeriod && mIndex < mList.Length(); ++mIndex, ++iter) { + nsCookie* cookie = static_cast(mList[mIndex].get()); + if (cookie->CreationTime() > mSinceWhen && + NS_FAILED(mSelf->Remove(cookie->Host(), cookie->OriginAttributesRef(), + cookie->Name(), cookie->Path()))) { + continue; + } + } + } + + private: + RefPtr mPromise; + RefPtr mSelf; + CookieArray mList; + CookieArray::size_type mIndex; + int64_t mSinceWhen; + static const CookieArray::size_type kYieldPeriod = 10; +}; + +} // namespace + +NS_IMETHODIMP +nsCookieService::RemoveAllSince(int64_t aSinceWhen, JSContext* aCx, + Promise** aRetVal) { + nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx); + if (NS_WARN_IF(!globalObject)) { + return NS_ERROR_UNEXPECTED; + } + + ErrorResult result; + RefPtr promise = Promise::Create(globalObject, result); + if (NS_WARN_IF(result.Failed())) { + return result.StealNSResult(); + } + + EnsureReadComplete(true); + + typedef RemoveAllSinceRunnable::CookieArray CookieArray; + CookieArray cookieList(mDBState->cookieCount); + for (auto iter = mDBState->hostTable.Iter(); !iter.Done(); iter.Next()) { + const nsCookieEntry::ArrayType& cookies = iter.Get()->GetCookies(); + for (nsCookieEntry::IndexType i = 0; i < cookies.Length(); ++i) { + cookieList.AppendElement(cookies[i]); + } + } + + RefPtr runMe = new RemoveAllSinceRunnable( + promise, this, std::move(cookieList), aSinceWhen); + + promise.forget(aRetVal); + + return runMe->Run(); +} + // find an secure cookie specified by host and name bool nsCookieService::FindSecureCookie(const nsCookieKey& aKey, nsCookie* aCookie) { @@ -4784,7 +4837,7 @@ bool nsCookieService::FindSecureCookie(const nsCookieKey& aKey, // aren't "/", then this situation needs to compare paths to // ensure only that a newly-created non-secure cookie does not // overlay an existing secure cookie. - if (PathMatches(cookie, aCookie->Path())) { + if (PathMatches(cookie, aCookie->GetFilePath())) { return true; } } diff --git a/netwerk/cookie/nsCookieService.h b/netwerk/cookie/nsCookieService.h index a8a30d9a17..1556e3a6fc 100644 --- a/netwerk/cookie/nsCookieService.h +++ b/netwerk/cookie/nsCookieService.h @@ -14,7 +14,6 @@ #include "nsCookie.h" #include "nsCookieKey.h" #include "nsString.h" -#include "nsAutoPtr.h" #include "nsHashKeys.h" #include "nsIMemoryReporter.h" #include "nsTHashtable.h" @@ -62,7 +61,7 @@ using mozilla::net::nsCookieKey; class nsCookieEntry : public nsCookieKey { public: // Hash methods - typedef nsTArray > ArrayType; + typedef nsTArray> ArrayType; typedef ArrayType::index_type IndexType; explicit nsCookieEntry(KeyTypePointer aKey) : nsCookieKey(aKey) {} @@ -225,6 +224,13 @@ class nsCookieService final : public nsICookieService, const OriginAttributes& aOriginAttrs, nsTArray& aCookieList); + /** + * This method is a helper that allows calling nsICookieManager::Remove() + * with OriginAttributes parameter. + */ + nsresult Remove(const nsACString& aHost, const OriginAttributes& aAttrs, + const nsACString& aName, const nsACString& aPath); + protected: virtual ~nsCookieService(); @@ -325,19 +331,11 @@ class nsCookieService final : public nsICookieService, nsresult GetCookiesWithOriginAttributes( const mozilla::OriginAttributesPattern& aPattern, - const nsCString& aBaseDomain, nsISimpleEnumerator** aEnumerator); + const nsCString& aBaseDomain, nsTArray>& aResult); nsresult RemoveCookiesWithOriginAttributes( const mozilla::OriginAttributesPattern& aPattern, const nsCString& aBaseDomain); - /** - * This method is a helper that allows calling nsICookieManager::Remove() - * with OriginAttributes parameter. - * NOTE: this could be added to a public interface if we happen to need it. - */ - nsresult Remove(const nsACString& aHost, const OriginAttributes& aAttrs, - const nsACString& aName, const nsACString& aPath); - protected: nsresult RemoveCookiesFromExactHost( const nsACString& aHost, diff --git a/netwerk/cookie/nsICookieManager.idl b/netwerk/cookie/nsICookieManager.idl index 296a2fc12e..0510762a89 100644 --- a/netwerk/cookie/nsICookieManager.idl +++ b/netwerk/cookie/nsICookieManager.idl @@ -12,17 +12,10 @@ class OriginAttributes; [ptr] native OriginAttributesPtr(mozilla::OriginAttributes); -interface nsISimpleEnumerator; interface nsICookie; interface nsIFile; -[scriptable, function, uuid(20709db8-8dad-4e45-b33e-6e7c761dfc5d)] -interface nsIPrivateModeCallback : nsISupports -{ - void callback(); -}; - -/** +/** * An optional interface for accessing or removing the cookies * that are in the cookie list */ @@ -37,20 +30,20 @@ interface nsICookieManager : nsISupports void removeAll(); /** - * Called to enumerate through each cookie in the cookie list. - * The objects enumerated over are of type nsICookie - * This enumerator should only be used for non-private browsing cookies. - * To retrieve an enumerator for private browsing cookies, use + * Returns an array of cookies in the cookie list. + * The objects in the array are of type nsICookie + * This array only contains non-private browsing cookies. + * To retrieve an array of private browsing cookies, use * getCookiesWithOriginAttributes. */ - readonly attribute nsISimpleEnumerator enumerator; + readonly attribute Array cookies; /** - * Called to enumerate through each session cookie in the cookie list. - * The objects enumerated over are of type nsICookie - * This enumerator should only be used for non-private browsing cookies. + * Returns an array of session cookies in the cookie list. + * The objects in the array are of type nsICookie + * This array only contains non-private browsing cookies. */ - readonly attribute nsISimpleEnumerator sessionEnumerator; + readonly attribute Array sessionCookies; /** * Called to remove an individual cookie from the cookie list, specified @@ -183,7 +176,7 @@ interface nsICookieManager : nsISupports unsigned long countCookiesFromHost(in AUTF8String aHost); /** - * Returns an enumerator of cookies that exist within the base domain of + * Returns an array of cookies that exist within the base domain of * 'aHost'. Thus, for a host "weather.yahoo.com", the base domain would be * "yahoo.com", and any host or domain cookies for "yahoo.com" and its * subdomains would be returned. @@ -195,13 +188,13 @@ interface nsICookieManager : nsISupports * @param aOriginAttributes The originAttributes of cookies that would be * retrived. * - * @return an nsISimpleEnumerator of nsICookie objects. + * @return an array of nsICookie objects. * * @see countCookiesFromHost */ [implicit_jscontext] - nsISimpleEnumerator getCookiesFromHost(in AUTF8String aHost, - in jsval aOriginAttributes); + Array getCookiesFromHost(in AUTF8String aHost, + in jsval aOriginAttributes); /** * Import an old-style cookie file. Imported cookies will be added to the @@ -213,7 +206,7 @@ interface nsICookieManager : nsISupports void importCookies(in nsIFile aCookieFile); /** - * Returns an enumerator of all cookies whose origin attributes matches aPattern + * Returns an array of all cookies whose origin attributes matches aPattern * * @param aPattern origin attribute pattern in JSON format * @@ -223,8 +216,8 @@ interface nsICookieManager : nsISupports * acceptable host strings. This attribute is optional. It will search * all hosts if this attribute is not given. */ - nsISimpleEnumerator getCookiesWithOriginAttributes(in AString aPattern, - [optional] in AUTF8String aHost); + Array getCookiesWithOriginAttributes(in AString aPattern, + [optional] in AUTF8String aHost); /** * Remove all the cookies whose origin attributes matches aPattern @@ -242,4 +235,15 @@ interface nsICookieManager : nsISupports * @param aPattern origin attribute pattern in JSON format */ void removeCookiesFromExactHost(in AUTF8String aHost, in AString aPattern); + + /** + * Removes all cookies that were created on or after aSinceWhen, and returns + * a Promise which will be resolved when the last such cookie has been + * removed. + * + * @param aSinceWhen the starting point in time after which no cookies should + * be created when the Promise returned from this method is resolved. + */ + [implicit_jscontext] + Promise removeAllSince(in int64_t aSinceWhen); }; diff --git a/netwerk/cookie/nsICookieService.idl b/netwerk/cookie/nsICookieService.idl index 1f8871c3cd..be70504aa6 100644 --- a/netwerk/cookie/nsICookieService.idl +++ b/netwerk/cookie/nsICookieService.idl @@ -5,7 +5,6 @@ #include "nsISupports.idl" interface nsIURI; -interface nsIPrompt; interface nsIChannel; /** @@ -142,10 +141,6 @@ interface nsICookieService : nsISupports * file:// URIs (i.e. with an empty host) are allowed, but any other * scheme must have a non-empty host. A trailing dot in the host * is acceptable, and will be stripped. This argument must not be null. - * @param aPrompt - * the prompt to use for all user-level cookie notifications. This is - * presently ignored and can be null. (Prompt information is determined - * from the channel if necessary.) * @param aCookie * the cookie string to set. * @param aChannel @@ -155,8 +150,8 @@ interface nsICookieService : nsISupports * to determine the originating URI of the document; if it is not * provided, the cookies will be assumed third-party.) */ - void setCookieString(in nsIURI aURI, in nsIPrompt aPrompt, - in ACString aCookie, in nsIChannel aChannel); + void setCookieString(in nsIURI aURI, in ACString aCookie, + in nsIChannel aChannel); /* * Set the cookie string and expires associated with the URI. @@ -172,10 +167,6 @@ interface nsICookieService : nsISupports * @param aFirstURI * the URI that the user originally typed in or clicked on to initiate * the load of the document referenced by aURI. - * @param aPrompt - * the prompt to use for all user-level cookie notifications. This is - * presently ignored and can be null. (Prompt information is determined - * from the channel if necessary.) * @param aCookie * the cookie string to set. * @param aServerTime @@ -192,8 +183,8 @@ interface nsICookieService : nsISupports * provided, the cookies will be assumed third-party.) */ void setCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, - in nsIPrompt aPrompt, in ACString aCookie, - in ACString aServerTime, in nsIChannel aChannel); + in ACString aCookie, in ACString aServerTime, + in nsIChannel aChannel); /* diff --git a/netwerk/cookie/test/browser/browser_originattributes.js b/netwerk/cookie/test/browser/browser_originattributes.js index ecdad67372..044d104402 100644 --- a/netwerk/cookie/test/browser/browser_originattributes.js +++ b/netwerk/cookie/test/browser/browser_originattributes.js @@ -91,10 +91,10 @@ async function checkCookies(expectedValues, time) { function getCookiesFromManager(userContextId) { let cookies = {}; - let enumerator = cm.getCookiesWithOriginAttributes( + let allCookies = cm.getCookiesWithOriginAttributes( JSON.stringify({ userContextId }) ); - for (let cookie of enumerator) { + for (let cookie of allCookies) { cookies[cookie.name] = cookie.value; } return cookies; diff --git a/netwerk/cookie/test/unit/test_bug1155169.js b/netwerk/cookie/test/unit/test_bug1155169.js index 82e5c03c5b..c57aab3726 100644 --- a/netwerk/cookie/test/unit/test_bug1155169.js +++ b/netwerk/cookie/test/unit/test_bug1155169.js @@ -73,7 +73,7 @@ function setCookie(value, expected) { } Services.obs.addObserver(observer, "cookie-changed"); - cs.setCookieStringFromHttp(URI, null, null, valueInternal, null, null); + cs.setCookieStringFromHttp(URI, null, valueInternal, null, null); Services.obs.removeObserver(observer, "cookie-changed"); } diff --git a/netwerk/cookie/test/unit/test_bug1321912.js b/netwerk/cookie/test/unit/test_bug1321912.js index 2fc10c917d..fec4dc5a05 100644 --- a/netwerk/cookie/test/unit/test_bug1321912.js +++ b/netwerk/cookie/test/unit/test_bug1321912.js @@ -58,8 +58,8 @@ conn.executeSimpleSQL( ); // Now start the cookie service, and then check the fields in the table. -// Get sessionEnumerator to wait for the initialization in cookie thread -const enumerator = Services.cookies.sessionEnumerator; +// Get sessionCookies to wait for the initialization in cookie thread +const cookies = Services.cookies.sessionCookies; Assert.equal(conn.schemaVersion, 9); let stmt = conn.createStatement( diff --git a/netwerk/cookie/test/unit/test_bug643051.js b/netwerk/cookie/test/unit/test_bug643051.js index 4deba3a917..300578ea3d 100644 --- a/netwerk/cookie/test/unit/test_bug643051.js +++ b/netwerk/cookie/test/unit/test_bug643051.js @@ -11,13 +11,13 @@ function run_test() { let set = "foo=bar\nbaz=foo"; let expected = "foo=bar; baz=foo"; - cs.setCookieStringFromHttp(uri, null, null, set, null, null); + cs.setCookieStringFromHttp(uri, null, set, null, null); let actual = cs.getCookieStringFromHttp(uri, null, null); Assert.equal(actual, expected); uri = NetUtil.newURI("http://example.com/"); - cs.setCookieString(uri, null, set, null); + cs.setCookieString(uri, set, null); expected = "foo=bar"; actual = cs.getCookieString(uri, null, null); diff --git a/netwerk/cookie/test/unit/test_eviction.js b/netwerk/cookie/test/unit/test_eviction.js index 1d93d04a4b..34579d0cec 100644 --- a/netwerk/cookie/test/unit/test_eviction.js +++ b/netwerk/cookie/test/unit/test_eviction.js @@ -174,7 +174,7 @@ function setCookie(name, domain, path, maxAge, url) { } s += " for " + url.spec; info(s); - cs.setCookieStringFromHttp(url, null, null, value, null, null); + cs.setCookieStringFromHttp(url, null, value, null, null); return new Promise(function(resolve) { // Windows XP has low precision timestamps that cause our cookie eviction // algorithm to produce different results from other platforms. We work around diff --git a/netwerk/cookie/test/unit/test_parser_0001.js b/netwerk/cookie/test/unit/test_parser_0001.js index 40f70d01e1..091be5752f 100644 --- a/netwerk/cookie/test/unit/test_parser_0001.js +++ b/netwerk/cookie/test/unit/test_parser_0001.js @@ -16,7 +16,7 @@ function run_test() { let uri = NetUtil.newURI("http://example.org/"); let set = "foo=bar"; - cs.setCookieStringFromHttp(uri, null, null, set, null, null); + cs.setCookieStringFromHttp(uri, null, set, null, null); let expected = "foo=bar"; let actual = cs.getCookieStringFromHttp(uri, null, null); diff --git a/netwerk/cookie/test/unit/test_parser_0019.js b/netwerk/cookie/test/unit/test_parser_0019.js index d5fdc7946a..ffb8685c92 100644 --- a/netwerk/cookie/test/unit/test_parser_0019.js +++ b/netwerk/cookie/test/unit/test_parser_0019.js @@ -16,7 +16,7 @@ function run_test() { let uri = NetUtil.newURI("http://example.org/"); let set = "foo=b;max-age=3600, c=d;path=/"; - cs.setCookieStringFromHttp(uri, null, null, set, null, null); + cs.setCookieStringFromHttp(uri, null, set, null, null); let expected = "foo=b"; let actual = cs.getCookieStringFromHttp(uri, null, null); diff --git a/netwerk/dns/DNSRequestChild.cpp b/netwerk/dns/DNSRequestChild.cpp index 874e69b014..c97a30741a 100644 --- a/netwerk/dns/DNSRequestChild.cpp +++ b/netwerk/dns/DNSRequestChild.cpp @@ -105,7 +105,8 @@ ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr** result) { nsresult rv = GetNextAddr(port, &addr); if (NS_FAILED(rv)) return rv; - NS_ADDREF(*result = new nsNetAddr(&addr)); + RefPtr netaddr = new nsNetAddr(&addr); + netaddr.forget(result); return NS_OK; } diff --git a/netwerk/dns/GetAddrInfo.cpp b/netwerk/dns/GetAddrInfo.cpp index 64202cedb2..d76f5cd0df 100644 --- a/netwerk/dns/GetAddrInfo.cpp +++ b/netwerk/dns/GetAddrInfo.cpp @@ -8,7 +8,6 @@ #include "nsHostResolver.h" #include "nsError.h" #include "mozilla/Mutex.h" -#include "nsAutoPtr.h" #include "mozilla/StaticPtr.h" #include "MainThreadUtils.h" #include "mozilla/DebugOnly.h" diff --git a/netwerk/dns/TRR.cpp b/netwerk/dns/TRR.cpp index 868ab8a539..9df4f7c95f 100644 --- a/netwerk/dns/TRR.cpp +++ b/netwerk/dns/TRR.cpp @@ -24,9 +24,11 @@ #include "mozilla/DebugOnly.h" #include "mozilla/Logging.h" #include "mozilla/Preferences.h" +#include "mozilla/StaticPrefs_network.h" #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" #include "mozilla/Tokenizer.h" +#include "mozilla/UniquePtr.h" namespace mozilla { namespace net { @@ -230,17 +232,18 @@ nsresult TRR::SendHTTPRequest() { return rv; } - rv = NS_NewChannel( - getter_AddRefs(mChannel), dnsURI, nsContentUtils::GetSystemPrincipal(), - nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, - nsIContentPolicy::TYPE_OTHER, - nullptr, // nsICookieSettings - nullptr, // PerformanceStorage - nullptr, // aLoadGroup - this, - nsIRequest::LOAD_ANONYMOUS | (mPB ? nsIRequest::INHIBIT_CACHING : 0) | - nsIChannel::LOAD_BYPASS_URL_CLASSIFIER, - ios); + rv = NS_NewChannel(getter_AddRefs(mChannel), dnsURI, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, + nsIContentPolicy::TYPE_OTHER, + nullptr, // nsICookieSettings + nullptr, // PerformanceStorage + nullptr, // aLoadGroup + this, + nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING | + nsIRequest::LOAD_BYPASS_CACHE | + nsIChannel::LOAD_BYPASS_URL_CLASSIFIER, + ios); if (NS_FAILED(rv)) { LOG(("TRR:SendHTTPRequest: NewChannel failed!\n")); return rv; @@ -302,6 +305,21 @@ nsresult TRR::SendHTTPRequest() { NS_ENSURE_SUCCESS(rv, rv); } + // Sanitize the request by removing the Accept-Language header so we minimize + // the amount of fingerprintable information we send to the server. + if (!StaticPrefs::network_trr_send_accept_language_headers()) { + rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Language"), + EmptyCString(), false); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Sanitize the request by removing the User-Agent + if (!StaticPrefs::network_trr_send_user_agent_headers()) { + rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), + EmptyCString(), false); + NS_ENSURE_SUCCESS(rv, rv); + } + // set the *default* response content type if (NS_FAILED(httpChannel->SetContentType( NS_LITERAL_CSTRING("application/dns-message")))) { @@ -432,6 +450,10 @@ nsresult TRR::ReceivePush(nsIHttpChannel* pushed, nsHostRecord* pushedRec) { return NS_ERROR_UNEXPECTED; } + if (gTRRService->IsExcludedFromTRR(mHost)) { + return NS_ERROR_FAILURE; + } + RefPtr hostRecord; nsresult rv; rv = mHostResolver->GetHostRecord( @@ -1041,7 +1063,7 @@ TRR::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream, nsresult DOHresp::Add(uint32_t TTL, unsigned char* dns, int index, uint16_t len, bool aLocalAllowed) { - nsAutoPtr doh(new DOHaddr); + auto doh = MakeUnique(); NetAddr* addr = &doh->mNet; if (4 == len) { // IPv4 @@ -1071,7 +1093,7 @@ nsresult DOHresp::Add(uint32_t TTL, unsigned char* dns, int index, uint16_t len, NetAddrToString(addr, buf, sizeof(buf)); LOG(("DOHresp:Add %s\n", buf)); } - mAddresses.insertBack(doh.forget()); + mAddresses.insertBack(doh.release()); return NS_OK; } diff --git a/netwerk/dns/TRRService.cpp b/netwerk/dns/TRRService.cpp index 5c5b719314..50a228e17f 100644 --- a/netwerk/dns/TRRService.cpp +++ b/netwerk/dns/TRRService.cpp @@ -10,12 +10,14 @@ #include "TRRService.h" #include "mozilla/Preferences.h" +#include "mozilla/StaticPrefs_network.h" #include "mozilla/Tokenizer.h" static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login"; static const char kClearPrivateData[] = "clear-private-data"; static const char kPurge[] = "browser:purge-session-history"; static const char kDisableIpv6Pref[] = "network.dns.disableIPv6"; +static const char kCaptivedetectCanonicalURL[] = "captivedetect.canonicalURL"; #define TRR_PREF_PREFIX "network.trr." #define TRR_PREF(x) TRR_PREF_PREFIX x @@ -35,7 +37,6 @@ TRRService::TRRService() : mInitialized(false), mMode(0), mTRRBlacklistExpireTime(72 * 3600), - mTRRTimeout(3000), mLock("trrservice"), mConfirmationNS(NS_LITERAL_CSTRING("example.com")), mWaitForCaptive(true), @@ -71,6 +72,7 @@ nsresult TRRService::Init() { if (prefBranch) { prefBranch->AddObserver(TRR_PREF_PREFIX, this, true); prefBranch->AddObserver(kDisableIpv6Pref, this, true); + prefBranch->AddObserver(kCaptivedetectCanonicalURL, this, true); } nsCOMPtr captivePortalService = do_GetService(NS_CAPTIVEPORTAL_CID); @@ -122,14 +124,25 @@ void TRRService::GetPrefBranch(nsIPrefBranch** result) { nsresult TRRService::ReadPrefs(const char* name) { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); + + // Whenever a pref change occurs that would cause us to clear the cache + // we set this to true then do it at the end of the method. + bool clearEntireCache = false; + if (!name || !strcmp(name, TRR_PREF("mode"))) { - // 0 - off, 1 - parallel, 2 - TRR first, 3 - TRR only, 4 - shadow, + // 0 - off, 1 - reserved, 2 - TRR first, 3 - TRR only, 4 - reserved, // 5 - explicit off uint32_t tmp; if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("mode"), &tmp))) { if (tmp > MODE_TRROFF) { tmp = MODE_TRROFF; } + if (tmp == MODE_RESERVED1) { + tmp = MODE_TRROFF; + } + if (tmp == MODE_RESERVED4) { + tmp = MODE_TRROFF; + } mMode = tmp; } } @@ -184,6 +197,7 @@ nsresult TRRService::ReadPrefs(const char* name) { if (!old.IsEmpty() && !mPrivateURI.Equals(old)) { mClearTRRBLStorage = true; LOG(("TRRService clearing blacklist because of change is uri service\n")); + clearEntireCache = true; } } if (!name || !strcmp(name, TRR_PREF("credentials"))) { @@ -203,6 +217,7 @@ nsresult TRRService::ReadPrefs(const char* name) { if (!name || !strcmp(name, TRR_PREF("bootstrapAddress"))) { AutoLock lock(mLock); Preferences::GetCString(TRR_PREF("bootstrapAddress"), mBootstrapAddr); + clearEntireCache = true; } if (!name || !strcmp(name, TRR_PREF("wait-for-portal"))) { // Wait for captive portal? @@ -231,19 +246,27 @@ nsresult TRRService::ReadPrefs(const char* name) { mTRRBlacklistExpireTime = secs; } } - if (!name || !strcmp(name, TRR_PREF("request-timeout"))) { - // number of milliseconds - uint32_t ms; - if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("request-timeout"), &ms))) { - mTRRTimeout = ms; - } - } if (!name || !strcmp(name, TRR_PREF("early-AAAA"))) { bool tmp; if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("early-AAAA"), &tmp))) { mEarlyAAAA = tmp; } } + + if (!name || !strcmp(name, TRR_PREF("skip-AAAA-when-not-supported"))) { + bool tmp; + if (NS_SUCCEEDED(Preferences::GetBool( + TRR_PREF("skip-AAAA-when-not-supported"), &tmp))) { + mCheckIPv6Connectivity = tmp; + } + } + if (!name || !strcmp(name, TRR_PREF("wait-for-A-and-AAAA"))) { + bool tmp; + if (NS_SUCCEEDED( + Preferences::GetBool(TRR_PREF("wait-for-A-and-AAAA"), &tmp))) { + mWaitForAllResponses = tmp; + } + } if (!name || !strcmp(name, kDisableIpv6Pref)) { bool tmp; if (NS_SUCCEEDED(Preferences::GetBool(kDisableIpv6Pref, &tmp))) { @@ -262,17 +285,57 @@ nsresult TRRService::ReadPrefs(const char* name) { mDisableAfterFails = fails; } } - if (!name || !strcmp(name, TRR_PREF("excluded-domains"))) { - nsAutoCString excludedDomains; - Preferences::GetCString(TRR_PREF("excluded-domains"), excludedDomains); - + if (!name || !strcmp(name, TRR_PREF("excluded-domains")) || + !strcmp(name, TRR_PREF("builtin-excluded-domains")) || + !strcmp(name, kCaptivedetectCanonicalURL)) { + AutoLock lock(mLock); mExcludedDomains.Clear(); - nsCCharSeparatedTokenizer tokenizer( - excludedDomains, ',', nsCCharSeparatedTokenizer::SEPARATOR_OPTIONAL); - while (tokenizer.hasMoreTokens()) { - nsAutoCString token(tokenizer.nextToken()); - LOG(("TRRService::ReadPrefs excluded-domains host:[%s]\n", token.get())); - mExcludedDomains.PutEntry(token); + + auto parseExcludedDomains = [this](const char* aPrefName) { + nsAutoCString excludedDomains; + Preferences::GetCString(aPrefName, excludedDomains); + if (excludedDomains.IsEmpty()) { + return; + } + + nsCCharSeparatedTokenizer tokenizer( + excludedDomains, ',', nsCCharSeparatedTokenizer::SEPARATOR_OPTIONAL); + while (tokenizer.hasMoreTokens()) { + nsAutoCString token(tokenizer.nextToken()); + LOG(("TRRService::ReadPrefs %s host:[%s]\n", aPrefName, token.get())); + mExcludedDomains.PutEntry(token); + } + }; + + parseExcludedDomains(TRR_PREF("excluded-domains")); + parseExcludedDomains(TRR_PREF("builtin-excluded-domains")); + clearEntireCache = true; + + nsAutoCString canonicalSiteURL; + Preferences::GetCString(kCaptivedetectCanonicalURL, canonicalSiteURL); + + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), canonicalSiteURL, + UTF_8_ENCODING, nullptr); + if (NS_SUCCEEDED(rv)) { + nsAutoCString host; + uri->GetHost(host); + LOG(("TRRService::ReadPrefs captive portal URL:[%s]\n", host.get())); + mExcludedDomains.PutEntry(host); + } + } + + // if name is null, then we're just now initializing. In that case we don't + // need to clear the cache. + if (name && clearEntireCache) { + bool tmp; + if (NS_SUCCEEDED(Preferences::GetBool( + TRR_PREF("clear-cache-on-pref-change"), &tmp)) && + tmp) { + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID); + if (dns) { + dns->ClearCache(true); + } } } @@ -291,6 +354,14 @@ nsresult TRRService::GetCredentials(nsCString& result) { return NS_OK; } +uint32_t TRRService::GetRequestTimeout() { + if (mMode == MODE_TRRONLY) { + return StaticPrefs::network_trr_request_timeout_mode_trronly_ms(); + } + + return StaticPrefs::network_trr_request_timeout_ms(); +} + nsresult TRRService::Start() { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); if (!mInitialized) { @@ -425,56 +496,26 @@ bool TRRService::MaybeBootstrap(const nsACString& aPossible, return true; } -// When running in TRR-only mode, the blacklist is not used and it will also -// try resolving the localhost / .local names. -bool TRRService::IsTRRBlacklisted(const nsACString& aHost, - const nsACString& aOriginSuffix, - bool aPrivateBrowsing, - bool aParentsToo) // false if domain -{ +bool TRRService::IsDomainBlacklisted(const nsACString& aHost, + const nsACString& aOriginSuffix, + bool aPrivateBrowsing) { // Only use the Storage API on the main thread - MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); - - if (mMode == MODE_TRRONLY) { - return false; // might as well try - } - - LOG(("Checking if host [%s] is blacklisted", aHost.BeginReading())); - // hardcode these so as to not worry about expiration - if (StringEndsWith(aHost, NS_LITERAL_CSTRING(".local")) || - aHost.Equals(NS_LITERAL_CSTRING("localhost"))) { - return true; - } - - if (mExcludedDomains.GetEntry(aHost)) { - LOG(("Host [%s] is TRR blacklisted via pref\n", aHost.BeginReading())); - return true; - } + MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(), "wrong thread"); if (!Enabled()) { return true; } - int32_t dot = aHost.FindChar('.'); - if ((dot == kNotFound) && aParentsToo) { - // Only if a full host name. Domains can be dotless to be able to - // blacklist entire TLDs + // It's OK to call this method here because it only happens on the main + // thread, and we only change the excluded domains/dns suffix list + // on the main thread in response to observer notifications. + // Calling the locking version of this method would cause us to grab + // the mutex for every label of the hostname, which would be very + // inefficient. + if (IsExcludedFromTRR_unlocked(aHost)) { return true; - } else if (dot != kNotFound) { - // there was a dot, check the parent first - dot++; - nsDependentCSubstring domain = Substring(aHost, dot, aHost.Length() - dot); - nsAutoCString check(domain); - - // recursively check the domain part of this name - if (IsTRRBlacklisted(check, aOriginSuffix, aPrivateBrowsing, false)) { - // the domain name of this name is already TRR blacklisted - return true; - } } - // These checks need to happen after the recursive result, otherwise we - // might not check the pref for parent domains. if (!mTRRBLStorage) { return false; } @@ -507,23 +548,76 @@ bool TRRService::IsTRRBlacklisted(const nsACString& aHost, return false; } -bool TRRService::IsExcludedFromTRR(const nsACString& aHost) { - if (mExcludedDomains.GetEntry(aHost)) { - LOG(("Host [%s] Is Excluded From TRR via pref\n", aHost.BeginReading())); - return true; +// When running in TRR-only mode, the blacklist is not used and it will also +// try resolving the localhost / .local names. +bool TRRService::IsTRRBlacklisted(const nsACString& aHost, + const nsACString& aOriginSuffix, + bool aPrivateBrowsing, + bool aParentsToo) // false if domain +{ + if (mMode == MODE_TRRONLY) { + return false; // might as well try } + LOG(("Checking if host [%s] is blacklisted", aHost.BeginReading())); + int32_t dot = aHost.FindChar('.'); - if (dot != kNotFound) { - // there was a dot, check the parent first + if ((dot == kNotFound) && aParentsToo) { + // Only if a full host name. Domains can be dotless to be able to + // blacklist entire TLDs + return true; + } + + if (IsDomainBlacklisted(aHost, aOriginSuffix, aPrivateBrowsing)) { + return true; + } + + nsDependentCSubstring domain = Substring(aHost, 0); + while (dot != kNotFound) { dot++; - nsDependentCSubstring domain = Substring(aHost, dot, aHost.Length() - dot); - nsAutoCString check(domain); + domain.Rebind(domain, dot, domain.Length() - dot); - // recursively check the domain part of this name - if (IsExcludedFromTRR(check)) { + if (IsDomainBlacklisted(domain, aOriginSuffix, aPrivateBrowsing)) { return true; } + + dot = domain.FindChar('.'); + } + + return false; +} + +bool TRRService::IsExcludedFromTRR(const nsACString& aHost) { + // This method may be called off the main thread. We need to lock so + // mExcludedDomains and mDNSSuffixDomains don't change while this code + // is running. + AutoLock lock(mLock); + + return IsExcludedFromTRR_unlocked(aHost); +} + +bool TRRService::IsExcludedFromTRR_unlocked(const nsACString& aHost) { + if (!NS_IsMainThread()) { + mLock.AssertCurrentThreadOwns(); + } + + int32_t dot = 0; + // iteratively check the sub-domain of |aHost| + while (dot < static_cast(aHost.Length())) { + nsDependentCSubstring subdomain = + Substring(aHost, dot, aHost.Length() - dot); + + if (mExcludedDomains.GetEntry(subdomain)) { + LOG(("Subdomain [%s] of host [%s] Is Excluded From TRR via pref\n", + subdomain.BeginReading(), aHost.BeginReading())); + return true; + } + + dot = aHost.FindChar('.', dot + 1); + if (dot == kNotFound) { + break; + } + dot++; } return false; diff --git a/netwerk/dns/TRRService.h b/netwerk/dns/TRRService.h index 8b6ddd1e82..8a9c3be04d 100644 --- a/netwerk/dns/TRRService.h +++ b/netwerk/dns/TRRService.h @@ -34,11 +34,13 @@ class TRRService : public nsIObserver, bool AllowRFC1918() { return mRfc1918; } bool UseGET() { return mUseGET; } bool EarlyAAAA() { return mEarlyAAAA; } + bool CheckIPv6Connectivity() { return mCheckIPv6Connectivity; } + bool WaitForAllResponses() { return mWaitForAllResponses; } bool DisableIPv6() { return mDisableIPv6; } bool DisableECS() { return mDisableECS; } nsresult GetURI(nsCString& result); nsresult GetCredentials(nsCString& result); - uint32_t GetRequestTimeout() { return mTRRTimeout; } + uint32_t GetRequestTimeout(); LookupStatus CompleteLookup(nsHostRecord*, nsresult, mozilla::net::AddrInfo*, bool pb, @@ -64,10 +66,14 @@ class TRRService : public nsIObserver, void MaybeConfirm(); void MaybeConfirm_locked(); + bool IsDomainBlacklisted(const nsACString& aHost, + const nsACString& aOriginSuffix, + bool aPrivateBrowsing); + bool IsExcludedFromTRR_unlocked(const nsACString& aHost); + bool mInitialized; Atomic mMode; Atomic mTRRBlacklistExpireTime; - Atomic mTRRTimeout; Lock mLock; @@ -84,8 +90,10 @@ class TRRService : public nsIObserver, mCaptiveIsPassed; // set when captive portal check is passed Atomic mUseGET; // do DOH using GET requests (instead of POST) Atomic mEarlyAAAA; // allow use of AAAA results before A is in - Atomic mDisableIPv6; // don't even try - Atomic mDisableECS; // disable EDNS Client Subnet in requests + Atomic mCheckIPv6Connectivity; // check IPv6 connectivity + Atomic mWaitForAllResponses; // Don't notify until all are in + Atomic mDisableIPv6; // don't even try + Atomic mDisableECS; // disable EDNS Client Subnet in requests Atomic mDisableAfterFails; // this many fails in a row means failed TRR service diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index 150805f2ee..685cbf3146 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -12,7 +12,6 @@ #include "nsProxyRelease.h" #include "nsReadableUtils.h" #include "nsString.h" -#include "nsAutoPtr.h" #include "nsNetCID.h" #include "nsError.h" #include "nsDNSPrefetch.h" @@ -227,7 +226,8 @@ nsDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr** result) { nsresult rv = GetNextAddr(port, &addr); if (NS_FAILED(rv)) return rv; - NS_ADDREF(*result = new nsNetAddr(&addr)); + RefPtr netaddr = new nsNetAddr(&addr); + netaddr.forget(result); return NS_OK; } diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h index f2f9997daa..bdb37ccec4 100644 --- a/netwerk/dns/nsDNSService2.h +++ b/netwerk/dns/nsDNSService2.h @@ -10,7 +10,6 @@ #include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "nsHostResolver.h" -#include "nsAutoPtr.h" #include "nsString.h" #include "nsTHashtable.h" #include "nsHashKeys.h" diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index a34681d221..ecaae66717 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -18,7 +18,6 @@ #include "nsISupportsBase.h" #include "nsISupportsUtils.h" #include "nsIThreadManager.h" -#include "nsAutoPtr.h" #include "nsComponentManagerUtils.h" #include "nsPrintfCString.h" #include "nsXPCOMCIDInternal.h" @@ -441,45 +440,7 @@ void AddrHostRecord::ResolveComplete() { } } - if (mTRRUsed && mNativeUsed && mNativeSuccess && - mTRRSuccess) { // race or shadow! - static const TimeDuration k50ms = TimeDuration::FromMilliseconds(50); - static const TimeDuration k100ms = TimeDuration::FromMilliseconds(100); - if (mTrrDuration <= mNativeDuration) { - if ((mNativeDuration - mTrrDuration) > k100ms) { - AccumulateCategorical(Telemetry::LABELS_DNS_TRR_RACE2::TRRFasterBy100); - } else if ((mNativeDuration - mTrrDuration) > k50ms) { - AccumulateCategorical(Telemetry::LABELS_DNS_TRR_RACE2::TRRFasterBy50); - } else { - AccumulateCategorical(Telemetry::LABELS_DNS_TRR_RACE2::TRRFaster); - } - LOG(("nsHostRecord::Complete %s Dns Race: TRR\n", host.get())); - } else { - if ((mTrrDuration - mNativeDuration) > k100ms) { - AccumulateCategorical( - Telemetry::LABELS_DNS_TRR_RACE2::NativeFasterBy100); - } else if ((mTrrDuration - mNativeDuration) > k50ms) { - AccumulateCategorical( - Telemetry::LABELS_DNS_TRR_RACE2::NativeFasterBy50); - } else { - AccumulateCategorical(Telemetry::LABELS_DNS_TRR_RACE2::NativeFaster); - } - LOG(("nsHostRecord::Complete %s Dns Race: NATIVE\n", host.get())); - } - } - - if (mTRRUsed && mNativeUsed && - ((mResolverMode == MODE_SHADOW) || (mResolverMode == MODE_PARALLEL))) { - // both were used, accumulate comparative success - AccumulateCategorical( - mNativeSuccess && mTRRSuccess - ? Telemetry::LABELS_DNS_TRR_COMPARE::BothWorked - : ((mNativeSuccess - ? Telemetry::LABELS_DNS_TRR_COMPARE::NativeWorked - : (mTRRSuccess - ? Telemetry::LABELS_DNS_TRR_COMPARE::TRRWorked - : Telemetry::LABELS_DNS_TRR_COMPARE::BothFailed)))); - } else if (mResolverMode == MODE_TRRFIRST) { + if (mResolverMode == MODE_TRRFIRST) { if (flags & nsIDNSService::RESOLVE_DISABLE_TRR) { // TRR is disabled on request, which is a next-level back-off method. Telemetry::Accumulate(Telemetry::DNS_TRR_DISABLED, mNativeSuccess); @@ -504,17 +465,17 @@ void AddrHostRecord::ResolveComplete() { case MODE_TRROFF: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::nativeOnly); break; - case MODE_PARALLEL: - AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrRace); - break; case MODE_TRRFIRST: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrFirst); break; case MODE_TRRONLY: AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOnly); break; - case MODE_SHADOW: - AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrShadow); + case MODE_RESERVED1: + MOZ_DIAGNOSTIC_ASSERT(false, "MODE_RESERVED1 should not be used"); + break; + case MODE_RESERVED4: + MOZ_DIAGNOSTIC_ASSERT(false, "MODE_RESERVED4 should not be used"); break; } @@ -635,6 +596,7 @@ nsresult nsHostResolver::Init() { LOG(("nsHostResolver::Init this=%p", this)); mShutdown = false; + mNCS = NetworkConnectivityService::GetSingleton(); // The preferences probably haven't been loaded from the disk yet, so we // need to register a callback that will set up the experiment once they @@ -782,6 +744,8 @@ void nsHostResolver::Shutdown() { } // empty host database mRecordDB.Clear(); + + mNCS = nullptr; } ClearPendingQueue(pendingQHigh); @@ -895,6 +859,10 @@ nsresult nsHostResolver::ResolveHost(const nsACString& aHost, uint16_t type, nsAutoCString originSuffix; aOriginAttributes.CreateSuffix(originSuffix); + if (gTRRService && gTRRService->IsExcludedFromTRR(host)) { + flags |= RES_DISABLE_TRR; + } + nsHostKey key(host, type, flags, af, (aOriginAttributes.mPrivateBrowsingId > 0), originSuffix); RefPtr& entry = mRecordDB.GetOrInsert(key); @@ -1281,7 +1249,9 @@ nsresult nsHostResolver::TrrLookup(nsHostRecord* aRec, TRR* pushedTRR) { do { sendAgain = false; if ((TRRTYPE_AAAA == rectype) && gTRRService && - gTRRService->DisableIPv6()) { + (gTRRService->DisableIPv6() || + (gTRRService->CheckIPv6Connectivity() && mNCS && + mNCS->GetIPv6() == nsINetworkConnectivityService::NOT_AVAILABLE))) { break; } LOG(("TRR Resolve %s type %d\n", addrRec->host.get(), (int)rectype)); @@ -1414,6 +1384,7 @@ nsresult nsHostResolver::NameLookup(nsHostRecord* rec) { } ResolverMode mode = rec->mResolverMode = Mode(); + MOZ_ASSERT(mode != MODE_RESERVED1); if (rec->IsAddrRecord()) { RefPtr addrRec = do_QueryObject(rec); @@ -1428,13 +1399,6 @@ nsresult nsHostResolver::NameLookup(nsHostRecord* rec) { addrRec->mTrrAAAAUsed = AddrHostRecord::INIT; } - if (rec->flags & RES_DISABLE_TRR) { - if (mode == MODE_TRRONLY) { - return rv; - } - mode = MODE_NATIVEONLY; - } - // For domains that are excluded from TRR we fallback to NativeLookup. // This happens even in MODE_TRRONLY. // By default localhost and local are excluded (so we cover *.local hosts) @@ -1444,12 +1408,18 @@ nsresult nsHostResolver::NameLookup(nsHostRecord* rec) { skipTRR = gTRRService->IsExcludedFromTRR(rec->host); } + if (rec->flags & RES_DISABLE_TRR) { + if (mode == MODE_TRRONLY && !skipTRR) { + return rv; + } + mode = MODE_NATIVEONLY; + } + if (!TRR_DISABLED(mode) && !skipTRR) { rv = TrrLookup(rec); } - if ((mode == MODE_PARALLEL) || TRR_DISABLED(mode) || (mode == MODE_SHADOW) || - ((mode == MODE_TRRFIRST) && NS_FAILED(rv)) || + if (TRR_DISABLED(mode) || ((mode == MODE_TRRFIRST) && NS_FAILED(rv)) || (mode == MODE_TRRONLY && skipTRR)) { if (!rec->IsAddrRecord()) { return rv; @@ -1689,7 +1659,6 @@ void nsHostResolver::AddToEvictionQ(nsHostRecord* rec) { // // CompleteLookup() checks if the resolving should be redone and if so it // returns LOOKUP_RESOLVEAGAIN, but only if 'status' is not NS_ERROR_ABORT. -// takes ownership of AddrInfo parameter nsHostResolver::LookupStatus nsHostResolver::CompleteLookup( nsHostRecord* rec, nsresult status, AddrInfo* aNewRRSet, bool pb, const nsACString& aOriginsuffix) { @@ -1742,8 +1711,7 @@ nsHostResolver::LookupStatus nsHostResolver::CompleteLookup( if (addrRec->mTRRSuccess == 1) { // Store the duration on first succesful TRR response. We // don't know that there will be a second response nor can we - // tell which of two has useful data, especially in - // MODE_SHADOW where the actual results are discarded. + // tell which of two has useful data. addrRec->mTrrDuration = TimeStamp::Now() - addrRec->mTrrStart; } } @@ -1759,7 +1727,12 @@ nsHostResolver::LookupStatus nsHostResolver::CompleteLookup( addrRec->mFirstTRR.swap(newRRSet); // autoPtr.swap() MOZ_ASSERT(addrRec->mFirstTRR && !newRRSet); - if (addrRec->mDidCallbacks || addrRec->mResolverMode == MODE_SHADOW) { + if (addrRec->mDidCallbacks) { + return LOOKUP_OK; + } + + if (gTRRService && gTRRService->WaitForAllResponses()) { + LOG(("CompleteLookup: waiting for all responses!\n")); return LOOKUP_OK; } @@ -1833,8 +1806,7 @@ nsHostResolver::LookupStatus nsHostResolver::CompleteLookup( // update record fields. We might have a addrRec->addr_info already if a // previous lookup result expired and we're reresolving it or we get // a late second TRR response. - // note that we don't update the addr_info if this is trr shadow results - if (!mShutdown && !(trrResult && addrRec->mResolverMode == MODE_SHADOW)) { + if (!mShutdown) { AutoLock lock(addrRec->addr_info_lock); RefPtr old_addr_info; if (different_rrset(addrRec->addr_info, newRRSet)) { @@ -1854,14 +1826,7 @@ nsHostResolver::LookupStatus nsHostResolver::CompleteLookup( bool doCallbacks = true; - if (trrResult && (addrRec->mResolverMode == MODE_SHADOW) && - !addrRec->mDidCallbacks) { - // don't report result based only on suppressed TRR info - doCallbacks = false; - LOG(( - "nsHostResolver Suppressing TRR %s because it is first shadow result\n", - addrRec->host.get())); - } else if (trrResult && addrRec->mDidCallbacks) { + if (trrResult && addrRec->mDidCallbacks) { // already callback'ed on the first TRR response LOG(("nsHostResolver Suppressing callback for second TRR response for %s\n", addrRec->host.get())); diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h index 88f592101b..001249c773 100644 --- a/netwerk/dns/nsHostResolver.h +++ b/netwerk/dns/nsHostResolver.h @@ -23,6 +23,7 @@ #include "mozilla/UniquePtr.h" #include "nsRefPtrHashtable.h" #include "nsIThreadPool.h" +#include "mozilla/net/NetworkConnectivityService.h" class nsHostResolver; class nsResolveHostCallback; @@ -31,10 +32,10 @@ namespace net { class TRR; enum ResolverMode { MODE_NATIVEONLY, // 0 - TRR OFF (by default) - MODE_PARALLEL, // 1 - race and use the first response + MODE_RESERVED1, // 1 - Reserved value. Used to be parallel resolve. MODE_TRRFIRST, // 2 - fallback to native on TRR failure MODE_TRRONLY, // 3 - don't even fallback - MODE_SHADOW, // 4 - race for stats, but always use native result + MODE_RESERVED4, // 4 - Reserved value. Used to be race TRR with native. MODE_TRROFF // 5 - identical to MODE_NATIVEONLY but explicitly selected }; } // namespace net @@ -547,6 +548,7 @@ class nsHostResolver : public nsISupports, public AHostResolver { mozilla::TimeDuration mShortIdleTimeout; RefPtr mResolverThreads; + RefPtr mNCS; mozilla::Atomic mShutdown; mozilla::Atomic mNumIdleTasks; diff --git a/netwerk/ipc/ChannelEventQueue.cpp b/netwerk/ipc/ChannelEventQueue.cpp index a940c4c8da..f87ee3b4f1 100644 --- a/netwerk/ipc/ChannelEventQueue.cpp +++ b/netwerk/ipc/ChannelEventQueue.cpp @@ -72,7 +72,7 @@ void ChannelEventQueue::FlushQueue() { // Next event needs to run on another thread. Put it back to // the front of the queue can try resume on that thread. Suspend(); - PrependEvent(event); + PrependEvent(std::move(event)); needResumeOnOtherThread = true; { diff --git a/netwerk/ipc/ChannelEventQueue.h b/netwerk/ipc/ChannelEventQueue.h index 18e86f99f4..23d6bf6cae 100644 --- a/netwerk/ipc/ChannelEventQueue.h +++ b/netwerk/ipc/ChannelEventQueue.h @@ -6,7 +6,6 @@ #define mozilla_net_ChannelEventQueue_h #include "nsTArray.h" -#include "nsAutoPtr.h" #include "nsIEventTarget.h" #include "nsThreadUtils.h" #include "nsXULAppAPI.h" @@ -66,6 +65,58 @@ class NeckoTargetChannelEvent : public ChannelEvent { T* mChild; }; +class ChannelFunctionEvent : public ChannelEvent { + public: + ChannelFunctionEvent( + std::function()>&& aGetEventTarget, + std::function&& aCallback) + : mGetEventTarget(std::move(aGetEventTarget)), + mCallback(std::move(aCallback)) {} + + void Run() override { mCallback(); } + already_AddRefed GetEventTarget() override { + return mGetEventTarget(); + } + + private: + const std::function()> mGetEventTarget; + const std::function mCallback; +}; + +// UnsafePtr is a work-around our static analyzer that requires all +// ref-counted objects to be captured in lambda via a RefPtr +// The ChannelEventQueue makes it safe to capture "this" by pointer only. +// This is required as work-around to prevent cycles until bug 1596295 +// is resolved. +template +class UnsafePtr { + public: + explicit UnsafePtr(T* aPtr) : mPtr(aPtr) {} + + T& operator*() const { return *mPtr; } + T* operator->() const { + MOZ_ASSERT(mPtr, "dereferencing a null pointer"); + return mPtr; + } + operator T*() const& { return mPtr; } + explicit operator bool() const { return mPtr != nullptr; } + + private: + T* const mPtr; +}; + +class NeckoTargetChannelFunctionEvent : public ChannelFunctionEvent { + public: + template + NeckoTargetChannelFunctionEvent(T* aChild, std::function&& aCallback) + : ChannelFunctionEvent( + [child = UnsafePtr(aChild)]() { + MOZ_ASSERT(child); + return child->GetNeckoTarget(); + }, + std::move(aCallback)) {} +}; + // Workaround for Necko re-entrancy dangers. We buffer IPDL messages in a // queue if still dispatching previous one(s) to listeners/observers. // Otherwise synchronous XMLHttpRequests and/or other code that spins the @@ -98,7 +149,7 @@ class ChannelEventQueue final { bool aAssertionWhenNotQueued = false); // Append ChannelEvent in front of the event queue. - inline nsresult PrependEvent(UniquePtr& aEvent); + inline nsresult PrependEvent(UniquePtr&& aEvent); inline nsresult PrependEvents(nsTArray>& aEvents); // After StartForcedQueueing is called, RunOrEnqueue() will start enqueuing @@ -227,7 +278,7 @@ inline void ChannelEventQueue::EndForcedQueueing() { } inline nsresult ChannelEventQueue::PrependEvent( - UniquePtr& aEvent) { + UniquePtr&& aEvent) { MutexAutoLock lock(mMutex); // Prepending event while no queue flush foreseen might cause the following diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 80041316d1..126586e215 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -134,6 +134,7 @@ struct LoadInfoArgs bool serviceWorkerTaintingSynthesized; bool documentHasUserInteracted; bool documentHasLoaded; + bool allowListFutureDocumentsCreatedFromThisRedirectChain; nsString cspNonce; bool isFromProcessingFrameAttributes; CookieSettingsArgs cookieSettings; @@ -174,6 +175,7 @@ struct ParentLoadInfoForwarderArgs bool documentHasUserInteracted; bool documentHasLoaded; + bool allowListFutureDocumentsCreatedFromThisRedirectChain; CookieSettingsArgs? cookieSettings; @@ -201,6 +203,8 @@ struct ChildLoadInfoForwarderArgs // The ServiceWorker controller may be cleared in the child during // a redirect. IPCServiceWorkerDescriptor? controller; + + uint32_t requestBlockingReason; }; //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/about/nsAboutProtocolHandler.cpp b/netwerk/protocol/about/nsAboutProtocolHandler.cpp index c94ec20339..f9c388b77c 100644 --- a/netwerk/protocol/about/nsAboutProtocolHandler.cpp +++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp @@ -15,7 +15,6 @@ #include "nsNetUtil.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" -#include "nsAutoPtr.h" #include "nsIWritablePropertyBag2.h" #include "nsIChannel.h" #include "nsIScriptError.h" diff --git a/netwerk/protocol/file/nsFileChannel.cpp b/netwerk/protocol/file/nsFileChannel.cpp index 93891dad5b..9e51926b56 100644 --- a/netwerk/protocol/file/nsFileChannel.cpp +++ b/netwerk/protocol/file/nsFileChannel.cpp @@ -16,7 +16,6 @@ #include "nsIFileStreams.h" #include "nsFileProtocolHandler.h" #include "nsProxyRelease.h" -#include "nsAutoPtr.h" #include "nsIContentPolicy.h" #include "nsContentUtils.h" diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.h b/netwerk/protocol/ftp/nsFtpConnectionThread.h index 01f1cb55fd..7586c420f8 100644 --- a/netwerk/protocol/ftp/nsFtpConnectionThread.h +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.h @@ -10,7 +10,6 @@ #include "nsString.h" #include "nsCOMPtr.h" #include "nsIAsyncInputStream.h" -#include "nsAutoPtr.h" #include "nsITransport.h" #include "mozilla/net/DNS.h" #include "nsFtpControlConnection.h" diff --git a/netwerk/protocol/ftp/nsFtpControlConnection.h b/netwerk/protocol/ftp/nsFtpControlConnection.h index 4cece5df2f..0e3ce2ae4d 100644 --- a/netwerk/protocol/ftp/nsFtpControlConnection.h +++ b/netwerk/protocol/ftp/nsFtpControlConnection.h @@ -9,7 +9,6 @@ #include "nsISocketTransport.h" #include "nsIAsyncInputStream.h" -#include "nsAutoPtr.h" #include "nsString.h" #include "mozilla/Attributes.h" diff --git a/netwerk/protocol/http/AlternateServices.cpp b/netwerk/protocol/http/AlternateServices.cpp index 47f413455c..961da8e11a 100644 --- a/netwerk/protocol/http/AlternateServices.cpp +++ b/netwerk/protocol/http/AlternateServices.cpp @@ -6,6 +6,7 @@ #include "AlternateServices.h" #include "LoadInfo.h" +#include "nsComponentManagerUtils.h" #include "nsEscape.h" #include "nsHttpConnectionInfo.h" #include "nsHttpChannel.h" @@ -657,38 +658,15 @@ class WellKnownChecker { if (accepted) { MOZ_ASSERT(!mMapping->HTTPS()); // https:// does not use .wk - nsresult rv = uu->Verify(mTransactionAlternate->mWKResponse, mOrigin, - mAlternatePort); + nsresult rv = uu->Verify(mTransactionAlternate->mWKResponse, mOrigin); if (NS_SUCCEEDED(rv)) { bool validWK = false; - bool mixedScheme = false; - int32_t lifetime = 0; Unused << uu->GetValid(&validWK); - Unused << uu->GetLifetime(&lifetime); - Unused << uu->GetMixed(&mixedScheme); if (!validWK) { LOG(("WellKnownChecker::Done %p json parser declares invalid\n%s\n", this, mTransactionAlternate->mWKResponse.get())); accepted = false; } - if (accepted && (lifetime > 0)) { - if (mMapping->TTL() > lifetime) { - LOG(( - "WellKnownChecker::Done %p atl-svc lifetime reduced by .wk\n", - this)); - mMapping->SetExpiresAt(NowInSeconds() + lifetime); - } else { - LOG( - ("WellKnownChecker::Done %p .wk lifetime exceeded alt-svc ma " - "so ignored\n", - this)); - } - } - if (accepted && mixedScheme) { - mMapping->SetMixedScheme(true); - LOG(("WellKnownChecker::Done %p atl-svc .wk allows mixed scheme\n", - this)); - } } else { LOG(("WellKnownChecker::Done %p .wk jason eval failed to run\n", this)); @@ -722,8 +700,7 @@ class WellKnownChecker { nsLoadFlags flags; nsContentPolicyType contentPolicyType = - loadInfo ? loadInfo->GetExternalContentPolicyType() - : nsIContentPolicy::TYPE_OTHER; + loadInfo->GetExternalContentPolicyType(); if (NS_FAILED(gHttpHandler->NewChannelId(channelId)) || NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId, diff --git a/netwerk/protocol/http/ClassifierDummyChannel.cpp b/netwerk/protocol/http/ClassifierDummyChannel.cpp index 21962169d0..b37f56cc73 100644 --- a/netwerk/protocol/http/ClassifierDummyChannel.cpp +++ b/netwerk/protocol/http/ClassifierDummyChannel.cpp @@ -575,9 +575,11 @@ ClassifierDummyChannel::GetProxyURI(nsIURI** aProxyURI) { } void ClassifierDummyChannel::SetCorsPreflightParameters( - const nsTArray& aUnsafeHeaders) {} + const nsTArray& aUnsafeHeaders, + bool aShouldStripRequestBodyHeader) {} void ClassifierDummyChannel::SetAltDataForChild(bool aIsForChild) {} +void ClassifierDummyChannel::DisableAltDataCache() {} NS_IMETHODIMP ClassifierDummyChannel::GetBlockAuthPrompt(bool* aBlockAuthPrompt) { diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index 4e6bc26467..0676afdfc4 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -1914,7 +1914,7 @@ nsresult Http2Session::RecvPushPromise(Http2Session* self) { RefPtr transactionBuffer = new Http2PushTransactionBuffer(); transactionBuffer->SetConnection(self); - nsAutoPtr pushedStream(new Http2PushedStream( + UniquePtr pushedStream(new Http2PushedStream( transactionBuffer, self, associatedStream, promisedID, self->mCurrentForegroundTabOuterContentWindowId)); @@ -1941,7 +1941,7 @@ nsresult Http2Session::RecvPushPromise(Http2Session* self) { return rv; } - WeakPtr pushedWeak = pushedStream.forget(); + WeakPtr pushedWeak = pushedStream.release(); // Ownership of the pushed stream is by the transaction hash, just as it // is for a client initiated stream. Errors that aren't fatal to the diff --git a/netwerk/protocol/http/Http2Stream.h b/netwerk/protocol/http/Http2Stream.h index 08046c7b5c..fddd23101e 100644 --- a/netwerk/protocol/http/Http2Stream.h +++ b/netwerk/protocol/http/Http2Stream.h @@ -247,7 +247,7 @@ class Http2Stream : public nsAHttpSegmentReader, uint64_t mTransactionTabId; private: - friend class nsAutoPtr; + friend class mozilla::DefaultDelete; MOZ_MUST_USE nsresult ParseHttpRequestHeaders(const char*, uint32_t, uint32_t*); diff --git a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp index 63bffb64c0..0ed5938345 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp +++ b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp @@ -181,62 +181,6 @@ IPCResult HttpBackgroundChannelChild::RecvOnStopRequest( return IPC_OK(); } -IPCResult HttpBackgroundChannelChild::RecvOnProgress( - const int64_t& aProgress, const int64_t& aProgressMax) { - LOG(("HttpBackgroundChannelChild::RecvOnProgress [this=%p progress=%" PRId64 - " max=%" PRId64 "]\n", - this, aProgress, aProgressMax)); - MOZ_ASSERT(OnSocketThread()); - - if (NS_WARN_IF(!mChannelChild)) { - return IPC_OK(); - } - - if (IsWaitingOnStartRequest()) { - LOG((" > pending until OnStartRequest [progress=%" PRId64 " max=%" PRId64 - "]\n", - aProgress, aProgressMax)); - - mQueuedRunnables.AppendElement( - NewRunnableMethod( - "HttpBackgroundChannelChild::RecvOnProgress", this, - &HttpBackgroundChannelChild::RecvOnProgress, aProgress, - aProgressMax)); - - return IPC_OK(); - } - - mChannelChild->ProcessOnProgress(aProgress, aProgressMax); - - return IPC_OK(); -} - -IPCResult HttpBackgroundChannelChild::RecvOnStatus(const nsresult& aStatus) { - LOG(("HttpBackgroundChannelChild::RecvOnStatus [this=%p status=%" PRIx32 - "]\n", - this, static_cast(aStatus))); - MOZ_ASSERT(OnSocketThread()); - - if (NS_WARN_IF(!mChannelChild)) { - return IPC_OK(); - } - - if (IsWaitingOnStartRequest()) { - LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n", - static_cast(aStatus))); - - mQueuedRunnables.AppendElement(NewRunnableMethod( - "HttpBackgroundChannelChild::RecvOnStatus", this, - &HttpBackgroundChannelChild::RecvOnStatus, aStatus)); - - return IPC_OK(); - } - - mChannelChild->ProcessOnStatus(aStatus); - - return IPC_OK(); -} - IPCResult HttpBackgroundChannelChild::RecvFlushedForDiversion() { LOG(("HttpBackgroundChannelChild::RecvFlushedForDiversion [this=%p]\n", this)); diff --git a/netwerk/protocol/http/HttpBackgroundChannelChild.h b/netwerk/protocol/http/HttpBackgroundChannelChild.h index 054e1ba76d..18cae62913 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelChild.h +++ b/netwerk/protocol/http/HttpBackgroundChannelChild.h @@ -50,11 +50,6 @@ class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild { const TimeStamp& aLastActiveTabOptHit, const nsHttpHeaderArray& aResponseTrailers); - IPCResult RecvOnProgress(const int64_t& aProgress, - const int64_t& aProgressMax); - - IPCResult RecvOnStatus(const nsresult& aStatus); - IPCResult RecvFlushedForDiversion(); IPCResult RecvDivertMessages(); diff --git a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp index 312ef0fe48..b88977741e 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp +++ b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp @@ -227,58 +227,6 @@ bool HttpBackgroundChannelParent::OnStopRequest( aResponseTrailers); } -bool HttpBackgroundChannelParent::OnProgress(const int64_t& aProgress, - const int64_t& aProgressMax) { - LOG(("HttpBackgroundChannelParent::OnProgress [this=%p progress=%" PRId64 - " max=%" PRId64 "]\n", - this, aProgress, aProgressMax)); - AssertIsInMainProcess(); - - if (NS_WARN_IF(!mIPCOpened)) { - return false; - } - - if (!IsOnBackgroundThread()) { - MutexAutoLock lock(mBgThreadMutex); - nsresult rv = mBackgroundThread->Dispatch( - NewRunnableMethod( - "net::HttpBackgroundChannelParent::OnProgress", this, - &HttpBackgroundChannelParent::OnProgress, aProgress, aProgressMax), - NS_DISPATCH_NORMAL); - - MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); - - return NS_SUCCEEDED(rv); - } - - return SendOnProgress(aProgress, aProgressMax); -} - -bool HttpBackgroundChannelParent::OnStatus(const nsresult& aStatus) { - LOG(("HttpBackgroundChannelParent::OnStatus [this=%p stauts=%" PRIx32 "]\n", - this, static_cast(aStatus))); - AssertIsInMainProcess(); - - if (NS_WARN_IF(!mIPCOpened)) { - return false; - } - - if (!IsOnBackgroundThread()) { - MutexAutoLock lock(mBgThreadMutex); - nsresult rv = mBackgroundThread->Dispatch( - NewRunnableMethod( - "net::HttpBackgroundChannelParent::OnStatus", this, - &HttpBackgroundChannelParent::OnStatus, aStatus), - NS_DISPATCH_NORMAL); - - MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); - - return NS_SUCCEEDED(rv); - } - - return SendOnStatus(aStatus); -} - bool HttpBackgroundChannelParent::OnDiversion() { LOG(("HttpBackgroundChannelParent::OnDiversion [this=%p]\n", this)); AssertIsInMainProcess(); diff --git a/netwerk/protocol/http/HttpBackgroundChannelParent.h b/netwerk/protocol/http/HttpBackgroundChannelParent.h index e34fd85e72..4dfd84d049 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelParent.h +++ b/netwerk/protocol/http/HttpBackgroundChannelParent.h @@ -50,12 +50,6 @@ class HttpBackgroundChannelParent final : public PHttpBackgroundChannelParent { const ResourceTimingStruct& aTiming, const nsHttpHeaderArray& aResponseTrailers); - // To send OnProgress message over background channel. - bool OnProgress(const int64_t& aProgress, const int64_t& aProgressMax); - - // To send OnStatus message over background channel. - bool OnStatus(const nsresult& aStatus); - // To send FlushedForDiversion and DivertMessages messages // over background channel. bool OnDiversion(); diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index e6b6602c2b..80fc17bb0c 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -3,79 +3,75 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // HttpLog.h should generally be included first -#include "HttpLog.h" - #include "mozilla/net/HttpBaseChannel.h" -#include "nsGlobalWindowOuter.h" -#include "nsHttpHandler.h" -#include "nsMimeTypes.h" -#include "nsNetCID.h" -#include "nsNetUtil.h" -#include "nsReadableUtils.h" +#include +#include -#include "mozilla/BasePrincipal.h" -#include "nsICachingChannel.h" -#include "nsIPrincipal.h" -#include "nsIScriptError.h" -#include "nsISeekableStream.h" -#include "nsIStorageStream.h" -#include "nsITimedChannel.h" -#include "nsIEncodedChannel.h" -#include "nsIApplicationCacheChannel.h" -#include "nsIMutableArray.h" -#include "nsEscape.h" -#include "nsStreamListenerWrapper.h" -#include "nsISecurityConsoleMessage.h" -#include "nsURLHelper.h" -#include "nsICookieService.h" -#include "nsIStreamConverterService.h" -#include "nsCRT.h" -#include "nsContentUtils.h" -#include "nsIMutableArray.h" -#include "nsIURIMutator.h" -#include "nsIScriptSecurityManager.h" -#include "nsIObserverService.h" -#include "nsIProtocolProxyService.h" -#include "nsProxyRelease.h" -#include "nsPIDOMWindow.h" -#include "nsIDocShell.h" -#include "nsINetworkInterceptController.h" +#include "HttpBaseChannel.h" +#include "HttpLog.h" +#include "LoadInfo.h" +#include "mozIThirdPartyUtil.h" #include "mozilla/AntiTrackingCommon.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/BinarySearch.h" +#include "mozilla/ConsoleReportCollector.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/InputStreamLengthHelper.h" +#include "mozilla/NullPrincipal.h" +#include "mozilla/Services.h" +#include "mozilla/Telemetry.h" +#include "mozilla/Tokenizer.h" #include "mozilla/dom/Performance.h" #include "mozilla/dom/PerformanceStorage.h" +#include "mozilla/net/PartiallySeekableInputStream.h" +#include "mozilla/net/UrlClassifierCommon.h" #include "mozilla/net/UrlClassifierFeatureFactory.h" -#include "mozilla/NullPrincipal.h" -#include "mozilla/Services.h" -#include "mozIThirdPartyUtil.h" -#include "nsStreamUtils.h" -#include "nsThreadUtils.h" +#include "nsCRT.h" #include "nsContentSecurityManager.h" +#include "nsContentUtils.h" +#include "nsEscape.h" +#include "nsGlobalWindowOuter.h" +#include "nsHttpChannel.h" +#include "nsHttpHandler.h" +#include "nsIApplicationCacheChannel.h" +#include "nsICacheInfoChannel.h" +#include "nsICachingChannel.h" #include "nsIChannelEventSink.h" -#include "nsILoadGroupChild.h" -#include "mozilla/ConsoleReportCollector.h" -#include "LoadInfo.h" -#include "nsISSLSocketControl.h" -#include "mozilla/Telemetry.h" #include "nsIConsoleService.h" -#include "mozilla/BinarySearch.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/Move.h" -#include "mozilla/net/PartiallySeekableInputStream.h" -#include "mozilla/net/UrlClassifierCommon.h" -#include "mozilla/InputStreamLengthHelper.h" -#include "mozilla/Tokenizer.h" +#include "nsICookieService.h" +#include "nsIDOMWindowUtils.h" +#include "nsIDocShell.h" +#include "nsIEncodedChannel.h" #include "nsIHttpHeaderVisitor.h" +#include "nsILoadGroupChild.h" #include "nsIMIMEInputStream.h" -#include "nsICacheInfoChannel.h" -#include "nsIDOMWindowUtils.h" -#include "nsHttpChannel.h" +#include "nsIMutableArray.h" +#include "nsINetworkInterceptController.h" +#include "nsIObserverService.h" +#include "nsIPrincipal.h" +#include "nsIProtocolProxyService.h" +#include "nsISSLSocketControl.h" +#include "nsIScriptError.h" +#include "nsIScriptSecurityManager.h" +#include "nsISecurityConsoleMessage.h" +#include "nsISeekableStream.h" +#include "nsIStorageStream.h" +#include "nsIStreamConverterService.h" +#include "nsITimedChannel.h" +#include "nsIURIMutator.h" +#include "nsMimeTypes.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsPIDOMWindow.h" +#include "nsProxyRelease.h" +#include "nsReadableUtils.h" #include "nsRedirectHistoryEntry.h" #include "nsServerTiming.h" -#include "mozilla/Tokenizer.h" - -#include -#include "HttpBaseChannel.h" +#include "nsStreamListenerWrapper.h" +#include "nsStreamUtils.h" +#include "nsThreadUtils.h" +#include "nsURLHelper.h" namespace mozilla { namespace net { @@ -224,6 +220,7 @@ HttpBaseChannel::HttpBaseChannel() mAfterOnStartRequestBegun(false), mRequireCORSPreflight(false), mAltDataForChild(false), + mDisableAltDataCache(false), mForceMainDocumentChannel(false), mPendingInputStreamLengthOperation(false) { this->mSelfAddr.inet = {}; @@ -279,18 +276,12 @@ void HttpBaseChannel::ReleaseMainThreadOnlyReferences() { } nsTArray> arrayToRelease; - arrayToRelease.AppendElement(mURI.forget()); - arrayToRelease.AppendElement(mOriginalURI.forget()); - arrayToRelease.AppendElement(mDocumentURI.forget()); arrayToRelease.AppendElement(mLoadGroup.forget()); arrayToRelease.AppendElement(mLoadInfo.forget()); arrayToRelease.AppendElement(mCallbacks.forget()); arrayToRelease.AppendElement(mProgressSink.forget()); arrayToRelease.AppendElement(mApplicationCache.forget()); - arrayToRelease.AppendElement(mAPIRedirectToURI.forget()); - arrayToRelease.AppendElement(mProxyURI.forget()); arrayToRelease.AppendElement(mPrincipal.forget()); - arrayToRelease.AppendElement(mTopWindowURI.forget()); arrayToRelease.AppendElement(mContentBlockingAllowListPrincipal.forget()); arrayToRelease.AppendElement(mListener.forget()); arrayToRelease.AppendElement(mCompressListener.forget()); @@ -518,8 +509,7 @@ HttpBaseChannel::SetDocshellUserAgentOverride() { NS_IMETHODIMP HttpBaseChannel::GetOriginalURI(nsIURI** aOriginalURI) { NS_ENSURE_ARG_POINTER(aOriginalURI); - *aOriginalURI = mOriginalURI; - NS_ADDREF(*aOriginalURI); + *aOriginalURI = do_AddRef(mOriginalURI).take(); return NS_OK; } @@ -535,8 +525,7 @@ HttpBaseChannel::SetOriginalURI(nsIURI* aOriginalURI) { NS_IMETHODIMP HttpBaseChannel::GetURI(nsIURI** aURI) { NS_ENSURE_ARG_POINTER(aURI); - *aURI = mURI; - NS_ADDREF(*aURI); + *aURI = do_AddRef(mURI).take(); return NS_OK; } @@ -693,14 +682,14 @@ HttpBaseChannel::GetContentDispositionFilename( return NS_OK; } - return NS_GetFilenameFromDisposition(aContentDispositionFilename, header, - mURI); + return NS_GetFilenameFromDisposition(aContentDispositionFilename, header); } NS_IMETHODIMP HttpBaseChannel::SetContentDispositionFilename( const nsAString& aContentDispositionFilename) { - mContentDispositionFilename = new nsString(aContentDispositionFilename); + mContentDispositionFilename = + MakeUnique(aContentDispositionFilename); return NS_OK; } @@ -1036,13 +1025,13 @@ HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream* aStream, return NS_OK; } -nsresult HttpBaseChannel::ExplicitSetUploadStreamLength( - uint64_t aContentLength, bool aStreamHasHeaders) { +void HttpBaseChannel::ExplicitSetUploadStreamLength(uint64_t aContentLength, + bool aStreamHasHeaders) { // We already have the content length. We don't need to determinate it. mReqContentLength = aContentLength; if (aStreamHasHeaders) { - return NS_OK; + return; } nsAutoCString header; @@ -1052,7 +1041,7 @@ nsresult HttpBaseChannel::ExplicitSetUploadStreamLength( nsAutoCString value; nsresult rv = GetRequestHeader(header, value); if (NS_SUCCEEDED(rv) && !value.IsEmpty()) { - return NS_OK; + return; } // SetRequestHeader propagates headers to chrome if HttpChannelChild @@ -1060,8 +1049,6 @@ nsresult HttpBaseChannel::ExplicitSetUploadStreamLength( nsAutoCString contentLengthStr; contentLengthStr.AppendInt(aContentLength); SetRequestHeader(header, contentLengthStr, false); - - return NS_OK; } NS_IMETHODIMP @@ -1275,8 +1262,9 @@ HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings) { *aEncodings = nullptr; return NS_OK; } - nsContentEncodings* enumerator = new nsContentEncodings(this, encoding.get()); - NS_ADDREF(*aEncodings = enumerator); + RefPtr enumerator = + new nsContentEncodings(this, encoding.get()); + enumerator.forget(aEncodings); return NS_OK; } @@ -1489,8 +1477,6 @@ HttpBaseChannel::IsThirdPartyTrackingResource(bool* aIsTrackingResource) { NS_IMETHODIMP HttpBaseChannel::GetClassificationFlags(uint32_t* aFlags) { - MOZ_ASSERT(!mFirstPartyClassificationFlags || - !mThirdPartyClassificationFlags); if (mThirdPartyClassificationFlags) { *aFlags = mThirdPartyClassificationFlags; } else { @@ -1501,16 +1487,12 @@ HttpBaseChannel::GetClassificationFlags(uint32_t* aFlags) { NS_IMETHODIMP HttpBaseChannel::GetFirstPartyClassificationFlags(uint32_t* aFlags) { - MOZ_ASSERT( - !(mFirstPartyClassificationFlags && mFirstPartyClassificationFlags)); *aFlags = mFirstPartyClassificationFlags; return NS_OK; } NS_IMETHODIMP HttpBaseChannel::GetThirdPartyClassificationFlags(uint32_t* aFlags) { - MOZ_ASSERT( - !(mFirstPartyClassificationFlags && mThirdPartyClassificationFlags)); *aFlags = mThirdPartyClassificationFlags; return NS_OK; } @@ -1908,10 +1890,8 @@ HttpBaseChannel::RedirectTo(nsIURI* targetURI) { // and to bypass CORS for early redirects. // To avoid any bypasses after the channel was flagged by // the WebRequst API, we are dropping the flag here. - if (mLoadInfo) { - mLoadInfo->SetBypassCORSChecks(false); - mLoadInfo->SetAllowInsecureRedirectToDataURI(false); - } + mLoadInfo->SetBypassCORSChecks(false); + mLoadInfo->SetAllowInsecureRedirectToDataURI(false); return NS_OK; } @@ -2159,8 +2139,8 @@ HttpBaseChannel::SetCookie(const nsACString& aCookieHeader) { nsAutoCString date; // empty date is not an error Unused << mResponseHead->GetHeader(nsHttp::Date, date); - nsresult rv = cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, - aCookieHeader, date, this); + nsresult rv = + cs->SetCookieStringFromHttp(mURI, nullptr, aCookieHeader, date, this); if (NS_SUCCEEDED(rv)) { NotifySetCookie(aCookieHeader); } @@ -2220,7 +2200,7 @@ HttpBaseChannel::SetChannelIsForDownload(bool aChannelIsForDownload) { NS_IMETHODIMP HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray* cacheKeys) { - mRedirectedCachekeys = cacheKeys; + mRedirectedCachekeys = WrapUnique(cacheKeys); return NS_OK; } @@ -2862,10 +2842,6 @@ void HttpBaseChannel::RemoveAsNonTailRequest() { void HttpBaseChannel::AssertPrivateBrowsingId() { nsCOMPtr loadContext; NS_QueryNotificationCallbacks(this, loadContext); - // For addons it's possible that mLoadInfo is null. - if (!mLoadInfo) { - return; - } if (!loadContext) { return; @@ -2874,8 +2850,8 @@ void HttpBaseChannel::AssertPrivateBrowsingId() { // We skip testing of favicon loading here since it could be triggered by XUL // image which uses SystemPrincipal. The SystemPrincpal doesn't have // mPrivateBrowsingId. - if (mLoadInfo->LoadingPrincipal() && - mLoadInfo->LoadingPrincipal()->IsSystemPrincipal() && + if (mLoadInfo->GetLoadingPrincipal() && + mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal() && mLoadInfo->InternalContentPolicyType() == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) { return; @@ -2894,10 +2870,6 @@ already_AddRefed HttpBaseChannel::CloneLoadInfoForRedirect( nsIURI* newURI, uint32_t redirectFlags) { // make a copy of the loadinfo, append to the redirectchain // this will be set on the newly created channel for the redirect target. - if (!mLoadInfo) { - return nullptr; - } - nsCOMPtr newLoadInfo = static_cast(mLoadInfo.get())->Clone(); @@ -3046,7 +3018,7 @@ void HttpBaseChannel::DoNotifyListener() { if (!IsNavigation()) { if (mLoadGroup) { FlushConsoleReports(mLoadGroup); - } else if (mLoadInfo) { + } else { RefPtr doc; mLoadInfo->GetLoadingDocument(getter_AddRefs(doc)); FlushConsoleReports(doc); @@ -3111,6 +3083,27 @@ bool HttpBaseChannel::ShouldRewriteRedirectToGET( return false; } +NS_IMETHODIMP +HttpBaseChannel::ShouldStripRequestBodyHeader(const nsACString& aMethod, + bool* aResult) { + *aResult = false; + uint32_t httpStatus = 0; + if (NS_FAILED(GetResponseStatus(&httpStatus))) { + return NS_OK; + } + + nsAutoCString method(aMethod); + nsHttpRequestHead::ParsedMethodType parsedMethod; + nsHttpRequestHead::ParseMethod(method, parsedMethod); + // Fetch 4.4.11, which is slightly different than the perserved method + // algrorithm: strip request-body-header for GET->GET redirection for 303. + *aResult = + ShouldRewriteRedirectToGET(httpStatus, parsedMethod) && + !(httpStatus == 303 && parsedMethod == nsHttpRequestHead::kMethod_Get); + + return NS_OK; +} + nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, nsIChannel* newChannel, bool preserveMethod, @@ -3180,7 +3173,7 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, httpInternal->SetLastRedirectFlags(redirectFlags); if (mRequireCORSPreflight) { - httpInternal->SetCorsPreflightParameters(mUnsafeHeaders); + httpInternal->SetCorsPreflightParameters(mUnsafeHeaders, false); } } @@ -3326,8 +3319,7 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, realChannel->SetContentBlockingAllowListPrincipal( mContentBlockingAllowListPrincipal); - rv = realChannel->SetTopWindowURI(mTopWindowURI); - MOZ_ASSERT(NS_SUCCEEDED(rv)); + realChannel->SetTopWindowURI(mTopWindowURI); } // update the DocumentURI indicator since we are being redirected. @@ -3348,7 +3340,7 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, "[this=%p] transferring chain of redirect cache-keys", this)); rv = httpInternal->SetCacheKeysRedirectChain( - mRedirectedCachekeys.forget()); + mRedirectedCachekeys.release()); MOZ_ASSERT(NS_SUCCEEDED(rv)); } @@ -3365,6 +3357,9 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, MOZ_ASSERT(NS_SUCCEEDED(rv)); httpInternal->SetAltDataForChild(mAltDataForChild); + if (mDisableAltDataCache) { + httpInternal->DisableAltDataCache(); + } } // transfer application cache information @@ -3455,7 +3450,7 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, // AllRedirectsPassTimingAllowCheck on them. if (loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) { - nsCOMPtr principal = loadInfo->LoadingPrincipal(); + nsCOMPtr principal = loadInfo->GetLoadingPrincipal(); newTimedChannel->SetAllRedirectsPassTimingAllowCheck( mAllRedirectsPassTimingAllowCheck && oldTimedChannel->TimingAllowCheck(principal)); @@ -3710,7 +3705,7 @@ HttpBaseChannel::TimingAllowCheck(nsIPrincipal* aOrigin, bool* _retval) { } nsAutoCString origin; - nsContentUtils::GetASCIIOrigin(aOrigin, origin); + aOrigin->GetAsciiOrigin(origin); Tokenizer p(headerValue); Tokenizer::Token t; @@ -3945,48 +3940,7 @@ mozilla::dom::PerformanceStorage* HttpBaseChannel::GetPerformanceStorage() { if (XRE_IsE10sParentProcess()) { return nullptr; } - - if (!mLoadInfo) { - return nullptr; - } - - // If a custom performance storage is set, let's use it. - mozilla::dom::PerformanceStorage* performanceStorage = - mLoadInfo->GetPerformanceStorage(); - if (performanceStorage) { - return performanceStorage; - } - - RefPtr loadingDocument; - mLoadInfo->GetLoadingDocument(getter_AddRefs(loadingDocument)); - if (!loadingDocument) { - return nullptr; - } - - if (!mLoadInfo->TriggeringPrincipal()->Equals( - loadingDocument->NodePrincipal())) { - return nullptr; - } - - if (mLoadInfo->GetExternalContentPolicyType() == - nsIContentPolicy::TYPE_SUBDOCUMENT && - !mLoadInfo->GetIsFromProcessingFrameAttributes()) { - // We only report loads caused by processing the attributes of the - // browsing context container. - return nullptr; - } - - nsCOMPtr innerWindow = loadingDocument->GetInnerWindow(); - if (!innerWindow) { - return nullptr; - } - - mozilla::dom::Performance* performance = innerWindow->GetPerformance(); - if (!performance) { - return nullptr; - } - - return performance->AsPerformanceStorage(); + return mLoadInfo->GetPerformanceStorage(); } void HttpBaseChannel::MaybeReportTimingData() { @@ -4139,11 +4093,20 @@ void HttpBaseChannel::EnsureTopLevelOuterContentWindowId() { } void HttpBaseChannel::SetCorsPreflightParameters( - const nsTArray& aUnsafeHeaders) { + const nsTArray& aUnsafeHeaders, + bool aShouldStripRequestBodyHeader) { MOZ_RELEASE_ASSERT(!mRequestObserversCalled); mRequireCORSPreflight = true; mUnsafeHeaders = aUnsafeHeaders; + if (aShouldStripRequestBodyHeader) { + mUnsafeHeaders.RemoveElementsBy([&](const nsCString& aHeader) { + return aHeader.LowerCaseEqualsASCII("content-type") || + aHeader.LowerCaseEqualsASCII("content-encoding") || + aHeader.LowerCaseEqualsASCII("content-language") || + aHeader.LowerCaseEqualsASCII("content-location"); + }); + } } void HttpBaseChannel::SetAltDataForChild(bool aIsForChild) { @@ -4243,7 +4206,7 @@ void HttpBaseChannel::CallTypeSniffers(void* aClosure, const uint8_t* aData, template static void ParseServerTimingHeader( - const nsAutoPtr& aHeader, nsTArray>& aOutput) { + const UniquePtr& aHeader, nsTArray>& aOutput) { if (!aHeader) { return; } diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 4ec0077ad6..d86f91b6c7 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -5,49 +5,48 @@ #ifndef mozilla_net_HttpBaseChannel_h #define mozilla_net_HttpBaseChannel_h +#include + #include "mozilla/Atomics.h" -#include "nsHttp.h" -#include "nsAutoPtr.h" +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/Tuple.h" +#include "mozilla/dom/ReferrerInfo.h" +#include "mozilla/net/ChannelEventQueue.h" +#include "mozilla/net/DNS.h" +#include "mozilla/net/NeckoCommon.h" +#include "mozilla/net/PrivateBrowsingChannel.h" +#include "nsCOMArray.h" +#include "nsCOMPtr.h" #include "nsHashPropertyBag.h" -#include "nsProxyInfo.h" +#include "nsHttp.h" +#include "nsHttpConnectionInfo.h" +#include "nsHttpHandler.h" #include "nsHttpRequestHead.h" #include "nsHttpResponseHead.h" -#include "nsHttpConnectionInfo.h" +#include "nsIApplicationCache.h" +#include "nsIClassOfService.h" +#include "nsIClassifiedChannel.h" #include "nsIConsoleReportCollector.h" #include "nsIEncodedChannel.h" -#include "nsIHttpChannel.h" -#include "nsHttpHandler.h" -#include "nsIHttpChannelInternal.h" #include "nsIForcePendingChannel.h" #include "nsIFormPOSTActionChannel.h" -#include "nsIUploadChannel2.h" +#include "nsIHttpChannel.h" +#include "nsIHttpChannelInternal.h" +#include "nsILoadInfo.h" #include "nsIProgressEventSink.h" -#include "nsIURI.h" -#include "nsIStringEnumerator.h" -#include "nsISupportsPriority.h" -#include "nsIClassOfService.h" -#include "nsIClassifiedChannel.h" -#include "nsIApplicationCache.h" #include "nsIResumableChannel.h" -#include "nsITraceableChannel.h" -#include "nsILoadInfo.h" -#include "mozilla/net/NeckoCommon.h" -#include "nsThreadUtils.h" -#include "mozilla/net/PrivateBrowsingChannel.h" -#include "mozilla/net/DNS.h" -#include "nsITimedChannel.h" -#include "nsIHttpChannel.h" #include "nsISecurityConsoleMessage.h" -#include "nsCOMArray.h" -#include "mozilla/net/ChannelEventQueue.h" -#include "mozilla/Move.h" -#include "mozilla/Tuple.h" +#include "nsIStringEnumerator.h" +#include "nsISupportsPriority.h" #include "nsIThrottledInputChannel.h" -#include "nsTArray.h" -#include "nsCOMPtr.h" -#include "mozilla/IntegerPrintfMacros.h" +#include "nsITimedChannel.h" +#include "nsITraceableChannel.h" +#include "nsIURI.h" +#include "nsIUploadChannel2.h" +#include "nsProxyInfo.h" #include "nsStringEnumerator.h" -#include "mozilla/dom/ReferrerInfo.h" +#include "nsTArray.h" +#include "nsThreadUtils.h" #define HTTP_BASE_CHANNEL_IID \ { \ @@ -191,6 +190,8 @@ class HttpBaseChannel : public nsHashPropertyBag, NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor* visitor) override; NS_IMETHOD VisitNonDefaultRequestHeaders( nsIHttpHeaderVisitor* visitor) override; + NS_IMETHOD ShouldStripRequestBodyHeader(const nsACString& aMethod, + bool* aResult) override; NS_IMETHOD GetResponseHeader(const nsACString& header, nsACString& value) override; NS_IMETHOD SetResponseHeader(const nsACString& header, @@ -299,8 +300,11 @@ class HttpBaseChannel : public nsHashPropertyBag, NS_IMETHOD SetTopWindowURIIfUnknown(nsIURI* aTopWindowURI) override; NS_IMETHOD GetProxyURI(nsIURI** proxyURI) override; virtual void SetCorsPreflightParameters( - const nsTArray& unsafeHeaders) override; + const nsTArray& unsafeHeaders, + bool aShouldStripRequestBodyHeader) override; virtual void SetAltDataForChild(bool aIsForChild) override; + virtual void DisableAltDataCache() override { mDisableAltDataCache = true; }; + NS_IMETHOD GetConnectionInfoHashKey( nsACString& aConnectionInfoHashKey) override; NS_IMETHOD GetIntegrityMetadata(nsAString& aIntegrityMetadata) override; @@ -387,9 +391,11 @@ class HttpBaseChannel : public nsHashPropertyBag, bool mReady; }; - nsHttpResponseHead* GetResponseHead() const { return mResponseHead; } + nsHttpResponseHead* GetResponseHead() const { return mResponseHead.get(); } nsHttpRequestHead* GetRequestHead() { return &mRequestHead; } - nsHttpHeaderArray* GetResponseTrailers() const { return mResponseTrailers; } + nsHttpHeaderArray* GetResponseTrailers() const { + return mResponseTrailers.get(); + } const NetAddr& GetSelfAddr() { return mSelfAddr; } const NetAddr& GetPeerAddr() { return mPeerAddr; } @@ -448,10 +454,7 @@ class HttpBaseChannel : public nsHashPropertyBag, return mRequestHead.ClearHeader(nsHttp::Referer); } - MOZ_MUST_USE nsresult SetTopWindowURI(nsIURI* aTopWindowURI) { - mTopWindowURI = aTopWindowURI; - return NS_OK; - } + void SetTopWindowURI(nsIURI* aTopWindowURI) { mTopWindowURI = aTopWindowURI; } void SetContentBlockingAllowListPrincipal(nsIPrincipal* aPrincipal) { mContentBlockingAllowListPrincipal = aPrincipal; @@ -567,8 +570,8 @@ class HttpBaseChannel : public nsHashPropertyBag, // Proxy release all members above on main thread. void ReleaseMainThreadOnlyReferences(); - nsresult ExplicitSetUploadStreamLength(uint64_t aContentLength, - bool aStreamHasHeaders); + void ExplicitSetUploadStreamLength(uint64_t aContentLength, + bool aStreamHasHeaders); void MaybeResumeAsyncOpen(); @@ -605,17 +608,17 @@ class HttpBaseChannel : public nsHashPropertyBag, nsCOMPtr mThrottleQueue; nsCOMPtr mUploadStream; nsCOMPtr mUploadCloneableCallback; - nsAutoPtr mResponseHead; - nsAutoPtr mResponseTrailers; + UniquePtr mResponseHead; + UniquePtr mResponseTrailers; RefPtr mConnectionInfo; nsCOMPtr mProxyInfo; nsCOMPtr mSecurityInfo; nsCOMPtr mUpgradeProtocolCallback; - nsAutoPtr mContentDispositionFilename; + UniquePtr mContentDispositionFilename; nsCOMPtr mReportCollector; RefPtr mHttpHandler; // keep gHttpHandler alive - nsAutoPtr> mRedirectedCachekeys; + UniquePtr> mRedirectedCachekeys; nsCOMPtr mRequestContext; NetAddr mSelfAddr; @@ -788,6 +791,11 @@ class HttpBaseChannel : public nsHashPropertyBag, // consumer is in the child process. bool mAltDataForChild; + // This flag will be true if the consumer cannot process alt-data. This + // is used in the webextension StreamFilter handler. If true, we bypass + // using alt-data for the request. + bool mDisableAltDataCache; + bool mForceMainDocumentChannel; // This is set true if the channel is waiting for the // InputStreamLengthHelper::GetAsyncLength callback. diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 44adfdcaed..916493bdc4 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -87,8 +87,8 @@ InterceptStreamListener::OnStartRequest(nsIRequest* aRequest) { } NS_IMETHODIMP -InterceptStreamListener::OnStatus(nsIRequest* aRequest, nsISupports* aContext, - nsresult status, const char16_t* aStatusArg) { +InterceptStreamListener::OnStatus(nsIRequest* aRequest, nsresult status, + const char16_t* aStatusArg) { if (mOwner) { mOwner->DoOnStatus(mOwner, status); } @@ -96,8 +96,8 @@ InterceptStreamListener::OnStatus(nsIRequest* aRequest, nsISupports* aContext, } NS_IMETHODIMP -InterceptStreamListener::OnProgress(nsIRequest* aRequest, nsISupports* aContext, - int64_t aProgress, int64_t aProgressMax) { +InterceptStreamListener::OnProgress(nsIRequest* aRequest, int64_t aProgress, + int64_t aProgressMax) { if (mOwner) { mOwner->DoOnProgress(mOwner, aProgress, aProgressMax); } @@ -122,11 +122,10 @@ InterceptStreamListener::OnDataAvailable(nsIRequest* aRequest, nsAutoCString host; uri->GetHost(host); - OnStatus(mOwner, nullptr, NS_NET_STATUS_READING, - NS_ConvertUTF8toUTF16(host).get()); + OnStatus(mOwner, NS_NET_STATUS_READING, NS_ConvertUTF8toUTF16(host).get()); int64_t progress = aOffset + aCount; - OnProgress(mOwner, nullptr, progress, mOwner->mSynthesizedStreamLength); + OnProgress(mOwner, progress, mOwner->mSynthesizedStreamLength); } mOwner->DoOnDataAvailable(mOwner, nullptr, aInputStream, aOffset, aCount); @@ -217,7 +216,7 @@ void HttpChannelChild::ReleaseMainThreadOnlyReferences() { arrayToRelease.AppendElement(mRedirectChannelChild.forget()); // To solve multiple inheritence of nsISupports in InterceptStreamListener - nsCOMPtr listener = mInterceptListener.forget(); + nsCOMPtr listener = std::move(mInterceptListener); arrayToRelease.AppendElement(listener.forget()); arrayToRelease.AppendElement(mInterceptedRedirectListener.forget()); @@ -332,7 +331,7 @@ void HttpChannelChild::OnBackgroundChildDestroyed( } mBgChild = nullptr; - callback = mBgInitFailCallback.forget(); + callback = std::move(mBgInitFailCallback); } if (callback) { @@ -341,131 +340,37 @@ void HttpChannelChild::OnBackgroundChildDestroyed( } } -class AssociateApplicationCacheEvent - : public NeckoTargetChannelEvent { - public: - AssociateApplicationCacheEvent(HttpChannelChild* aChild, - const nsCString& aGroupID, - const nsCString& aClientID) - : NeckoTargetChannelEvent(aChild), - groupID(aGroupID), - clientID(aClientID) {} - - void Run() override { mChild->AssociateApplicationCache(groupID, clientID); } - - private: - nsCString groupID; - nsCString clientID; -}; - mozilla::ipc::IPCResult HttpChannelChild::RecvAssociateApplicationCache( - const nsCString& groupID, const nsCString& clientID) { + const nsCString& aGroupID, const nsCString& aClientID) { LOG(("HttpChannelChild::RecvAssociateApplicationCache [this=%p]\n", this)); - mEventQ->RunOrEnqueue( - new AssociateApplicationCacheEvent(this, groupID, clientID)); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr(this), aGroupID, aClientID]() { + self->AssociateApplicationCache(aGroupID, aClientID); + })); return IPC_OK(); } -void HttpChannelChild::AssociateApplicationCache(const nsCString& groupID, - const nsCString& clientID) { +void HttpChannelChild::AssociateApplicationCache(const nsCString& aGroupID, + const nsCString& aClientID) { LOG(("HttpChannelChild::AssociateApplicationCache [this=%p]\n", this)); mApplicationCache = new nsApplicationCache(); mLoadedFromApplicationCache = true; - mApplicationCache->InitAsHandle(groupID, clientID); + mApplicationCache->InitAsHandle(aGroupID, aClientID); } -class StartRequestEvent : public NeckoTargetChannelEvent { - public: - StartRequestEvent( - HttpChannelChild* aChild, const nsresult& aChannelStatus, - const nsHttpResponseHead& aResponseHead, const bool& aUseResponseHead, - const nsHttpHeaderArray& aRequestHeaders, - const ParentLoadInfoForwarderArgs& loadInfoForwarder, - const bool& aIsFromCache, const bool& aIsRacing, - const bool& aCacheEntryAvailable, const uint64_t& aCacheEntryId, - const int32_t& aCacheFetchCount, const uint32_t& aCacheExpirationTime, - const nsCString& aCachedCharset, - const nsCString& aSecurityInfoSerialization, const NetAddr& aSelfAddr, - const NetAddr& aPeerAddr, const uint32_t& aCacheKey, - const nsCString& altDataType, const int64_t& altDataLen, - const bool& deliveringAltData, const bool& aApplyConversion, - const bool& aIsResolvedByTRR, const ResourceTimingStruct& aTiming, - const bool& aAllRedirectsSameOrigin) - : NeckoTargetChannelEvent(aChild), - mChannelStatus(aChannelStatus), - mResponseHead(aResponseHead), - mRequestHeaders(aRequestHeaders), - mUseResponseHead(aUseResponseHead), - mApplyConversion(aApplyConversion), - mIsFromCache(aIsFromCache), - mIsRacing(aIsRacing), - mCacheEntryAvailable(aCacheEntryAvailable), - mCacheEntryId(aCacheEntryId), - mCacheFetchCount(aCacheFetchCount), - mCacheExpirationTime(aCacheExpirationTime), - mCachedCharset(aCachedCharset), - mSecurityInfoSerialization(aSecurityInfoSerialization), - mSelfAddr(aSelfAddr), - mPeerAddr(aPeerAddr), - mCacheKey(aCacheKey), - mAltDataType(altDataType), - mAltDataLen(altDataLen), - mDeliveringAltData(deliveringAltData), - mLoadInfoForwarder(loadInfoForwarder), - mIsResolvedByTRR(aIsResolvedByTRR), - mTiming(aTiming), - mAllRedirectsSameOrigin(aAllRedirectsSameOrigin) {} - - void Run() override { - LOG(("StartRequestEvent [this=%p]\n", mChild)); - mChild->OnStartRequest( - mChannelStatus, mResponseHead, mUseResponseHead, mRequestHeaders, - mLoadInfoForwarder, mIsFromCache, mIsRacing, mCacheEntryAvailable, - mCacheEntryId, mCacheFetchCount, mCacheExpirationTime, mCachedCharset, - mSecurityInfoSerialization, mSelfAddr, mPeerAddr, mCacheKey, - mAltDataType, mAltDataLen, mDeliveringAltData, mApplyConversion, - mIsResolvedByTRR, mTiming, mAllRedirectsSameOrigin); - } - - private: - nsresult mChannelStatus; - nsHttpResponseHead mResponseHead; - nsHttpHeaderArray mRequestHeaders; - bool mUseResponseHead; - bool mApplyConversion; - bool mIsFromCache; - bool mIsRacing; - bool mCacheEntryAvailable; - uint64_t mCacheEntryId; - int32_t mCacheFetchCount; - uint32_t mCacheExpirationTime; - nsCString mCachedCharset; - nsCString mSecurityInfoSerialization; - NetAddr mSelfAddr; - NetAddr mPeerAddr; - uint32_t mCacheKey; - nsCString mAltDataType; - int64_t mAltDataLen; - bool mDeliveringAltData; - ParentLoadInfoForwarderArgs mLoadInfoForwarder; - bool mIsResolvedByTRR; - ResourceTimingStruct mTiming; - bool mAllRedirectsSameOrigin; -}; - mozilla::ipc::IPCResult HttpChannelChild::RecvOnStartRequest( - const nsresult& channelStatus, const nsHttpResponseHead& responseHead, - const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders, - const ParentLoadInfoForwarderArgs& loadInfoForwarder, - const bool& isFromCache, const bool& isRacing, - const bool& cacheEntryAvailable, const uint64_t& cacheEntryId, - const int32_t& cacheFetchCount, const uint32_t& cacheExpirationTime, - const nsCString& cachedCharset, const nsCString& securityInfoSerialization, - const NetAddr& selfAddr, const NetAddr& peerAddr, - const int16_t& redirectCount, const uint32_t& cacheKey, - const nsCString& altDataType, const int64_t& altDataLen, - const bool& deliveringAltData, const bool& aApplyConversion, + const nsresult& aChannelStatus, const nsHttpResponseHead& aResponseHead, + const bool& aUseResponseHead, const nsHttpHeaderArray& aRequestHeaders, + const ParentLoadInfoForwarderArgs& aLoadInfoForwarder, + const bool& aIsFromCache, const bool& aIsRacing, + const bool& aCacheEntryAvailable, const uint64_t& aCacheEntryId, + const int32_t& aCacheFetchCount, const uint32_t& aCacheExpirationTime, + const nsCString& aCachedCharset, const nsCString& aSecurityInfoSerialization, + const NetAddr& aSelfAddr, const NetAddr& aPeerAddr, + const int16_t& aRedirectCount, const uint32_t& aCacheKey, + const nsCString& aAltDataType, const int64_t& aAltDataLen, + const bool& aDeliveringAltData, const bool& aApplyConversion, const bool& aIsResolvedByTRR, const ResourceTimingStruct& aTiming, const bool& aAllRedirectsSameOrigin) { AUTO_PROFILER_LABEL("HttpChannelChild::RecvOnStartRequest", NETWORK); @@ -479,15 +384,26 @@ mozilla::ipc::IPCResult HttpChannelChild::RecvOnStartRequest( !mDivertingToParent, "mDivertingToParent should be unset before OnStartRequest!"); - mRedirectCount = redirectCount; - - mEventQ->RunOrEnqueue(new StartRequestEvent( - this, channelStatus, responseHead, useResponseHead, requestHeaders, - loadInfoForwarder, isFromCache, isRacing, cacheEntryAvailable, - cacheEntryId, cacheFetchCount, cacheExpirationTime, cachedCharset, - securityInfoSerialization, selfAddr, peerAddr, cacheKey, altDataType, - altDataLen, deliveringAltData, aApplyConversion, aIsResolvedByTRR, - aTiming, aAllRedirectsSameOrigin)); + mRedirectCount = aRedirectCount; + + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, + [self = UnsafePtr(this), aChannelStatus, aResponseHead, + aUseResponseHead, aRequestHeaders, aLoadInfoForwarder, aIsFromCache, + aIsRacing, aCacheEntryAvailable, aCacheEntryId, aCacheFetchCount, + aCacheExpirationTime, aCachedCharset, aSecurityInfoSerialization, + aSelfAddr, aPeerAddr, aCacheKey, aAltDataType, aAltDataLen, + aDeliveringAltData, aApplyConversion, aIsResolvedByTRR, aTiming, + aAllRedirectsSameOrigin]() { + self->OnStartRequest( + aChannelStatus, aResponseHead, aUseResponseHead, aRequestHeaders, + aLoadInfoForwarder, aIsFromCache, aIsRacing, aCacheEntryAvailable, + aCacheEntryId, aCacheFetchCount, aCacheExpirationTime, + aCachedCharset, aSecurityInfoSerialization, aSelfAddr, aPeerAddr, + aCacheKey, aAltDataType, aAltDataLen, aDeliveringAltData, + aApplyConversion, aIsResolvedByTRR, aTiming, + aAllRedirectsSameOrigin); + })); { // Child's mEventQ is to control the execution order of the IPC messages @@ -511,16 +427,16 @@ mozilla::ipc::IPCResult HttpChannelChild::RecvOnStartRequest( } void HttpChannelChild::OnStartRequest( - const nsresult& channelStatus, const nsHttpResponseHead& responseHead, - const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders, - const ParentLoadInfoForwarderArgs& loadInfoForwarder, - const bool& isFromCache, const bool& isRacing, - const bool& cacheEntryAvailable, const uint64_t& cacheEntryId, - const int32_t& cacheFetchCount, const uint32_t& cacheExpirationTime, - const nsCString& cachedCharset, const nsCString& securityInfoSerialization, - const NetAddr& selfAddr, const NetAddr& peerAddr, const uint32_t& cacheKey, - const nsCString& altDataType, const int64_t& altDataLen, - const bool& deliveringAltData, const bool& aApplyConversion, + const nsresult& aChannelStatus, const nsHttpResponseHead& aResponseHead, + const bool& aUseResponseHead, const nsHttpHeaderArray& aRequestHeaders, + const ParentLoadInfoForwarderArgs& aLoadInfoForwarder, + const bool& aIsFromCache, const bool& aIsRacing, + const bool& aCacheEntryAvailable, const uint64_t& aCacheEntryId, + const int32_t& aCacheFetchCount, const uint32_t& aCacheExpirationTime, + const nsCString& aCachedCharset, const nsCString& aSecurityInfoSerialization, + const NetAddr& aSelfAddr, const NetAddr& aPeerAddr, const uint32_t& aCacheKey, + const nsCString& aAltDataType, const int64_t& aAltDataLen, + const bool& aDeliveringAltData, const bool& aApplyConversion, const bool& aIsResolvedByTRR, const ResourceTimingStruct& aTiming, const bool& aAllRedirectsSameOrigin) { LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this)); @@ -543,39 +459,39 @@ void HttpChannelChild::OnStartRequest( } if (!mCanceled && NS_SUCCEEDED(mStatus)) { - mStatus = channelStatus; + mStatus = aChannelStatus; } // Cookies headers should not be visible to the child process - MOZ_ASSERT(!requestHeaders.HasHeader(nsHttp::Cookie)); - MOZ_ASSERT(!nsHttpResponseHead(responseHead).HasHeader(nsHttp::Set_Cookie)); + MOZ_ASSERT(!aRequestHeaders.HasHeader(nsHttp::Cookie)); + MOZ_ASSERT(!nsHttpResponseHead(aResponseHead).HasHeader(nsHttp::Set_Cookie)); - if (useResponseHead && !mCanceled) - mResponseHead = new nsHttpResponseHead(responseHead); + if (aUseResponseHead && !mCanceled) + mResponseHead = MakeUnique(aResponseHead); - if (!securityInfoSerialization.IsEmpty()) { - nsresult rv = NS_DeserializeObject(securityInfoSerialization, + if (!aSecurityInfoSerialization.IsEmpty()) { + nsresult rv = NS_DeserializeObject(aSecurityInfoSerialization, getter_AddRefs(mSecurityInfo)); MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserializing security info should not fail"); Unused << rv; // So we don't get an unused error in release builds. } - ipc::MergeParentLoadInfoForwarder(loadInfoForwarder, mLoadInfo); + ipc::MergeParentLoadInfoForwarder(aLoadInfoForwarder, mLoadInfo); - mIsFromCache = isFromCache; - mIsRacing = isRacing; - mCacheEntryAvailable = cacheEntryAvailable; - mCacheEntryId = cacheEntryId; - mCacheFetchCount = cacheFetchCount; - mCacheExpirationTime = cacheExpirationTime; - mCachedCharset = cachedCharset; - mSelfAddr = selfAddr; - mPeerAddr = peerAddr; - - mAvailableCachedAltDataType = altDataType; - mDeliveringAltData = deliveringAltData; - mAltDataLength = altDataLen; + mIsFromCache = aIsFromCache; + mIsRacing = aIsRacing; + mCacheEntryAvailable = aCacheEntryAvailable; + mCacheEntryId = aCacheEntryId; + mCacheFetchCount = aCacheFetchCount; + mCacheExpirationTime = aCacheExpirationTime; + mCachedCharset = aCachedCharset; + mSelfAddr = aSelfAddr; + mPeerAddr = aPeerAddr; + + mAvailableCachedAltDataType = aAltDataType; + mDeliveringAltData = aDeliveringAltData; + mAltDataLength = aAltDataLen; mResolvedByTRR = aIsResolvedByTRR; SetApplyConversion(aApplyConversion); @@ -584,10 +500,10 @@ void HttpChannelChild::OnStartRequest( AutoEventEnqueuer ensureSerialDispatch(mEventQ); - mCacheKey = cacheKey; + mCacheKey = aCacheKey; // replace our request headers with what actually got sent in the parent - mRequestHead.SetHeaders(requestHeaders); + mRequestHead.SetHeaders(aRequestHeaders); // Note: this is where we would notify "http-on-examine-response" observers. // We have deliberately disabled this for child processes (see bug 806753) @@ -714,38 +630,6 @@ void HttpChannelChild::DoOnStartRequest(nsIRequest* aRequest, } } -class TransportAndDataEvent : public ChannelEvent { - public: - TransportAndDataEvent(HttpChannelChild* child, const nsresult& channelStatus, - const nsresult& transportStatus, const nsCString& data, - const uint64_t& offset, const uint32_t& count) - : mChild(child), - mChannelStatus(channelStatus), - mTransportStatus(transportStatus), - mData(data), - mOffset(offset), - mCount(count) {} - - void Run() override { - mChild->OnTransportAndData(mChannelStatus, mTransportStatus, mOffset, - mCount, mData); - } - - already_AddRefed GetEventTarget() override { - MOZ_ASSERT(mChild); - nsCOMPtr target = mChild->GetODATarget(); - return target.forget(); - } - - private: - HttpChannelChild* mChild; - nsresult mChannelStatus; - nsresult mTransportStatus; - nsCString mData; - uint64_t mOffset; - uint32_t mCount; -}; - void HttpChannelChild::ProcessOnTransportAndData( const nsresult& aChannelStatus, const nsresult& aTransportStatus, const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData) { @@ -754,48 +638,37 @@ void HttpChannelChild::ProcessOnTransportAndData( MOZ_RELEASE_ASSERT(!mFlushedForDiversion, "Should not be receiving any more callbacks from parent!"); mEventQ->RunOrEnqueue( - new TransportAndDataEvent(this, aChannelStatus, aTransportStatus, aData, - aOffset, aCount), + new ChannelFunctionEvent([self = UnsafePtr( + this)]() { return self->GetODATarget(); }, + [self = UnsafePtr(this), + aChannelStatus, aTransportStatus, aOffset, + aCount, aData]() { + self->OnTransportAndData( + aChannelStatus, aTransportStatus, aOffset, + aCount, aData); + }), mDivertingToParent); } -class MaybeDivertOnDataHttpEvent - : public NeckoTargetChannelEvent { - public: - MaybeDivertOnDataHttpEvent(HttpChannelChild* child, const nsCString& data, - const uint64_t& offset, const uint32_t& count) - : NeckoTargetChannelEvent(child), - mData(data), - mOffset(offset), - mCount(count) {} - - void Run() override { mChild->MaybeDivertOnData(mData, mOffset, mCount); } - - private: - nsCString mData; - uint64_t mOffset; - uint32_t mCount; -}; - -void HttpChannelChild::MaybeDivertOnData(const nsCString& data, - const uint64_t& offset, - const uint32_t& count) { +void HttpChannelChild::MaybeDivertOnData(const nsCString& aData, + const uint64_t& aOffset, + const uint32_t& aCount) { LOG(("HttpChannelChild::MaybeDivertOnData [this=%p]", this)); if (mDivertingToParent) { - SendDivertOnDataAvailable(data, offset, count); + SendDivertOnDataAvailable(aData, aOffset, aCount); } } -void HttpChannelChild::OnTransportAndData(const nsresult& channelStatus, - const nsresult& transportStatus, - const uint64_t& offset, - const uint32_t& count, - const nsCString& data) { +void HttpChannelChild::OnTransportAndData(const nsresult& aChannelStatus, + const nsresult& aTransportStatus, + const uint64_t& aOffset, + const uint32_t& aCount, + const nsCString& aData) { LOG(("HttpChannelChild::OnTransportAndData [this=%p]\n", this)); if (!mCanceled && NS_SUCCEEDED(mStatus)) { - mStatus = channelStatus; + mStatus = aChannelStatus; } // For diversion to parent, just SendDivertOnDataAvailable. @@ -805,18 +678,23 @@ void HttpChannelChild::OnTransportAndData(const nsresult& channelStatus, !mFlushedForDiversion, "Should not be processing any more callbacks from parent!"); - SendDivertOnDataAvailable(data, offset, count); + SendDivertOnDataAvailable(aData, aOffset, aCount); return; } - if (mCanceled) return; + if (mCanceled) { + return; + } if (mUnknownDecoderInvolved) { LOG(("UnknownDecoder is involved queue OnDataAvailable call. [this=%p]", this)); MOZ_ASSERT(NS_IsMainThread()); mUnknownDecoderEventQ.AppendElement( - MakeUnique(this, data, offset, count)); + MakeUnique( + this, + [self = UnsafePtr(this), aData, aOffset, + aCount]() { self->MaybeDivertOnData(aData, aOffset, aCount); })); } // Hold queue lock throughout all three calls, else we might process a later @@ -828,14 +706,14 @@ void HttpChannelChild::OnTransportAndData(const nsresult& channelStatus, progressMax = -1; } - const int64_t progress = offset + count; + const int64_t progress = aOffset + aCount; // OnTransportAndData will be run on retargeted thread if applicable, however // OnStatus/OnProgress event can only be fired on main thread. We need to // dispatch the status/progress event handling back to main thread with the // appropriate event target for networking. if (NS_IsMainThread()) { - DoOnStatus(this, transportStatus); + DoOnStatus(this, aTransportStatus); DoOnProgress(this, progress, progressMax); } else { RefPtr self = this; @@ -845,8 +723,8 @@ void HttpChannelChild::OnTransportAndData(const nsresult& channelStatus, DebugOnly rv = neckoTarget->Dispatch( NS_NewRunnableFunction( "net::HttpChannelChild::OnTransportAndData", - [self, transportStatus, progress, progressMax]() { - self->DoOnStatus(self, transportStatus); + [self, aTransportStatus, progress, progressMax]() { + self->DoOnStatus(self, aTransportStatus); self->DoOnProgress(self, progress, progressMax); }), NS_DISPATCH_NORMAL); @@ -863,17 +741,17 @@ void HttpChannelChild::OnTransportAndData(const nsresult& channelStatus, nsCOMPtr stringStream; nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), - MakeSpan(data).To(count), NS_ASSIGNMENT_DEPEND); + MakeSpan(aData).To(aCount), NS_ASSIGNMENT_DEPEND); if (NS_FAILED(rv)) { Cancel(rv); return; } - DoOnDataAvailable(this, nullptr, stringStream, offset, count); + DoOnDataAvailable(this, nullptr, stringStream, aOffset, aCount); stringStream->Close(); if (NeedToReportBytesRead()) { - mUnreportBytesRead += count; + mUnreportBytesRead += aCount; if (mUnreportBytesRead >= gHttpHandler->SendWindowSize() >> 2) { if (NS_IsMainThread()) { Unused << SendBytesRead(mUnreportBytesRead); @@ -928,22 +806,13 @@ void HttpChannelChild::DoOnStatus(nsIRequest* aRequest, nsresult status) { // cache the progress sink so we don't have to query for it each time. if (!mProgressSink) GetCallback(mProgressSink); - // Temporary fix for bug 1116124 - // See 1124971 - Child removes LOAD_BACKGROUND flag from channel - if (status == NS_OK) return; - // block status/progress after Cancel or OnStopRequest has been called, // or if channel has LOAD_BACKGROUND set. if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending && !(mLoadFlags & LOAD_BACKGROUND)) { - // OnStatus - // - MOZ_ASSERT(status == NS_NET_STATUS_RECEIVING_FROM || - status == NS_NET_STATUS_READING); - nsAutoCString host; mURI->GetHost(host); - mProgressSink->OnStatus(aRequest, nullptr, status, + mProgressSink->OnStatus(aRequest, status, NS_ConvertUTF8toUTF16(host).get()); } } @@ -960,12 +829,11 @@ void HttpChannelChild::DoOnProgress(nsIRequest* aRequest, int64_t progress, // block status/progress after Cancel or OnStopRequest has been called, // or if channel has LOAD_BACKGROUND set. - if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending && - !(mLoadFlags & LOAD_BACKGROUND)) { + if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending) { // OnProgress // if (progress > 0) { - mProgressSink->OnProgress(aRequest, nullptr, progress, progressMax); + mProgressSink->OnProgress(aRequest, progress, progressMax); } } } @@ -973,40 +841,20 @@ void HttpChannelChild::DoOnProgress(nsIRequest* aRequest, int64_t progress, void HttpChannelChild::DoOnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream, - uint64_t offset, uint32_t count) { + uint64_t aOffset, uint32_t aCount) { AUTO_PROFILER_LABEL("HttpChannelChild::DoOnDataAvailable", NETWORK); LOG(("HttpChannelChild::DoOnDataAvailable [this=%p]\n", this)); if (mCanceled) return; if (mListener) { nsCOMPtr listener(mListener); - nsresult rv = listener->OnDataAvailable(aRequest, aStream, offset, count); + nsresult rv = listener->OnDataAvailable(aRequest, aStream, aOffset, aCount); if (NS_FAILED(rv)) { CancelOnMainThread(rv); } } } -class StopRequestEvent : public NeckoTargetChannelEvent { - public: - StopRequestEvent(HttpChannelChild* child, const nsresult& channelStatus, - const ResourceTimingStruct& timing, - const nsHttpHeaderArray& aResponseTrailers) - : NeckoTargetChannelEvent(child), - mChannelStatus(channelStatus), - mTiming(timing), - mResponseTrailers(aResponseTrailers) {} - - void Run() override { - mChild->OnStopRequest(mChannelStatus, mTiming, mResponseTrailers); - } - - private: - nsresult mChannelStatus; - ResourceTimingStruct mTiming; - nsHttpHeaderArray mResponseTrailers; -}; - void HttpChannelChild::ProcessOnStopRequest( const nsresult& aChannelStatus, const ResourceTimingStruct& aTiming, const nsHttpHeaderArray& aResponseTrailers) { @@ -1015,25 +863,16 @@ void HttpChannelChild::ProcessOnStopRequest( MOZ_RELEASE_ASSERT(!mFlushedForDiversion, "Should not be receiving any more callbacks from parent!"); - mEventQ->RunOrEnqueue( - new StopRequestEvent(this, aChannelStatus, aTiming, aResponseTrailers), - mDivertingToParent); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, + [self = UnsafePtr(this), + aChannelStatus, aTiming, aResponseTrailers]() { + self->OnStopRequest(aChannelStatus, aTiming, + aResponseTrailers); + }), + mDivertingToParent); } -class MaybeDivertOnStopHttpEvent - : public NeckoTargetChannelEvent { - public: - MaybeDivertOnStopHttpEvent(HttpChannelChild* child, - const nsresult& channelStatus) - : NeckoTargetChannelEvent(child), - mChannelStatus(channelStatus) {} - - void Run() override { mChild->MaybeDivertOnStop(mChannelStatus); } - - private: - nsresult mChannelStatus; -}; - void HttpChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus) { LOG( ("HttpChannelChild::MaybeDivertOnStop [this=%p, " @@ -1046,10 +885,10 @@ void HttpChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus) { } void HttpChannelChild::OnStopRequest( - const nsresult& channelStatus, const ResourceTimingStruct& timing, + const nsresult& aChannelStatus, const ResourceTimingStruct& aTiming, const nsHttpHeaderArray& aResponseTrailers) { LOG(("HttpChannelChild::OnStopRequest [this=%p status=%" PRIx32 "]\n", this, - static_cast(channelStatus))); + static_cast(aChannelStatus))); MOZ_ASSERT(NS_IsMainThread()); // If this channel was aborted by ActorDestroy, then there may be other @@ -1065,7 +904,7 @@ void HttpChannelChild::OnStopRequest( !mFlushedForDiversion, "Should not be processing any more callbacks from parent!"); - SendDivertOnStopRequest(channelStatus); + SendDivertOnStopRequest(aChannelStatus); return; } @@ -1074,7 +913,10 @@ void HttpChannelChild::OnStopRequest( this)); MOZ_ASSERT(NS_IsMainThread()); mUnknownDecoderEventQ.AppendElement( - MakeUnique(this, channelStatus)); + MakeUnique( + this, [self = UnsafePtr(this), aChannelStatus]() { + self->MaybeDivertOnStop(aChannelStatus); + })); } nsCOMPtr conv = do_QueryInterface(mCompressListener); @@ -1082,15 +924,15 @@ void HttpChannelChild::OnStopRequest( conv->GetDecodedDataLength(&mDecodedBodySize); } - mTransactionTimings.domainLookupStart = timing.domainLookupStart; - mTransactionTimings.domainLookupEnd = timing.domainLookupEnd; - mTransactionTimings.connectStart = timing.connectStart; - mTransactionTimings.tcpConnectEnd = timing.tcpConnectEnd; - mTransactionTimings.secureConnectionStart = timing.secureConnectionStart; - mTransactionTimings.connectEnd = timing.connectEnd; - mTransactionTimings.requestStart = timing.requestStart; - mTransactionTimings.responseStart = timing.responseStart; - mTransactionTimings.responseEnd = timing.responseEnd; + mTransactionTimings.domainLookupStart = aTiming.domainLookupStart; + mTransactionTimings.domainLookupEnd = aTiming.domainLookupEnd; + mTransactionTimings.connectStart = aTiming.connectStart; + mTransactionTimings.tcpConnectEnd = aTiming.tcpConnectEnd; + mTransactionTimings.secureConnectionStart = aTiming.secureConnectionStart; + mTransactionTimings.connectEnd = aTiming.connectEnd; + mTransactionTimings.requestStart = aTiming.requestStart; + mTransactionTimings.responseStart = aTiming.responseStart; + mTransactionTimings.responseEnd = aTiming.responseEnd; // Do not overwrite or adjust the original mAsyncOpenTime by timing.fetchStart // We must use the original child process time in order to account for child @@ -1099,14 +941,14 @@ void HttpChannelChild::OnStopRequest( // This is true for modern hardware but for older platforms it is not always // true. - mRedirectStartTimeStamp = timing.redirectStart; - mRedirectEndTimeStamp = timing.redirectEnd; - mTransferSize = timing.transferSize; - mEncodedBodySize = timing.encodedBodySize; - mProtocolVersion = timing.protocolVersion; + mRedirectStartTimeStamp = aTiming.redirectStart; + mRedirectEndTimeStamp = aTiming.redirectEnd; + mTransferSize = aTiming.transferSize; + mEncodedBodySize = aTiming.encodedBodySize; + mProtocolVersion = aTiming.protocolVersion; - mCacheReadStart = timing.cacheReadStart; - mCacheReadEnd = timing.cacheReadEnd; + mCacheReadStart = aTiming.cacheReadStart; + mCacheReadEnd = aTiming.cacheReadEnd; #ifdef MOZ_GECKO_PROFILER if (profiler_can_accept_markers()) { @@ -1119,16 +961,16 @@ void HttpChannelChild::OnStopRequest( } #endif - mResponseTrailers = new nsHttpHeaderArray(aResponseTrailers); + mResponseTrailers = MakeUnique(aResponseTrailers); - DoPreOnStopRequest(channelStatus); + DoPreOnStopRequest(aChannelStatus); { // We must flush the queue before we Send__delete__ // (although we really shouldn't receive any msgs after OnStop), // so make sure this goes out of scope before then. AutoEventEnqueuer ensureSerialDispatch(mEventQ); - DoOnStopRequest(this, channelStatus, nullptr); + DoOnStopRequest(this, aChannelStatus, nullptr); // DoOnStopRequest() calls ReleaseListeners() } @@ -1153,7 +995,7 @@ void HttpChannelChild::OnStopRequest( // message but request the cache entry to be kept by the parent. // If the channel has failed, the cache entry is in a non-writtable state and // we want to release it to not block following consumers. - if (NS_SUCCEEDED(channelStatus) && !mPreferredCachedAltDataTypes.IsEmpty()) { + if (NS_SUCCEEDED(aChannelStatus) && !mPreferredCachedAltDataTypes.IsEmpty()) { mKeptAlive = true; SendDocumentChannelCleanup(false); // don't clear cache entry return; @@ -1200,10 +1042,8 @@ void HttpChannelChild::CollectOMTTelemetry() { } // Use content policy type to accumulate data by usage. - nsContentPolicyType type = mLoadInfo ? mLoadInfo->InternalContentPolicyType() - : nsIContentPolicy::TYPE_OTHER; - - nsAutoCString key(NS_CP_ContentTypeName(type)); + nsAutoCString key( + NS_CP_ContentTypeName(mLoadInfo->InternalContentPolicyType())); Telemetry::AccumulateCategoricalKeyed(key, mOMTResult); } @@ -1271,106 +1111,36 @@ void HttpChannelChild::DoOnStopRequest(nsIRequest* aRequest, if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus); } -class ProgressEvent : public NeckoTargetChannelEvent { - public: - ProgressEvent(HttpChannelChild* child, const int64_t& progress, - const int64_t& progressMax) - : NeckoTargetChannelEvent(child), - mProgress(progress), - mProgressMax(progressMax) {} - - void Run() override { mChild->OnProgress(mProgress, mProgressMax); } - - private: - int64_t mProgress, mProgressMax; -}; - -void HttpChannelChild::ProcessOnProgress(const int64_t& aProgress, - const int64_t& aProgressMax) { - LOG(("HttpChannelChild::ProcessOnProgress [this=%p]\n", this)); - MOZ_ASSERT(OnSocketThread()); - mEventQ->RunOrEnqueue(new ProgressEvent(this, aProgress, aProgressMax)); -} - -void HttpChannelChild::OnProgress(const int64_t& progress, - const int64_t& progressMax) { - AUTO_PROFILER_LABEL("HttpChannelChild::OnProgress", NETWORK); - LOG(("HttpChannelChild::OnProgress [this=%p progress=%" PRId64 "/%" PRId64 - "]\n", - this, progress, progressMax)); - - if (mCanceled) return; - - // cache the progress sink so we don't have to query for it each time. - if (!mProgressSink) { - GetCallback(mProgressSink); - } - - AutoEventEnqueuer ensureSerialDispatch(mEventQ); - - // Block socket status event after Cancel or OnStopRequest has been called. - if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending) { - if (progress > 0) { - mProgressSink->OnProgress(this, nullptr, progress, progressMax); - } - } -} - -class StatusEvent : public NeckoTargetChannelEvent { - public: - StatusEvent(HttpChannelChild* child, const nsresult& status) - : NeckoTargetChannelEvent(child), mStatus(status) {} - - void Run() override { mChild->OnStatus(mStatus); } - - private: - nsresult mStatus; -}; - -void HttpChannelChild::ProcessOnStatus(const nsresult& aStatus) { - LOG(("HttpChannelChild::ProcessOnStatus [this=%p]\n", this)); - MOZ_ASSERT(OnSocketThread()); - mEventQ->RunOrEnqueue(new StatusEvent(this, aStatus)); +mozilla::ipc::IPCResult HttpChannelChild::RecvOnProgress( + const int64_t& aProgress, const int64_t& aProgressMax) { + LOG(("HttpChannelChild::RecvOnProgress [this=%p]\n", this)); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, + [self = UnsafePtr(this), aProgress, aProgressMax]() { + AutoEventEnqueuer ensureSerialDispatch(self->mEventQ); + self->DoOnProgress(self, aProgress, aProgressMax); + })); + return IPC_OK(); } -void HttpChannelChild::OnStatus(const nsresult& status) { - AUTO_PROFILER_LABEL("HttpChannelChild::OnStatus", NETWORK); - LOG(("HttpChannelChild::OnStatus [this=%p status=%" PRIx32 "]\n", this, - static_cast(status))); - - if (mCanceled) return; - - // cache the progress sink so we don't have to query for it each time. - if (!mProgressSink) GetCallback(mProgressSink); - - AutoEventEnqueuer ensureSerialDispatch(mEventQ); - - // block socket status event after Cancel or OnStopRequest has been called, - // or if channel has LOAD_BACKGROUND set - if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending && - !(mLoadFlags & LOAD_BACKGROUND)) { - nsAutoCString host; - mURI->GetHost(host); - mProgressSink->OnStatus(this, nullptr, status, - NS_ConvertUTF8toUTF16(host).get()); - } +mozilla::ipc::IPCResult HttpChannelChild::RecvOnStatus( + const nsresult& aStatus) { + LOG(("HttpChannelChild::RecvOnStatus [this=%p]\n", this)); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr(this), aStatus]() { + AutoEventEnqueuer ensureSerialDispatch(self->mEventQ); + self->DoOnStatus(self, aStatus); + })); + return IPC_OK(); } -class FailedAsyncOpenEvent : public NeckoTargetChannelEvent { - public: - FailedAsyncOpenEvent(HttpChannelChild* child, const nsresult& status) - : NeckoTargetChannelEvent(child), mStatus(status) {} - - void Run() override { mChild->FailedAsyncOpen(mStatus); } - - private: - nsresult mStatus; -}; - mozilla::ipc::IPCResult HttpChannelChild::RecvFailedAsyncOpen( - const nsresult& status) { + const nsresult& aStatus) { LOG(("HttpChannelChild::RecvFailedAsyncOpen [this=%p]\n", this)); - mEventQ->RunOrEnqueue(new FailedAsyncOpenEvent(this, status)); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr(this), aStatus]() { + self->FailedAsyncOpen(aStatus); + })); return IPC_OK(); } @@ -1421,7 +1191,7 @@ void HttpChannelChild::CleanupBackgroundChannel() { return; } - RefPtr bgChild = mBgChild.forget(); + RefPtr bgChild = std::move(mBgChild); MOZ_RELEASE_ASSERT(gSocketTransportService); if (!OnSocketThread()) { @@ -1450,31 +1220,26 @@ void HttpChannelChild::DoAsyncAbort(nsresult aStatus) { Unused << AsyncAbort(aStatus); } -class DeleteSelfEvent : public NeckoTargetChannelEvent { - public: - explicit DeleteSelfEvent(HttpChannelChild* child) - : NeckoTargetChannelEvent(child) {} - void Run() override { mChild->DeleteSelf(); } -}; - mozilla::ipc::IPCResult HttpChannelChild::RecvDeleteSelf() { LOG(("HttpChannelChild::RecvDeleteSelf [this=%p]\n", this)); - mEventQ->RunOrEnqueue(new DeleteSelfEvent(this)); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, + [self = UnsafePtr(this)]() { self->DeleteSelf(); })); return IPC_OK(); } HttpChannelChild::OverrideRunnable::OverrideRunnable( HttpChannelChild* aChannel, HttpChannelChild* aNewChannel, InterceptStreamListener* aListener, nsIInputStream* aInput, - nsIInterceptedBodyCallback* aCallback, nsAutoPtr& aHead, - nsICacheInfoChannel* aCacheInfo) + nsIInterceptedBodyCallback* aCallback, + UniquePtr&& aHead, nsICacheInfoChannel* aCacheInfo) : Runnable("net::HttpChannelChild::OverrideRunnable") { mChannel = aChannel; mNewChannel = aNewChannel; mListener = aListener; mInput = aInput; mCallback = aCallback; - mHead = aHead; + mHead = std::move(aHead); mSynthesizedCacheInfo = aCacheInfo; } @@ -1543,14 +1308,6 @@ mozilla::ipc::IPCResult HttpChannelChild::RecvFinishInterceptedRedirect() { void HttpChannelChild::DeleteSelf() { Send__delete__(this); } -class ContinueDoNotifyListenerEvent - : public NeckoTargetChannelEvent { - public: - explicit ContinueDoNotifyListenerEvent(HttpChannelChild* child) - : NeckoTargetChannelEvent(child) {} - void Run() override { mChild->ContinueDoNotifyListener(); } -}; - void HttpChannelChild::DoNotifyListener() { LOG(("HttpChannelChild::DoNotifyListener this=%p", this)); MOZ_ASSERT(NS_IsMainThread()); @@ -1569,7 +1326,10 @@ void HttpChannelChild::DoNotifyListener() { } mOnStartRequestCalled = true; - mEventQ->RunOrEnqueue(new ContinueDoNotifyListenerEvent(this)); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr(this)] { + self->ContinueDoNotifyListener(); + })); } void HttpChannelChild::ContinueDoNotifyListener() { @@ -1609,7 +1369,7 @@ void HttpChannelChild::ContinueDoNotifyListener() { if (!IsNavigation()) { if (mLoadGroup) { FlushConsoleReports(mLoadGroup); - } else if (mLoadInfo) { + } else { RefPtr doc; mLoadInfo->GetLoadingDocument(getter_AddRefs(doc)); FlushConsoleReports(doc); @@ -1643,63 +1403,30 @@ mozilla::ipc::IPCResult HttpChannelChild::RecvReportSecurityMessage( return IPC_OK(); } -class Redirect1Event : public NeckoTargetChannelEvent { - public: - Redirect1Event(HttpChannelChild* child, const uint32_t& registrarId, - const URIParams& newURI, const uint32_t& newLoadFlags, - const uint32_t& redirectFlags, - const ParentLoadInfoForwarderArgs& loadInfoForwarder, - const nsHttpResponseHead& responseHead, - const nsACString& securityInfoSerialization, - const uint64_t& channelId, const ResourceTimingStruct& timing) - : NeckoTargetChannelEvent(child), - mRegistrarId(registrarId), - mNewURI(newURI), - mNewLoadFlags(newLoadFlags), - mRedirectFlags(redirectFlags), - mResponseHead(responseHead), - mSecurityInfoSerialization(securityInfoSerialization), - mChannelId(channelId), - mLoadInfoForwarder(loadInfoForwarder), - mTiming(timing) {} - - void Run() override { - mChild->Redirect1Begin(mRegistrarId, mNewURI, mNewLoadFlags, mRedirectFlags, - mLoadInfoForwarder, mResponseHead, - mSecurityInfoSerialization, mChannelId, mTiming); - } - - private: - uint32_t mRegistrarId; - URIParams mNewURI; - uint32_t mNewLoadFlags; - uint32_t mRedirectFlags; - nsHttpResponseHead mResponseHead; - nsCString mSecurityInfoSerialization; - uint64_t mChannelId; - ParentLoadInfoForwarderArgs mLoadInfoForwarder; - ResourceTimingStruct mTiming; -}; - mozilla::ipc::IPCResult HttpChannelChild::RecvRedirect1Begin( - const uint32_t& registrarId, const URIParams& newUri, - const uint32_t& newLoadFlags, const uint32_t& redirectFlags, - const ParentLoadInfoForwarderArgs& loadInfoForwarder, - const nsHttpResponseHead& responseHead, - const nsCString& securityInfoSerialization, const uint64_t& channelId, - const NetAddr& oldPeerAddr, const ResourceTimingStruct& timing) { + const uint32_t& aRegistrarId, const URIParams& aNewUri, + const uint32_t& aNewLoadFlags, const uint32_t& aRedirectFlags, + const ParentLoadInfoForwarderArgs& aLoadInfoForwarder, + const nsHttpResponseHead& aResponseHead, + const nsCString& aSecurityInfoSerialization, const uint64_t& aChannelId, + const NetAddr& aOldPeerAddr, const ResourceTimingStruct& aTiming) { // TODO: handle security info LOG(("HttpChannelChild::RecvRedirect1Begin [this=%p]\n", this)); // We set peer address of child to the old peer, // Then it will be updated to new peer in OnStartRequest - mPeerAddr = oldPeerAddr; + mPeerAddr = aOldPeerAddr; // Cookies headers should not be visible to the child process - MOZ_ASSERT(!nsHttpResponseHead(responseHead).HasHeader(nsHttp::Set_Cookie)); - - mEventQ->RunOrEnqueue(new Redirect1Event( - this, registrarId, newUri, newLoadFlags, redirectFlags, loadInfoForwarder, - responseHead, securityInfoSerialization, channelId, timing)); + MOZ_ASSERT(!nsHttpResponseHead(aResponseHead).HasHeader(nsHttp::Set_Cookie)); + + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr(this), aRegistrarId, aNewUri, + aNewLoadFlags, aRedirectFlags, aLoadInfoForwarder, aResponseHead, + aSecurityInfoSerialization, aChannelId, aTiming]() { + self->Redirect1Begin(aRegistrarId, aNewUri, aNewLoadFlags, + aRedirectFlags, aLoadInfoForwarder, aResponseHead, + aSecurityInfoSerialization, aChannelId, aTiming); + })); return IPC_OK(); } @@ -1725,7 +1452,7 @@ nsresult HttpChannelChild::SetupRedirect(nsIURI* uri, NS_ENSURE_SUCCESS(rv, rv); // We won't get OnStartRequest, set cookies here. - mResponseHead = new nsHttpResponseHead(*responseHead); + mResponseHead = MakeUnique(*responseHead); bool rewriteToGET = HttpBaseChannel::ShouldRewriteRedirectToGET( mResponseHead->Status(), mRequestHead.ParsedMethod()); @@ -1884,36 +1611,26 @@ void HttpChannelChild::OverrideSecurityInfoForNonIPCRedirect( MOZ_ASSERT(NS_SUCCEEDED(rv)); } -class Redirect3Event : public NeckoTargetChannelEvent { - public: - explicit Redirect3Event(HttpChannelChild* child) - : NeckoTargetChannelEvent(child) {} - void Run() override { mChild->Redirect3Complete(nullptr); } -}; - mozilla::ipc::IPCResult HttpChannelChild::RecvRedirect3Complete() { LOG(("HttpChannelChild::RecvRedirect3Complete [this=%p]\n", this)); - mEventQ->RunOrEnqueue(new Redirect3Event(this)); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr(this)]() { + self->Redirect3Complete(nullptr); + })); return IPC_OK(); } -class HttpFlushedForDiversionEvent - : public NeckoTargetChannelEvent { - public: - explicit HttpFlushedForDiversionEvent(HttpChannelChild* aChild) - : NeckoTargetChannelEvent(aChild) { - MOZ_RELEASE_ASSERT(aChild); - } - - void Run() override { mChild->FlushedForDiversion(); } -}; - void HttpChannelChild::ProcessFlushedForDiversion() { LOG(("HttpChannelChild::ProcessFlushedForDiversion [this=%p]\n", this)); MOZ_ASSERT(OnSocketThread()); MOZ_RELEASE_ASSERT(mDivertingToParent); - mEventQ->RunOrEnqueue(new HttpFlushedForDiversionEvent(this), true); + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, + [self = UnsafePtr(this)]() { + self->FlushedForDiversion(); + }), + true); } void HttpChannelChild::ProcessNotifyChannelClassifierProtectionDisabled( @@ -2068,6 +1785,12 @@ bool HttpChannelChild::Redirect3Complete(OverrideRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); nsresult rv = NS_OK; + nsCOMPtr vetoHook; + GetCallback(vetoHook); + if (vetoHook) { + vetoHook->OnRedirectResult(true); + } + nsCOMPtr chan = do_QueryInterface(mRedirectChannelChild); RefPtr httpChannelChild = static_cast(chan.get()); @@ -2103,19 +1826,17 @@ void HttpChannelChild::CleanupRedirectingChannel(nsresult rv) { if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED); if (NS_SUCCEEDED(rv)) { - if (mLoadInfo) { - nsCString remoteAddress; - Unused << GetRemoteAddress(remoteAddress); - nsCOMPtr referrer; - if (mReferrerInfo) { - referrer = mReferrerInfo->GetComputedReferrer(); - } + nsCString remoteAddress; + Unused << GetRemoteAddress(remoteAddress); + nsCOMPtr referrer; + if (mReferrerInfo) { + referrer = mReferrerInfo->GetComputedReferrer(); + } - nsCOMPtr entry = new nsRedirectHistoryEntry( - GetURIPrincipal(), referrer, remoteAddress); + nsCOMPtr entry = + new nsRedirectHistoryEntry(GetURIPrincipal(), referrer, remoteAddress); - mLoadInfo->AppendRedirectHistoryEntry(entry, false); - } + mLoadInfo->AppendRedirectHistoryEntry(entry, false); } else { NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?"); } @@ -2200,14 +1921,14 @@ HttpChannelChild::ConnectParent(uint32_t registrarId) { return rv; } - mBgChild = bgChild.forget(); + mBgChild = std::move(bgChild); } return NS_OK; } NS_IMETHODIMP -HttpChannelChild::CompleteRedirectSetup(nsIStreamListener* listener, +HttpChannelChild::CompleteRedirectSetup(nsIStreamListener* aListener, nsISupports* aContext) { LOG(("HttpChannelChild::FinishRedirectSetup [this=%p]\n", this)); MOZ_ASSERT(NS_IsMainThread()); @@ -2229,7 +1950,7 @@ HttpChannelChild::CompleteRedirectSetup(nsIStreamListener* listener, // 3. Cleanup the redirecting channel (the one calling Redirect3Complete) // 4. [optional] Call OverrideWithSynthesizedResponse on the redirected // channel if the call came from OverrideRunnable. - mInterceptedRedirectListener = listener; + mInterceptedRedirectListener = aListener; mInterceptedRedirectContext = aContext; // This will send a message to the parent notifying it that we are closing @@ -2251,7 +1972,7 @@ HttpChannelChild::CompleteRedirectSetup(nsIStreamListener* listener, mIsPending = true; mWasOpened = true; - mListener = listener; + mListener = aListener; // add ourselves to the load group. if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr); @@ -2267,7 +1988,7 @@ HttpChannelChild::CompleteRedirectSetup(nsIStreamListener* listener, //----------------------------------------------------------------------------- NS_IMETHODIMP -HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { +HttpChannelChild::OnRedirectVerifyCallback(nsresult aResult) { LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this)); MOZ_ASSERT(NS_IsMainThread()); Maybe redirectURI; @@ -2276,7 +1997,7 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { nsCOMPtr newHttpChannel = do_QueryInterface(mRedirectChannelChild); - if (NS_SUCCEEDED(result) && !mRedirectChannelChild) { + if (NS_SUCCEEDED(aResult) && !mRedirectChannelChild) { // mRedirectChannelChild doesn't exist means we're redirecting to a protocol // that doesn't implement nsIChildChannel. The redirect result should be set // as failed by veto listeners and shouldn't enter this condition. As the @@ -2284,7 +2005,7 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { // to let nsHttpChannel::ContinueProcessResponse2 know it's redirecting to // another protocol and throw an error. LOG((" redirecting to a protocol that doesn't implement nsIChildChannel")); - result = NS_ERROR_DOM_BAD_URI; + aResult = NS_ERROR_DOM_BAD_URI; } nsCOMPtr referrerInfo; @@ -2309,12 +2030,12 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { MOZ_ASSERT(neckoTarget); nsCOMPtr callback = - mSynthesizedCallback.forget(); + std::move(mSynthesizedCallback); Unused << neckoTarget->Dispatch( new OverrideRunnable(this, redirectedChannel, streamListener, - mSynthesizedInput, callback, mResponseHead, - mSynthesizedCacheInfo), + mSynthesizedInput, callback, + std::move(mResponseHead), mSynthesizedCacheInfo), NS_DISPATCH_NORMAL); return NS_OK; @@ -2327,7 +2048,7 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { nsCOMPtr newHttpChannelChild = do_QueryInterface(mRedirectChannelChild); - if (newHttpChannelChild && NS_SUCCEEDED(result)) { + if (newHttpChannelChild && NS_SUCCEEDED(aResult)) { rv = newHttpChannelChild->AddCookiesToRequest(); MOZ_ASSERT(NS_SUCCEEDED(rv)); rv = newHttpChannelChild->GetClientSetRequestHeaders(&headerTuples); @@ -2339,7 +2060,7 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { * redirect URI */ SerializeURI(nullptr, redirectURI); - if (NS_SUCCEEDED(result)) { + if (NS_SUCCEEDED(aResult)) { // Note: this is where we would notify "http-on-modify-response" observers. // We have deliberately disabled this for child processes (see bug 806753) // @@ -2375,19 +2096,22 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { appCacheChannel->GetChooseApplicationCache(&chooseAppcache); } - nsCOMPtr newChannelLoadInfo = nullptr; + uint32_t sourceRequestBlockingReason = 0; + mLoadInfo->GetRequestBlockingReason(&sourceRequestBlockingReason); + + Maybe targetLoadInfoForwarder; nsCOMPtr newChannel = do_QueryInterface(mRedirectChannelChild); if (newChannel) { - newChannelLoadInfo = newChannel->LoadInfo(); + ChildLoadInfoForwarderArgs args; + nsCOMPtr loadInfo = newChannel->LoadInfo(); + LoadInfoToChildLoadInfoForwarder(loadInfo, &args); + targetLoadInfoForwarder.emplace(args); } - ChildLoadInfoForwarderArgs loadInfoForwarder; - LoadInfoToChildLoadInfoForwarder(newChannelLoadInfo, &loadInfoForwarder); - if (CanSend()) - SendRedirect2Verify(result, *headerTuples, loadInfoForwarder, loadFlags, - referrerInfo, redirectURI, corsPreflightArgs, - chooseAppcache); + SendRedirect2Verify(aResult, *headerTuples, sourceRequestBlockingReason, + targetLoadInfoForwarder, loadFlags, referrerInfo, + redirectURI, corsPreflightArgs, chooseAppcache); return NS_OK; } @@ -2397,9 +2121,9 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result) { //----------------------------------------------------------------------------- NS_IMETHODIMP -HttpChannelChild::Cancel(nsresult status) { +HttpChannelChild::Cancel(nsresult aStatus) { LOG(("HttpChannelChild::Cancel [this=%p, status=%" PRIx32 "]\n", this, - static_cast(status))); + static_cast(aStatus))); LogCallingScriptLocation(this); MOZ_ASSERT(NS_IsMainThread()); @@ -2408,15 +2132,15 @@ HttpChannelChild::Cancel(nsresult status) { // If this cancel occurs before nsHttpChannel has been set up, AsyncOpen // is responsible for cleaning up. mCanceled = true; - mStatus = status; + mStatus = aStatus; if (RemoteChannelExists()) { - SendCancel(status); + SendCancel(aStatus); } // If the channel is intercepted and already pumping, then just // cancel the pump. This will call OnStopRequest(). if (mSynthesizedResponsePump) { - mSynthesizedResponsePump->Cancel(status); + mSynthesizedResponsePump->Cancel(aStatus); } // If we are canceled while intercepting, but not yet pumping, then @@ -2424,7 +2148,7 @@ HttpChannelChild::Cancel(nsresult status) { else if (mInterceptListener) { mInterceptListener->Cleanup(); mInterceptListener = nullptr; - Unused << AsyncAbort(status); + Unused << AsyncAbort(aStatus); } } return NS_OK; @@ -2516,9 +2240,7 @@ HttpChannelChild::AsyncOpen(nsIStreamListener* aListener) { nsresult rv = AsyncOpenInternal(aListener); if (NS_FAILED(rv)) { uint32_t blockingReason = 0; - if (mLoadInfo) { - mLoadInfo->GetRequestBlockingReason(&blockingReason); - } + mLoadInfo->GetRequestBlockingReason(&blockingReason); LOG( ("HttpChannelChild::AsyncOpen failed [this=%p rv=0x%08x " "blocking-reason=%u]\n", @@ -2540,12 +2262,12 @@ nsresult HttpChannelChild::AsyncOpenInternal(nsIStreamListener* aListener) { } MOZ_ASSERT( - !mLoadInfo || mLoadInfo->GetSecurityMode() == 0 || + mLoadInfo->GetSecurityMode() == 0 || mLoadInfo->GetInitialSecurityCheckDone() || (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL && - mLoadInfo->LoadingPrincipal() && - mLoadInfo->LoadingPrincipal()->IsSystemPrincipal()), + mLoadInfo->GetLoadingPrincipal() && + mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()), "security flags in loadInfo but doContentSecurityCheck() not called"); LogCallingScriptLocation(this); @@ -2934,7 +2656,7 @@ nsresult HttpChannelChild::ContinueAsyncOpen() { // creating the new one, to prevent receiving further notification // from it. if (mBgChild) { - RefPtr prevBgChild = mBgChild.forget(); + RefPtr prevBgChild = std::move(mBgChild); gSocketTransportService->Dispatch( NewRunnableMethod("HttpBackgroundChannelChild::OnChannelClosed", prevBgChild, @@ -2962,7 +2684,7 @@ nsresult HttpChannelChild::ContinueAsyncOpen() { return rv; } - mBgChild = bgChild.forget(); + mBgChild = std::move(bgChild); } return NS_OK; @@ -3749,23 +3471,6 @@ nsresult HttpChannelChild::SetReferrerHeader(const nsACString& aReferrer) { return HttpBaseChannel::SetReferrerHeader(aReferrer); } -class CancelEvent final : public NeckoTargetChannelEvent { - public: - CancelEvent(HttpChannelChild* aChild, nsresult aRv) - : NeckoTargetChannelEvent(aChild), mRv(aRv) { - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ASSERT(aChild); - } - - void Run() override { - MOZ_ASSERT(NS_IsMainThread()); - mChild->Cancel(mRv); - } - - private: - const nsresult mRv; -}; - void HttpChannelChild::CancelOnMainThread(nsresult aRv) { LOG(("HttpChannelChild::CancelOnMainThread [this=%p]", this)); @@ -3778,13 +3483,15 @@ void HttpChannelChild::CancelOnMainThread(nsresult aRv) { // Cancel is expected to preempt any other channel events, thus we put this // event in the front of mEventQ to make sure nsIStreamListener not receiving // any ODA/OnStopRequest callbacks. - UniquePtr cancelEvent = MakeUnique(this, aRv); - mEventQ->PrependEvent(cancelEvent); + mEventQ->PrependEvent(MakeUnique( + this, [self = UnsafePtr(this), aRv]() { + self->Cancel(aRv); + })); mEventQ->Resume(); } void HttpChannelChild::OverrideWithSynthesizedResponse( - nsAutoPtr& aResponseHead, + UniquePtr& aResponseHead, nsIInputStream* aSynthesizedInput, nsIInterceptedBodyCallback* aSynthesizedCallback, InterceptStreamListener* aStreamListener, @@ -3813,11 +3520,11 @@ void HttpChannelChild::OverrideWithSynthesizedResponse( // Intercepted responses should already be decoded. If its a redirect, // however, we want to respect the encoding of the final result instead. - if (!nsHttpChannel::WillRedirect(aResponseHead)) { + if (!nsHttpChannel::WillRedirect(*aResponseHead)) { SetApplyConversion(false); } - mResponseHead = aResponseHead; + mResponseHead = std::move(aResponseHead); mSynthesizedResponse = true; mSynthesizedInput = aSynthesizedInput; @@ -3828,7 +3535,7 @@ void HttpChannelChild::OverrideWithSynthesizedResponse( NS_ENSURE_SUCCESS_VOID(rv); } - if (nsHttpChannel::WillRedirect(mResponseHead)) { + if (nsHttpChannel::WillRedirect(*mResponseHead)) { // Normally we handle redirect limits in the parent process. The way // e10s synthesized redirects work, however, the parent process does not // get an accurate redirect count. Therefore we need to enforce it here. @@ -3922,16 +3629,16 @@ mozilla::ipc::IPCResult HttpChannelChild::RecvIssueDeprecationWarning( bool HttpChannelChild::ShouldInterceptURI(nsIURI* aURI, bool& aShouldUpgrade) { nsCOMPtr resultPrincipal; - if (!aURI->SchemeIs("https") && mLoadInfo) { + if (!aURI->SchemeIs("https")) { nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal( this, getter_AddRefs(resultPrincipal)); } OriginAttributes originAttributes; NS_ENSURE_TRUE(NS_GetOriginAttributes(this, originAttributes), false); bool notused = false; - nsresult rv = NS_ShouldSecureUpgrade(aURI, mLoadInfo, resultPrincipal, - mPrivateBrowsing, mAllowSTS, originAttributes, - aShouldUpgrade, nullptr, notused); + nsresult rv = NS_ShouldSecureUpgrade( + aURI, mLoadInfo, resultPrincipal, mPrivateBrowsing, mAllowSTS, + originAttributes, aShouldUpgrade, nullptr, notused); NS_ENSURE_SUCCESS(rv, false); nsCOMPtr upgradedURI; @@ -3999,15 +3706,12 @@ mozilla::ipc::IPCResult HttpChannelChild::RecvLogBlockedCORSRequest( NS_IMETHODIMP HttpChannelChild::LogBlockedCORSRequest(const nsAString& aMessage, const nsACString& aCategory) { - if (mLoadInfo) { - uint64_t innerWindowID = mLoadInfo->GetInnerWindowID(); - bool privateBrowsing = - !!mLoadInfo->GetOriginAttributes().mPrivateBrowsingId; - bool fromChromeContext = - mLoadInfo->TriggeringPrincipal()->IsSystemPrincipal(); - nsCORSListenerProxy::LogBlockedCORSRequest( - innerWindowID, privateBrowsing, fromChromeContext, aMessage, aCategory); - } + uint64_t innerWindowID = mLoadInfo->GetInnerWindowID(); + bool privateBrowsing = !!mLoadInfo->GetOriginAttributes().mPrivateBrowsingId; + bool fromChromeContext = + mLoadInfo->TriggeringPrincipal()->IsSystemPrincipal(); + nsCORSListenerProxy::LogBlockedCORSRequest( + innerWindowID, privateBrowsing, fromChromeContext, aMessage, aCategory); return NS_OK; } @@ -4023,9 +3727,7 @@ HttpChannelChild::LogMimeTypeMismatch(const nsACString& aMessageName, bool aWarning, const nsAString& aURL, const nsAString& aContentType) { RefPtr doc; - if (mLoadInfo) { - mLoadInfo->GetLoadingDocument(getter_AddRefs(doc)); - } + mLoadInfo->GetLoadingDocument(getter_AddRefs(doc)); AutoTArray params; params.AppendElement(aURL); diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index a42dfe8ece..aa179bfde0 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -204,6 +204,11 @@ class HttpChannelChild final : public PHttpChannelChild, const nsAString& aURL, const nsAString& aContentType) override; + mozilla::ipc::IPCResult RecvOnProgress(const int64_t& aProgress, + const int64_t& aProgressMax) override; + + mozilla::ipc::IPCResult RecvOnStatus(const nsresult& aStatus) override; + private: // We want to handle failure result of AsyncOpen, hence AsyncOpen calls the // Internal method @@ -217,7 +222,7 @@ class HttpChannelChild final : public PHttpChannelChild, OverrideRunnable(HttpChannelChild* aChannel, HttpChannelChild* aNewChannel, InterceptStreamListener* aListener, nsIInputStream* aInput, nsIInterceptedBodyCallback* aCallback, - nsAutoPtr& aHead, + UniquePtr&& aHead, nsICacheInfoChannel* aCacheInfo); NS_IMETHOD Run() override; @@ -229,7 +234,7 @@ class HttpChannelChild final : public PHttpChannelChild, RefPtr mListener; nsCOMPtr mInput; nsCOMPtr mCallback; - nsAutoPtr mHead; + UniquePtr mHead; nsCOMPtr mSynthesizedCacheInfo; }; @@ -254,8 +259,6 @@ class HttpChannelChild final : public PHttpChannelChild, void ProcessOnStopRequest(const nsresult& aStatusCode, const ResourceTimingStruct& aTiming, const nsHttpHeaderArray& aResponseTrailers); - void ProcessOnProgress(const int64_t& aProgress, const int64_t& aProgressMax); - void ProcessOnStatus(const nsresult& aStatus); void ProcessFlushedForDiversion(); void ProcessDivertMessages(); void ProcessNotifyChannelClassifierProtectionDisabled( @@ -297,7 +300,7 @@ class HttpChannelChild final : public PHttpChannelChild, // Override this channel's pending response with a synthesized one. The // content will be asynchronously read from the pump. void OverrideWithSynthesizedResponse( - nsAutoPtr& aResponseHead, + UniquePtr& aResponseHead, nsIInputStream* aSynthesizedInput, nsIInterceptedBodyCallback* aSynthesizedCallback, InterceptStreamListener* aStreamListener, @@ -478,8 +481,6 @@ class HttpChannelChild final : public PHttpChannelChild, const ResourceTimingStruct& timing, const nsHttpHeaderArray& aResponseTrailers); void MaybeDivertOnStop(const nsresult& aChannelStatus); - void OnProgress(const int64_t& progress, const int64_t& progressMax); - void OnStatus(const nsresult& status); void FailedAsyncOpen(const nsresult& status); void HandleAsyncAbort(); void Redirect1Begin(const uint32_t& registrarId, const URIParams& newUri, @@ -513,26 +514,11 @@ class HttpChannelChild final : public PHttpChannelChild, // Collect telemetry for the successful rate of OMT. void CollectOMTTelemetry(); - friend class AssociateApplicationCacheEvent; - friend class StartRequestEvent; - friend class StopRequestEvent; - friend class TransportAndDataEvent; - friend class MaybeDivertOnDataHttpEvent; - friend class MaybeDivertOnStopHttpEvent; - friend class ProgressEvent; - friend class StatusEvent; - friend class FailedAsyncOpenEvent; - friend class Redirect1Event; - friend class Redirect3Event; - friend class DeleteSelfEvent; - friend class HttpFlushedForDiversionEvent; - friend class CancelEvent; friend class HttpAsyncAborter; friend class InterceptStreamListener; friend class InterceptedChannelContent; friend class HttpBackgroundChannelChild; - friend class NeckoTargetChannelEvent; - friend class ContinueDoNotifyListenerEvent; + friend class NeckoTargetChannelFunctionEvent; }; NS_DEFINE_STATIC_IID_ACCESSOR(HttpChannelChild, HTTP_CHANNEL_CHILD_IID) diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 67af3cccba..9f7580f5bb 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -220,7 +220,7 @@ void HttpChannelParent::CleanupBackgroundChannel() { MOZ_ASSERT(NS_IsMainThread()); if (mBgParent) { - RefPtr bgParent = mBgParent.forget(); + RefPtr bgParent = std::move(mBgParent); bgParent->OnChannelClosed(); return; } @@ -485,8 +485,7 @@ bool HttpChannelParent::DoAsyncOpen( if (apiRedirectToUri) httpChannel->RedirectTo(apiRedirectToUri); if (topWindowUri) { - rv = httpChannel->SetTopWindowURI(topWindowUri); - MOZ_ASSERT(NS_SUCCEEDED(rv)); + httpChannel->SetTopWindowURI(topWindowUri); } if (contentBlockingAllowListPrincipal) { @@ -518,7 +517,7 @@ bool HttpChannelParent::DoAsyncOpen( if (aCorsPreflightArgs.isSome()) { const CorsPreflightArgs& args = aCorsPreflightArgs.ref(); - httpChannel->SetCorsPreflightParameters(args.unsafeHeaders()); + httpChannel->SetCorsPreflightParameters(args.unsafeHeaders(), false); } nsCOMPtr stream = DeserializeIPCStream(uploadStream); @@ -646,8 +645,8 @@ bool HttpChannelParent::DoAsyncOpen( // Store the strong reference of channel and parent listener object until // all the initialization procedure is complete without failure, to remove // cycle reference in fail case and to avoid memory leakage. - mChannel = httpChannel.forget(); - mParentListener = parentListener.forget(); + mChannel = std::move(httpChannel); + mParentListener = std::move(parentListener); mChannel->SetNotificationCallbacks(mParentListener); mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse; @@ -842,7 +841,8 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvSetCacheTokenCachedCharset( mozilla::ipc::IPCResult HttpChannelParent::RecvRedirect2Verify( const nsresult& aResult, const RequestHeaderTuples& changedHeaders, - const ChildLoadInfoForwarderArgs& aLoadInfoForwarder, + const uint32_t& aSourceRequestBlockingReason, + const Maybe& aTargetLoadInfoForwarder, const uint32_t& loadFlags, nsIReferrerInfo* aReferrerInfo, const Maybe& aAPIRedirectURI, const Maybe& aCorsPreflightArgs, @@ -891,7 +891,8 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvRedirect2Verify( do_QueryInterface(newHttpChannel); MOZ_RELEASE_ASSERT(newInternalChannel); const CorsPreflightArgs& args = aCorsPreflightArgs.ref(); - newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders()); + newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders(), + false); } if (aReferrerInfo) { @@ -907,17 +908,46 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvRedirect2Verify( nsCOMPtr appCacheChannel = do_QueryInterface(newHttpChannel); if (appCacheChannel) { - appCacheChannel->SetChooseApplicationCache(aChooseAppcache); + bool setChooseAppCache = false; + if (aChooseAppcache) { + nsCOMPtr uri; + // Using GetURI because this is what DoAsyncOpen uses. + newHttpChannel->GetURI(getter_AddRefs(uri)); + + OriginAttributes attrs; + NS_GetOriginAttributes(newHttpChannel, attrs); + + nsCOMPtr principal = + BasePrincipal::CreateCodebasePrincipal(uri, attrs); + + setChooseAppCache = NS_ShouldCheckAppCache(principal); + } + + appCacheChannel->SetChooseApplicationCache(setChooseAppCache); } - nsCOMPtr newLoadInfo = newHttpChannel->LoadInfo(); - rv = MergeChildLoadInfoForwarder(aLoadInfoForwarder, newLoadInfo); - if (NS_FAILED(rv) && NS_SUCCEEDED(result)) { - result = rv; + if (aTargetLoadInfoForwarder.isSome()) { + nsCOMPtr newLoadInfo = newHttpChannel->LoadInfo(); + rv = MergeChildLoadInfoForwarder(aTargetLoadInfoForwarder.ref(), + newLoadInfo); + if (NS_FAILED(rv) && NS_SUCCEEDED(result)) { + result = rv; + } } } } + // If the redirect is vetoed, reason is set on the source (current) channel's + // load info, so we must carry iver the change. + // The channel may have already been cleaned up, so there is nothing we can + // do. + if (MOZ_UNLIKELY(aSourceRequestBlockingReason) && mChannel) { + nsCOMPtr sourceLoadInfo = mChannel->LoadInfo(); + if (sourceLoadInfo) { + sourceLoadInfo->SetRequestBlockingReason(aSourceRequestBlockingReason); + } + } + // Continue the verification procedure if child has veto the redirection. if (NS_FAILED(result)) { ContinueRedirect2Verify(result); @@ -1390,8 +1420,8 @@ HttpChannelParent::OnStartRequest(nsIRequest* aRequest) { if (httpChannelImpl) { httpChannelImpl->GetLoadedFromApplicationCache(&loadedFromApplicationCache); if (loadedFromApplicationCache) { - mOfflineForeignMarker = - httpChannelImpl->GetOfflineCacheEntryAsForeignMarker(); + mOfflineForeignMarker.reset( + httpChannelImpl->GetOfflineCacheEntryAsForeignMarker()); nsCOMPtr appCache; httpChannelImpl->GetApplicationCache(getter_AddRefs(appCache)); nsCString appCacheGroupId; @@ -1752,13 +1782,18 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvOpenAltDataCacheInputStream( //----------------------------------------------------------------------------- NS_IMETHODIMP -HttpChannelParent::OnProgress(nsIRequest* aRequest, nsISupports* aContext, - int64_t aProgress, int64_t aProgressMax) { - LOG(("HttpChannelParent::OnStatus [this=%p progress=%" PRId64 "max=%" PRId64 +HttpChannelParent::OnProgress(nsIRequest* aRequest, int64_t aProgress, + int64_t aProgressMax) { + LOG(("HttpChannelParent::OnProgress [this=%p progress=%" PRId64 "max=%" PRId64 "]\n", this, aProgress, aProgressMax)); MOZ_ASSERT(NS_IsMainThread()); + // If IPC channel is closed, there is nothing we can do. Just return NS_OK. + if (mIPCClosed) { + return NS_OK; + } + // If it indicates this precedes OnDataAvailable, child can derive the value // in ODA. if (mIgnoreProgress) { @@ -1766,15 +1801,10 @@ HttpChannelParent::OnProgress(nsIRequest* aRequest, nsISupports* aContext, return NS_OK; } - // Either IPC channel is closed or background channel - // is ready to send OnProgress. - MOZ_ASSERT(mIPCClosed || mBgParent); - // Send OnProgress events to the child for data upload progress notifications // (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has // LOAD_BACKGROUND set. - if (mIPCClosed || !mBgParent || - !mBgParent->OnProgress(aProgress, aProgressMax)) { + if (!SendOnProgress(aProgress, aProgressMax)) { return NS_ERROR_UNEXPECTED; } @@ -1782,12 +1812,17 @@ HttpChannelParent::OnProgress(nsIRequest* aRequest, nsISupports* aContext, } NS_IMETHODIMP -HttpChannelParent::OnStatus(nsIRequest* aRequest, nsISupports* aContext, - nsresult aStatus, const char16_t* aStatusArg) { +HttpChannelParent::OnStatus(nsIRequest* aRequest, nsresult aStatus, + const char16_t* aStatusArg) { LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32 "]\n", this, static_cast(aStatus))); MOZ_ASSERT(NS_IsMainThread()); + // If IPC channel is closed, there is nothing we can do. Just return NS_OK. + if (mIPCClosed) { + return NS_OK; + } + // If this precedes OnDataAvailable, transportStatus will be derived in ODA. if (aStatus == NS_NET_STATUS_RECEIVING_FROM || aStatus == NS_NET_STATUS_READING) { @@ -1798,12 +1833,8 @@ HttpChannelParent::OnStatus(nsIRequest* aRequest, nsISupports* aContext, return NS_OK; } - // Either IPC channel is closed or background channel - // is ready to send OnStatus. - MOZ_ASSERT(mIPCClosed || mBgParent); - // Otherwise, send to child now - if (mIPCClosed || !mBgParent || !mBgParent->OnStatus(aStatus)) { + if (!SendOnStatus(aStatus)) { return NS_ERROR_UNEXPECTED; } @@ -2298,12 +2329,11 @@ void HttpChannelParent::StartDiversion() { Unused << mChannel->DoApplyContentConversions( mDivertListener, getter_AddRefs(converterListener)); if (converterListener) { - mDivertListener = converterListener.forget(); + mDivertListener = std::move(converterListener); } // Now mParentListener can be diverted to mDivertListener. - DebugOnly rvdbg = mParentListener->DivertTo(mDivertListener); - MOZ_ASSERT(NS_SUCCEEDED(rvdbg)); + mParentListener->DivertTo(mDivertListener); mDivertListener = nullptr; // Either IPC channel is closed or background channel diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 93e6038bc7..a318a5d658 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -182,7 +182,8 @@ class HttpChannelParent final : public nsIInterfaceRequestor, virtual mozilla::ipc::IPCResult RecvCancel(const nsresult& status) override; virtual mozilla::ipc::IPCResult RecvRedirect2Verify( const nsresult& result, const RequestHeaderTuples& changedHeaders, - const ChildLoadInfoForwarderArgs& aLoadInfoForwarder, + const uint32_t& aSourceRequestBlockingReason, + const Maybe& aTargetLoadInfoForwarder, const uint32_t& loadFlags, nsIReferrerInfo* aReferrerInfo, const Maybe& apiRedirectUri, const Maybe& aCorsPreflightArgs, @@ -277,7 +278,7 @@ class HttpChannelParent final : public nsIInterfaceRequestor, nsCOMPtr mRedirectChannel; nsCOMPtr mRedirectCallback; - nsAutoPtr + UniquePtr mOfflineForeignMarker; nsCOMPtr mLoadContext; RefPtr mHttpHandler; diff --git a/netwerk/protocol/http/InterceptedChannel.cpp b/netwerk/protocol/http/InterceptedChannel.cpp index 6d471273fe..0cd98acf8f 100644 --- a/netwerk/protocol/http/InterceptedChannel.cpp +++ b/netwerk/protocol/http/InterceptedChannel.cpp @@ -66,8 +66,8 @@ void InterceptedChannelBase::DoNotifyController() { mController = nullptr; } -nsresult InterceptedChannelBase::DoSynthesizeStatus(uint16_t aStatus, - const nsACString& aReason) { +void InterceptedChannelBase::DoSynthesizeStatus(uint16_t aStatus, + const nsACString& aReason) { EnsureSynthesizedResponse(); // Always assume HTTP 1.1 for synthesized responses. @@ -78,7 +78,6 @@ nsresult InterceptedChannelBase::DoSynthesizeStatus(uint16_t aStatus, statusLine.Append(aReason); (*mSynthesizedResponseHead)->ParseStatusLine(statusLine); - return NS_OK; } nsresult InterceptedChannelBase::DoSynthesizeHeader(const nsACString& aName, @@ -87,9 +86,7 @@ nsresult InterceptedChannelBase::DoSynthesizeHeader(const nsACString& aName, nsAutoCString header = aName + NS_LITERAL_CSTRING(": ") + aValue; // Overwrite any existing header. - nsresult rv = (*mSynthesizedResponseHead)->ParseHeaderLine(header); - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; + return (*mSynthesizedResponseHead)->ParseHeaderLine(header); } NS_IMETHODIMP @@ -268,7 +265,8 @@ InterceptedChannelContent::SynthesizeStatus(uint16_t aStatus, return NS_ERROR_NOT_AVAILABLE; } - return DoSynthesizeStatus(aStatus, aReason); + DoSynthesizeStatus(aStatus, aReason); + return NS_OK; } NS_IMETHODIMP @@ -311,7 +309,7 @@ InterceptedChannelContent::StartSynthesizedResponse( originalURI->Equals(responseURI, &equal); if (!equal) { mChannel->ForceIntercepted(aBody, aBodyCallback, aCacheInfoChannel); - mChannel->BeginNonIPCRedirect(responseURI, *mSynthesizedResponseHead.ptr(), + mChannel->BeginNonIPCRedirect(responseURI, mSynthesizedResponseHead->get(), aResponseRedirected); } else { mChannel->OverrideWithSynthesizedResponse( diff --git a/netwerk/protocol/http/InterceptedChannel.h b/netwerk/protocol/http/InterceptedChannel.h index 9d6e4ae8be..b18d70c3b9 100644 --- a/netwerk/protocol/http/InterceptedChannel.h +++ b/netwerk/protocol/http/InterceptedChannel.h @@ -31,7 +31,7 @@ class InterceptedChannelBase : public nsIInterceptedChannel { nsCOMPtr mController; // Response head for use when synthesizing - Maybe> mSynthesizedResponseHead; + Maybe> mSynthesizedResponseHead; nsCOMPtr mReportCollector; nsCOMPtr mReleaseHandle; @@ -40,8 +40,7 @@ class InterceptedChannelBase : public nsIInterceptedChannel { void EnsureSynthesizedResponse(); void DoNotifyController(); - MOZ_MUST_USE nsresult DoSynthesizeStatus(uint16_t aStatus, - const nsACString& aReason); + void DoSynthesizeStatus(uint16_t aStatus, const nsACString& aReason); MOZ_MUST_USE nsresult DoSynthesizeHeader(const nsACString& aName, const nsACString& aValue); diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp index 7aeebe159a..aac9cb7993 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.cpp +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp @@ -150,7 +150,7 @@ void InterceptedHttpChannel::AsyncOpenInternal() { bool InterceptedHttpChannel::ShouldRedirect() const { // Determine if the synthetic response requires us to perform a real redirect. - return nsHttpChannel::WillRedirect(mResponseHead) && + return nsHttpChannel::WillRedirect(*mResponseHead) && !mLoadInfo->GetDontFollowRedirects(); } @@ -202,7 +202,7 @@ nsresult InterceptedHttpChannel::FollowSyntheticRedirect() { redirectFlags); NS_ENSURE_SUCCESS(rv, rv); - mRedirectChannel = newChannel.forget(); + mRedirectChannel = std::move(newChannel); rv = gHttpHandler->AsyncOnChannelRedirect(this, mRedirectChannel, redirectFlags); @@ -228,10 +228,10 @@ nsresult InterceptedHttpChannel::RedirectForResponseURL( // We want to pass ownership of the body callback to the new synthesized // channel. We need to hold a reference to the callbacks on the stack // as well, though, so we can call them if a failure occurs. - nsCOMPtr bodyCallback = mBodyCallback.forget(); + nsCOMPtr bodyCallback = std::move(mBodyCallback); RefPtr newChannel = CreateForSynthesis( - mResponseHead, mBodyReader, bodyCallback, mChannelCreationTime, + mResponseHead.get(), mBodyReader, bodyCallback, mChannelCreationTime, mChannelCreationTimestamp, mAsyncOpenTime); // If the response has been redirected, propagate all the URLs to content. @@ -244,8 +244,7 @@ nsresult InterceptedHttpChannel::RedirectForResponseURL( CloneLoadInfoForRedirect(aResponseURI, flags); nsContentPolicyType contentPolicyType = - redirectLoadInfo ? redirectLoadInfo->GetExternalContentPolicyType() - : nsIContentPolicy::TYPE_OTHER; + redirectLoadInfo->GetExternalContentPolicyType(); rv = newChannel->Init( aResponseURI, mCaps, static_cast(mProxyInfo.get()), @@ -403,16 +402,15 @@ void InterceptedHttpChannel::MaybeCallStatusAndProgress() { CopyUTF8toUTF16(host, mStatusHost); } - mProgressSink->OnStatus(this, nullptr, NS_NET_STATUS_READING, - mStatusHost.get()); + mProgressSink->OnStatus(this, NS_NET_STATUS_READING, mStatusHost.get()); - mProgressSink->OnProgress(this, nullptr, progress, mSynthesizedStreamLength); + mProgressSink->OnProgress(this, progress, mSynthesizedStreamLength); mProgressReported = progress; } void InterceptedHttpChannel::MaybeCallBodyCallback() { - nsCOMPtr callback = mBodyCallback.forget(); + nsCOMPtr callback = std::move(mBodyCallback); if (callback) { callback->BodyComplete(mStatus); } @@ -446,7 +444,7 @@ InterceptedHttpChannel::CreateForSynthesis( RefPtr ref = new InterceptedHttpChannel( aCreationTime, aCreationTimestamp, aAsyncOpenTimestamp); - ref->mResponseHead = new nsHttpResponseHead(*aHead); + ref->mResponseHead = MakeUnique(*aHead); ref->mBodyReader = aBody; ref->mBodyCallback = aBodyCallback; @@ -645,7 +643,7 @@ InterceptedHttpChannel::ResetInterception(void) { NS_ENSURE_SUCCESS(rv, rv); } - mRedirectChannel = newChannel.forget(); + mRedirectChannel = std::move(newChannel); rv = gHttpHandler->AsyncOnChannelRedirect(this, mRedirectChannel, flags); @@ -735,7 +733,7 @@ InterceptedHttpChannel::StartSynthesizedResponse( mSynthesizedResponseHead.reset(new nsHttpResponseHead()); } - mResponseHead = mSynthesizedResponseHead.release(); + mResponseHead = std::move(mSynthesizedResponseHead); if (ShouldRedirect()) { rv = FollowSyntheticRedirect(); diff --git a/netwerk/protocol/http/NullHttpChannel.cpp b/netwerk/protocol/http/NullHttpChannel.cpp index 6c28555538..12b91efde2 100644 --- a/netwerk/protocol/http/NullHttpChannel.cpp +++ b/netwerk/protocol/http/NullHttpChannel.cpp @@ -253,6 +253,12 @@ NullHttpChannel::VisitOriginalResponseHeaders(nsIHttpHeaderVisitor* aVisitor) { return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +NullHttpChannel::ShouldStripRequestBodyHeader(const nsACString& aMethod, + bool* aResult) { + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP NullHttpChannel::IsNoStoreResponse(bool* _retval) { return NS_ERROR_NOT_IMPLEMENTED; @@ -761,7 +767,7 @@ NullHttpChannel::TimingAllowCheck(nsIPrincipal* aOrigin, bool* _retval) { } nsAutoCString origin; - nsContentUtils::GetASCIIOrigin(aOrigin, origin); + aOrigin->GetAsciiOrigin(origin); if (mTimingAllowOriginHeader == origin) { *_retval = true; diff --git a/netwerk/protocol/http/PHttpBackgroundChannel.ipdl b/netwerk/protocol/http/PHttpBackgroundChannel.ipdl index 8a935ba784..9c51dab960 100644 --- a/netwerk/protocol/http/PHttpBackgroundChannel.ipdl +++ b/netwerk/protocol/http/PHttpBackgroundChannel.ipdl @@ -40,10 +40,6 @@ child: TimeStamp lastActiveTabOptimization, nsHttpHeaderArray responseTrailers); - async OnProgress(int64_t progress, int64_t progressMax); - - async OnStatus(nsresult status); - // Parent has been suspended for diversion; no more events to be enqueued. async FlushedForDiversion(); diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl index b2e014c106..3e979b9b42 100644 --- a/netwerk/protocol/http/PHttpChannel.ipdl +++ b/netwerk/protocol/http/PHttpChannel.ipdl @@ -41,7 +41,8 @@ parent: // Reports approval/veto of redirect by child process redirect observers async Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders, - ChildLoadInfoForwarderArgs loadInfoForwarder, + uint32_t sourceRequestBlockingReason, + ChildLoadInfoForwarderArgs? targetLoadInfoForwarder, uint32_t loadFlags, nsIReferrerInfo referrerInfo, URIParams? apiRedirectTo, CorsPreflightArgs? corsPreflightArgs, @@ -188,6 +189,10 @@ child: async AltDataCacheInputStreamAvailable(IPCStream? stream); + async OnProgress(int64_t progress, int64_t progressMax); + + async OnStatus(nsresult status); + both: // After receiving this message, the parent also calls // SendFinishInterceptedRedirect, and makes sure not to send any more messages diff --git a/netwerk/protocol/http/PSpdyPush.h b/netwerk/protocol/http/PSpdyPush.h index ca77157080..a7a0145962 100644 --- a/netwerk/protocol/http/PSpdyPush.h +++ b/netwerk/protocol/http/PSpdyPush.h @@ -24,7 +24,6 @@ #ifndef mozilla_net_SpdyPush_Public_h #define mozilla_net_SpdyPush_Public_h -#include "nsAutoPtr.h" #include "nsDataHashtable.h" #include "nsISupports.h" #include "nsStringFwd.h" diff --git a/netwerk/protocol/http/TunnelUtils.cpp b/netwerk/protocol/http/TunnelUtils.cpp index 499627f0c6..c08e9c4818 100644 --- a/netwerk/protocol/http/TunnelUtils.cpp +++ b/netwerk/protocol/http/TunnelUtils.cpp @@ -144,15 +144,7 @@ void TLSFilterTransaction::Close(nsresult aReason) { } } - if (gHttpHandler->Bug1563538()) { - if (NS_FAILED(aReason)) { - mCloseReason = aReason; - } else { - mCloseReason = NS_BASE_STREAM_CLOSED; - } - } else { - MOZ_ASSERT(NS_ERROR_UNEXPECTED == mCloseReason); - } + mCloseReason = NS_FAILED(aReason) ? aReason : NS_BASE_STREAM_CLOSED; } nsresult TLSFilterTransaction::OnReadSegment(const char* aData, uint32_t aCount, @@ -378,57 +370,17 @@ nsresult TLSFilterTransaction::WriteSegmentsAgain(nsAHttpSegmentWriter* aWriter, return mCloseReason; } - bool againBeforeWriteSegmentsCall = *again; - mSegmentWriter = aWriter; - /* - * Bug 1562315 replaced TLSFilterTransaction::WriteSegments with - * WriteSegmentsAgain and the call of WriteSegments on the associated - * transaction was replaced with WriteSegmentsAgain call. - * - * When TLSFilterTransaction::WriteSegmentsAgain was called from outside, it - * internally called WriteSegments (nsAHttpTransaction default impl) and did - * not modify the 'again' out flag. - * - * So, to disable the bug fix, we only need two things: - * - call mTransaction->WriteSegments - * - don't modify 'again' (which is an automatic outcome of step 1, this - * method doesn't touch it itself) - */ - - nsresult rv = - gHttpHandler->Bug1562315() - ? mTransaction->WriteSegmentsAgain(this, aCount, outCountWritten, - again) - : mTransaction->WriteSegments(this, aCount, outCountWritten); + nsresult rv = mTransaction->WriteSegmentsAgain(this, aCount, outCountWritten, + again); - if (NS_SUCCEEDED(rv) && !(*outCountWritten)) { - if (NS_FAILED(mFilterReadCode)) { + if (NS_SUCCEEDED(rv) && !(*outCountWritten) && NS_FAILED(mFilterReadCode)) { // nsPipe turns failures into silent OK.. undo that! rv = mFilterReadCode; if (Connection() && (mFilterReadCode == NS_BASE_STREAM_WOULD_BLOCK)) { Unused << Connection()->ResumeRecv(); } - } - if (againBeforeWriteSegmentsCall && !*again) { - // This code can never be reached if bug1562315 pref is off. - LOG( - ("TLSFilterTransaction %p called trans->WriteSegments which dropped " - "the 'again' flag", - this)); - // The transaction (=h2 session) wishes to break the loop. There is a - // pending close of the transaction that is being handled by the current - // input stream of the session. After cancellation of that transaction - // the state of the stream will change and move the state machine of the - // session forward on the next call of WriteSegmentsAgain. But if there - // are no data on the socket to read to call this code again, the session - // and the stream will just hang in an intermediate state, blocking. Hence - // forcing receive to finish the stream cleanup. - if (Connection()) { - Unused << Connection()->ForceRecv(); - } - } } LOG(("TLSFilterTransaction %p called trans->WriteSegments rv=%" PRIx32 " %d\n", @@ -544,6 +496,17 @@ nsresult TLSFilterTransaction::StartTimerCallback() { return NS_OK; } +bool TLSFilterTransaction::HasDataToRecv() { + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + if (!mFD) { + return false; + } + int32_t n = 0; + char c; + n = PR_Recv(mFD, &c, 1, PR_MSG_PEEK, 0); + return n > 0; +} + PRStatus TLSFilterTransaction::GetPeerName(PRFileDesc* aFD, PRNetAddr* addr) { NetAddr peeraddr; TLSFilterTransaction* self = @@ -1903,33 +1866,30 @@ SocketTransportShim::Close(nsresult aReason) { LOG(("SocketTransportShim::Close %p", this)); } - if (gHttpHandler->Bug1563538()) { - // Must always post, because mSession->CloseTransaction releases the - // Http2Stream which is still on stack. - RefPtr self(this); + // Must always post, because mSession->CloseTransaction releases the + // Http2Stream which is still on stack. + RefPtr self(this); - nsCOMPtr sts = - do_GetService("@mozilla.org/network/socket-transport-service;1"); - Unused << sts->Dispatch(NS_NewRunnableFunction( - "SocketTransportShim::Close", [self = std::move(self), aReason]() { - RefPtr baseTrans = - self->mWeakTrans->QueryTransaction(); - if (!baseTrans) { - return; - } - SpdyConnectTransaction* trans = - baseTrans->QuerySpdyConnectTransaction(); - MOZ_ASSERT(trans); - if (!trans) { - return; - } - - trans->mSession->CloseTransaction(trans, aReason); - })); - return NS_OK; - } + nsCOMPtr sts = + do_GetService("@mozilla.org/network/socket-transport-service;1"); + Unused << sts->Dispatch(NS_NewRunnableFunction( + "SocketTransportShim::Close", [self = std::move(self), aReason]() { + RefPtr baseTrans = + self->mWeakTrans->QueryTransaction(); + if (!baseTrans) { + return; + } + SpdyConnectTransaction* trans = + baseTrans->QuerySpdyConnectTransaction(); + MOZ_ASSERT(trans); + if (!trans) { + return; + } - return NS_ERROR_NOT_IMPLEMENTED; + trans->mSession->CloseTransaction(trans, aReason); + })); + + return NS_OK; } NS_IMETHODIMP diff --git a/netwerk/protocol/http/TunnelUtils.h b/netwerk/protocol/http/TunnelUtils.h index 0fac959bdd..3177150bff 100644 --- a/netwerk/protocol/http/TunnelUtils.h +++ b/netwerk/protocol/http/TunnelUtils.h @@ -147,6 +147,8 @@ class TLSFilterTransaction final : public nsAHttpTransaction, uint32_t* countWritten, bool* again) override; + bool HasDataToRecv(); + private: MOZ_MUST_USE nsresult StartTimerCallback(); void Cleanup(); diff --git a/netwerk/protocol/http/WellKnownOpportunisticUtils.jsm b/netwerk/protocol/http/WellKnownOpportunisticUtils.jsm index 4c32234008..3655516335 100644 --- a/netwerk/protocol/http/WellKnownOpportunisticUtils.jsm +++ b/netwerk/protocol/http/WellKnownOpportunisticUtils.jsm @@ -13,15 +13,12 @@ function WellKnownOpportunisticUtils() { WellKnownOpportunisticUtils.prototype = { QueryInterface: ChromeUtils.generateQI([Ci.nsIWellKnownOpportunisticUtils]), - verify(aJSON, aOrigin, aAlternatePort) { + verify(aJSON, aOrigin) { try { - let obj = JSON.parse(aJSON.toLowerCase()); - let ports = obj[aOrigin.toLowerCase()]["tls-ports"]; - if (!ports.includes(aAlternatePort)) { - throw new Error("invalid port"); + let arr = JSON.parse(aJSON.toLowerCase()); + if (!arr.includes(aOrigin.toLowerCase())) { + throw new Error("invalid origin"); } - this.lifetime = obj[aOrigin.toLowerCase()].lifetime; - this.mixed = obj[aOrigin.toLowerCase()]["mixed-scheme"]; } catch (e) { return; } diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index dd67024cf8..630390c331 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -178,10 +178,10 @@ static nsPreflightCache* sPreflightCache = nullptr; static bool EnsurePreflightCache() { if (sPreflightCache) return true; - nsAutoPtr newCache(new nsPreflightCache()); + UniquePtr newCache(new nsPreflightCache()); if (newCache->Initialize()) { - sPreflightCache = newCache.forget(); + sPreflightCache = newCache.release(); return true; } @@ -559,7 +559,7 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) { if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*")) { MOZ_ASSERT(!nsContentUtils::IsExpandedPrincipal(mOriginHeaderPrincipal)); nsAutoCString origin; - nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin); + mOriginHeaderPrincipal->GetAsciiOrigin(origin); if (!allowedOriginHeader.Equals(origin)) { LogBlockedRequest( @@ -742,8 +742,18 @@ nsCORSListenerProxy::AsyncOnChannelRedirect( } } + bool rewriteToGET = false; + nsCOMPtr oldHttpChannel = do_QueryInterface(aOldChannel); + if (oldHttpChannel) { + nsAutoCString method; + Unused << oldHttpChannel->GetRequestMethod(method); + Unused << oldHttpChannel->ShouldStripRequestBodyHeader(method, + &rewriteToGET); + } + rv = UpdateChannel(aNewChannel, DataURIHandling::Disallow, - UpdateType::Default); + rewriteToGET ? UpdateType::StripRequestBodyHeader + : UpdateType::Default); if (NS_FAILED(rv)) { NS_WARNING( "nsCORSListenerProxy::AsyncOnChannelRedirect: " @@ -1018,8 +1028,9 @@ nsresult nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel, return NS_ERROR_DOM_BAD_URI; } - internal->SetCorsPreflightParameters(headers.IsEmpty() ? loadInfoHeaders - : headers); + internal->SetCorsPreflightParameters( + headers.IsEmpty() ? loadInfoHeaders : headers, + aUpdateType == UpdateType::StripRequestBodyHeader); return NS_OK; } @@ -1384,7 +1395,7 @@ nsresult nsCORSListenerProxy::StartCORSPreflight( nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, "how did we end up here?"); - nsCOMPtr principal = originalLoadInfo->LoadingPrincipal(); + nsCOMPtr principal = originalLoadInfo->GetLoadingPrincipal(); MOZ_ASSERT(principal && originalLoadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT, "Should not do CORS loads for top-level loads, so a " diff --git a/netwerk/protocol/http/nsCORSListenerProxy.h b/netwerk/protocol/http/nsCORSListenerProxy.h index 2bb39b7dd6..e139e1d7e9 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.h +++ b/netwerk/protocol/http/nsCORSListenerProxy.h @@ -32,7 +32,11 @@ class nsHttpChannel; enum class DataURIHandling { Allow, Disallow }; -enum class UpdateType { Default, InternalOrHSTSRedirect }; +enum class UpdateType { + Default, + StripRequestBodyHeader, + InternalOrHSTSRedirect +}; class nsCORSListenerProxy final : public nsIStreamListener, public nsIInterfaceRequestor, diff --git a/netwerk/protocol/http/nsHttp.cpp b/netwerk/protocol/http/nsHttp.cpp index e3e75de1e6..e6046ab147 100644 --- a/netwerk/protocol/http/nsHttp.cpp +++ b/netwerk/protocol/http/nsHttp.cpp @@ -416,7 +416,8 @@ bool ValidationRequired(bool isForcedValid, LOG((" not validating, expire time not in the past")); } else if (cachedResponseHead->MustValidateIfExpired()) { doValidation = true; - } else if (cachedResponseHead->StaleWhileRevalidate(now, expiration)) { + } else if (cachedResponseHead->StaleWhileRevalidate(now, expiration) && + StaticPrefs::network_http_stale_while_revalidate_enabled()) { LOG((" not validating, in the stall-while-revalidate window")); doValidation = false; if (performBackgroundRevalidation) { diff --git a/netwerk/protocol/http/nsHttp.h b/netwerk/protocol/http/nsHttp.h index 1f51bd1b4b..50d8c0756c 100644 --- a/netwerk/protocol/http/nsHttp.h +++ b/netwerk/protocol/http/nsHttp.h @@ -7,7 +7,6 @@ #include #include "prtime.h" -#include "nsAutoPtr.h" #include "nsString.h" #include "nsError.h" #include "nsTArray.h" diff --git a/netwerk/protocol/http/nsHttpActivityDistributor.cpp b/netwerk/protocol/http/nsHttpActivityDistributor.cpp index 69009d1a8e..6354220cae 100644 --- a/netwerk/protocol/http/nsHttpActivityDistributor.cpp +++ b/netwerk/protocol/http/nsHttpActivityDistributor.cpp @@ -7,7 +7,6 @@ #include "nsHttpActivityDistributor.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "nsThreadUtils.h" namespace mozilla { diff --git a/netwerk/protocol/http/nsHttpAuthCache.cpp b/netwerk/protocol/http/nsHttpAuthCache.cpp index 06a8e70321..ef4e76ac9a 100644 --- a/netwerk/protocol/http/nsHttpAuthCache.cpp +++ b/netwerk/protocol/http/nsHttpAuthCache.cpp @@ -61,8 +61,7 @@ nsHttpAuthCache::nsHttpAuthCache() nsHttpAuthCache::~nsHttpAuthCache() { LOG(("nsHttpAuthCache::~nsHttpAuthCache %p", this)); - DebugOnly rv = ClearAll(); - MOZ_ASSERT(NS_SUCCEEDED(rv)); + ClearAll(); nsCOMPtr obsSvc = services::GetObserverService(); if (obsSvc) { obsSvc->RemoveObserver(mObserver, "clear-origin-attributes-data"); @@ -143,10 +142,9 @@ void nsHttpAuthCache::ClearAuthEntry(const char* scheme, const char* host, mDB.Remove(key); } -nsresult nsHttpAuthCache::ClearAll() { +void nsHttpAuthCache::ClearAll() { LOG(("nsHttpAuthCache::ClearAll %p\n", this)); mDB.Clear(); - return NS_OK; } //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsHttpAuthCache.h b/netwerk/protocol/http/nsHttpAuthCache.h index a54bb55cf6..f9b31fff36 100644 --- a/netwerk/protocol/http/nsHttpAuthCache.h +++ b/netwerk/protocol/http/nsHttpAuthCache.h @@ -195,7 +195,7 @@ class nsHttpAuthCache { const char* realm, nsACString const& originSuffix); // expire all existing auth list entries including proxy auths. - MOZ_MUST_USE nsresult ClearAll(); + void ClearAll(); private: nsHttpAuthNode* LookupAuthNode(const char* scheme, const char* host, diff --git a/netwerk/protocol/http/nsHttpAuthManager.cpp b/netwerk/protocol/http/nsHttpAuthManager.cpp index 6a87160be7..243533bb1d 100644 --- a/netwerk/protocol/http/nsHttpAuthManager.cpp +++ b/netwerk/protocol/http/nsHttpAuthManager.cpp @@ -103,10 +103,8 @@ nsHttpAuthManager::SetAuthIdentity( NS_IMETHODIMP nsHttpAuthManager::ClearAll() { - nsresult rv = mAuthCache->ClearAll(); - nsresult rv2 = mPrivateAuthCache->ClearAll(); - if (NS_FAILED(rv)) return rv; - if (NS_FAILED(rv2)) return rv2; + mAuthCache->ClearAll(); + mPrivateAuthCache->ClearAll(); return NS_OK; } diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 8ff2f23170..15519aba36 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -103,7 +103,6 @@ #include "HttpChannelParentListener.h" #include "InterceptedHttpChannel.h" #include "../../cache2/CacheFileUtils.h" -#include "../../cache2/CacheHashUtils.h" #include "nsINetworkLinkService.h" #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/Promise.h" @@ -227,9 +226,9 @@ bool IsInSubpathOfAppCacheManifest(nsIApplicationCache* cache, // We only treat 3xx responses as redirects if they have a Location header and // the status code is in a whitelist. -bool nsHttpChannel::WillRedirect(nsHttpResponseHead* response) { - return IsRedirectStatus(response->Status()) && - response->HasHeader(nsHttp::Location); +bool nsHttpChannel::WillRedirect(const nsHttpResponseHead& response) { + return IsRedirectStatus(response.Status()) && + response.HasHeader(nsHttp::Location); } nsresult StoreAuthorizationMetaData(nsICacheEntry* entry, @@ -359,7 +358,6 @@ void nsHttpChannel::ReleaseMainThreadOnlyReferences() { nsTArray> arrayToRelease; arrayToRelease.AppendElement(mApplicationCacheForWrite.forget()); arrayToRelease.AppendElement(mAuthProvider.forget()); - arrayToRelease.AppendElement(mRedirectURI.forget()); arrayToRelease.AppendElement(mRedirectChannel.forget()); arrayToRelease.AppendElement(mPreflightChannel.forget()); arrayToRelease.AppendElement(mDNSPrefetch.forget()); @@ -818,8 +816,45 @@ nsresult nsHttpChannel::ContinueConnect() { } nsresult nsHttpChannel::DoConnect(nsHttpTransaction* aTransWithStickyConn) { - LOG(("nsHttpChannel::DoConnect [this=%p, aTransWithStickyConn=%p]\n", this, - aTransWithStickyConn)); + LOG(("nsHttpChannel::DoConnect [this=%p]\n", this)); + + if (!mDNSBlockingPromise.IsEmpty()) { + LOG((" waiting for DNS prefetch")); + + // Transaction is passed only from auth retry for which we will definitely + // not block on DNS to alter the origin server name for IP; it has already + // been done. + MOZ_ASSERT(!aTransWithStickyConn); + MOZ_ASSERT(mDNSBlockingThenable); + + nsCOMPtr target(do_GetMainThread()); + RefPtr self(this); + mDNSBlockingThenable->Then( + target, __func__, + [self](const nsCOMPtr& aRec) { + nsresult rv = self->DoConnectActual(nullptr); + if (NS_FAILED(rv)) { + self->CloseCacheEntry(false); + Unused << self->AsyncAbort(rv); + } + }, + [self](nsresult err) { + self->CloseCacheEntry(false); + Unused << self->AsyncAbort(err); + }); + + // The connection will continue when the promise is resolved in + // OnLookupComplete. + return NS_OK; + } + + return DoConnectActual(aTransWithStickyConn); +} + +nsresult nsHttpChannel::DoConnectActual( + nsHttpTransaction* aTransWithStickyConn) { + LOG(("nsHttpChannel::DoConnectActual [this=%p, aTransWithStickyConn=%p]\n", + this, aTransWithStickyConn)); nsresult rv = SetupTransaction(); if (NS_FAILED(rv)) { @@ -1415,20 +1450,18 @@ nsresult EnsureMIMEOfScript(nsHttpChannel* aChannel, nsIURI* aURI, break; } - nsCOMPtr requestURI; - aLoadInfo->LoadingPrincipal()->GetURI(getter_AddRefs(requestURI)); - - nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; - nsresult rv = ssm->CheckSameOriginURI(requestURI, aURI, false, isPrivateWin); - if (NS_SUCCEEDED(rv)) { + bool isSameOrigin = false; + aLoadInfo->GetLoadingPrincipal()->IsSameOrigin(aURI, isPrivateWin, + &isSameOrigin); + if (isSameOrigin) { // same origin AccumulateCategorical( Telemetry::LABELS_SCRIPT_BLOCK_INCORRECT_MIME_3::same_origin); } else { bool cors = false; nsAutoCString corsOrigin; - rv = aResponseHead->GetHeader( + nsresult rv = aResponseHead->GetHeader( nsHttp::ResolveAtom("Access-Control-Allow-Origin"), corsOrigin); if (NS_SUCCEEDED(rv)) { if (corsOrigin.Equals("*")) { @@ -1439,9 +1472,10 @@ nsresult EnsureMIMEOfScript(nsHttpChannel* aChannel, nsIURI* aURI, if (NS_SUCCEEDED(rv)) { bool isPrivateWin = aLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; - rv = ssm->CheckSameOriginURI(requestURI, corsOriginURI, false, - isPrivateWin); - if (NS_SUCCEEDED(rv)) { + bool isSameOrigin = false; + aLoadInfo->GetLoadingPrincipal()->IsSameOrigin( + corsOriginURI, isPrivateWin, &isSameOrigin); + if (isSameOrigin) { cors = true; } } @@ -1625,33 +1659,6 @@ void nsHttpChannel::SetCachedContentType() { mCacheEntry->SetContentType(contentType); } -void nsHttpChannel::StoreSiteAccessToCacheEntry() { - nsresult rv; - - nsCOMPtr topWindowURI; - rv = GetTopWindowURI(getter_AddRefs(topWindowURI)); - if (NS_FAILED(rv)) { - return; - } - - nsCOMPtr eTLDService = - do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) { - return; - } - - nsAutoCString baseDomain; - rv = eTLDService->GetBaseDomain(topWindowURI, 0, baseDomain); - if (NS_FAILED(rv)) { - return; - } - - RefPtr hash = new CacheHash(); - hash->Update(baseDomain.get(), baseDomain.Length()); - - Unused << mCacheEntry->AddBaseDomainAccess(hash->GetHash()); -} - nsresult nsHttpChannel::CallOnStartRequest() { LOG(("nsHttpChannel::CallOnStartRequest [this=%p]", this)); @@ -1692,13 +1699,13 @@ nsresult nsHttpChannel::CallOnStartRequest() { mOnStartRequestCalled = true; }); - nsresult rv = EnsureMIMEOfScript(this, mURI, mResponseHead, mLoadInfo); + nsresult rv = EnsureMIMEOfScript(this, mURI, mResponseHead.get(), mLoadInfo); NS_ENSURE_SUCCESS(rv, rv); - rv = ProcessXCTO(this, mURI, mResponseHead, mLoadInfo); + rv = ProcessXCTO(this, mURI, mResponseHead.get(), mLoadInfo); NS_ENSURE_SUCCESS(rv, rv); - WarnWrongMIMEOfScript(this, mURI, mResponseHead, mLoadInfo); + WarnWrongMIMEOfScript(this, mURI, mResponseHead.get(), mLoadInfo); // Allow consumers to override our content type if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { @@ -1752,10 +1759,6 @@ nsresult nsHttpChannel::CallOnStartRequest() { SetCachedContentType(); } - if (mCacheEntry) { - StoreSiteAccessToCacheEntry(); - } - LOG((" calling mListener->OnStartRequest [this=%p, listener=%p]\n", this, mListener.get())); @@ -2311,7 +2314,7 @@ nsresult nsHttpChannel::ProcessResponse() { if (referrer) { nsCOMPtr lci = GetLoadContextInfo(this); mozilla::net::Predictor::UpdateCacheability( - referrer, mURI, httpStatus, mRequestHead, mResponseHead, lci, + referrer, mURI, httpStatus, mRequestHead, mResponseHead.get(), lci, IsThirdPartyTrackingResource()); } @@ -3403,8 +3406,7 @@ nsresult nsHttpChannel::ProcessPartialContent( } // merge any new headers with the cached response headers - rv = mCachedResponseHead->UpdateHeaders(mResponseHead); - if (NS_FAILED(rv)) return rv; + mCachedResponseHead->UpdateHeaders(mResponseHead.get()); // update the cached response head nsAutoCString head; @@ -3547,8 +3549,7 @@ nsresult nsHttpChannel::ProcessNotModified( } // merge any new headers with the cached response headers - rv = mCachedResponseHead->UpdateHeaders(mResponseHead); - if (NS_FAILED(rv)) return rv; + mCachedResponseHead->UpdateHeaders(mResponseHead.get()); // update the cached response head nsAutoCString head; @@ -4003,7 +4004,7 @@ nsresult nsHttpChannel::CheckPartial(nsICacheEntry* aEntry, int64_t* aSize, int64_t* aContentLength) { return nsHttp::CheckPartial( aEntry, aSize, aContentLength, - mCachedResponseHead ? mCachedResponseHead : mResponseHead); + mCachedResponseHead ? mCachedResponseHead.get() : mResponseHead.get()); } void nsHttpChannel::UntieValidationRequest() { @@ -4092,12 +4093,13 @@ nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, (gHttpHandler->SessionStartTime() > lastModifiedTime); // Get the cached HTTP response headers - mCachedResponseHead = new nsHttpResponseHead(); + mCachedResponseHead = MakeUnique(); - rv = nsHttp::GetHttpResponseHeadFromCacheEntry(entry, mCachedResponseHead); + rv = nsHttp::GetHttpResponseHeadFromCacheEntry(entry, + mCachedResponseHead.get()); NS_ENSURE_SUCCESS(rv, rv); - bool isCachedRedirect = WillRedirect(mCachedResponseHead); + bool isCachedRedirect = WillRedirect(*mCachedResponseHead); // Do not return 304 responses from the cache, and also do not return // any other non-redirect 3xx responses from the cache (see bug 759043). @@ -4222,8 +4224,8 @@ nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, entry->GetIsForcedValid(&isForcedValid); bool weaklyFramed, isImmutable; - nsHttp::DetermineFramingAndImmutability(entry, mCachedResponseHead, isHttps, - &weaklyFramed, &isImmutable); + nsHttp::DetermineFramingAndImmutability(entry, mCachedResponseHead.get(), + isHttps, &weaklyFramed, &isImmutable); // Cached entry is not the entity we request (see bug #633743) if (ResponseWouldVary(entry)) { @@ -4232,9 +4234,10 @@ nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, doValidation = true; } else { doValidation = nsHttp::ValidationRequired( - isForcedValid, mCachedResponseHead, mLoadFlags, mAllowStaleCacheContent, - isImmutable, mCustomConditionalRequest, mRequestHead, entry, - cacheControlRequest, fromPreviousSession, &doBackgroundValidation); + isForcedValid, mCachedResponseHead.get(), mLoadFlags, + mAllowStaleCacheContent, isImmutable, mCustomConditionalRequest, + mRequestHead, entry, cacheControlRequest, fromPreviousSession, + &doBackgroundValidation); } nsAutoCString requestedETag; @@ -4286,7 +4289,7 @@ nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, MOZ_ASSERT(NS_SUCCEEDED(rv)); if (!mRedirectedCachekeys) - mRedirectedCachekeys = new nsTArray(); + mRedirectedCachekeys = MakeUnique>(); else if (mRedirectedCachekeys->Contains(cacheKey)) doValidation = true; @@ -4766,8 +4769,8 @@ nsresult DoUpdateExpirationTime(nsHttpChannel* aSelf, // nsresult nsHttpChannel::UpdateExpirationTime() { uint32_t expirationTime = 0; - nsresult rv = - DoUpdateExpirationTime(this, mCacheEntry, mResponseHead, expirationTime); + nsresult rv = DoUpdateExpirationTime(this, mCacheEntry, mResponseHead.get(), + expirationTime); NS_ENSURE_SUCCESS(rv, rv); if (mOfflineCacheEntry) { @@ -4845,7 +4848,7 @@ nsresult nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry, rv = NS_OK; - if (WillRedirect(mCachedResponseHead)) { + if (WillRedirect(*mCachedResponseHead)) { // Do not even try to read the entity for a redirect because we do not // return an entity to the application when we process redirects. LOG(("Will skip read of cached redirect entity\n")); @@ -4898,7 +4901,8 @@ nsresult nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry, bool foundAltData = false; bool deliverAltData = true; - if (!altDataType.IsEmpty() && !mPreferredCachedAltDataTypes.IsEmpty() && + if (!mDisableAltDataCache && !altDataType.IsEmpty() && + !mPreferredCachedAltDataTypes.IsEmpty() && altDataFromChild == mAltDataForChild) { for (auto& pref : mPreferredCachedAltDataTypes) { if (pref.type() == altDataType && @@ -5089,7 +5093,7 @@ nsresult nsHttpChannel::ReadFromCache(bool alreadyMarkedValid) { // Keep the conditions below in sync with the conditions in // StartBufferingCachedEntity. - if (WillRedirect(mResponseHead)) { + if (WillRedirect(*mResponseHead)) { // TODO: Bug 759040 - We should call HandleAsyncRedirect directly here, // to avoid event dispatching latency. MOZ_ASSERT(!mCacheInputStream); @@ -5432,7 +5436,7 @@ nsresult DoAddCacheEntryHeaders(nsHttpChannel* self, nsICacheEntry* entry, } nsresult nsHttpChannel::AddCacheEntryHeaders(nsICacheEntry* entry) { - return DoAddCacheEntryHeaders(this, entry, &mRequestHead, mResponseHead, + return DoAddCacheEntryHeaders(this, entry, &mRequestHead, mResponseHead.get(), mSecurityInfo); } @@ -6183,8 +6187,8 @@ nsHttpChannel::AsyncOpen(nsIStreamListener* aListener) { mLoadInfo->GetInitialSecurityCheckDone() || (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL && - mLoadInfo->LoadingPrincipal() && - mLoadInfo->LoadingPrincipal()->IsSystemPrincipal()), + mLoadInfo->GetLoadingPrincipal() && + mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()), "security flags in loadInfo but doContentSecurityCheck() not called"); LOG(("nsHttpChannel::AsyncOpen [this=%p]\n", this)); @@ -6372,6 +6376,26 @@ nsHttpChannel::GetOrCreateChannelClassifier() { return classifier.forget(); } +uint16_t nsHttpChannel::GetProxyDNSStrategy() { + // This function currently only supports returning DNS_PREFETCH_ORIGIN. + // Support for the rest of the DNS_* flags will be added later. + + if (!mProxyInfo) { + return DNS_PREFETCH_ORIGIN; + } + + nsAutoCString type; + mProxyInfo->GetType(type); + + if (!StaticPrefs::network_proxy_socks_remote_dns()) { + if (type.EqualsLiteral("socks")) { + return DNS_PREFETCH_ORIGIN; + } + } + + return 0; +} + // BeginConnect() SHOULD NOT call AsyncAbort(). AsyncAbort will be called by // functions that called BeginConnect if needed. Only AsyncOpen and // OnProxyAvailable ever call BeginConnect. @@ -6519,7 +6543,8 @@ nsresult nsHttpChannel::BeginConnect() { // if this somehow fails we can go on without it Unused << gHttpHandler->AddConnectionHeader(&mRequestHead, mCaps); - if (mLoadFlags & VALIDATE_ALWAYS || BYPASS_LOCAL_CACHE(mLoadFlags)) + if (!mIsTRRServiceChannel && (mLoadFlags & VALIDATE_ALWAYS || + BYPASS_LOCAL_CACHE(mLoadFlags))) mCaps |= NS_HTTP_REFRESH_DNS; // Adjust mCaps according to our request headers: @@ -6566,7 +6591,14 @@ nsresult nsHttpChannel::BeginConnect() { } if (!NS_ShouldClassifyChannel(this)) { - MaybeStartDNSPrefetch(); + rv = MaybeStartDNSPrefetch(); + if (NS_FAILED(rv)) { + auto dnsStrategy = GetProxyDNSStrategy(); + if (dnsStrategy & DNS_BLOCK_ON_ORIGIN_RESOLVE) { + // TODO: Should this be fatal? + return rv; + } + } return ContinueBeginConnectWithResult(); } @@ -6619,30 +6651,55 @@ nsresult nsHttpChannel::BeginConnect() { return NS_OK; } -void nsHttpChannel::MaybeStartDNSPrefetch() { - if (!mConnectionInfo->UsingHttpProxy() && - !(mLoadFlags & (LOAD_NO_NETWORK_IO | LOAD_ONLY_FROM_CACHE))) { - // Start a DNS lookup very early in case the real open is queued the DNS can - // happen in parallel. Do not do so in the presence of an HTTP proxy as - // all lookups other than for the proxy itself are done by the proxy. - // Also we don't do a lookup if the LOAD_NO_NETWORK_IO or - // LOAD_ONLY_FROM_CACHE flags are set. - // - // We keep the DNS prefetch object around so that we can retrieve - // timing information from it. There is no guarantee that we actually - // use the DNS prefetch data for the real connection, but as we keep - // this data around for 3 minutes by default, this should almost always - // be correct, and even when it isn't, the timing still represents _a_ - // valid DNS lookup timing for the site, even if it is not _the_ - // timing we used. - LOG(("nsHttpChannel::MaybeStartDNSPrefetch [this=%p] prefetching%s\n", this, - mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : "")); +nsresult nsHttpChannel::MaybeStartDNSPrefetch() { + // Start a DNS lookup very early in case the real open is queued the DNS can + // happen in parallel. Do not do so in the presence of an HTTP proxy as + // all lookups other than for the proxy itself are done by the proxy. + // Also we don't do a lookup if the LOAD_NO_NETWORK_IO or + // LOAD_ONLY_FROM_CACHE flags are set. + // + // We keep the DNS prefetch object around so that we can retrieve + // timing information from it. There is no guarantee that we actually + // use the DNS prefetch data for the real connection, but as we keep + // this data around for 3 minutes by default, this should almost always + // be correct, and even when it isn't, the timing still represents _a_ + // valid DNS lookup timing for the site, even if it is not _the_ + // timing we used. + if (mLoadFlags & (LOAD_NO_NETWORK_IO | LOAD_ONLY_FROM_CACHE)) { + return NS_OK; + } + + auto dnsStrategy = GetProxyDNSStrategy(); + + LOG( + ("nsHttpChannel::MaybeStartDNSPrefetch [this=%p, strategy=%u] " + "prefetching%s\n", + this, dnsStrategy, + mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : "")); + + if (dnsStrategy & DNS_PREFETCH_ORIGIN) { OriginAttributes originAttributes; NS_GetOriginAttributes(this, originAttributes); + mDNSPrefetch = new nsDNSPrefetch(mURI, originAttributes, this, mTimingEnabled); - mDNSPrefetch->PrefetchHigh(mCaps & NS_HTTP_REFRESH_DNS); + nsresult rv = mDNSPrefetch->PrefetchHigh(mCaps & NS_HTTP_REFRESH_DNS); + + if (dnsStrategy & DNS_BLOCK_ON_ORIGIN_RESOLVE) { + LOG((" blocking on prefetching origin")); + + if (NS_WARN_IF(NS_FAILED(rv))) { + LOG((" lookup failed with 0x%08" PRIx32 ", aborting request", + static_cast(rv))); + return rv; + } + + // Resolved in OnLookupComplete. + mDNSBlockingThenable = mDNSBlockingPromise.Ensure(__func__); + } } + + return NS_OK; } nsresult nsHttpChannel::BeginConnectActual() { @@ -7249,9 +7306,7 @@ nsHttpChannel::HasCrossOriginOpenerPolicyMismatch(bool* aMismatch) { } // Maybe the channel failed and we have no response head? - nsHttpResponseHead* head = - mResponseHead ? mResponseHead : mCachedResponseHead; - if (!head) { + if (!mResponseHead && !mCachedResponseHead) { return NS_ERROR_NOT_AVAILABLE; } @@ -7409,8 +7464,9 @@ nsHttpChannel::OnStartRequest(nsIRequest* request) { static_cast(mFirstResponseSource), request == mCachePump, request == mTransactionPump)); if (mFirstResponseSource == RESPONSE_PENDING) { - // When the cache wins mFirstResponseSource is set to RESPONSE_FROM_CACHE - // earlier in ReadFromCache, so this must be a response from the network. + // When the cache wins mFirstResponseSource is set to + // RESPONSE_FROM_CACHE earlier in ReadFromCache, so this must be a + // response from the network. MOZ_ASSERT(request == mTransactionPump); LOG((" First response from network\n")); { @@ -7468,8 +7524,8 @@ nsHttpChannel::OnStartRequest(nsIRequest* request) { // don't enter this block if we're reading from the cache... if (NS_SUCCEEDED(mStatus) && !mCachePump && mTransaction) { // mTransactionPump doesn't hit OnInputStreamReady and call this until - // all of the response headers have been acquired, so we can take ownership - // of them from the transaction. + // all of the response headers have been acquired, so we can take + // ownership of them from the transaction. mResponseHead = mTransaction->TakeResponseHead(); // the response head may be null if the transaction was cancelled. in // which case we just need to call OnStartRequest/OnStopRequest. @@ -7643,7 +7699,8 @@ nsHttpChannel::OnStopRequest(nsIRequest* request, nsresult status) { // allow content to be cached if it was loaded successfully (bug #482935) bool contentComplete = NS_SUCCEEDED(status); - // honor the cancelation status even if the underlying transaction completed. + // honor the cancelation status even if the underlying transaction + // completed. if (mCanceled || NS_FAILED(mStatus)) status = mStatus; if (mCachedContentIsPartial) { @@ -7923,7 +7980,8 @@ nsresult nsHttpChannel::ContinueOnStopRequest(nsresult aStatus, bool aIsFromNet, chanDisposition = static_cast(chanDisposition + kHttpsCanceled); } else if (mLoadInfo->GetBrowserWouldUpgradeInsecureRequests()) { - // HTTP content the browser would upgrade to HTTPS if upgrading was enabled + // HTTP content the browser would upgrade to HTTPS if upgrading was + // enabled upgradeKey = NS_LITERAL_CSTRING("disabledUpgrade"); } else { // HTTP content that wouldn't upgrade @@ -7956,7 +8014,7 @@ nsresult nsHttpChannel::ContinueOnStopRequest(nsresult aStatus, bool aIsFromNet, rv = MaybeSetupByteRangeRequest(size, contentLength, true); if (NS_SUCCEEDED(rv) && mIsPartialRequest) { // Prevent read from cache again - mCachedContentIsValid = 0; + mCachedContentIsValid = false; mCachedContentIsPartial = 1; // Perform the range request @@ -7984,8 +8042,9 @@ nsresult nsHttpChannel::ContinueOnStopRequest(nsresult aStatus, bool aIsFromNet, // perform any final cache operations before we close the cache entry. if (mCacheEntry && mRequestTimeInitialized) { bool writeAccess; - // New implementation just returns value of the !mCacheEntryIsReadOnly flag - // passed in. Old implementation checks on nsICache::ACCESS_WRITE flag. + // New implementation just returns value of the !mCacheEntryIsReadOnly + // flag passed in. Old implementation checks on nsICache::ACCESS_WRITE + // flag. mCacheEntry->HasWriteAccess(!mCacheEntryIsReadOnly, &writeAccess); if (writeAccess) { nsresult rv = FinalizeCacheEntry(); @@ -8318,11 +8377,23 @@ nsHttpChannel::OnTransportStatus(nsITransport* trans, nsresult status, (mLoadFlags & LOAD_BACKGROUND) ? "" : " and status", this, static_cast(status), progress, progressMax)); + nsAutoCString host; + mURI->GetHost(host); if (!(mLoadFlags & LOAD_BACKGROUND)) { - nsAutoCString host; - mURI->GetHost(host); - mProgressSink->OnStatus(this, nullptr, status, - NS_ConvertUTF8toUTF16(host).get()); + mProgressSink->OnStatus(this, status, NS_ConvertUTF8toUTF16(host).get()); + } else { + nsCOMPtr parentChannel; + NS_QueryNotificationCallbacks(this, parentChannel); + // If the event sink is |HttpChannelParent|, we have to send status + // events to it even if LOAD_BACKGROUND is set. |HttpChannelParent| + // needs to be aware of whether the status is + // |NS_NET_STATUS_RECEIVING_FROM| or |NS_NET_STATUS_READING|. + // LOAD_BACKGROUND is checked again in |HttpChannelChild|, so the final + // consumer won't get this event. + if (SameCOMIdentity(parentChannel, mProgressSink)) { + mProgressSink->OnStatus(this, status, + NS_ConvertUTF8toUTF16(host).get()); + } } if (progress > 0) { @@ -8335,7 +8406,7 @@ nsHttpChannel::OnTransportStatus(nsITransport* trans, nsresult status, GetCallback(mProgressSink); } if (mProgressSink) { - mProgressSink->OnProgress(this, nullptr, progress, progressMax); + mProgressSink->OnProgress(this, progress, progressMax); } } } @@ -8815,7 +8886,7 @@ NS_IMETHODIMP nsHttpChannel::MarkOfflineCacheEntryAsForeign() { nsresult rv; - nsAutoPtr marker( + UniquePtr marker( GetOfflineCacheEntryAsForeignMarker()); if (!marker) return NS_ERROR_NOT_AVAILABLE; @@ -8954,6 +9025,15 @@ nsHttpChannel::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, } } + if (!mDNSBlockingPromise.IsEmpty()) { + if (NS_SUCCEEDED(status)) { + nsCOMPtr record(rec); + mDNSBlockingPromise.Resolve(record, __func__); + } else { + mDNSBlockingPromise.Reject(status, __func__); + } + } + return NS_OK; } @@ -9342,12 +9422,13 @@ nsHttpChannel::ResumeInternal() { // notification is already pending in the queue right now, because // AsyncRead doesn't (regardless if called after Suspend) respect // the suspend coutner and the right order would not be preserved. - // Hence, we do another dispatch round to actually Resume after the - // notification from the original pump. + // Hence, we do another dispatch round to actually Resume after + // the notification from the original pump. if (transactionPump != self->mTransactionPump && self->mTransactionPump) { LOG( - ("nsHttpChannel::CallOnResume async-resuming new transaction " + ("nsHttpChannel::CallOnResume async-resuming new " + "transaction " "pump %p, this=%p", self->mTransactionPump.get(), self.get())); @@ -10026,9 +10107,7 @@ nsresult nsHttpChannel::RedirectToInterceptedChannel() { InterceptedHttpChannel::CreateForInterception( mChannelCreationTime, mChannelCreationTimestamp, mAsyncOpenTime); - nsContentPolicyType type = mLoadInfo - ? mLoadInfo->GetExternalContentPolicyType() - : nsIContentPolicy::TYPE_OTHER; + nsContentPolicyType type = mLoadInfo->GetExternalContentPolicyType(); nsresult rv = intercepted->Init( mURI, mCaps, static_cast(mProxyInfo.get()), @@ -10155,6 +10234,15 @@ NS_IMPL_ISUPPORTS(BackgroundRevalidatingListener, nsIStreamListener, } // namespace void nsHttpChannel::PerformBackgroundCacheRevalidation() { + if (!StaticPrefs::network_http_stale_while_revalidate_enabled()) { + return; + } + + // This is a channel doing a revalidation. It shouldn't do it again. + if (mStaleRevalidation) { + return; + } + LOG(("nsHttpChannel::PerformBackgroundCacheRevalidation %p", this)); Unused << NS_DispatchToMainThreadQueue( @@ -10194,6 +10282,11 @@ void nsHttpChannel::PerformBackgroundCacheRevalidationNow() { cos->AddClassFlags(nsIClassOfService::Tail); } + RefPtr httpChan = do_QueryObject(validatingChannel); + if (httpChan) { + httpChan->mStaleRevalidation = true; + } + RefPtr listener = new BackgroundRevalidatingListener(); rv = validatingChannel->AsyncOpen(listener); diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 6321b8acaf..a0129edb35 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -27,11 +27,13 @@ #include "nsICorsPreflightCallback.h" #include "AlternateServices.h" #include "nsIRaceCacheWithNetwork.h" +#include "mozilla/Atomics.h" #include "mozilla/extensions/PStreamFilterParent.h" #include "mozilla/Mutex.h" class nsDNSPrefetch; class nsICancelable; +class nsIDNSRecord; class nsIHttpChannelAuthProvider; class nsInputStreamPump; class nsITransportSecurityInfo; @@ -42,6 +44,8 @@ namespace net { class nsChannelClassifier; class Http2PushedStream; +using DNSPromise = MozPromise, nsresult, false>; + class HttpChannelSecurityWarningReporter : public nsISupports { public: virtual MOZ_MUST_USE nsresult ReportSecurityMessage( @@ -142,7 +146,7 @@ class nsHttpChannel final : public HttpBaseChannel, Http2PushedStreamWrapper* pushedStream); static bool IsRedirectStatus(uint32_t status); - static bool WillRedirect(nsHttpResponseHead* response); + static bool WillRedirect(const nsHttpResponseHead& response); // Methods HttpBaseChannel didn't implement for us or that we override. // @@ -311,7 +315,23 @@ class nsHttpChannel final : public HttpBaseChannel, // Connections will only be established in this function. // (including DNS prefetch and speculative connection.) nsresult BeginConnectActual(); - void MaybeStartDNSPrefetch(); + nsresult MaybeStartDNSPrefetch(); + + // Tells the channel to resolve the origin of the end server we are connecting + // to. + static uint16_t const DNS_PREFETCH_ORIGIN = 1 << 0; + // Tells the channel to resolve the host name of the proxy. + static uint16_t const DNS_PREFETCH_PROXY = 1 << 1; + // Will be set if the current channel uses an HTTP/HTTPS proxy. + static uint16_t const DNS_PROXY_IS_HTTP = 1 << 2; + // Tells the channel to wait for the result of the origin server resolution + // before any connection attempts are made. + static uint16_t const DNS_BLOCK_ON_ORIGIN_RESOLVE = 1 << 3; + + // Based on the proxy configuration determine the strategy for resolving the + // end server host name. + // Returns a combination of the above flags. + uint16_t GetProxyDNSStrategy(); // We might synchronously or asynchronously call BeginConnectActual, // which includes DNS prefetch and speculative connection, according to @@ -436,6 +456,8 @@ class nsHttpChannel final : public HttpBaseChannel, aContinueOnStopRequestFunc); MOZ_MUST_USE nsresult DoConnect(nsHttpTransaction* aTransWithStickyConn = nullptr); + MOZ_MUST_USE nsresult + DoConnectActual(nsHttpTransaction* aTransWithStickyConn); MOZ_MUST_USE nsresult ContinueOnStopRequestAfterAuthRetry( nsresult aStatus, bool aAuthRetry, bool aIsFromNet, bool aContentComplete, nsHttpTransaction* aTransWithStickyConn); @@ -548,10 +570,6 @@ class nsHttpChannel final : public HttpBaseChannel, // writing a new entry. The content type is used in cache internally only. void SetCachedContentType(); - // Stores information about access from eTLD+1 of the top level document to - // the cache entry. - void StoreSiteAccessToCacheEntry(); - private: // this section is for main-thread-only object // all the references need to be proxy released on main thread. @@ -610,7 +628,7 @@ class nsHttpChannel final : public HttpBaseChannel, // We must close mCacheInputStream explicitly to avoid leaks. AutoClose mCacheInputStream; RefPtr mCachePump; - nsAutoPtr mCachedResponseHead; + UniquePtr mCachedResponseHead; nsCOMPtr mCachedSecurityInfo; uint32_t mPostID; uint32_t mRequestTime; @@ -646,8 +664,9 @@ class nsHttpChannel final : public HttpBaseChannel, bool mCacheOpenWithPriority; uint32_t mCacheQueueSizeWhenOpen; + Atomic mCachedContentIsValid; + // state flags - uint32_t mCachedContentIsValid : 1; uint32_t mCachedContentIsPartial : 1; uint32_t mCacheOnlyMetadata : 1; uint32_t mTransactionReplaced : 1; @@ -796,6 +815,7 @@ class nsHttpChannel final : public HttpBaseChannel, // Is true if the network request has been triggered. bool mNetworkTriggered = false; bool mWaitingForProxy = false; + bool mStaleRevalidation = false; // Will be true if the onCacheEntryAvailable callback is not called by the // time we send the network request Atomic mRaceCacheWithNetwork; @@ -810,6 +830,14 @@ class nsHttpChannel final : public HttpBaseChannel, TimeStamp mNavigationStartTimeStamp; + // Promise that blocks connection creation when we want to resolve the origin + // host name to be able to give the configured proxy only the resolved IP + // to not leak names. + MozPromiseHolder mDNSBlockingPromise; + // When we hit DoConnect before the resolution is done, Then() will be set + // here to resume DoConnect. + RefPtr mDNSBlockingThenable; + protected: virtual void DoNotifyListenerCleanup() override; diff --git a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp index 619c89f9fc..3768fdd836 100644 --- a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp +++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp @@ -930,17 +930,14 @@ bool nsHttpChannelAuthProvider::BlockPrompt(bool proxyAuth) { if (!topDoc && !xhr) { nsCOMPtr topURI; Unused << chanInternal->GetTopWindowURI(getter_AddRefs(topURI)); - - if (!topURI) { - // If we do not have topURI try the loadingPrincipal. - nsCOMPtr loadingPrinc = loadInfo->LoadingPrincipal(); - if (loadingPrinc) { - loadingPrinc->GetURI(getter_AddRefs(topURI)); - } - } - - if (!NS_SecurityCompareURIs(topURI, mURI, true)) { - mCrossOrigin = true; + if (topURI) { + mCrossOrigin = !NS_SecurityCompareURIs(topURI, mURI, true); + } else { + nsIPrincipal* loadingPrinc = loadInfo->GetLoadingPrincipal(); + MOZ_ASSERT(loadingPrinc); + bool sameOrigin = false; + loadingPrinc->IsSameOrigin(mURI, false, &sameOrigin); + mCrossOrigin = !sameOrigin; } } diff --git a/netwerk/protocol/http/nsHttpChunkedDecoder.cpp b/netwerk/protocol/http/nsHttpChunkedDecoder.cpp index cc547f15b8..503c661f32 100644 --- a/netwerk/protocol/http/nsHttpChunkedDecoder.cpp +++ b/netwerk/protocol/http/nsHttpChunkedDecoder.cpp @@ -110,7 +110,7 @@ nsresult nsHttpChunkedDecoder::ParseChunkRemaining(char* buf, uint32_t count, LOG(("got trailer: %s\n", buf)); // allocate a header array for the trailers on demand if (!mTrailers) { - mTrailers = new nsHttpHeaderArray(); + mTrailers = MakeUnique(); } nsHttpAtom hdr = {nullptr}; diff --git a/netwerk/protocol/http/nsHttpChunkedDecoder.h b/netwerk/protocol/http/nsHttpChunkedDecoder.h index ed119b76e2..ec947f3570 100644 --- a/netwerk/protocol/http/nsHttpChunkedDecoder.h +++ b/netwerk/protocol/http/nsHttpChunkedDecoder.h @@ -5,7 +5,6 @@ #ifndef nsHttpChunkedDecoder_h__ #define nsHttpChunkedDecoder_h__ -#include "nsAutoPtr.h" #include "nsError.h" #include "nsString.h" #include "nsHttpHeaderArray.h" @@ -31,7 +30,7 @@ class nsHttpChunkedDecoder { nsHttpHeaderArray* Trailers() { return mTrailers.get(); } - nsHttpHeaderArray* TakeTrailers() { return mTrailers.forget(); } + UniquePtr TakeTrailers() { return std::move(mTrailers); } // How mush data is still missing(needs to arrive) from the current chunk. uint32_t GetChunkRemaining() { return mChunkRemaining; } @@ -41,7 +40,7 @@ class nsHttpChunkedDecoder { uint32_t* countRead); private: - nsAutoPtr mTrailers; + UniquePtr mTrailers; uint32_t mChunkRemaining; nsCString mLineBuf; // may hold a partial line bool mReachedEOF; diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index b350c800ac..e342c5fb8f 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -696,12 +696,15 @@ bool nsHttpConnection::EnsureNPNComplete(nsresult& aOut0RTTWriteHandshakeValue, if (ssl) { // Telemetry for tls failure rate with and without esni; - bool esni; - mSocketTransport->GetEsniUsed(&esni); - Telemetry::Accumulate( - Telemetry::ESNI_NOESNI_TLS_SUCCESS_RATE, - (esni) ? ((handshakeSucceeded) ? ESNI_SUCCESSFUL : ESNI_FAILED) - : ((handshakeSucceeded) ? NO_ESNI_SUCCESSFUL : NO_ESNI_FAILED)); + bool esni = false; + rv = mSocketTransport->GetEsniUsed(&esni); + if (NS_SUCCEEDED(rv)) { + Telemetry::Accumulate( + Telemetry::ESNI_NOESNI_TLS_SUCCESS_RATE, + (esni) + ? ((handshakeSucceeded) ? ESNI_SUCCESSFUL : ESNI_FAILED) + : ((handshakeSucceeded) ? NO_ESNI_SUCCESSFUL : NO_ESNI_FAILED)); + } } if (rv == psm::GetXPCOMFromNSSError( @@ -1684,7 +1687,12 @@ nsresult nsHttpConnection::ResumeRecv() { // may get done before the ResumeRecv() call mLastReadTime = PR_IntervalNow(); - if (mSocketIn) return mSocketIn->AsyncWait(this, 0, 0, nullptr); + if (mSocketIn) { + if (!mTLSFilter || !mTLSFilter->HasDataToRecv() || NS_FAILED(ForceRecv())) { + return mSocketIn->AsyncWait(this, 0, 0, nullptr); + } + return NS_OK; + } MOZ_ASSERT_UNREACHABLE("no socket input stream"); return NS_ERROR_UNEXPECTED; diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index d0ae70751a..aedf65de57 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -9,7 +9,6 @@ #include "nsHttpResponseHead.h" #include "nsAHttpTransaction.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "nsProxyRelease.h" #include "prinrval.h" #include "TunnelUtils.h" diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index cbbba8f13e..bcd983ec6c 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -11,31 +11,30 @@ #undef LOG_ENABLED #define LOG_ENABLED() LOG5_ENABLED() -#include "nsHttpConnectionMgr.h" -#include "nsHttpConnection.h" -#include "nsHttpHandler.h" -#include "nsIHttpChannelInternal.h" -#include "nsNetCID.h" -#include "nsCOMPtr.h" -#include "nsNetUtil.h" -#include "mozilla/net/DNS.h" -#include "nsISocketTransport.h" +#include +#include + +#include "NullHttpTransaction.h" +#include "mozilla/ChaosMode.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" +#include "mozilla/Unused.h" +#include "mozilla/net/DNS.h" #include "mozilla/net/DashboardTypes.h" -#include "NullHttpTransaction.h" +#include "nsCOMPtr.h" +#include "nsHttpConnection.h" +#include "nsHttpConnectionMgr.h" +#include "nsHttpHandler.h" #include "nsIDNSRecord.h" -#include "nsITransport.h" -#include "nsInterfaceRequestorAgg.h" +#include "nsIHttpChannelInternal.h" #include "nsIRequestContext.h" +#include "nsISocketTransport.h" #include "nsISocketTransportService.h" -#include -#include "mozilla/ChaosMode.h" -#include "mozilla/Unused.h" +#include "nsITransport.h" #include "nsIXPConnect.h" - -#include "mozilla/Move.h" -#include "mozilla/Telemetry.h" +#include "nsInterfaceRequestorAgg.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" namespace mozilla { namespace net { @@ -123,6 +122,7 @@ nsHttpConnectionMgr::nsHttpConnectionMgr() mThrottleReadInterval(0), mThrottleHoldTime(0), mThrottleMaxTime(0), + mBeConservativeForProxy(true), mIsShuttingDown(false), mNumActiveConns(0), mNumIdleConns(0), @@ -170,7 +170,8 @@ nsresult nsHttpConnectionMgr::Init( uint16_t maxRequestDelay, bool throttleEnabled, uint32_t throttleVersion, uint32_t throttleSuspendFor, uint32_t throttleResumeFor, uint32_t throttleReadLimit, uint32_t throttleReadInterval, - uint32_t throttleHoldTime, uint32_t throttleMaxTime) { + uint32_t throttleHoldTime, uint32_t throttleMaxTime, + bool beConservativeForProxy) { LOG(("nsHttpConnectionMgr::Init\n")); { @@ -191,6 +192,8 @@ nsresult nsHttpConnectionMgr::Init( mThrottleHoldTime = throttleHoldTime; mThrottleMaxTime = TimeDuration::FromMilliseconds(throttleMaxTime); + mBeConservativeForProxy = beConservativeForProxy; + mIsShuttingDown = false; } @@ -619,7 +622,7 @@ nsresult nsHttpConnectionMgr::UpdateRequestTokenBucket( aBucket); } -nsresult nsHttpConnectionMgr::ClearConnectionHistory() { +void nsHttpConnectionMgr::ClearConnectionHistory() { MOZ_ASSERT(OnSocketThread(), "not on socket thread"); for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) { @@ -631,8 +634,6 @@ nsresult nsHttpConnectionMgr::ClearConnectionHistory() { iter.Remove(); } } - - return NS_OK; } nsresult nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection* conn) { @@ -2978,6 +2979,9 @@ void nsHttpConnectionMgr::OnMsgUpdateParam(int32_t inParam, ARefBase*) { case THROTTLING_MAX_TIME: mThrottleMaxTime = TimeDuration::FromMilliseconds(value); break; + case PROXY_BE_CONSERVATIVE: + mBeConservativeForProxy = !!value; + break; default: MOZ_ASSERT_UNREACHABLE("unexpected parameter name"); } @@ -3988,6 +3992,24 @@ nsHttpConnectionMgr::nsHalfOpenSocket::~nsHalfOpenSocket() { if (mEnt) mEnt->RemoveHalfOpen(this); } +bool nsHttpConnectionMgr::BeConservativeIfProxied(nsIProxyInfo* proxy) { + if (mBeConservativeForProxy) { + // The pref says to be conservative for proxies. + return true; + } + + if (!proxy) { + // There is no proxy, so be conservative by default. + return true; + } + + // Be conservative only if there is no proxy host set either. + // This logic was copied from nsSSLIOLayerAddToSocket. + nsAutoCString proxyHost; + proxy->GetHost(proxyHost); + return proxyHost.IsEmpty(); +} + nsresult nsHttpConnectionMgr::nsHalfOpenSocket::SetupStreams( nsISocketTransport** transport, nsIAsyncInputStream** instream, nsIAsyncOutputStream** outstream, bool isBackup) { @@ -4060,7 +4082,8 @@ nsresult nsHttpConnectionMgr::nsHalfOpenSocket::SetupStreams( tmpFlags |= nsISocketTransport::DONT_TRY_ESNI; } - if ((mCaps & NS_HTTP_BE_CONSERVATIVE) || ci->GetBeConservative()) { + if (((mCaps & NS_HTTP_BE_CONSERVATIVE) || ci->GetBeConservative()) && + gHttpHandler->ConnMgr()->BeConservativeIfProxied(ci->ProxyInfo())) { LOG(("Setting Socket to BE_CONSERVATIVE")); tmpFlags |= nsISocketTransport::BE_CONSERVATIVE; } diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h index bea1b8ad74..1cb85bca68 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.h +++ b/netwerk/protocol/http/nsHttpConnectionMgr.h @@ -11,7 +11,6 @@ #include "nsThreadUtils.h" #include "nsClassHashtable.h" #include "nsDataHashtable.h" -#include "nsAutoPtr.h" #include "mozilla/ReentrantMonitor.h" #include "mozilla/TimeStamp.h" #include "mozilla/Attributes.h" @@ -64,7 +63,8 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache { THROTTLING_READ_LIMIT, THROTTLING_READ_INTERVAL, THROTTLING_HOLD_TIME, - THROTTLING_MAX_TIME + THROTTLING_MAX_TIME, + PROXY_BE_CONSERVATIVE }; //------------------------------------------------------------------------- @@ -80,7 +80,8 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache { bool throttleEnabled, uint32_t throttleVersion, uint32_t throttleSuspendFor, uint32_t throttleResumeFor, uint32_t throttleReadLimit, uint32_t throttleReadInterval, - uint32_t throttleHoldTime, uint32_t throttleMaxTime); + uint32_t throttleHoldTime, uint32_t throttleMaxTime, + bool beConservativeForProxy); MOZ_MUST_USE nsresult Shutdown(); //------------------------------------------------------------------------- @@ -179,7 +180,7 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache { MOZ_MUST_USE nsresult UpdateRequestTokenBucket(EventTokenBucket* aBucket); // clears the connection history mCT - MOZ_MUST_USE nsresult ClearConnectionHistory(); + void ClearConnectionHistory(); void ReportFailedToProcess(nsIURI* uri); @@ -564,6 +565,7 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache { uint32_t mThrottleReadInterval; uint32_t mThrottleHoldTime; TimeDuration mThrottleMaxTime; + bool mBeConservativeForProxy; Atomic mIsShuttingDown; //------------------------------------------------------------------------- @@ -817,6 +819,10 @@ class nsHttpConnectionMgr final : public nsIObserver, public AltSvcCache { // Then, it notifies selected transactions' connection of the new active tab // id. void NotifyConnectionOfWindowIdChange(uint64_t previousWindowId); + + // A test if be-conservative should be used when proxy is setup for the + // connection + bool BeConservativeIfProxied(nsIProxyInfo* proxy); }; NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnectionMgr::nsHalfOpenSocket, diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 8229ea7387..605b25df84 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -58,6 +58,7 @@ #include "mozilla/ipc/URIUtils.h" #include "mozilla/Telemetry.h" #include "mozilla/Unused.h" +#include "mozilla/AntiTrackingCommon.h" #include "mozilla/BasePrincipal.h" #include "mozilla/LazyIdleThread.h" @@ -111,8 +112,8 @@ "network.tcp.tcp_fastopen_http_stalls_timeout" #define ACCEPT_HEADER_NAVIGATION \ - "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" -#define ACCEPT_HEADER_IMAGE "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5" + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" +#define ACCEPT_HEADER_IMAGE "image/webp,*/*" #define ACCEPT_HEADER_STYLE "text/css,*/*;q=0.1" #define ACCEPT_HEADER_ALL "*/*" @@ -126,7 +127,6 @@ //----------------------------------------------------------------------------- using mozilla::dom::Promise; -using mozilla::Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME; namespace mozilla { namespace net { @@ -153,9 +153,9 @@ static nsCString GetDeviceModelId() { deviceString.Trim(" ", true, true); deviceString.ReplaceSubstring(NS_LITERAL_CSTRING("%DEVICEID%"), deviceModelId); - return deviceString; + return std::move(deviceString); } - return deviceModelId; + return std::move(deviceModelId); } #endif @@ -215,9 +215,11 @@ nsHttpHandler::nsHttpHandler() mTailDelayMax(6000), mTailTotalMax(0), mRedirectionLimit(10), + mBeConservativeForProxy(true), mPhishyUserPassLength(1), mQoSBits(0x00), mEnforceAssocReq(false), + mImageAcceptHeader(ACCEPT_HEADER_IMAGE), mLastUniqueID(NowInSeconds()), mSessionStartTime(0), mLegacyAppName("Mozilla"), @@ -267,9 +269,7 @@ nsHttpHandler::nsHttpHandler() mTCPKeepaliveLongLivedIdleTimeS(600), mEnforceH1Framing(FRAMECHECK_BARELY), mDefaultHpackBuffer(4096), - mBug1563538(true), mBug1563695(true), - mBug1562315(true), mBug1556491(true), mMaxHttpResponseHeaderSize(393216), mFocusedWindowTransactionRatio(0.9f), @@ -430,6 +430,7 @@ static const char* gCallbackPrefs[] = { TCP_FAST_OPEN_STALLS_LIMIT, TCP_FAST_OPEN_STALLS_IDLE, TCP_FAST_OPEN_STALLS_TIMEOUT, + "image.http.accept", nullptr, }; @@ -450,9 +451,6 @@ nsresult nsHttpHandler::Init() { mIOService = new nsMainThreadPtrHolder( "nsHttpHandler::mIOService", service); - mBackgroundThread = new mozilla::LazyIdleThread( - 10000, NS_LITERAL_CSTRING("HTTP Handler Background")); - if (IsNeckoChild()) NeckoChild::InitNeckoChild(); InitUserAgentComponents(); @@ -607,7 +605,7 @@ nsresult nsHttpHandler::InitConnectionMgr() { mMaxPersistentConnectionsPerServer, mMaxPersistentConnectionsPerProxy, mMaxRequestDelay, mThrottleEnabled, mThrottleVersion, mThrottleSuspendFor, mThrottleResumeFor, mThrottleReadLimit, mThrottleReadInterval, - mThrottleHoldTime, mThrottleMaxTime); + mThrottleHoldTime, mThrottleMaxTime, mBeConservativeForProxy); return rv; } @@ -646,7 +644,7 @@ nsresult nsHttpHandler::AddStandardRequestHeaders( accept.Assign(ACCEPT_HEADER_NAVIGATION); } else if (aContentPolicyType == nsIContentPolicy::TYPE_IMAGE || aContentPolicyType == nsIContentPolicy::TYPE_IMAGESET) { - accept.Assign(ACCEPT_HEADER_IMAGE); + accept.Assign(mImageAcceptHeader); } else if (aContentPolicyType == nsIContentPolicy::TYPE_STYLESHEET) { accept.Assign(ACCEPT_HEADER_STYLE); } else { @@ -774,8 +772,7 @@ nsresult nsHttpHandler::GetStreamConverterService( mStreamConvSvc = new nsMainThreadPtrHolder( "nsHttpHandler::mStreamConvSvc", service); } - *result = mStreamConvSvc; - NS_ADDREF(*result); + *result = do_AddRef(mStreamConvSvc.get()).take(); return NS_OK; } @@ -802,7 +799,7 @@ nsICookieService* nsHttpHandler::GetCookieService() { nsresult nsHttpHandler::GetIOService(nsIIOService** result) { NS_ENSURE_ARG_POINTER(result); - NS_ADDREF(*result = mIOService); + *result = do_AddRef(mIOService.get()).take(); return NS_OK; } @@ -836,18 +833,15 @@ nsresult nsHttpHandler::AsyncOnChannelRedirect( nsIEventTarget* mainThreadEventTarget) { MOZ_ASSERT(NS_IsMainThread() && (oldChan && newChan)); + nsCOMPtr oldURI; + oldChan->GetURI(getter_AddRefs(oldURI)); + MOZ_ASSERT(oldURI); + nsCOMPtr newURI; newChan->GetURI(getter_AddRefs(newURI)); MOZ_ASSERT(newURI); - nsAutoCString scheme; - newURI->GetScheme(scheme); - MOZ_ASSERT(!scheme.IsEmpty()); - - Telemetry::AccumulateCategoricalKeyed( - scheme, oldChan->IsDocument() - ? LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::topLevel - : LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::subresource); + AntiTrackingCommon::RedirectHeuristic(oldChan, oldURI, newChan, newURI); // TODO E10S This helper has to be initialized on the other process RefPtr redirectCallbackHelper = @@ -954,8 +948,8 @@ void nsHttpHandler::BuildUserAgent() { } #ifdef XP_WIN -# define WNT_BASE "Windows NT %ld.%ld" -# define W64_PREFIX "; Win64" +# define OSCPU_WINDOWS "Windows NT %ld.%ld" +# define OSCPU_WIN64 OSCPU_WINDOWS "; Win64; x64" #endif void nsHttpHandler::InitUserAgentComponents() { @@ -1031,18 +1025,18 @@ void nsHttpHandler::InitUserAgentComponents() { # pragma warning(disable : 4996) if (GetVersionEx(&info)) { # pragma warning(pop) + const char* format; -# if defined _M_IA64 - format = WNT_BASE W64_PREFIX "; IA64"; -# elif defined _M_X64 || defined _M_AMD64 - format = WNT_BASE W64_PREFIX "; x64"; +# if defined _M_X64 || defined _M_AMD64 + format = OSCPU_WIN64; # else BOOL isWow64 = FALSE; if (!IsWow64Process(GetCurrentProcess(), &isWow64)) { isWow64 = FALSE; } - format = isWow64 ? WNT_BASE "; WOW64" : WNT_BASE; + format = isWow64 ? OSCPU_WIN64 : OSCPU_WINDOWS; # endif + SmprintfPointer buf = mozilla::Smprintf(format, info.dwMajorVersion, info.dwMinorVersion); if (buf) { @@ -1061,35 +1055,22 @@ void nsHttpHandler::InitUserAgentComponents() { static_cast(minorVersion)); # elif defined(XP_UNIX) struct utsname name; - int ret = uname(&name); if (ret >= 0) { nsAutoCString buf; buf = (char*)name.sysname; - - if (strcmp(name.machine, "x86_64") == 0 && - sizeof(void*) == sizeof(int32_t)) { - // We're running 32-bit code on x86_64. Make this browser - // look like it's running on i686 hardware, but append " - // (x86_64)" to the end of the oscpu identifier to be able - // to differentiate this from someone running 64-bit code - // on x86_64.. - - buf += " i686 on x86_64"; - } else { - buf += ' '; + buf += ' '; # ifdef AIX - // AIX uname returns machine specific info in the uname.machine - // field and does not return the cpu type like other platforms. - // We use the AIX version and release numbers instead. - buf += (char*)name.version; - buf += '.'; - buf += (char*)name.release; + // AIX uname returns machine specific info in the uname.machine + // field and does not return the cpu type like other platforms. + // We use the AIX version and release numbers instead. + buf += (char*)name.version; + buf += '.'; + buf += (char*)name.release; # else - buf += (char*)name.machine; + buf += (char*)name.machine; # endif - } mOscpu.Assign(buf); } @@ -1349,6 +1330,19 @@ void nsHttpHandler::PrefsChanged(const char* pref) { } } + if (PREF_CHANGED(HTTP_PREF("proxy.respect-be-conservative"))) { + rv = + Preferences::GetBool(HTTP_PREF("proxy.respect-be-conservative"), &cVar); + if (NS_SUCCEEDED(rv)) { + mBeConservativeForProxy = cVar; + if (mConnMgr) { + Unused << mConnMgr->UpdateParam( + nsHttpConnectionMgr::PROXY_BE_CONSERVATIVE, + static_cast(mBeConservativeForProxy)); + } + } + } + if (PREF_CHANGED(HTTP_PREF("qos"))) { rv = Preferences::GetInt(HTTP_PREF("qos"), &val); if (NS_SUCCEEDED(rv)) mQoSBits = (uint8_t)clamped(val, 0, 0xff); @@ -1905,24 +1899,12 @@ void nsHttpHandler::PrefsChanged(const char* pref) { } } - if (PREF_CHANGED(HTTP_PREF("spdy.bug1563538"))) { - rv = Preferences::GetBool(HTTP_PREF("spdy.bug1563538"), &cVar); - if (NS_SUCCEEDED(rv)) { - mBug1563538 = cVar; - } - } if (PREF_CHANGED(HTTP_PREF("spdy.bug1563695"))) { rv = Preferences::GetBool(HTTP_PREF("spdy.bug1563695"), &cVar); if (NS_SUCCEEDED(rv)) { mBug1563695 = cVar; } } - if (PREF_CHANGED(HTTP_PREF("spdy.bug1562315"))) { - rv = Preferences::GetBool(HTTP_PREF("spdy.bug1562315"), &cVar); - if (NS_SUCCEEDED(rv)) { - mBug1562315 = cVar; - } - } if (PREF_CHANGED(HTTP_PREF("spdy.bug1556491"))) { rv = Preferences::GetBool(HTTP_PREF("spdy.bug1556491"), &cVar); if (NS_SUCCEEDED(rv)) { @@ -1930,6 +1912,13 @@ void nsHttpHandler::PrefsChanged(const char* pref) { } } + if (PREF_CHANGED("image.http.accept")) { + rv = Preferences::GetCString("image.http.accept", mImageAcceptHeader); + if (NS_FAILED(rv)) { + mImageAcceptHeader.Assign(ACCEPT_HEADER_IMAGE); + } + } + // Enable HTTP response timeout if TCP Keepalives are disabled. mResponseTimeoutEnabled = !mTCPKeepaliveShortLivedEnabled && !mTCPKeepaliveLongLivedEnabled; @@ -2091,12 +2080,8 @@ nsHttpHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* givenProxyInfo, nsresult rv = NewChannelId(channelId); NS_ENSURE_SUCCESS(rv, rv); - nsContentPolicyType contentPolicyType = - aLoadInfo ? aLoadInfo->GetExternalContentPolicyType() - : nsIContentPolicy::TYPE_OTHER; - rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, - channelId, contentPolicyType); + channelId, aLoadInfo->GetExternalContentPolicyType()); if (NS_FAILED(rv)) return rv; // set the loadInfo on the new channel @@ -2170,8 +2155,8 @@ nsHttpHandler::Observe(nsISupports* subject, const char* topic, mHandlerActive = false; // clear cache of all authentication credentials. - Unused << mAuthCache.ClearAll(); - Unused << mPrivateAuthCache.ClearAll(); + mAuthCache.ClearAll(); + mPrivateAuthCache.ClearAll(); if (mWifiTickler) mWifiTickler->Cancel(); // Inform nsIOService that network is tearing down. @@ -2206,8 +2191,8 @@ nsHttpHandler::Observe(nsISupports* subject, const char* topic, rv = InitConnectionMgr(); MOZ_ASSERT(NS_SUCCEEDED(rv)); } else if (!strcmp(topic, "net:clear-active-logins")) { - Unused << mAuthCache.ClearAll(); - Unused << mPrivateAuthCache.ClearAll(); + mAuthCache.ClearAll(); + mPrivateAuthCache.ClearAll(); } else if (!strcmp(topic, "net:cancel-all-connections")) { if (mConnMgr) { mConnMgr->AbortAndCloseAllConnections(0, nullptr); @@ -2240,7 +2225,7 @@ nsHttpHandler::Observe(nsISupports* subject, const char* topic, nsCOMPtr uri = do_QueryInterface(subject); #endif } else if (!strcmp(topic, "last-pb-context-exited")) { - Unused << mPrivateAuthCache.ClearAll(); + mPrivateAuthCache.ClearAll(); if (mConnMgr) { mConnMgr->ClearAltServiceMappings(); } @@ -2356,15 +2341,9 @@ void nsHttpHandler::MaybeEnableSpeculativeConnect() { return; } - if (!mBackgroundThread) { - NS_WARNING( - "nsHttpHandler::MaybeEnableSpeculativeConnect() no background thread"); - return; - } - net_EnsurePSMInit(); - mBackgroundThread->Dispatch( + NS_DispatchBackgroundTask( NS_NewRunnableFunction("CanEnableSpeculativeConnect", [] { gHttpHandler->mSpeculativeConnectEnabled = CanEnableSpeculativeConnect(); diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h index b8e106abaf..2d8a2f6c7b 100644 --- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -429,9 +429,7 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, uint32_t DefaultHpackBuffer() const { return mDefaultHpackBuffer; } - bool Bug1563538() const { return mBug1563538; } bool Bug1563695() const { return mBug1563695; } - bool Bug1562315() const { return mBug1562315; } bool Bug1556491() const { return mBug1556491; } uint32_t MaxHttpResponseHeaderSize() const { @@ -499,10 +497,6 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, // the connection manager RefPtr mConnMgr; - // This thread is used for performing operations that should not block - // the main thread. - nsCOMPtr mBackgroundThread; - // // prefs // @@ -548,6 +542,8 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, uint8_t mRedirectionLimit; + bool mBeConservativeForProxy; + // we'll warn the user if we load an URL containing a userpass field // unless its length is less than this threshold. this warning is // intended to protect the user against spoofing attempts that use @@ -558,6 +554,8 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, bool mEnforceAssocReq; + nsCString mImageAcceptHeader; + nsCString mAcceptLanguages; nsCString mHttpAcceptEncodings; nsCString mHttpsAcceptEncodings; @@ -674,10 +672,7 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, // The default size (in bytes) of the HPACK decompressor table. uint32_t mDefaultHpackBuffer; - // Pref for the whole fix that bug provides - Atomic mBug1563538; Atomic mBug1563695; - Atomic mBug1562315; Atomic mBug1556491; // The max size (in bytes) for received Http response header. diff --git a/netwerk/protocol/http/nsHttpNTLMAuth.cpp b/netwerk/protocol/http/nsHttpNTLMAuth.cpp index 7f4ae72fb9..7b866df1b9 100644 --- a/netwerk/protocol/http/nsHttpNTLMAuth.cpp +++ b/netwerk/protocol/http/nsHttpNTLMAuth.cpp @@ -26,6 +26,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Base64.h" #include "mozilla/CheckedInt.h" +#include "mozilla/Maybe.h" #include "mozilla/Tokenizer.h" #include "mozilla/UniquePtr.h" #include "mozilla/Unused.h" @@ -215,9 +216,8 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel* channel, if (!*sessionState) { // Remember the fact that we cannot use the "sys-ntlm" module, // so we don't ever bother trying again for this auth domain. - *sessionState = new nsNTLMSessionState(); - if (!*sessionState) return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(*sessionState); + RefPtr state = new nsNTLMSessionState(); + state.forget(sessionState); } // Use our internal NTLM implementation. Note, this is less secure, @@ -281,6 +281,7 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel* authChannel, void *inBuf, *outBuf; uint32_t inBufLen, outBufLen; + Maybe> certArray; // initial challenge if (PL_strcasecmp(challenge, "NTLM") == 0) { @@ -329,15 +330,14 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel* authChannel, rv = secInfo->GetServerCert(getter_AddRefs(cert)); if (NS_FAILED(rv)) return rv; - uint32_t length; - uint8_t* certArray; - rv = cert->GetRawDER(&length, &certArray); + certArray.emplace(); + rv = cert->GetRawDER(*certArray); if (NS_FAILED(rv)) return rv; // If there is a server certificate, we pass it along the // first time we call GetNextToken(). - inBufLen = length; - inBuf = certArray; + inBufLen = certArray->Length(); + inBuf = certArray->Elements(); } else { // If there is no server certificate, we don't pass anything. inBufLen = 0; @@ -385,7 +385,10 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel* authChannel, free(outBuf); } - if (inBuf) free(inBuf); + // inBuf needs to be freed if it's not pointing into certArray + if (inBuf && !certArray) { + free(inBuf); + } return rv; } diff --git a/netwerk/protocol/http/nsHttpRequestHead.cpp b/netwerk/protocol/http/nsHttpRequestHead.cpp index 65212f562d..e0e1ee924f 100644 --- a/netwerk/protocol/http/nsHttpRequestHead.cpp +++ b/netwerk/protocol/http/nsHttpRequestHead.cpp @@ -240,22 +240,29 @@ bool nsHttpRequestHead::IsHTTPS() { void nsHttpRequestHead::SetMethod(const nsACString& method) { RecursiveMutexAutoLock mon(mRecursiveMutex); - mParsedMethod = kMethod_Custom; + mMethod = method; - if (!strcmp(mMethod.get(), "GET")) { - mParsedMethod = kMethod_Get; - } else if (!strcmp(mMethod.get(), "POST")) { - mParsedMethod = kMethod_Post; - } else if (!strcmp(mMethod.get(), "OPTIONS")) { - mParsedMethod = kMethod_Options; - } else if (!strcmp(mMethod.get(), "CONNECT")) { - mParsedMethod = kMethod_Connect; - } else if (!strcmp(mMethod.get(), "HEAD")) { - mParsedMethod = kMethod_Head; - } else if (!strcmp(mMethod.get(), "PUT")) { - mParsedMethod = kMethod_Put; - } else if (!strcmp(mMethod.get(), "TRACE")) { - mParsedMethod = kMethod_Trace; + ParseMethod(mMethod, mParsedMethod); +} + +// static +void nsHttpRequestHead::ParseMethod(const nsCString& aRawMethod, + ParsedMethodType& aParsedMethod) { + aParsedMethod = kMethod_Custom; + if (!strcmp(aRawMethod.get(), "GET")) { + aParsedMethod = kMethod_Get; + } else if (!strcmp(aRawMethod.get(), "POST")) { + aParsedMethod = kMethod_Post; + } else if (!strcmp(aRawMethod.get(), "OPTIONS")) { + aParsedMethod = kMethod_Options; + } else if (!strcmp(aRawMethod.get(), "CONNECT")) { + aParsedMethod = kMethod_Connect; + } else if (!strcmp(aRawMethod.get(), "HEAD")) { + aParsedMethod = kMethod_Head; + } else if (!strcmp(aRawMethod.get(), "PUT")) { + aParsedMethod = kMethod_Put; + } else if (!strcmp(aRawMethod.get(), "TRACE")) { + aParsedMethod = kMethod_Trace; } } diff --git a/netwerk/protocol/http/nsHttpRequestHead.h b/netwerk/protocol/http/nsHttpRequestHead.h index 35465f3a1d..3b0dc6b8c5 100644 --- a/netwerk/protocol/http/nsHttpRequestHead.h +++ b/netwerk/protocol/http/nsHttpRequestHead.h @@ -91,6 +91,9 @@ class nsHttpRequestHead { kMethod_Trace }; + static void ParseMethod(const nsCString& aRawMethod, + ParsedMethodType& aParsedMethod); + ParsedMethodType ParsedMethod(); bool EqualsMethod(ParsedMethodType aType); bool IsGet() { return EqualsMethod(kMethod_Get); } diff --git a/netwerk/protocol/http/nsHttpResponseHead.cpp b/netwerk/protocol/http/nsHttpResponseHead.cpp index 5f7fde3aae..9b19044b31 100644 --- a/netwerk/protocol/http/nsHttpResponseHead.cpp +++ b/netwerk/protocol/http/nsHttpResponseHead.cpp @@ -34,6 +34,7 @@ nsHttpResponseHead::nsHttpResponseHead(const nsHttpResponseHead& aOther) mContentLength = other.mContentLength; mContentType = other.mContentType; mContentCharset = other.mContentCharset; + mCacheControlPublic = other.mCacheControlPublic; mCacheControlPrivate = other.mCacheControlPrivate; mCacheControlNoStore = other.mCacheControlNoStore; mCacheControlNoCache = other.mCacheControlNoCache; @@ -54,6 +55,7 @@ nsHttpResponseHead& nsHttpResponseHead::operator=( mContentLength = other.mContentLength; mContentType = other.mContentType; mContentCharset = other.mContentCharset; + mCacheControlPublic = other.mCacheControlPublic; mCacheControlPrivate = other.mCacheControlPrivate; mCacheControlNoStore = other.mCacheControlNoStore; mCacheControlNoCache = other.mCacheControlNoCache; @@ -68,7 +70,7 @@ HttpVersion nsHttpResponseHead::Version() { return mVersion; } -uint16_t nsHttpResponseHead::Status() { +uint16_t nsHttpResponseHead::Status() const { RecursiveMutexAutoLock monitor(mRecursiveMutex); return mStatus; } @@ -93,6 +95,11 @@ void nsHttpResponseHead::ContentCharset(nsACString& aContentCharset) { aContentCharset = mContentCharset; } +bool nsHttpResponseHead::Public() { + RecursiveMutexAutoLock monitor(mRecursiveMutex); + return mCacheControlPublic; +} + bool nsHttpResponseHead::Private() { RecursiveMutexAutoLock monitor(mRecursiveMutex); return mCacheControlPrivate; @@ -180,7 +187,7 @@ bool nsHttpResponseHead::HasHeaderValue(nsHttpAtom h, const char* v) { return mHeaders.HasHeaderValue(h, v); } -bool nsHttpResponseHead::HasHeader(nsHttpAtom h) { +bool nsHttpResponseHead::HasHeader(nsHttpAtom h) const { RecursiveMutexAutoLock monitor(mRecursiveMutex); return mHeaders.HasHeader(h); } @@ -656,6 +663,20 @@ nsresult nsHttpResponseHead::ComputeFreshnessLifetime(uint32_t* result) { return NS_OK; } + // From RFC 7234 Section 4.2.2, heuristics can only be used on responses + // without explicit freshness whose status codes are defined as cacheable + // by default, and those responses without explicit freshness that have been + // marked as explicitly cacheable. + // Note that |MustValidate| handled most of non-cacheable status codes. + if ((mStatus == 302 || mStatus == 304 || mStatus == 307) && + !mCacheControlPublic && !mCacheControlPrivate) { + LOG(( + "nsHttpResponseHead::ComputeFreshnessLifetime [this = %p] " + "Do not calculate heuristic max-age for non-cacheable status code %u\n", + this, unsigned(mStatus))); + return NS_OK; + } + // Fallback on heuristic using last modified header... if (NS_SUCCEEDED(GetLastModifiedValue_locked(&date2))) { LOG(("using last-modified to determine freshness-lifetime\n")); @@ -682,12 +703,13 @@ bool nsHttpResponseHead::MustValidate() { RecursiveMutexAutoLock monitor(mRecursiveMutex); LOG(("nsHttpResponseHead::MustValidate ??\n")); - // Some response codes are cacheable, but the rest are not. This switch - // should stay in sync with the list in nsHttpChannel::ProcessResponse + // Some response codes are cacheable, but the rest are not. This switch should + // stay in sync with the list in nsHttpChannel::ContinueProcessResponse3 switch (mStatus) { // Success codes case 200: case 203: + case 204: case 206: // Cacheable redirects case 300: @@ -707,6 +729,7 @@ bool nsHttpResponseHead::MustValidate() { case 407: case 412: case 416: + case 425: case 429: default: // revalidate unknown error pages LOG(("Must validate since response is an uncacheable error page\n")); @@ -813,7 +836,7 @@ bool nsHttpResponseHead::ExpiresInPast_locked() const { NS_SUCCEEDED(GetDateValue_locked(&dateVal)) && expiresVal < dateVal; } -nsresult nsHttpResponseHead::UpdateHeaders(nsHttpResponseHead* aOther) { +void nsHttpResponseHead::UpdateHeaders(nsHttpResponseHead* aOther) { LOG(("nsHttpResponseHead::UpdateHeaders [this=%p]\n", this)); RecursiveMutexAutoLock monitor(mRecursiveMutex); @@ -856,8 +879,6 @@ nsresult nsHttpResponseHead::UpdateHeaders(nsHttpResponseHead* aOther) { MOZ_ASSERT(NS_SUCCEEDED(rv)); } } - - return NS_OK; } void nsHttpResponseHead::Reset() { @@ -870,6 +891,7 @@ void nsHttpResponseHead::Reset() { mVersion = HttpVersion::v1_1; mStatus = 200; mContentLength = -1; + mCacheControlPublic = false; mCacheControlPrivate = false; mCacheControlNoStore = false; mCacheControlNoCache = false; @@ -1016,6 +1038,7 @@ bool nsHttpResponseHead::operator==(const nsHttpResponseHead& aOther) const { mContentLength == aOther.mContentLength && mContentType == aOther.mContentType && mContentCharset == aOther.mContentCharset && + mCacheControlPublic == aOther.mCacheControlPublic && mCacheControlPrivate == aOther.mCacheControlPrivate && mCacheControlNoCache == aOther.mCacheControlNoCache && mCacheControlNoStore == aOther.mCacheControlNoStore && @@ -1097,6 +1120,7 @@ void nsHttpResponseHead::ParseVersion(const char* str) { void nsHttpResponseHead::ParseCacheControl(const char* val) { if (!(val && *val)) { // clear flags + mCacheControlPublic = false; mCacheControlPrivate = false; mCacheControlNoCache = false; mCacheControlNoStore = false; @@ -1104,6 +1128,11 @@ void nsHttpResponseHead::ParseCacheControl(const char* val) { return; } + // search header value for occurrence of "public" + if (nsHttp::FindToken(val, "public", HTTP_HEADER_VALUE_SEPS)) { + mCacheControlPublic = true; + } + // search header value for occurrence of "private" if (nsHttp::FindToken(val, "private", HTTP_HEADER_VALUE_SEPS)) mCacheControlPrivate = true; diff --git a/netwerk/protocol/http/nsHttpResponseHead.h b/netwerk/protocol/http/nsHttpResponseHead.h index e8d48404e2..1cdae75fe9 100644 --- a/netwerk/protocol/http/nsHttpResponseHead.h +++ b/netwerk/protocol/http/nsHttpResponseHead.h @@ -41,6 +41,7 @@ class nsHttpResponseHead { : mVersion(HttpVersion::v1_1), mStatus(200), mContentLength(-1), + mCacheControlPublic(false), mCacheControlPrivate(false), mCacheControlNoStore(false), mCacheControlNoCache(false), @@ -56,11 +57,12 @@ class nsHttpResponseHead { void Exit() { mRecursiveMutex.Unlock(); } HttpVersion Version(); - uint16_t Status(); + uint16_t Status() const; void StatusText(nsACString& aStatusText); int64_t ContentLength(); void ContentType(nsACString& aContentType); void ContentCharset(nsACString& aContentCharset); + bool Public(); bool Private(); bool NoStore(); bool NoCache(); @@ -80,7 +82,7 @@ class nsHttpResponseHead { void ClearHeader(nsHttpAtom h); void ClearHeaders(); bool HasHeaderValue(nsHttpAtom h, const char* v); - bool HasHeader(nsHttpAtom h); + bool HasHeader(nsHttpAtom h) const; void SetContentType(const nsACString& s); void SetContentCharset(const nsACString& s); @@ -129,7 +131,7 @@ class nsHttpResponseHead { bool ExpiresInPast(); // update headers... - MOZ_MUST_USE nsresult UpdateHeaders(nsHttpResponseHead* headers); + void UpdateHeaders(nsHttpResponseHead* headers); // reset the response head to it's initial state void Reset(); @@ -193,6 +195,7 @@ class nsHttpResponseHead { int64_t mContentLength; nsCString mContentType; nsCString mContentCharset; + bool mCacheControlPublic; bool mCacheControlPrivate; bool mCacheControlNoStore; bool mCacheControlNoCache; @@ -201,7 +204,7 @@ class nsHttpResponseHead { // We are using RecursiveMutex instead of a Mutex because VisitHeader // function calls nsIHttpHeaderVisitor::VisitHeader while under lock. - RecursiveMutex mRecursiveMutex; + mutable RecursiveMutex mRecursiveMutex; // During VisitHeader we sould not allow cal to SetHeader. bool mInVisitHeaders; diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 22cbe6c8b8..31bfcfae07 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -3,49 +3,47 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // HttpLog.h should generally be included first -#include "HttpLog.h" +#include "nsHttpTransaction.h" -#include "base/basictypes.h" +#include +#include +#include "HttpLog.h" +#include "NSSErrorsService.h" +#include "TCPFastOpenLayer.h" +#include "TunnelUtils.h" +#include "base/basictypes.h" +#include "mozilla/Tokenizer.h" +#include "nsCRT.h" +#include "nsComponentManagerUtils.h" // do_CreateInstance #include "nsHttpBasicAuth.h" #include "nsHttpChunkedDecoder.h" #include "nsHttpDigestAuth.h" #include "nsHttpHandler.h" -#include "nsHttpNegotiateAuth.h" #include "nsHttpNTLMAuth.h" +#include "nsHttpNegotiateAuth.h" #include "nsHttpRequestHead.h" #include "nsHttpResponseHead.h" -#include "nsHttpTransaction.h" -#include "nsTransportUtils.h" -#include "nsNetCID.h" -#include "nsNetUtil.h" -#include "nsIPipe.h" -#include "nsCRT.h" -#include "mozilla/Tokenizer.h" -#include "mozilla/Move.h" -#include "TCPFastOpenLayer.h" - -#include "nsISeekableStream.h" -#include "nsMultiplexInputStream.h" -#include "nsStringStream.h" - -#include "nsComponentManagerUtils.h" // do_CreateInstance -#include "nsIHttpActivityObserver.h" -#include "nsSocketTransportService2.h" #include "nsIClassOfService.h" #include "nsIEventTarget.h" +#include "nsIHttpActivityObserver.h" +#include "nsIHttpAuthenticator.h" #include "nsIHttpChannelInternal.h" -#include "nsIMultiplexInputStream.h" #include "nsIInputStream.h" -#include "nsIThrottledInputChannel.h" -#include "nsITransport.h" +#include "nsIMultiplexInputStream.h" #include "nsIOService.h" +#include "nsIPipe.h" #include "nsIRequestContext.h" -#include "nsIHttpAuthenticator.h" -#include "NSSErrorsService.h" -#include "TunnelUtils.h" +#include "nsISeekableStream.h" +#include "nsIThrottledInputChannel.h" +#include "nsITransport.h" +#include "nsMultiplexInputStream.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsSocketTransportService2.h" +#include "nsStringStream.h" +#include "nsTransportUtils.h" #include "sslerr.h" -#include //----------------------------------------------------------------------------- @@ -457,7 +455,7 @@ void nsHttpTransaction::SetH2WSConnRefTaken() { } } -nsHttpResponseHead* nsHttpTransaction::TakeResponseHead() { +UniquePtr nsHttpTransaction::TakeResponseHead() { MOZ_ASSERT(!mResponseHeadTaken, "TakeResponseHead called 2x"); // Lock TakeResponseHead() against main thread @@ -472,19 +470,17 @@ nsHttpResponseHead* nsHttpTransaction::TakeResponseHead() { return nullptr; } - nsHttpResponseHead* head = mResponseHead; - mResponseHead = nullptr; - return head; + return WrapUnique(std::exchange(mResponseHead, nullptr)); } -nsHttpHeaderArray* nsHttpTransaction::TakeResponseTrailers() { +UniquePtr nsHttpTransaction::TakeResponseTrailers() { MOZ_ASSERT(!mResponseTrailersTaken, "TakeResponseTrailers called 2x"); // Lock TakeResponseTrailers() against main thread MutexAutoLock lock(*nsHttp::GetLock()); mResponseTrailersTaken = true; - return mForTakeResponseTrailers.forget(); + return std::move(mForTakeResponseTrailers); } void nsHttpTransaction::SetProxyConnectFailed() { mProxyConnectFailed = true; } @@ -2333,7 +2329,7 @@ void nsHttpTransaction::SetHttpTrailers(nsCString& aTrailers) { LOG(("[\n %s\n]", aTrailers.BeginReading())); // Introduce a local variable to minimize the critical section. - nsAutoPtr httpTrailers(new nsHttpHeaderArray()); + UniquePtr httpTrailers(new nsHttpHeaderArray()); // Given it's usually null, use double-check locking for performance. if (mForTakeResponseTrailers) { MutexAutoLock lock(*nsHttp::GetLock()); @@ -2374,7 +2370,7 @@ void nsHttpTransaction::SetHttpTrailers(nsCString& aTrailers) { } MutexAutoLock lock(*nsHttp::GetLock()); - Swap(mForTakeResponseTrailers, httpTrailers); + std::swap(mForTakeResponseTrailers, httpTrailers); } bool nsHttpTransaction::IsWebsocketUpgrade() { diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index 8002938ba3..6ba63a4a07 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -102,11 +102,11 @@ class nsHttpTransaction final : public nsAHttpTransaction, // Called to take ownership of the response headers; the transaction // will drop any reference to the response headers after this call. - nsHttpResponseHead* TakeResponseHead(); + UniquePtr TakeResponseHead(); // Called to take ownership of the trailer headers. // Returning null if there is no trailer. - nsHttpHeaderArray* TakeResponseTrailers(); + UniquePtr TakeResponseTrailers(); void SetH2WSConnRefTaken(); @@ -387,7 +387,7 @@ class nsHttpTransaction final : public nsAHttpTransaction, // protected by nsHttp::GetLock() bool mResponseHeadTaken; - nsAutoPtr mForTakeResponseTrailers; + UniquePtr mForTakeResponseTrailers; bool mResponseTrailersTaken; // The time when the transaction was submitted to the Connection Manager diff --git a/netwerk/protocol/http/nsIHttpChannel.idl b/netwerk/protocol/http/nsIHttpChannel.idl index e596808be1..efeda80d9f 100644 --- a/netwerk/protocol/http/nsIHttpChannel.idl +++ b/netwerk/protocol/http/nsIHttpChannel.idl @@ -177,6 +177,12 @@ interface nsIHttpChannel : nsIChannel [must_use] void visitNonDefaultRequestHeaders(in nsIHttpHeaderVisitor aVisitor); + /** + * Call this method to see if we need to strip the request body headers + * for the new http channel. This should be called during redirection. + */ + [must_use] bool ShouldStripRequestBodyHeader(in ACString aMethod); + /** * This attribute no longer has any effect, it remains for backwards compat * diff --git a/netwerk/protocol/http/nsIHttpChannelInternal.idl b/netwerk/protocol/http/nsIHttpChannelInternal.idl index fc47d6aa33..9863982c28 100644 --- a/netwerk/protocol/http/nsIHttpChannelInternal.idl +++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl @@ -334,11 +334,19 @@ interface nsIHttpChannelInternal : nsISupports * the CORS preflight parameters. */ [noscript, notxpcom, nostdcall] - void setCorsPreflightParameters(in CStringArrayRef unsafeHeaders); + void setCorsPreflightParameters(in CStringArrayRef unsafeHeaders, + in boolean shouldStripRequestBodyHeader); [noscript, notxpcom, nostdcall] void setAltDataForChild(in boolean aIsForChild); + /** + * Prevent the use of alt-data cache for this request. Use by the + * extension StreamFilter class to force use of the regular cache. + */ + [noscript, notxpcom, nostdcall] + void disableAltDataCache(); + /** * When set to true, the channel will not pop any authentication prompts up * to the user. When provided or cached credentials lead to an diff --git a/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl b/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl index 0f35583eaf..e79f7efab1 100644 --- a/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl +++ b/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl @@ -16,10 +16,7 @@ interface nsIWellKnownOpportunisticUtils : nsISupports { [must_use] void verify(in ACString aJSON, - in ACString aOrigin, - in long aAlternatePort); + in ACString aOrigin); [must_use] readonly attribute bool valid; - [must_use] readonly attribute bool mixed; /* mixed-scheme */ - [must_use] readonly attribute long lifetime; }; diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp index db1d1eaf7c..9176567142 100644 --- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp +++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp @@ -256,9 +256,7 @@ nsViewSourceChannel::Resume(void) { NS_IMETHODIMP nsViewSourceChannel::GetOriginalURI(nsIURI** aURI) { - NS_ASSERTION(aURI, "Null out param!"); - *aURI = mOriginalURI; - NS_ADDREF(*aURI); + *aURI = do_AddRef(mOriginalURI).take(); return NS_OK; } @@ -811,6 +809,14 @@ nsViewSourceChannel::VisitNonDefaultRequestHeaders( : mHttpChannel->VisitNonDefaultRequestHeaders(aVisitor); } +NS_IMETHODIMP +nsViewSourceChannel::ShouldStripRequestBodyHeader(const nsACString& aMethod, + bool* aResult) { + return !mHttpChannel + ? NS_ERROR_NULL_POINTER + : mHttpChannel->ShouldStripRequestBodyHeader(aMethod, aResult); +} + NS_IMETHODIMP nsViewSourceChannel::GetAllowPipelining(bool* aAllowPipelining) { return !mHttpChannel ? NS_ERROR_NULL_POINTER @@ -1000,14 +1006,20 @@ nsViewSourceChannel::SetIsMainDocumentChannel(bool aValue) { // Have to manually forward SetCorsPreflightParameters since it's [notxpcom] void nsViewSourceChannel::SetCorsPreflightParameters( - const nsTArray& aUnsafeHeaders) { - mHttpChannelInternal->SetCorsPreflightParameters(aUnsafeHeaders); + const nsTArray& aUnsafeHeaders, + bool aShouldStripRequestBodyHeader) { + mHttpChannelInternal->SetCorsPreflightParameters( + aUnsafeHeaders, aShouldStripRequestBodyHeader); } void nsViewSourceChannel::SetAltDataForChild(bool aIsForChild) { mHttpChannelInternal->SetAltDataForChild(aIsForChild); } +void nsViewSourceChannel::DisableAltDataCache() { + mHttpChannelInternal->DisableAltDataCache(); +} + NS_IMETHODIMP nsViewSourceChannel::LogBlockedCORSRequest(const nsAString& aMessage, const nsACString& aCategory) { diff --git a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp index 21dd4e2eb9..4172a400fd 100644 --- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp +++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp @@ -8,7 +8,6 @@ #include "nsILoadGroup.h" #include "nsINode.h" #include "nsIInterfaceRequestor.h" -#include "nsAutoPtr.h" #include "nsProxyRelease.h" #include "nsStandardURL.h" #include "LoadInfo.h" @@ -72,7 +71,7 @@ BaseWebSocketChannel::GetOriginalURI(nsIURI** aOriginalURI) { LOG(("BaseWebSocketChannel::GetOriginalURI() %p\n", this)); if (!mOriginalURI) return NS_ERROR_NOT_INITIALIZED; - NS_ADDREF(*aOriginalURI = mOriginalURI); + *aOriginalURI = do_AddRef(mOriginalURI).take(); return NS_OK; } @@ -81,10 +80,11 @@ BaseWebSocketChannel::GetURI(nsIURI** aURI) { LOG(("BaseWebSocketChannel::GetURI() %p\n", this)); if (!mOriginalURI) return NS_ERROR_NOT_INITIALIZED; - if (mURI) - NS_ADDREF(*aURI = mURI); - else - NS_ADDREF(*aURI = mOriginalURI); + if (mURI) { + *aURI = do_AddRef(mURI).take(); + } else { + *aURI = do_AddRef(mOriginalURI).take(); + } return NS_OK; } diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index c403664155..bbdd38cc4e 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -38,12 +38,12 @@ #include "nsIObserverService.h" #include "nsCharSeparatedTokenizer.h" -#include "nsAutoPtr.h" #include "nsNetCID.h" #include "nsServiceManagerUtils.h" #include "nsCRT.h" #include "nsThreadUtils.h" #include "nsError.h" +#include "mozilla/Base64.h" #include "nsStringStream.h" #include "nsAlgorithm.h" #include "nsProxyRelease.h" @@ -182,18 +182,13 @@ class FailDelayManager { } } - ~FailDelayManager() { - MOZ_COUNT_DTOR(FailDelayManager); - for (uint32_t i = 0; i < mEntries.Length(); i++) { - delete mEntries[i]; - } - } + ~FailDelayManager() { MOZ_COUNT_DTOR(FailDelayManager); } void Add(nsCString& address, int32_t port) { if (mDelaysDisabled) return; - FailDelay* record = new FailDelay(address, port); - mEntries.AppendElement(record); + UniquePtr record(new FailDelay(address, port)); + mEntries.AppendElement(std::move(record)); } // Element returned may not be valid after next main thread event: don't keep @@ -208,7 +203,7 @@ class FailDelayManager { // We also remove expired entries during search: iterate from end to make // indexing simpler for (int32_t i = mEntries.Length() - 1; i >= 0; --i) { - FailDelay* fail = mEntries[i]; + FailDelay* fail = mEntries[i].get(); if (fail->mAddress.Equals(address) && fail->mPort == port) { if (outIndex) *outIndex = i; result = fail; @@ -218,7 +213,6 @@ class FailDelayManager { break; } else if (fail->IsExpired(rightNow)) { mEntries.RemoveElementAt(i); - delete fail; } } return result; @@ -252,7 +246,6 @@ class FailDelayManager { // call } else if (fail->IsExpired(rightNow)) { mEntries.RemoveElementAt(failIndex); - delete fail; } } } @@ -269,17 +262,16 @@ class FailDelayManager { // iterate from end, to make deletion indexing easier for (int32_t i = mEntries.Length() - 1; i >= 0; --i) { - FailDelay* entry = mEntries[i]; + FailDelay* entry = mEntries[i].get(); if ((entry->mAddress.Equals(address) && entry->mPort == port) || entry->IsExpired(rightNow)) { mEntries.RemoveElementAt(i); - delete entry; } } } private: - nsTArray mEntries; + nsTArray> mEntries; bool mDelaysDisabled; }; @@ -323,9 +315,8 @@ class nsWSAdmissionManager { bool found = (sManager->IndexOf(ws->mAddress) >= 0); // Always add ourselves to queue, even if we'll connect immediately - nsOpenConn* newdata = new nsOpenConn(ws->mAddress, ws); - LOG(("Websocket: adding conn %p to the queue", newdata)); - sManager->mQueue.AppendElement(newdata); + UniquePtr newdata(new nsOpenConn(ws->mAddress, ws)); + sManager->mQueue.AppendElement(std::move(newdata)); if (found) { LOG( @@ -447,10 +438,7 @@ class nsWSAdmissionManager { MOZ_COUNT_CTOR(nsWSAdmissionManager); } - ~nsWSAdmissionManager() { - MOZ_COUNT_DTOR(nsWSAdmissionManager); - for (uint32_t i = 0; i < mQueue.Length(); i++) delete mQueue[i]; - } + ~nsWSAdmissionManager() { MOZ_COUNT_DTOR(nsWSAdmissionManager); } class nsOpenConn { public: @@ -484,10 +472,7 @@ class nsWSAdmissionManager { int32_t index = IndexOf(aChannel); MOZ_ASSERT(index >= 0, "connection to remove not in queue"); if (index >= 0) { - nsOpenConn* olddata = mQueue[index]; mQueue.RemoveElementAt(index); - LOG(("Websocket: removing conn %p from the queue", olddata)); - delete olddata; } } @@ -514,7 +499,7 @@ class nsWSAdmissionManager { // // We could hash hostnames instead of using a single big vector here, but the // dataset is expected to be small. - nsTArray mQueue; + nsTArray> mQueue; FailDelayManager mFailures; @@ -529,13 +514,12 @@ StaticMutex nsWSAdmissionManager::sLock; // CallOnMessageAvailable //----------------------------------------------------------------------------- -class CallOnMessageAvailable final : public nsIRunnable { +class CallOnMessageAvailable final : public Runnable { public: - NS_DECL_THREADSAFE_ISUPPORTS - CallOnMessageAvailable(WebSocketChannel* aChannel, nsACString& aData, int32_t aLen) - : mChannel(aChannel), + : Runnable("net::CallOnMessageAvailable"), + mChannel(aChannel), mListenerMT(aChannel->mListenerMT), mData(aData), mLen(aLen) {} @@ -571,18 +555,16 @@ class CallOnMessageAvailable final : public nsIRunnable { nsCString mData; int32_t mLen; }; -NS_IMPL_ISUPPORTS(CallOnMessageAvailable, nsIRunnable) //----------------------------------------------------------------------------- // CallOnStop //----------------------------------------------------------------------------- -class CallOnStop final : public nsIRunnable { +class CallOnStop final : public Runnable { public: - NS_DECL_THREADSAFE_ISUPPORTS - CallOnStop(WebSocketChannel* aChannel, nsresult aReason) - : mChannel(aChannel), + : Runnable("net::CallOnStop"), + mChannel(aChannel), mListenerMT(mChannel->mListenerMT), mReason(aReason) {} @@ -611,19 +593,17 @@ class CallOnStop final : public nsIRunnable { RefPtr mListenerMT; nsresult mReason; }; -NS_IMPL_ISUPPORTS(CallOnStop, nsIRunnable) //----------------------------------------------------------------------------- // CallOnServerClose //----------------------------------------------------------------------------- -class CallOnServerClose final : public nsIRunnable { +class CallOnServerClose final : public Runnable { public: - NS_DECL_THREADSAFE_ISUPPORTS - CallOnServerClose(WebSocketChannel* aChannel, uint16_t aCode, nsACString& aReason) - : mChannel(aChannel), + : Runnable("net::CallOnServerClose"), + mChannel(aChannel), mListenerMT(mChannel->mListenerMT), mCode(aCode), mReason(aReason) {} @@ -652,7 +632,6 @@ class CallOnServerClose final : public nsIRunnable { uint16_t mCode; nsCString mReason; }; -NS_IMPL_ISUPPORTS(CallOnServerClose, nsIRunnable) //----------------------------------------------------------------------------- // CallAcknowledge @@ -694,15 +673,14 @@ class CallAcknowledge final : public CancelableRunnable { // CallOnTransportAvailable //----------------------------------------------------------------------------- -class CallOnTransportAvailable final : public nsIRunnable { +class CallOnTransportAvailable final : public Runnable { public: - NS_DECL_THREADSAFE_ISUPPORTS - CallOnTransportAvailable(WebSocketChannel* aChannel, nsISocketTransport* aTransport, nsIAsyncInputStream* aSocketIn, nsIAsyncOutputStream* aSocketOut) - : mChannel(aChannel), + : Runnable("net::CallOnTransportAvailble"), + mChannel(aChannel), mTransport(aTransport), mSocketIn(aSocketIn), mSocketOut(aSocketOut) {} @@ -720,7 +698,6 @@ class CallOnTransportAvailable final : public nsIRunnable { nsCOMPtr mSocketIn; nsCOMPtr mSocketOut; }; -NS_IMPL_ISUPPORTS(CallOnTransportAvailable, nsIRunnable) //----------------------------------------------------------------------------- // PMCECompression @@ -928,22 +905,18 @@ static const char* msgNames[] = {"text", "binaryString", "binaryStream", class OutboundMessage { public: - OutboundMessage(WsMsgType type, nsCString* str) - : mMsgType(type), mDeflated(false), mOrigLength(0) { + OutboundMessage(WsMsgType type, const nsACString& str) + : mMsg(mozilla::AsVariant(pString(str))), + mMsgType(type), + mDeflated(false) { MOZ_COUNT_CTOR(OutboundMessage); - mMsg.pString.mValue = str; - mMsg.pString.mOrigValue = nullptr; - mLength = str ? str->Length() : 0; } OutboundMessage(nsIInputStream* stream, uint32_t length) - : mMsgType(kMsgTypeStream), - mLength(length), - mDeflated(false), - mOrigLength(0) { + : mMsg(mozilla::AsVariant(StreamWithLength(stream, length))), + mMsgType(kMsgTypeStream), + mDeflated(false) { MOZ_COUNT_CTOR(OutboundMessage); - mMsg.pStream = stream; - mMsg.pStream->AddRef(); } ~OutboundMessage() { @@ -953,14 +926,11 @@ class OutboundMessage { case kMsgTypeBinaryString: case kMsgTypePing: case kMsgTypePong: - delete mMsg.pString.mValue; - if (mMsg.pString.mOrigValue) delete mMsg.pString.mOrigValue; break; case kMsgTypeStream: // for now this only gets hit if msg deleted w/o being sent - if (mMsg.pStream) { - mMsg.pStream->Close(); - mMsg.pStream->Release(); + if (mMsg.as().mStream) { + mMsg.as().mStream->Close(); } break; case kMsgTypeFin: @@ -969,47 +939,65 @@ class OutboundMessage { } WsMsgType GetMsgType() const { return mMsgType; } - int32_t Length() const { return mLength; } - int32_t OrigLength() const { return mDeflated ? mOrigLength : mLength; } + int32_t Length() { + if (mMsg.is()) { + return mMsg.as().mValue.Length(); + } + + return mMsg.as().mLength; + } + int32_t OrigLength() { + if (mMsg.is()) { + pString& ref = mMsg.as(); + return mDeflated ? ref.mOrigValue.Length() : ref.mValue.Length(); + } + + return mMsg.as().mLength; + } uint8_t* BeginWriting() { MOZ_ASSERT(mMsgType != kMsgTypeStream, "Stream should have been converted to string by now"); - return (uint8_t*)(mMsg.pString.mValue ? mMsg.pString.mValue->BeginWriting() - : nullptr); + if (!mMsg.as().mValue.IsVoid()) { + return (uint8_t*)mMsg.as().mValue.BeginWriting(); + } + return nullptr; } uint8_t* BeginReading() { MOZ_ASSERT(mMsgType != kMsgTypeStream, "Stream should have been converted to string by now"); - return (uint8_t*)(mMsg.pString.mValue ? mMsg.pString.mValue->BeginReading() - : nullptr); + if (!mMsg.as().mValue.IsVoid()) { + return (uint8_t*)mMsg.as().mValue.BeginReading(); + } + return nullptr; } uint8_t* BeginOrigReading() { MOZ_ASSERT(mMsgType != kMsgTypeStream, "Stream should have been converted to string by now"); if (!mDeflated) return BeginReading(); - return (uint8_t*)(mMsg.pString.mOrigValue - ? mMsg.pString.mOrigValue->BeginReading() - : nullptr); + if (!mMsg.as().mOrigValue.IsVoid()) { + return (uint8_t*)mMsg.as().mOrigValue.BeginReading(); + } + return nullptr; } nsresult ConvertStreamToString() { MOZ_ASSERT(mMsgType == kMsgTypeStream, "Not a stream!"); + nsAutoCString temp; + { + StreamWithLength& ref = mMsg.as(); + nsresult rv = NS_ReadInputStreamToString(ref.mStream, temp, ref.mLength); - nsAutoPtr temp(new nsCString()); - nsresult rv = NS_ReadInputStreamToString(mMsg.pStream, *temp, mLength); - - NS_ENSURE_SUCCESS(rv, rv); - if (temp->Length() != mLength) { - return NS_ERROR_UNEXPECTED; + NS_ENSURE_SUCCESS(rv, rv); + if (temp.Length() != ref.mLength) { + return NS_ERROR_UNEXPECTED; + } + ref.mStream->Close(); } - mMsg.pStream->Close(); - mMsg.pStream->Release(); - mMsg.pString.mValue = temp.forget(); - mMsg.pString.mOrigValue = nullptr; + mMsg = mozilla::AsVariant(pString(temp)); mMsgType = kMsgTypeBinaryString; return NS_OK; @@ -1021,14 +1009,14 @@ class OutboundMessage { MOZ_ASSERT(!mDeflated); nsresult rv; - - if (mLength == 0) { + pString& ref = mMsg.as(); + if (ref.mValue.Length() == 0) { // Empty message return false; } - nsAutoPtr temp(new nsCString()); - rv = aCompressor->Deflate(BeginReading(), mLength, *temp); + nsAutoCString temp; + rv = aCompressor->Deflate(BeginReading(), ref.mValue.Length(), temp); if (NS_FAILED(rv)) { LOG( ("WebSocketChannel::OutboundMessage: Deflating payload failed " @@ -1037,7 +1025,8 @@ class OutboundMessage { return false; } - if (!aCompressor->UsingContextTakeover() && temp->Length() > mLength) { + if (!aCompressor->UsingContextTakeover() && + temp.Length() > ref.mValue.Length()) { // When "_no_context_takeover" was negotiated, do not send deflated // payload if it's larger that the original one. OTOH, it makes sense // to send the larger deflated payload when the sliding window is not @@ -1048,42 +1037,42 @@ class OutboundMessage { ("WebSocketChannel::OutboundMessage: Not deflating message since the " "deflated payload is larger than the original one [deflated=%d, " "original=%d]", - temp->Length(), mLength)); + temp.Length(), ref.mValue.Length())); return false; } - mOrigLength = mLength; mDeflated = true; - mLength = temp->Length(); - mMsg.pString.mOrigValue = mMsg.pString.mValue; - mMsg.pString.mValue = temp.forget(); + mMsg.as().mOrigValue = mMsg.as().mValue; + mMsg.as().mValue = temp; return true; } private: - union { - struct { - nsCString* mValue; - nsCString* mOrigValue; - } pString; - nsIInputStream* pStream; - } mMsg; + struct pString { + nsCString mValue; + nsCString mOrigValue; + explicit pString(const nsACString& value) + : mValue(value), mOrigValue(VoidCString()) {} + }; + struct StreamWithLength { + nsCOMPtr mStream; + uint32_t mLength; + explicit StreamWithLength(nsIInputStream* stream, uint32_t Length) + : mStream(stream), mLength(Length) {} + }; + mozilla::Variant mMsg; WsMsgType mMsgType; - uint32_t mLength; bool mDeflated; - uint32_t mOrigLength; }; //----------------------------------------------------------------------------- // OutboundEnqueuer //----------------------------------------------------------------------------- -class OutboundEnqueuer final : public nsIRunnable { +class OutboundEnqueuer final : public Runnable { public: - NS_DECL_THREADSAFE_ISUPPORTS - OutboundEnqueuer(WebSocketChannel* aChannel, OutboundMessage* aMsg) - : mChannel(aChannel), mMessage(aMsg) {} + : Runnable("OutboundEnquerer"), mChannel(aChannel), mMessage(aMsg) {} NS_IMETHOD Run() override { mChannel->EnqueueOutgoingMessage(mChannel->mOutgoingMessages, mMessage); @@ -1096,7 +1085,6 @@ class OutboundEnqueuer final : public nsIRunnable { RefPtr mChannel; OutboundMessage* mMessage; }; -NS_IMPL_ISUPPORTS(OutboundEnqueuer, nsIRunnable) //----------------------------------------------------------------------------- // WebSocketChannel @@ -1179,10 +1167,6 @@ WebSocketChannel::~WebSocketChannel() { while ((mCurrentOut = (OutboundMessage*)mOutgoingMessages.PopFront())) delete mCurrentOut; - NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mURI", mURI.forget()); - NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mOriginalURI", - mOriginalURI.forget()); - mListenerMT = nullptr; NS_ReleaseOnMainThreadSystemGroup("WebSocketChannel::mLoadGroup", @@ -1886,22 +1870,21 @@ void WebSocketChannel::ApplyMask(uint32_t mask, uint8_t* data, uint64_t len) { } void WebSocketChannel::GeneratePing() { - nsCString* buf = new nsCString(); - buf->AssignLiteral("PING"); + nsAutoCString buf; + buf.AssignLiteral("PING"); EnqueueOutgoingMessage(mOutgoingPingMessages, new OutboundMessage(kMsgTypePing, buf)); } void WebSocketChannel::GeneratePong(uint8_t* payload, uint32_t len) { - nsCString* buf = new nsCString(); - buf->SetLength(len); - if (buf->Length() < len) { + nsAutoCString buf; + buf.SetLength(len); + if (buf.Length() < len) { LOG(("WebSocketChannel::GeneratePong Allocation Failure\n")); - delete buf; return; } - memcpy(buf->BeginWriting(), payload, len); + memcpy(buf.BeginWriting(), payload, len); EnqueueOutgoingMessage(mOutgoingPongMessages, new OutboundMessage(kMsgTypePong, buf)); } @@ -2069,7 +2052,7 @@ void WebSocketChannel::PrimeNewOutgoingMessage() { // deflate the payload if PMCE is negotiated if (mPMCECompressor && (msgType == kMsgTypeString || msgType == kMsgTypeBinaryString)) { - if (mCurrentOut->DeflatePayload(mPMCECompressor)) { + if (mCurrentOut->DeflatePayload(mPMCECompressor.get())) { // The payload was deflated successfully, set RSV1 bit mOutHeader[0] |= kRsv1Bit; @@ -2402,7 +2385,8 @@ void WebSocketChannel::AbortSession(nsresult reason) { mRequestedClose = true; mStopOnClose = reason; mSocketThread->Dispatch( - new OutboundEnqueuer(this, new OutboundMessage(kMsgTypeFin, nullptr)), + new OutboundEnqueuer(this, + new OutboundMessage(kMsgTypeFin, VoidCString())), nsIEventTarget::DISPATCH_NORMAL); return; } @@ -2617,7 +2601,7 @@ nsresult WebSocketChannel::HandleExtensions() { serverMaxWindowBits = 15; } - mPMCECompressor = new PMCECompression( + mPMCECompressor = MakeUnique( clientNoContextTakeover, clientMaxWindowBits, serverMaxWindowBits); if (mPMCECompressor->Active()) { LOG( @@ -2762,11 +2746,12 @@ nsresult WebSocketChannel::SetupRequest() { rv = mRandomGenerator->GenerateRandomBytes(16, &secKey); NS_ENSURE_SUCCESS(rv, rv); - char* b64 = PL_Base64Encode((const char*)secKey, 16, nullptr); + rv = Base64Encode(nsDependentCSubstring((char*)secKey, 16), secKeyString); free(secKey); - if (!b64) return NS_ERROR_OUT_OF_MEMORY; - secKeyString.Assign(b64); - PR_Free(b64); // PL_Base64Encode() uses PR_Malloc. + if (NS_FAILED(rv)) { + return rv; + } + rv = mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Sec-WebSocket-Key"), secKeyString, false); MOZ_ASSERT(NS_SUCCEEDED(rv)); @@ -2824,10 +2809,12 @@ nsresult WebSocketChannel::ApplyForAdmission() { MOZ_ASSERT(!mCancelable); nsresult rv; - rv = pps->AsyncResolve(mHttpChannel, - nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY | - nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL, - this, nullptr, getter_AddRefs(mCancelable)); + rv = pps->AsyncResolve( + mHttpChannel, + nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY | + nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY | + nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL, + this, nullptr, getter_AddRefs(mCancelable)); NS_ASSERTION(NS_FAILED(rv) || mCancelable, "nsIProtocolProxyService::AsyncResolve succeeded but didn't " "return a cancelable object!"); @@ -3385,9 +3372,10 @@ WebSocketChannel::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin, // allow setting proxy uri/flags rv = ioService->NewChannelFromURIWithProxyFlags( localURI, mURI, - nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY | + nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY | + nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY | nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL, - mLoadInfo->LoadingNode(), mLoadInfo->LoadingPrincipal(), + mLoadInfo->LoadingNode(), mLoadInfo->GetLoadingPrincipal(), mLoadInfo->TriggeringPrincipal(), mLoadInfo->GetSecurityFlags(), mLoadInfo->InternalContentPolicyType(), getter_AddRefs(localChannel)); NS_ENSURE_SUCCESS(rv, rv); @@ -3484,7 +3472,8 @@ WebSocketChannel::Close(uint16_t code, const nsACString& reason) { if (mDataStarted) { return mSocketThread->Dispatch( - new OutboundEnqueuer(this, new OutboundMessage(kMsgTypeFin, nullptr)), + new OutboundEnqueuer(this, + new OutboundMessage(kMsgTypeFin, VoidCString())), nsIEventTarget::DISPATCH_NORMAL); } @@ -3509,23 +3498,23 @@ NS_IMETHODIMP WebSocketChannel::SendMsg(const nsACString& aMsg) { LOG(("WebSocketChannel::SendMsg() %p\n", this)); - return SendMsgCommon(&aMsg, false, aMsg.Length()); + return SendMsgCommon(aMsg, false, aMsg.Length()); } NS_IMETHODIMP WebSocketChannel::SendBinaryMsg(const nsACString& aMsg) { LOG(("WebSocketChannel::SendBinaryMsg() %p len=%d\n", this, aMsg.Length())); - return SendMsgCommon(&aMsg, true, aMsg.Length()); + return SendMsgCommon(aMsg, true, aMsg.Length()); } NS_IMETHODIMP WebSocketChannel::SendBinaryStream(nsIInputStream* aStream, uint32_t aLength) { LOG(("WebSocketChannel::SendBinaryStream() %p\n", this)); - return SendMsgCommon(nullptr, true, aLength, aStream); + return SendMsgCommon(VoidCString(), true, aLength, aStream); } -nsresult WebSocketChannel::SendMsgCommon(const nsACString* aMsg, bool aIsBinary, +nsresult WebSocketChannel::SendMsgCommon(const nsACString& aMsg, bool aIsBinary, uint32_t aLength, nsIInputStream* aStream) { MOZ_ASSERT(IsOnTargetThread(), "not target thread"); @@ -3560,9 +3549,9 @@ nsresult WebSocketChannel::SendMsgCommon(const nsACString* aMsg, bool aIsBinary, aStream ? new OutboundEnqueuer(this, new OutboundMessage(aStream, aLength)) : new OutboundEnqueuer( - this, new OutboundMessage( - aIsBinary ? kMsgTypeBinaryString : kMsgTypeString, - new nsCString(*aMsg))), + this, + new OutboundMessage( + aIsBinary ? kMsgTypeBinaryString : kMsgTypeString, aMsg)), nsIEventTarget::DISPATCH_NORMAL); } @@ -3628,7 +3617,7 @@ WebSocketChannel::OnTransportAvailable(nsISocketTransport* aTransport, serverMaxWindowBits = 15; } - mPMCECompressor = new PMCECompression( + mPMCECompressor = MakeUnique( serverNoContextTakeover, serverMaxWindowBits, clientMaxWindowBits); if (mPMCECompressor->Active()) { LOG( diff --git a/netwerk/protocol/websocket/WebSocketChannel.h b/netwerk/protocol/websocket/WebSocketChannel.h index d27eaabcdf..22dfb2ef33 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.h +++ b/netwerk/protocol/websocket/WebSocketChannel.h @@ -134,7 +134,7 @@ class WebSocketChannel : public BaseWebSocketChannel, friend class CallAcknowledge; // Common send code for binary + text msgs - MOZ_MUST_USE nsresult SendMsgCommon(const nsACString* aMsg, bool isBinary, + MOZ_MUST_USE nsresult SendMsgCommon(const nsACString& aMsg, bool isBinary, uint32_t length, nsIInputStream* aStream = nullptr); @@ -289,7 +289,7 @@ class WebSocketChannel : public BaseWebSocketChannel, uint32_t mHdrOutToSend; uint8_t* mHdrOut; uint8_t mOutHeader[kCopyBreak + 16]; - nsAutoPtr mPMCECompressor; + UniquePtr mPMCECompressor; uint32_t mDynamicOutputSize; uint8_t* mDynamicOutput; bool mPrivateBrowsing; diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.cpp b/netwerk/protocol/websocket/WebSocketChannelChild.cpp index ec80b93c3a..77726409d8 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -127,11 +127,11 @@ class WebSocketEvent { class WrappedWebSocketEvent : public Runnable { public: WrappedWebSocketEvent(WebSocketChannelChild* aChild, - WebSocketEvent* aWebSocketEvent) + UniquePtr&& aWebSocketEvent) : Runnable("net::WrappedWebSocketEvent"), mChild(aChild), - mWebSocketEvent(aWebSocketEvent) { - MOZ_RELEASE_ASSERT(aWebSocketEvent); + mWebSocketEvent(std::move(aWebSocketEvent)) { + MOZ_RELEASE_ASSERT(!!mWebSocketEvent); } NS_IMETHOD Run() override { mWebSocketEvent->Run(mChild); @@ -140,7 +140,7 @@ class WrappedWebSocketEvent : public Runnable { private: RefPtr mChild; - nsAutoPtr mWebSocketEvent; + UniquePtr mWebSocketEvent; }; class EventTargetDispatcher : public ChannelEvent { @@ -155,7 +155,7 @@ class EventTargetDispatcher : public ChannelEvent { void Run() override { if (mEventTarget) { mEventTarget->Dispatch( - new WrappedWebSocketEvent(mChild, mWebSocketEvent.forget()), + new WrappedWebSocketEvent(mChild, std::move(mWebSocketEvent)), NS_DISPATCH_NORMAL); return; } @@ -174,7 +174,7 @@ class EventTargetDispatcher : public ChannelEvent { private: // The lifetime of the child is ensured by ChannelEventQueue. WebSocketChannelChild* mChild; - nsAutoPtr mWebSocketEvent; + UniquePtr mWebSocketEvent; nsCOMPtr mEventTarget; }; diff --git a/netwerk/protocol/websocket/WebSocketEventService.h b/netwerk/protocol/websocket/WebSocketEventService.h index 13447377f9..fd274fd4ce 100644 --- a/netwerk/protocol/websocket/WebSocketEventService.h +++ b/netwerk/protocol/websocket/WebSocketEventService.h @@ -8,7 +8,6 @@ #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Atomics.h" #include "nsIWebSocketEventService.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsClassHashtable.h" #include "nsHashKeys.h" diff --git a/netwerk/protocol/websocket/WebSocketFrame.h b/netwerk/protocol/websocket/WebSocketFrame.h index 4fbc6e8c0f..2568f9168d 100644 --- a/netwerk/protocol/websocket/WebSocketFrame.h +++ b/netwerk/protocol/websocket/WebSocketFrame.h @@ -7,7 +7,6 @@ #include "nsIWebSocketEventService.h" -#include "nsAutoPtr.h" #include "nsIWebSocketEventService.h" #include "nsString.h" diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp index 6397b77393..ccee396677 100644 --- a/netwerk/sctp/datachannel/DataChannel.cpp +++ b/netwerk/sctp/datachannel/DataChannel.cpp @@ -28,10 +28,6 @@ # pragma warning(pop) #endif -#include "DataChannelLog.h" - -#define DATACHANNEL_LOG(args) LOG(args) - #include "nsServiceManagerUtils.h" #include "nsIObserverService.h" #include "nsIObserver.h" @@ -42,7 +38,6 @@ #include "nsProxyRelease.h" #include "nsThread.h" #include "nsThreadUtils.h" -#include "nsAutoPtr.h" #include "nsNetUtil.h" #include "nsNetCID.h" #include "mozilla/StaticMutex.h" @@ -221,7 +216,7 @@ class DataChannelRegistry : public nsIObserver { #endif void InitUsrSctp() { - LOG(("sctp_init")); + DC_DEBUG(("sctp_init")); #ifdef MOZ_PEERCONNECTION usrsctp_init(0, DataChannelRegistry::SctpDtlsOutput, debug_printf); #else @@ -253,7 +248,7 @@ class DataChannelRegistry : public nsIObserver { } void DeinitUsrSctp() { - LOG(("Shutting down SCTP")); + DC_DEBUG(("Shutting down SCTP")); usrsctp_finish(); } @@ -293,13 +288,13 @@ BufferedOutgoingMsg::BufferedOutgoingMsg(OutgoingMsg& msg) { BufferedOutgoingMsg::~BufferedOutgoingMsg() { delete mInfo; - delete mData; + delete[] mData; } static int receive_cb(struct socket* sock, union sctp_sockstore addr, void* data, size_t datalen, struct sctp_rcvinfo rcv, int flags, void* ulp_info) { - LOG(("In receive_cb, ulp_info=%p", ulp_info)); + DC_DEBUG(("In receive_cb, ulp_info=%p", ulp_info)); uintptr_t id = reinterpret_cast(ulp_info); RefPtr connection = DataChannelRegistry::Lookup(id); if (!connection) { @@ -336,13 +331,13 @@ static int threshold_event(struct socket* sock, uint32_t sb_free) { if (connection) { connection->SendDeferredMessages(); } else { - LOG(("Can't find connection for socket %p", sock)); + DC_ERROR(("Can't find connection for socket %p", sock)); } return 0; } DataChannelConnection::~DataChannelConnection() { - LOG(("Deleting DataChannelConnection %p", (void*)this)); + DC_DEBUG(("Deleting DataChannelConnection %p", (void*)this)); // This may die on the MainThread, or on the STS thread ASSERT_WEBRTC(mState == CLOSED); MOZ_ASSERT(!mMasterSocket); @@ -371,7 +366,7 @@ void DataChannelConnection::Destroy() { // if we really want it to do true clean shutdowns it can // create a dependant Internal object that would remain around // until the network shut down the association or timed out. - LOG(("Destroying DataChannelConnection %p", (void*)this)); + DC_DEBUG(("Destroying DataChannelConnection %p", (void*)this)); ASSERT_WEBRTC(NS_IsMainThread()); CloseAll(); @@ -408,7 +403,7 @@ void DataChannelConnection::DestroyOnSTS(struct socket* aMasterSocket, if (aMasterSocket) usrsctp_close(aMasterSocket); usrsctp_deregister_address(reinterpret_cast(mId)); - LOG( + DC_DEBUG( ("Deregistered %p from the SCTP stack.", reinterpret_cast(mId))); #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED mShutdown = true; @@ -442,8 +437,8 @@ DataChannelConnection::DataChannelConnection( mLock("netwerk::sctp::DataChannelConnection"), mListener(aListener), mTransportHandler(aHandler) { - LOG(("Constructor DataChannelConnection=%p, listener=%p", this, - mListener.get())); + DC_VERBOSE(("Constructor DataChannelConnection=%p, listener=%p", this, + mListener.get())); #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED mShutdown = false; #endif @@ -491,19 +486,19 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, if (usrsctp_setsockopt(mMasterSocket, SOL_SOCKET, SO_RCVBUF, (const void*)&buf_size, sizeof(buf_size)) < 0) { - LOG(("Couldn't change receive buffer size on SCTP socket")); + DC_ERROR(("Couldn't change receive buffer size on SCTP socket")); goto error_cleanup; } if (usrsctp_setsockopt(mMasterSocket, SOL_SOCKET, SO_SNDBUF, (const void*)&buf_size, sizeof(buf_size)) < 0) { - LOG(("Couldn't change send buffer size on SCTP socket")); + DC_ERROR(("Couldn't change send buffer size on SCTP socket")); goto error_cleanup; } // Make non-blocking for bind/connect. SCTP over UDP defaults to non-blocking // in associations for normal IO if (usrsctp_set_non_blocking(mMasterSocket, 1) < 0) { - LOG(("Couldn't set non_blocking on SCTP socket")); + DC_ERROR(("Couldn't set non_blocking on SCTP socket")); // We can't handle connect() safely if it will block, not that this will // even happen. goto error_cleanup; @@ -517,7 +512,7 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, l.l_linger = 0; if (usrsctp_setsockopt(mMasterSocket, SOL_SOCKET, SO_LINGER, (const void*)&l, (socklen_t)sizeof(struct linger)) < 0) { - LOG(("Couldn't set SO_LINGER on SCTP socket")); + DC_ERROR(("Couldn't set SO_LINGER on SCTP socket")); // unsafe to allow it to continue if this fails goto error_cleanup; } @@ -530,12 +525,12 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_REUSE_PORT, (const void*)&option_value, (socklen_t)sizeof(option_value)) < 0) { - LOG(("Couldn't set SCTP_REUSE_PORT on SCTP socket")); + DC_WARN(("Couldn't set SCTP_REUSE_PORT on SCTP socket")); } if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_NODELAY, (const void*)&option_value, (socklen_t)sizeof(option_value)) < 0) { - LOG(("Couldn't set SCTP_NODELAY on SCTP socket")); + DC_WARN(("Couldn't set SCTP_NODELAY on SCTP socket")); } } @@ -545,7 +540,7 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, (const void*)&option_value, (socklen_t)sizeof(option_value)) < 0) { - LOG(("*** failed enable explicit EOR mode %d", errno)); + DC_ERROR(("*** failed to enable explicit EOR mode %d", errno)); goto error_cleanup; } } @@ -557,7 +552,7 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, av.assoc_value = 1; if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_INTERLEAVING_SUPPORTED, &av, (socklen_t)sizeof(struct sctp_assoc_value)) < 0) { - LOG(("*** failed enable ndata errno %d", errno)); + DC_ERROR(("*** failed enable ndata errno %d", errno)); goto error_cleanup; } #endif @@ -566,7 +561,7 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, av.assoc_value = SCTP_ENABLE_RESET_STREAM_REQ | SCTP_ENABLE_CHANGE_ASSOC_REQ; if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, &av, (socklen_t)sizeof(struct sctp_assoc_value)) < 0) { - LOG(("*** failed enable stream reset errno %d", errno)); + DC_ERROR(("*** failed enable stream reset errno %d", errno)); goto error_cleanup; } @@ -578,30 +573,25 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, event.se_type = event_type; if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) { - LOG(("*** failed setsockopt SCTP_EVENT errno %d", errno)); + DC_ERROR(("*** failed setsockopt SCTP_EVENT errno %d", errno)); goto error_cleanup; } } - // Update number of streams - mStreams.AppendElements(aNumStreams); - for (uint32_t i = 0; i < aNumStreams; ++i) { - mStreams[i] = nullptr; - } memset(&initmsg, 0, sizeof(initmsg)); len = sizeof(initmsg); if (usrsctp_getsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, &len) < 0) { - LOG(("*** failed getsockopt SCTP_INITMSG")); + DC_ERROR(("*** failed getsockopt SCTP_INITMSG")); goto error_cleanup; } - LOG(("Setting number of SCTP streams to %u, was %u/%u", aNumStreams, - initmsg.sinit_num_ostreams, initmsg.sinit_max_instreams)); + DC_DEBUG(("Setting number of SCTP streams to %u, was %u/%u", aNumStreams, + initmsg.sinit_num_ostreams, initmsg.sinit_max_instreams)); initmsg.sinit_num_ostreams = aNumStreams; initmsg.sinit_max_instreams = MAX_NUM_STREAMS; if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, (socklen_t)sizeof(initmsg)) < 0) { - LOG(("*** failed setsockopt SCTP_INITMSG, errno %d", errno)); + DC_ERROR(("*** failed setsockopt SCTP_INITMSG, errno %d", errno)); goto error_cleanup; } @@ -609,7 +599,7 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort, mSTS->Dispatch( NS_NewRunnableFunction("DataChannelConnection::Init", [id = mId]() { usrsctp_register_address(reinterpret_cast(id)); - LOG(("Registered %p within the SCTP stack.", + DC_DEBUG(("Registered %p within the SCTP stack.", reinterpret_cast(id))); })); @@ -664,10 +654,10 @@ void DataChannelConnection::SetMaxMessageSize(bool aMaxMessageSizeSet, mMaxMessageSize = WEBRTC_DATACHANNEL_MAX_MESSAGE_SIZE_REMOTE; } - LOG(("Maximum message size (outgoing data): %" PRIu64 - " (set=%s, enforced=%s)", - mMaxMessageSize, mMaxMessageSizeSet ? "yes" : "no", - aMaxMessageSize != mMaxMessageSize ? "yes" : "no")); + DC_DEBUG(("Maximum message size (outgoing data): %" PRIu64 + " (set=%s, enforced=%s)", + mMaxMessageSize, mMaxMessageSizeSet ? "yes" : "no", + aMaxMessageSize != mMaxMessageSize ? "yes" : "no")); } uint64_t DataChannelConnection::GetMaxMessageSize() { return mMaxMessageSize; } @@ -675,42 +665,83 @@ uint64_t DataChannelConnection::GetMaxMessageSize() { return mMaxMessageSize; } #ifdef MOZ_PEERCONNECTION bool DataChannelConnection::ConnectToTransport(const std::string& aTransportId, - bool aClient, uint16_t localport, - uint16_t remoteport) { - LOG(("Connect DTLS local %u, remote %u", localport, remoteport)); + const bool aClient, + const uint16_t aLocalPort, + const uint16_t aRemotePort) { + MutexAutoLock lock(mLock); MOZ_ASSERT(mMasterSocket, "SCTP wasn't initialized before ConnectToTransport!"); + static const auto paramString = + [](const std::string& tId, const Maybe& client, + const uint16_t localPort, const uint16_t remotePort) -> std::string { + std::ostringstream stream; + stream << "Transport ID: '" << tId << "', Role: '" + << (client ? (client.value() ? "client" : "server") : "") + << "', Local Port: '" << localPort << "', Remote Port: '" + << remotePort << "'"; + return stream.str(); + }; + + const auto params = + paramString(aTransportId, Some(aClient), aLocalPort, aRemotePort); + DC_DEBUG(("ConnectToTransport connecting DTLS transport with parameters: %s", + params.c_str())); + + const auto currentReadyState = GetReadyState(); + if (currentReadyState == OPEN) { + if (aTransportId == mTransportId && mAllocateEven.isSome() && + mAllocateEven.value() == aClient && mLocalPort == aLocalPort && + mRemotePort == aRemotePort) { + DC_WARN( + ("Skipping attempt to connect to an already OPEN transport with " + "identical parameters.")); + return true; + } + DC_WARN( + ("Attempting to connect to an already OPEN transport, because " + "different parameters were provided.")); + DC_WARN(("Original transport parameters: %s", + paramString(mTransportId, mAllocateEven, mLocalPort, aRemotePort) + .c_str())); + DC_WARN(("New transport parameters: %s", params.c_str())); + } if (NS_WARN_IF(aTransportId.empty())) { return false; } - mLocalPort = localport; - mRemotePort = remoteport; - mState = CONNECTING; + mLocalPort = aLocalPort; + mRemotePort = aRemotePort; + SetReadyState(CONNECTING); + mAllocateEven = Some(aClient); - RUN_ON_THREAD( - mSTS, - WrapRunnable(RefPtr(this), - &DataChannelConnection::SetSignals, aTransportId, aClient), - NS_DISPATCH_NORMAL); + // Could be faster. Probably doesn't matter. + while (auto channel = mChannels.Get(INVALID_STREAM)) { + mChannels.Remove(channel); + channel->mStream = FindFreeStream(); + if (channel->mStream != INVALID_STREAM) { + mChannels.Insert(channel); + } + } + RUN_ON_THREAD(mSTS, + WrapRunnable(RefPtr(this), + &DataChannelConnection::SetSignals, aTransportId), + NS_DISPATCH_NORMAL); return true; } -void DataChannelConnection::SetSignals(const std::string& aTransportId, - bool aClient) { +void DataChannelConnection::SetSignals(const std::string& aTransportId) { ASSERT_WEBRTC(IsSTSThread()); mTransportId = aTransportId; - mAllocateEven = aClient; mTransportHandler->SignalPacketReceived.connect( this, &DataChannelConnection::SctpDtlsInput); // SignalStateChange() doesn't call you with the initial state if (mTransportHandler->GetState(mTransportId, false) == TransportLayer::TS_OPEN) { - LOG(("Setting transport signals, dtls already open")); + DC_DEBUG(("Setting transport signals, dtls already open")); CompleteConnect(); } else { - LOG(("Setting transport signals, dtls not open yet")); + DC_DEBUG(("Setting transport signals, dtls not open yet")); mTransportHandler->SignalStateChange.connect( this, &DataChannelConnection::TransportStateChange); } @@ -718,14 +749,15 @@ void DataChannelConnection::SetSignals(const std::string& aTransportId, void DataChannelConnection::TransportStateChange( const std::string& aTransportId, TransportLayer::State aState) { - if (aState == TransportLayer::TS_OPEN) { + if (aState == TransportLayer::TS_OPEN && aTransportId == mTransportId) { CompleteConnect(); } } void DataChannelConnection::CompleteConnect() { - LOG(("dtls open")); MutexAutoLock lock(mLock); + + DC_DEBUG(("dtls open")); ASSERT_WEBRTC(IsSTSThread()); if (!mMasterSocket) { return; @@ -740,15 +772,15 @@ void DataChannelConnection::CompleteConnect() { addr.sconn_port = htons(mLocalPort); addr.sconn_addr = reinterpret_cast(mId); - LOG(("Calling usrsctp_bind")); + DC_DEBUG(("Calling usrsctp_bind")); int r = usrsctp_bind(mMasterSocket, reinterpret_cast(&addr), sizeof(addr)); if (r < 0) { - LOG(("usrsctp_bind failed: %d", r)); + DC_ERROR(("usrsctp_bind failed: %d", r)); } else { // This is the remote addr addr.sconn_port = htons(mRemotePort); - LOG(("Calling usrsctp_connect")); + DC_DEBUG(("Calling usrsctp_connect")); r = usrsctp_connect( mMasterSocket, reinterpret_cast(&addr), sizeof(addr)); if (r >= 0 || errno == EINPROGRESS) { @@ -761,7 +793,7 @@ void DataChannelConnection::CompleteConnect() { r = usrsctp_getsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, &opt_len); if (r < 0) { - LOG(("usrsctp_getsockopt failed: %d", r)); + DC_ERROR(("usrsctp_getsockopt failed: %d", r)); } else { // draft-ietf-rtcweb-data-channel-13 section 5: max initial MTU IPV4 // 1200, IPV6 1280 @@ -772,10 +804,10 @@ void DataChannelConnection::CompleteConnect() { r = usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, opt_len); if (r < 0) { - LOG(("usrsctp_getsockopt failed: %d", r)); + DC_ERROR(("usrsctp_getsockopt failed: %d", r)); } else { - LOG(("usrsctp: PMTUD disabled, MTU set to %u", - paddrparams.spp_pathmtu)); + DC_ERROR(("usrsctp: PMTUD disabled, MTU set to %u", + paddrparams.spp_pathmtu)); } } } @@ -784,8 +816,8 @@ void DataChannelConnection::CompleteConnect() { // non-blocking return; } - LOG(("usrsctp_connect failed: %d", errno)); - mState = CLOSED; + DC_ERROR(("usrsctp_connect failed: %d", errno)); + SetReadyState(CLOSED); } else { // We fire ON_CONNECTION via SCTP_COMM_UP when we get that return; @@ -817,8 +849,8 @@ void DataChannelConnection::ProcessQueuedOpens() { while (nullptr != (channel = dont_AddRef(static_cast(temp.PopFront())))) { if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) { - LOG(("Processing queued open for %p (%u)", channel.get(), - channel->mStream)); + DC_DEBUG(("Processing queued open for %p (%u)", channel.get(), + channel->mStream)); channel->mFlags &= ~DATA_CHANNEL_FLAGS_FINISH_OPEN; // OpenFinish returns a reference itself, so we need to take it can // Release it @@ -857,7 +889,7 @@ void DataChannelConnection::SendPacket(std::unique_ptr&& packet) { "DataChannelConnection::SendPacket", [this, self = RefPtr(this), packet = std::move(packet)]() mutable { - // LOG(("%p: SCTP/DTLS sent %ld bytes", this, len)); + // DC_DEBUG(("%p: SCTP/DTLS sent %ld bytes", this, len)); if (!mTransportId.empty() && mTransportHandler) { mTransportHandler->SendPacket(mTransportId, std::move(*packet)); } @@ -917,39 +949,46 @@ bool DataChannelConnection::Listen(unsigned short port) { addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); - LOG(("Waiting for connections on port %u", ntohs(addr.sin_port))); - mState = CONNECTING; + DC_DEBUG(("Waiting for connections on port %u", ntohs(addr.sin_port))); + { + MutexAutoLock lock(mLock); + SetReadyState(CONNECTING); + } if (usrsctp_bind(mMasterSocket, reinterpret_cast(&addr), sizeof(struct sockaddr_in)) < 0) { - LOG(("***Failed userspace_bind")); + DC_ERROR(("***Failed userspace_bind")); return false; } if (usrsctp_listen(mMasterSocket, 1) < 0) { - LOG(("***Failed userspace_listen")); + DC_ERROR(("***Failed userspace_listen")); return false; } - LOG(("Accepting connection")); + DC_DEBUG(("Accepting connection")); addr_len = 0; if ((mSocket = usrsctp_accept(mMasterSocket, nullptr, &addr_len)) == nullptr) { - LOG(("***Failed accept")); + DC_ERROR(("***Failed accept")); return false; } - mState = OPEN; + + { + MutexAutoLock lock(mLock); + SetReadyState(OPEN); + } struct linger l; l.l_onoff = 1; l.l_linger = 0; if (usrsctp_setsockopt(mSocket, SOL_SOCKET, SO_LINGER, (const void*)&l, (socklen_t)sizeof(struct linger)) < 0) { - LOG(("Couldn't set SO_LINGER on SCTP socket")); + DC_WARN(("Couldn't set SO_LINGER on SCTP socket")); } // Notify Connection open // XXX We need to make sure connection sticks around until the message is // delivered - LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this)); + DC_DEBUG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this)); Dispatch(do_AddRef(new DataChannelOnMessageAvailable( DataChannelOnMessageAvailable::ON_CONNECTION, this, (DataChannel*)nullptr))); @@ -965,7 +1004,7 @@ bool DataChannelConnection::Connect(const char* addr, unsigned short port) { "Blocks, do not call from main thread!!!"); /* Acting as the connector */ - LOG(("Connecting to %s, port %u", addr, port)); + DC_DEBUG(("Connecting to %s, port %u", addr, port)); memset((void*)&addr4, 0, sizeof(struct sockaddr_in)); memset((void*)&addr6, 0, sizeof(struct sockaddr_in6)); # ifdef HAVE_SIN_LEN @@ -978,25 +1017,27 @@ bool DataChannelConnection::Connect(const char* addr, unsigned short port) { addr6.sin6_family = AF_INET6; addr4.sin_port = htons(port); addr6.sin6_port = htons(port); - mState = CONNECTING; - + { + MutexAutoLock lock(mLock); + SetReadyState(CONNECTING); + } # if !defined(__Userspace_os_Windows) if (inet_pton(AF_INET6, addr, &addr6.sin6_addr) == 1) { if (usrsctp_connect(mMasterSocket, reinterpret_cast(&addr6), sizeof(struct sockaddr_in6)) < 0) { - LOG(("*** Failed userspace_connect")); + DC_ERROR(("*** Failed userspace_connect")); return false; } } else if (inet_pton(AF_INET, addr, &addr4.sin_addr) == 1) { if (usrsctp_connect(mMasterSocket, reinterpret_cast(&addr4), sizeof(struct sockaddr_in)) < 0) { - LOG(("*** Failed userspace_connect")); + DC_ERROR(("*** Failed userspace_connect")); return false; } } else { - LOG(("*** Illegal destination address.")); + DC_ERROR(("*** Illegal destination address.")); } # else { @@ -1010,7 +1051,7 @@ bool DataChannelConnection::Connect(const char* addr, unsigned short port) { if (usrsctp_connect(mMasterSocket, reinterpret_cast(&addr6), sizeof(struct sockaddr_in6)) < 0) { - LOG(("*** Failed userspace_connect")); + DC_ERROR(("*** Failed userspace_connect")); return false; } } else if (!WSAStringToAddressA(const_cast(addr), AF_INET, nullptr, @@ -1019,24 +1060,26 @@ bool DataChannelConnection::Connect(const char* addr, unsigned short port) { if (usrsctp_connect(mMasterSocket, reinterpret_cast(&addr4), sizeof(struct sockaddr_in)) < 0) { - LOG(("*** Failed userspace_connect")); + DC_ERROR(("*** Failed userspace_connect")); return false; } } else { - LOG(("*** Illegal destination address.")); + DC_ERROR(("*** Illegal destination address.")); } } # endif mSocket = mMasterSocket; - LOG(("connect() succeeded! Entering connected mode")); - mState = OPEN; - + DC_DEBUG(("connect() succeeded! Entering connected mode")); + { + MutexAutoLock lock(mLock); + SetReadyState(OPEN); + } // Notify Connection open // XXX We need to make sure connection sticks around until the message is // delivered - LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this)); + DC_DEBUG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this)); Dispatch(do_AddRef(new DataChannelOnMessageAvailable( DataChannelOnMessageAvailable::ON_CONNECTION, this, (DataChannel*)nullptr))); @@ -1045,48 +1088,52 @@ bool DataChannelConnection::Connect(const char* addr, unsigned short port) { #endif DataChannel* DataChannelConnection::FindChannelByStream(uint16_t stream) { - return mStreams.SafeElementAt(stream); + return mChannels.Get(stream).get(); } uint16_t DataChannelConnection::FindFreeStream() { - uint32_t i, j, limit; + ASSERT_WEBRTC(NS_IsMainThread()); + uint16_t i, limit; - limit = mStreams.Length(); - if (limit > MAX_NUM_STREAMS) limit = MAX_NUM_STREAMS; + limit = MAX_NUM_STREAMS; - for (i = (mAllocateEven ? 0 : 1); i < limit; i += 2) { - if (!mStreams[i]) { - // Verify it's not still in the process of closing - for (j = 0; j < mStreamsResetting.Length(); ++j) { - if (mStreamsResetting[j] == i) { - break; - } + MOZ_ASSERT(mAllocateEven.isSome()); + for (i = (*mAllocateEven ? 0 : 1); i < limit; i += 2) { + if (mChannels.Get(i)) { + continue; + } + + // Verify it's not still in the process of closing + size_t j; + for (j = 0; j < mStreamsResetting.Length(); ++j) { + if (mStreamsResetting[j] == i) { + break; } - if (j == mStreamsResetting.Length()) break; + } + + if (j == mStreamsResetting.Length()) { + return i; } } - if (i >= limit) { - return INVALID_STREAM; - } - return i; + return INVALID_STREAM; } uint32_t DataChannelConnection::UpdateCurrentStreamIndex() { - if (mCurrentStream == mStreams.Length() - 1) { + RefPtr channel = mChannels.GetNextChannel(mCurrentStream); + if (!channel) { mCurrentStream = 0; } else { - ++mCurrentStream; + mCurrentStream = channel->mStream; } - return mCurrentStream; } uint32_t DataChannelConnection::GetCurrentStreamIndex() { - // Fix current stream index (in case #streams decreased) - if (mCurrentStream >= mStreams.Length()) { + if (!mChannels.Get(mCurrentStream)) { + // The stream muse have been removed, reset + DC_DEBUG(("Reset mCurrentChannel")); mCurrentStream = 0; } - return mCurrentStream; } @@ -1096,8 +1143,8 @@ bool DataChannelConnection::RequestMoreStreams(int32_t aNeeded) { uint32_t outStreamsNeeded; socklen_t len; - if (aNeeded + mStreams.Length() > MAX_NUM_STREAMS) { - aNeeded = MAX_NUM_STREAMS - mStreams.Length(); + if (aNeeded + mNegotiatedIdLimit > MAX_NUM_STREAMS) { + aNeeded = MAX_NUM_STREAMS - mNegotiatedIdLimit; } if (aNeeded <= 0) { return false; @@ -1106,7 +1153,7 @@ bool DataChannelConnection::RequestMoreStreams(int32_t aNeeded) { len = (socklen_t)sizeof(struct sctp_status); if (usrsctp_getsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_STATUS, &status, &len) < 0) { - LOG(("***failed: getsockopt SCTP_STATUS")); + DC_ERROR(("***failed: getsockopt SCTP_STATUS")); return false; } outStreamsNeeded = aNeeded; // number to add @@ -1120,16 +1167,16 @@ bool DataChannelConnection::RequestMoreStreams(int32_t aNeeded) { if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_ADD_STREAMS, &sas, (socklen_t)sizeof(struct sctp_add_streams)) < 0) { if (errno == EALREADY) { - LOG(("Already have %u output streams", outStreamsNeeded)); + DC_DEBUG(("Already have %u output streams", outStreamsNeeded)); return true; } - LOG(("***failed: setsockopt ADD errno=%d", errno)); + DC_ERROR(("***failed: setsockopt ADD errno=%d", errno)); return false; } - LOG(("Requested %u more streams", outStreamsNeeded)); - // We add to mStreams when we get a SCTP_STREAM_CHANGE_EVENT and the - // values are larger than mStreams.Length() + DC_DEBUG(("Requested %u more streams", outStreamsNeeded)); + // We add to mNegotiatedIdLimit when we get a SCTP_STREAM_CHANGE_EVENT and the + // values are larger than mNegotiatedIdLimit return true; } @@ -1237,9 +1284,10 @@ bool DataChannelConnection::SendDeferredMessages() { // This may block while something is modifying channels, but should not block // for IO + ASSERT_WEBRTC(!NS_IsMainThread()); mLock.AssertCurrentThreadOwns(); - LOG(("SendDeferredMessages called, pending type: %d", mPendingType)); + DC_DEBUG(("SendDeferredMessages called, pending type: %d", mPendingType)); if (!mPendingType) { return false; } @@ -1262,7 +1310,7 @@ bool DataChannelConnection::SendDeferredMessages() { uint32_t i = GetCurrentStreamIndex(); uint32_t end = i; do { - channel = mStreams[i]; + channel = mChannels.Get(i); // Should already be cleared if closing/closed if (!channel || channel->mBufferedData.IsEmpty()) { i = UpdateCurrentStreamIndex(); @@ -1308,7 +1356,7 @@ bool DataChannelConnection::SendDeferredMessages() { // buffer MUST have at least one item! // returns if we're still blocked (true) bool DataChannelConnection::SendBufferedMessages( - nsTArray>& buffer, size_t* aWritten) { + nsTArray>& buffer, size_t* aWritten) { do { // Re-send message int error = SendMsgInternal(*buffer[0], aWritten); @@ -1323,7 +1371,7 @@ bool DataChannelConnection::SendBufferedMessages( return true; default: buffer.RemoveElementAt(0); - LOG(("error on sending: %d", error)); + DC_ERROR(("error on sending: %d", error)); break; } } while (!buffer.IsEmpty()); @@ -1339,18 +1387,24 @@ void DataChannelConnection::HandleOpenRequestMessage( uint32_t prValue; uint16_t prPolicy; + ASSERT_WEBRTC(!NS_IsMainThread()); mLock.AssertCurrentThreadOwns(); const size_t requiredLength = (sizeof(*req) - 1) + ntohs(req->label_length) + ntohs(req->protocol_length); if (((size_t)length) != requiredLength) { - LOG(("%s: Inconsistent length: %u, should be %zu", __FUNCTION__, length, - requiredLength)); - if (((size_t)length) < requiredLength) return; + if (((size_t)length) < requiredLength) { + DC_ERROR( + ("%s: insufficient length: %u, should be %zu. Unable to continue.", + __FUNCTION__, length, requiredLength)); + return; + } + DC_WARN(("%s: Inconsistent length: %u, should be %zu", __FUNCTION__, length, + requiredLength)); } - LOG(("%s: length %u, sizeof(*req) = %zu", __FUNCTION__, length, - sizeof(*req))); + DC_DEBUG(("%s: length %u, sizeof(*req) = %zu", __FUNCTION__, length, + sizeof(*req))); switch (req->channel_type) { case DATA_CHANNEL_RELIABLE: @@ -1366,7 +1420,7 @@ void DataChannelConnection::HandleOpenRequestMessage( prPolicy = SCTP_PR_SCTP_TTL; break; default: - LOG(("Unknown channel type %d", req->channel_type)); + DC_ERROR(("Unknown channel type %d", req->channel_type)); /* XXX error handling */ return; } @@ -1374,20 +1428,20 @@ void DataChannelConnection::HandleOpenRequestMessage( bool ordered = !(req->channel_type & 0x80); if ((channel = FindChannelByStream(stream))) { - if (!(channel->mFlags & DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED)) { - LOG( - ("ERROR: HandleOpenRequestMessage: channel for pre-existing stream " + if (!channel->mNegotiated) { + DC_ERROR( + ("HandleOpenRequestMessage: channel for pre-existing stream " "%u that was not externally negotiated. JS is lying to us, or " "there's an id collision.", stream)); /* XXX: some error handling */ } else { - LOG(("Open for externally negotiated channel %u", stream)); + DC_DEBUG(("Open for externally negotiated channel %u", stream)); // XXX should also check protocol, maybe label if (prPolicy != channel->mPrPolicy || prValue != channel->mPrValue || ordered != channel->mOrdered) { - LOG( - ("WARNING: external negotiation mismatch with OpenRequest:" + DC_WARN( + ("external negotiation mismatch with OpenRequest:" "channel %u, policy %u/%u, value %u/%u, ordered %d/%d", stream, prPolicy, channel->mPrPolicy, prValue, channel->mPrValue, static_cast(ordered), static_cast(channel->mOrdered))); @@ -1395,9 +1449,9 @@ void DataChannelConnection::HandleOpenRequestMessage( } return; } - if (stream >= mStreams.Length()) { - LOG(("%s: stream %u out of bounds (%zu)", __FUNCTION__, stream, - mStreams.Length())); + if (stream >= mNegotiatedIdLimit) { + DC_ERROR(("%s: stream %u out of bounds (%zu)", __FUNCTION__, stream, + mNegotiatedIdLimit)); return; } @@ -1409,27 +1463,32 @@ void DataChannelConnection::HandleOpenRequestMessage( channel = new DataChannel(this, stream, DataChannel::OPEN, label, protocol, prPolicy, prValue, ordered, false, nullptr, nullptr); - mStreams[stream] = channel; + mChannels.Insert(channel); - LOG(("%s: sending ON_CHANNEL_CREATED for %s/%s: %u", __FUNCTION__, - channel->mLabel.get(), channel->mProtocol.get(), stream)); + DC_DEBUG(("%s: sending ON_CHANNEL_CREATED for %s/%s: %u", __FUNCTION__, + channel->mLabel.get(), channel->mProtocol.get(), stream)); Dispatch(do_AddRef(new DataChannelOnMessageAvailable( DataChannelOnMessageAvailable::ON_CHANNEL_CREATED, this, channel))); - LOG(("%s: deferring sending ON_CHANNEL_OPEN for %p", __FUNCTION__, - channel.get())); + DC_DEBUG(("%s: deferring sending ON_CHANNEL_OPEN for %p", __FUNCTION__, + channel.get())); channel->AnnounceOpen(); - int error = SendOpenAckMessage(stream); + // Note that any message can be buffered; SendOpenAckMessage may + // error later than this check. + const auto error = SendOpenAckMessage(channel->mStream); if (error) { - LOG(("SendOpenRequest failed, error = %d", error)); - // Close the channel, inform the user - CloseInt(channel); - // XXX send error via DataChannelOnMessageAvailable (bug 843625) + DC_ERROR(("SendOpenRequest failed, error = %d", error)); + Dispatch(NS_NewRunnableFunction( + "DataChannelConnection::HandleOpenRequestMessage", + [channel, connection = RefPtr(this)]() { + MutexAutoLock mLock(connection->mLock); + // Close the channel on failure + connection->CloseInt(channel); + })); return; } - - DeliverQueuedData(stream); + DeliverQueuedData(channel->mStream); } // NOTE: the updated spec from the IETF says we should set in-order until we @@ -1442,8 +1501,8 @@ void DataChannelConnection::DeliverQueuedData(uint16_t stream) { while (i < mQueuedData.Length()) { // Careful! we may modify the array length from within the loop! if (mQueuedData[i]->mStream == stream) { - LOG(("Delivering queued data for stream %u, length %u", stream, - mQueuedData[i]->mLength)); + DC_DEBUG(("Delivering queued data for stream %u, length %u", stream, + mQueuedData[i]->mLength)); // Deliver the queued data HandleDataMessage(mQueuedData[i]->mData, mQueuedData[i]->mLength, mQueuedData[i]->mPpid, mQueuedData[i]->mStream, @@ -1468,8 +1527,8 @@ void DataChannelConnection::HandleOpenAckMessage( return; } - LOG(("OpenAck received for stream %u, waiting=%d", stream, - (channel->mFlags & DATA_CHANNEL_FLAGS_WAITING_ACK) ? 1 : 0)); + DC_DEBUG(("OpenAck received for stream %u, waiting=%d", stream, + (channel->mFlags & DATA_CHANNEL_FLAGS_WAITING_ACK) ? 1 : 0)); channel->mFlags &= ~DATA_CHANNEL_FLAGS_WAITING_ACK; } @@ -1478,8 +1537,8 @@ void DataChannelConnection::HandleOpenAckMessage( void DataChannelConnection::HandleUnknownMessage(uint32_t ppid, uint32_t length, uint16_t stream) { /* XXX: Send an error message? */ - LOG(("unknown DataChannel message received: %u, len %u on stream %d", ppid, - length, stream)); + DC_ERROR(("unknown DataChannel message received: %u, len %u on stream %d", + ppid, length, stream)); // XXX Log to JS error console if possible } @@ -1526,8 +1585,9 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, // Note: Until we support SIZE_MAX sized messages, we need this check #if (SIZE_MAX > UINT32_MAX) if (length > UINT32_MAX) { - LOG(("DataChannel: Cannot handle message of size %zu (max=%" PRIu32 ")", - length, UINT32_MAX)); + DC_ERROR(("DataChannel: Cannot handle message of size %zu (max=%" PRIu32 + ")", + length, UINT32_MAX)); CloseInt(channel); return; } @@ -1549,7 +1609,7 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, // Since this is rare and non-performance, keep a single list of queued // data messages to deliver once the channel opens. - LOG(("Queuing data for stream %u, length %u", stream, data_length)); + DC_DEBUG(("Queuing data for stream %u, length %u", stream, data_length)); // Copies data mQueuedData.AppendElement( new QueuedDataMessage(stream, ppid, flags, data, data_length)); @@ -1576,13 +1636,12 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, // Remaining chunks of previously truncated message (due to the buffer being // full)? if (channel->mFlags & DATA_CHANNEL_FLAGS_CLOSING_TOO_LARGE) { - LOG( + DC_ERROR( ("DataChannel: Ignoring partial message of length %u, buffer full and " "closing", data_length)); // Only unblock if unordered - if ((channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED) && - (flags & MSG_EOR)) { + if (!channel->mOrdered && (flags & MSG_EOR)) { channel->mFlags &= ~DATA_CHANNEL_FLAGS_CLOSING_TOO_LARGE; } } @@ -1591,7 +1650,7 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, bufferFlags = BufferMessage(channel->mRecvBuffer, buffer, data_length, ppid, flags); if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_TOO_LARGE) { - LOG( + DC_ERROR( ("DataChannel: Buffered message would become too large to handle, " "closing channel")); channel->mRecvBuffer.Truncate(0); @@ -1600,7 +1659,7 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, return; } if (!(bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_COMPLETE)) { - LOG( + DC_DEBUG( ("DataChannel: Partial %s message of length %u (total %u) on channel " "id %u", is_binary ? "binary" : "string", data_length, @@ -1613,7 +1672,7 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, // Complain about large messages (only complain - we can handle it) if (data_length > WEBRTC_DATACHANNEL_MAX_MESSAGE_SIZE_LOCAL) { - LOG( + DC_WARN( ("DataChannel: Received message of length %u is > announced maximum " "message size (%u)", data_length, WEBRTC_DATACHANNEL_MAX_MESSAGE_SIZE_LOCAL)); @@ -1621,7 +1680,8 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, switch (ppid) { case DATA_CHANNEL_PPID_DOMSTRING: - LOG(("DataChannel: Received string message of length %u on channel %u", + DC_DEBUG( + ("DataChannel: Received string message of length %u on channel %u", data_length, channel->mStream)); type = DataChannelOnMessageAvailable::ON_DATA_STRING; if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_BUFFERED) { @@ -1633,7 +1693,8 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, break; case DATA_CHANNEL_PPID_BINARY: - LOG(("DataChannel: Received binary message of length %u on channel id %u", + DC_DEBUG( + ("DataChannel: Received binary message of length %u on channel id %u", data_length, channel->mStream)); type = DataChannelOnMessageAvailable::ON_DATA_BINARY; if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_BUFFERED) { @@ -1645,14 +1706,15 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length, default: NS_ERROR("Unknown data PPID"); + DC_ERROR(("Unknown data PPID %" PRIu32, ppid)); return; } // Notify onmessage - LOG(("%s: sending ON_DATA_%s%s for %p", __FUNCTION__, - (type == DataChannelOnMessageAvailable::ON_DATA_STRING) ? "STRING" - : "BINARY", - info, channel)); + DC_DEBUG(("%s: sending ON_DATA_%s%s for %p", __FUNCTION__, + (type == DataChannelOnMessageAvailable::ON_DATA_STRING) ? "STRING" + : "BINARY", + info, channel)); if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_BUFFERED) { channel->SendOrQueue(new DataChannelOnMessageAvailable( type, this, channel, channel->mRecvBuffer)); @@ -1673,8 +1735,8 @@ void DataChannelConnection::HandleDCEPMessage(const void* buffer, size_t length, // Note: Until we support SIZE_MAX sized messages, we need this check #if (SIZE_MAX > UINT32_MAX) if (length > UINT32_MAX) { - LOG(("DataChannel: Cannot handle message of size %zu (max=%u)", length, - UINT32_MAX)); + DC_ERROR(("DataChannel: Cannot handle message of size %zu (max=%u)", length, + UINT32_MAX)); Stop(); return; } @@ -1687,7 +1749,7 @@ void DataChannelConnection::HandleDCEPMessage(const void* buffer, size_t length, const uint8_t bufferFlags = BufferMessage(mRecvBuffer, buffer, data_length, ppid, flags); if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_TOO_LARGE) { - LOG( + DC_ERROR( ("DataChannel: Buffered message would become too large to handle, " "closing connection")); mRecvBuffer.Truncate(0); @@ -1695,7 +1757,7 @@ void DataChannelConnection::HandleDCEPMessage(const void* buffer, size_t length, return; } if (!(bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_COMPLETE)) { - LOG(("Buffered partial DCEP message of length %u", data_length)); + DC_DEBUG(("Buffered partial DCEP message of length %u", data_length)); return; } if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_BUFFERED) { @@ -1704,11 +1766,11 @@ void DataChannelConnection::HandleDCEPMessage(const void* buffer, size_t length, } req = static_cast(buffer); - LOG(("Handling DCEP message of length %u", data_length)); + DC_DEBUG(("Handling DCEP message of length %u", data_length)); // Ensure minimum message size (ack is the smallest DCEP message) if ((size_t)data_length < sizeof(*ack)) { - LOG(("Ignored invalid DCEP message (too short)")); + DC_WARN(("Ignored invalid DCEP message (too short)")); return; } @@ -1754,62 +1816,70 @@ void DataChannelConnection::HandleMessage(const void* buffer, size_t length, HandleDataMessage(buffer, length, ppid, stream, flags); break; default: - LOG(("Message of length %zu PPID %u on stream %u received (%s).", length, - ppid, stream, (flags & MSG_EOR) ? "complete" : "partial")); + DC_ERROR(( + "Unhandled message of length %zu PPID %u on stream %u received (%s).", + length, ppid, stream, (flags & MSG_EOR) ? "complete" : "partial")); break; } } void DataChannelConnection::HandleAssociationChangeEvent( const struct sctp_assoc_change* sac) { - uint32_t i, n; + mLock.AssertCurrentThreadOwns(); + uint32_t i, n; + const auto readyState = GetReadyState(); switch (sac->sac_state) { case SCTP_COMM_UP: - LOG(("Association change: SCTP_COMM_UP")); - if (mState == CONNECTING) { + DC_DEBUG(("Association change: SCTP_COMM_UP")); + if (readyState == CONNECTING) { mSocket = mMasterSocket; - mState = OPEN; + SetReadyState(OPEN); - // Check for older Firefox by looking at the amount of incoming streams - LOG(("Negotiated number of incoming streams: %" PRIu16, - sac->sac_inbound_streams)); + DC_DEBUG(("Negotiated number of incoming streams: %" PRIu16, + sac->sac_inbound_streams)); + DC_DEBUG(("Negotiated number of outgoing streams: %" PRIu16, + sac->sac_outbound_streams)); + mNegotiatedIdLimit = + std::max(mNegotiatedIdLimit, + static_cast(std::max(sac->sac_outbound_streams, + sac->sac_inbound_streams))); Dispatch(do_AddRef(new DataChannelOnMessageAvailable( DataChannelOnMessageAvailable::ON_CONNECTION, this))); - LOG(("DTLS connect() succeeded! Entering connected mode")); + DC_DEBUG(("DTLS connect() succeeded! Entering connected mode")); // Open any streams pending... ProcessQueuedOpens(); - } else if (mState == OPEN) { - LOG(("DataConnection Already OPEN")); + } else if (readyState == OPEN) { + DC_DEBUG(("DataConnection Already OPEN")); } else { - LOG(("Unexpected state: %d", mState)); + DC_ERROR(("Unexpected state: %d", readyState)); } break; case SCTP_COMM_LOST: - LOG(("Association change: SCTP_COMM_LOST")); + DC_DEBUG(("Association change: SCTP_COMM_LOST")); // This association is toast, so also close all the channels -- from // mainthread! Stop(); break; case SCTP_RESTART: - LOG(("Association change: SCTP_RESTART")); + DC_DEBUG(("Association change: SCTP_RESTART")); break; case SCTP_SHUTDOWN_COMP: - LOG(("Association change: SCTP_SHUTDOWN_COMP")); + DC_DEBUG(("Association change: SCTP_SHUTDOWN_COMP")); Stop(); break; case SCTP_CANT_STR_ASSOC: - LOG(("Association change: SCTP_CANT_STR_ASSOC")); + DC_DEBUG(("Association change: SCTP_CANT_STR_ASSOC")); break; default: - LOG(("Association change: UNKNOWN")); + DC_DEBUG(("Association change: UNKNOWN")); break; } - LOG(("Association change: streams (in/out) = (%u/%u)", - sac->sac_inbound_streams, sac->sac_outbound_streams)); + DC_DEBUG(("Association change: streams (in/out) = (%u/%u)", + sac->sac_inbound_streams, sac->sac_outbound_streams)); if (NS_WARN_IF(!sac)) { return; @@ -1821,30 +1891,30 @@ void DataChannelConnection::HandleAssociationChangeEvent( for (i = 0; i < n; ++i) { switch (sac->sac_info[i]) { case SCTP_ASSOC_SUPPORTS_PR: - LOG(("Supports: PR")); + DC_DEBUG(("Supports: PR")); break; case SCTP_ASSOC_SUPPORTS_AUTH: - LOG(("Supports: AUTH")); + DC_DEBUG(("Supports: AUTH")); break; case SCTP_ASSOC_SUPPORTS_ASCONF: - LOG(("Supports: ASCONF")); + DC_DEBUG(("Supports: ASCONF")); break; case SCTP_ASSOC_SUPPORTS_MULTIBUF: - LOG(("Supports: MULTIBUF")); + DC_DEBUG(("Supports: MULTIBUF")); break; case SCTP_ASSOC_SUPPORTS_RE_CONFIG: - LOG(("Supports: RE-CONFIG")); + DC_DEBUG(("Supports: RE-CONFIG")); break; #if defined(SCTP_ASSOC_SUPPORTS_INTERLEAVING) case SCTP_ASSOC_SUPPORTS_INTERLEAVING: - LOG(("Supports: NDATA")); + DC_DEBUG(("Supports: NDATA")); // TODO: This should probably be set earlier above in 'case // SCTP_COMM_UP' but we also need this for 'SCTP_RESTART'. mSendInterleaved = true; break; #endif default: - LOG(("Supports: UNKNOWN(0x%02x)", sac->sac_info[i])); + DC_ERROR(("Supports: UNKNOWN(0x%02x)", sac->sac_info[i])); break; } } @@ -1852,9 +1922,9 @@ void DataChannelConnection::HandleAssociationChangeEvent( } else if (((sac->sac_state == SCTP_COMM_LOST) || (sac->sac_state == SCTP_CANT_STR_ASSOC)) && (n > 0)) { - LOG(("Association: ABORT =")); + DC_DEBUG(("Association: ABORT =")); for (i = 0; i < n; ++i) { - LOG((" 0x%02x", sac->sac_info[i])); + DC_DEBUG((" 0x%02x", sac->sac_info[i])); } } if ((sac->sac_state == SCTP_CANT_STR_ASSOC) || @@ -1892,31 +1962,33 @@ void DataChannelConnection::HandlePeerAddressChangeEvent( default: break; } - LOG(("Peer address %s is now ", addr)); + DC_DEBUG(("Peer address %s is now ", addr)); switch (spc->spc_state) { case SCTP_ADDR_AVAILABLE: - LOG(("SCTP_ADDR_AVAILABLE")); + DC_DEBUG(("SCTP_ADDR_AVAILABLE")); break; case SCTP_ADDR_UNREACHABLE: - LOG(("SCTP_ADDR_UNREACHABLE")); + DC_DEBUG(("SCTP_ADDR_UNREACHABLE")); break; case SCTP_ADDR_REMOVED: - LOG(("SCTP_ADDR_REMOVED")); + DC_DEBUG(("SCTP_ADDR_REMOVED")); break; case SCTP_ADDR_ADDED: - LOG(("SCTP_ADDR_ADDED")); + DC_DEBUG(("SCTP_ADDR_ADDED")); break; case SCTP_ADDR_MADE_PRIM: - LOG(("SCTP_ADDR_MADE_PRIM")); + DC_DEBUG(("SCTP_ADDR_MADE_PRIM")); break; case SCTP_ADDR_CONFIRMED: - LOG(("SCTP_ADDR_CONFIRMED")); + DC_DEBUG(("SCTP_ADDR_CONFIRMED")); break; default: - LOG(("UNKNOWN")); + DC_ERROR(("UNKNOWN SCP STATE")); break; } - LOG((" (error = 0x%08x).\n", spc->spc_error)); + if (spc->spc_error) { + DC_ERROR((" (error = 0x%08x).\n", spc->spc_error)); + } } void DataChannelConnection::HandleRemoteErrorEvent( @@ -1924,22 +1996,22 @@ void DataChannelConnection::HandleRemoteErrorEvent( size_t i, n; n = sre->sre_length - sizeof(struct sctp_remote_error); - LOG(("Remote Error (error = 0x%04x): ", sre->sre_error)); + DC_WARN(("Remote Error (error = 0x%04x): ", sre->sre_error)); for (i = 0; i < n; ++i) { - LOG((" 0x%02x", sre->sre_data[i])); + DC_WARN((" 0x%02x", sre->sre_data[i])); } } void DataChannelConnection::HandleShutdownEvent( const struct sctp_shutdown_event* sse) { - LOG(("Shutdown event.")); + DC_DEBUG(("Shutdown event.")); /* XXX: notify all channels. */ // Attempts to actually send anything will fail } void DataChannelConnection::HandleAdaptationIndication( const struct sctp_adaptation_event* sai) { - LOG(("Adaptation indication: %x.", sai->sai_adaptation_ind)); + DC_DEBUG(("Adaptation indication: %x.", sai->sai_adaptation_ind)); } void DataChannelConnection::HandlePartialDeliveryEvent( @@ -1947,30 +2019,30 @@ void DataChannelConnection::HandlePartialDeliveryEvent( // Note: Be aware that stream and sequence number being u32 instead of u16 is // a bug in the SCTP API. This may change in the future. - LOG(("Partial delivery event: ")); + DC_DEBUG(("Partial delivery event: ")); switch (spde->pdapi_indication) { case SCTP_PARTIAL_DELIVERY_ABORTED: - LOG(("delivery aborted ")); + DC_DEBUG(("delivery aborted ")); break; default: - LOG(("??? ")); + DC_ERROR(("??? ")); break; } - LOG(("(flags = %x), stream = %" PRIu32 ", sn = %" PRIu32, spde->pdapi_flags, - spde->pdapi_stream, spde->pdapi_seq)); + DC_DEBUG(("(flags = %x), stream = %" PRIu32 ", sn = %" PRIu32, + spde->pdapi_flags, spde->pdapi_stream, spde->pdapi_seq)); // Validate stream ID if (spde->pdapi_stream >= UINT16_MAX) { - LOG(("Invalid stream id in partial delivery event: %" PRIu32 "\n", - spde->pdapi_stream)); + DC_ERROR(("Invalid stream id in partial delivery event: %" PRIu32 "\n", + spde->pdapi_stream)); return; } // Find channel and reset buffer DataChannel* channel = FindChannelByStream((uint16_t)spde->pdapi_stream); if (channel) { - LOG(("Abort partially delivered message of %u bytes\n", - channel->mRecvBuffer.Length())); + DC_WARN(("Abort partially delivered message of %u bytes\n", + channel->mRecvBuffer.Length())); channel->mRecvBuffer.Truncate(0); } } @@ -1980,36 +2052,39 @@ void DataChannelConnection::HandleSendFailedEvent( size_t i, n; if (ssfe->ssfe_flags & SCTP_DATA_UNSENT) { - LOG(("Unsent ")); + DC_DEBUG(("Unsent ")); } if (ssfe->ssfe_flags & SCTP_DATA_SENT) { - LOG(("Sent ")); + DC_DEBUG(("Sent ")); } if (ssfe->ssfe_flags & ~(SCTP_DATA_SENT | SCTP_DATA_UNSENT)) { - LOG(("(flags = %x) ", ssfe->ssfe_flags)); + DC_DEBUG(("(flags = %x) ", ssfe->ssfe_flags)); } - LOG(("message with PPID = %u, SID = %d, flags: 0x%04x due to error = 0x%08x", + DC_DEBUG( + ("message with PPID = %u, SID = %d, flags: 0x%04x due to error = 0x%08x", ntohl(ssfe->ssfe_info.snd_ppid), ssfe->ssfe_info.snd_sid, ssfe->ssfe_info.snd_flags, ssfe->ssfe_error)); n = ssfe->ssfe_length - sizeof(struct sctp_send_failed_event); for (i = 0; i < n; ++i) { - LOG((" 0x%02x", ssfe->ssfe_data[i])); + DC_DEBUG((" 0x%02x", ssfe->ssfe_data[i])); } } void DataChannelConnection::ClearResets() { // Clear all pending resets if (!mStreamsResetting.IsEmpty()) { - LOG(("Clearing resets for %zu streams", mStreamsResetting.Length())); + DC_DEBUG(("Clearing resets for %zu streams", mStreamsResetting.Length())); } for (uint32_t i = 0; i < mStreamsResetting.Length(); ++i) { RefPtr channel; channel = FindChannelByStream(mStreamsResetting[i]); if (channel) { - LOG(("Forgetting channel %u (%p) with pending reset", channel->mStream, - channel.get())); - mStreams[channel->mStream] = nullptr; + DC_DEBUG(("Forgetting channel %u (%p) with pending reset", + channel->mStream, channel.get())); + // TODO: Do we _really_ want to remove this? Are we allowed to reuse the + // id? + mChannels.Remove(channel); } } mStreamsResetting.Clear(); @@ -2019,7 +2094,8 @@ void DataChannelConnection::ResetOutgoingStream(uint16_t stream) { uint32_t i; mLock.AssertCurrentThreadOwns(); - LOG(("Connection %p: Resetting outgoing stream %u", (void*)this, stream)); + DC_DEBUG( + ("Connection %p: Resetting outgoing stream %u", (void*)this, stream)); // Rarely has more than a couple items and only for a short time for (i = 0; i < mStreamsResetting.Length(); ++i) { if (mStreamsResetting[i] == stream) { @@ -2034,11 +2110,11 @@ void DataChannelConnection::SendOutgoingStreamReset() { uint32_t i; size_t len; - LOG(("Connection %p: Sending outgoing stream reset for %zu streams", - (void*)this, mStreamsResetting.Length())); + DC_DEBUG(("Connection %p: Sending outgoing stream reset for %zu streams", + (void*)this, mStreamsResetting.Length())); mLock.AssertCurrentThreadOwns(); if (mStreamsResetting.IsEmpty()) { - LOG(("No streams to reset")); + DC_DEBUG(("No streams to reset")); return; } len = sizeof(sctp_assoc_t) + @@ -2053,7 +2129,7 @@ void DataChannelConnection::SendOutgoingStreamReset() { } if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_RESET_STREAMS, srs, (socklen_t)len) < 0) { - LOG(("***failed: setsockopt RESET, errno %d", errno)); + DC_ERROR(("***failed: setsockopt RESET, errno %d", errno)); // if errno == EALREADY, this is normal - we can't send another reset // with one pending. // When we get an incoming reset (which may be a response to our @@ -2090,18 +2166,17 @@ void DataChannelConnection::HandleStreamResetEvent( // I believe this is impossible, as we don't have an input stream // yet. - LOG(("Incoming: Channel %u closed", channel->mStream)); - if (mStreams[channel->mStream]) { + DC_DEBUG(("Incoming: Channel %u closed", channel->mStream)); + if (mChannels.Remove(channel)) { // Mark the stream for reset (the reset is sent below) ResetOutgoingStream(channel->mStream); } - mStreams[channel->mStream] = nullptr; - LOG(("Disconnected DataChannel %p from connection %p", - (void*)channel.get(), (void*)channel->mConnection.get())); + DC_DEBUG(("Disconnected DataChannel %p from connection %p", + (void*)channel.get(), (void*)channel->mConnection.get())); channel->StreamClosedLocked(); } else { - LOG(("Can't find incoming channel %d", i)); + DC_WARN(("Can't find incoming channel %d", i)); } } } @@ -2109,58 +2184,53 @@ void DataChannelConnection::HandleStreamResetEvent( // Process any pending resets now: if (!mStreamsResetting.IsEmpty()) { - LOG(("Sending %zu pending resets", mStreamsResetting.Length())); + DC_DEBUG(("Sending %zu pending resets", mStreamsResetting.Length())); SendOutgoingStreamReset(); } } void DataChannelConnection::HandleStreamChangeEvent( const struct sctp_stream_change_event* strchg) { - uint16_t stream; - RefPtr channel; - + ASSERT_WEBRTC(!NS_IsMainThread()); if (strchg->strchange_flags == SCTP_STREAM_CHANGE_DENIED) { - LOG(("*** Failed increasing number of streams from %zu (%u/%u)", - mStreams.Length(), strchg->strchange_instrms, - strchg->strchange_outstrms)); + DC_ERROR(("*** Failed increasing number of streams from %zu (%u/%u)", + mNegotiatedIdLimit, strchg->strchange_instrms, + strchg->strchange_outstrms)); // XXX FIX! notify pending opens of failure return; } - if (strchg->strchange_instrms > mStreams.Length()) { - LOG(("Other side increased streams from %zu to %u", mStreams.Length(), - strchg->strchange_instrms)); - } - if (strchg->strchange_outstrms > mStreams.Length() || - strchg->strchange_instrms > mStreams.Length()) { - uint16_t old_len = mStreams.Length(); - uint16_t new_len = - std::max(strchg->strchange_outstrms, strchg->strchange_instrms); - LOG(("Increasing number of streams from %u to %u - adding %u (in: %u)", - old_len, new_len, new_len - old_len, strchg->strchange_instrms)); + if (strchg->strchange_instrms > mNegotiatedIdLimit) { + DC_DEBUG(("Other side increased streams from %zu to %u", mNegotiatedIdLimit, + strchg->strchange_instrms)); + } + uint16_t old_limit = mNegotiatedIdLimit; + uint16_t new_limit = + std::max(strchg->strchange_outstrms, strchg->strchange_instrms); + if (new_limit > mNegotiatedIdLimit) { + DC_DEBUG(("Increasing number of streams from %u to %u - adding %u (in: %u)", + old_limit, new_limit, new_limit - old_limit, + strchg->strchange_instrms)); // make sure both are the same length - mStreams.AppendElements(new_len - old_len); - LOG(("New length = %zu (was %d)", mStreams.Length(), old_len)); - for (size_t i = old_len; i < mStreams.Length(); ++i) { - mStreams[i] = nullptr; - } + mNegotiatedIdLimit = new_limit; + DC_DEBUG(("New length = %zu (was %d)", mNegotiatedIdLimit, old_limit)); // Re-process any channels waiting for streams. // Linear search, but we don't increase channels often and // the array would only get long in case of an app error normally // Make sure we request enough streams if there's a big jump in streams // Could make a more complex API for OpenXxxFinish() and avoid this loop - size_t num_needed = mPending.GetSize(); - LOG(("%zu of %d new streams already needed", num_needed, - new_len - old_len)); - num_needed -= (new_len - old_len); // number we added - if (num_needed > 0) { - if (num_needed < 16) num_needed = 16; - LOG(("Not enough new streams, asking for %zu more", num_needed)); + auto channels = mChannels.GetAll(); + size_t num_needed = + channels.Length() ? (channels.LastElement()->mStream + 1) : 0; + MOZ_ASSERT(num_needed != INVALID_STREAM); + if (num_needed > new_limit) { + int32_t more_needed = num_needed - ((int32_t)mNegotiatedIdLimit) + 16; + DC_DEBUG(("Not enough new streams, asking for %d more", more_needed)); // TODO: parameter is an int32_t but we pass size_t - RequestMoreStreams(num_needed); + RequestMoreStreams(more_needed); } else if (strchg->strchange_outstrms < strchg->strchange_instrms) { - LOG(("Requesting %d output streams to match partner", - strchg->strchange_instrms - strchg->strchange_outstrms)); + DC_DEBUG(("Requesting %d output streams to match partner", + strchg->strchange_instrms - strchg->strchange_outstrms)); RequestMoreStreams(strchg->strchange_instrms - strchg->strchange_outstrms); } @@ -2169,41 +2239,14 @@ void DataChannelConnection::HandleStreamChangeEvent( } // else probably not a change in # of streams - for (uint32_t i = 0; i < mStreams.Length(); ++i) { - channel = mStreams[i]; - if (!channel) continue; - - if (channel->mStream == INVALID_STREAM) { - if ((strchg->strchange_flags & SCTP_STREAM_CHANGE_DENIED) || - (strchg->strchange_flags & SCTP_STREAM_CHANGE_FAILED)) { + if ((strchg->strchange_flags & SCTP_STREAM_CHANGE_DENIED) || + (strchg->strchange_flags & SCTP_STREAM_CHANGE_FAILED)) { + // Other side denied our request. Need to AnnounceClosed some stuff. + for (auto& channel : mChannels.GetAll()) { + if (channel->mStream >= mNegotiatedIdLimit) { /* XXX: Signal to the other end. */ channel->AnnounceClosed(); // maybe fire onError (bug 843625) - } else { - stream = FindFreeStream(); - if (stream != INVALID_STREAM) { - channel->mStream = stream; - mStreams[stream] = channel; - - // Send open request - int error = SendOpenRequestMessage( - channel->mLabel, channel->mProtocol, channel->mStream, - !!(channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED), - channel->mPrPolicy, channel->mPrValue); - if (error) { - LOG(("SendOpenRequest failed, error = %d", error)); - // Close the channel, inform the user - mStreams[channel->mStream] = nullptr; - channel->AnnounceClosed(); - // Don't need to reset; we didn't open it - } else { - channel->mFlags |= DATA_CHANNEL_FLAGS_READY; - channel->AnnounceOpen(); - } - } else { - /* We will not find more ... */ - break; - } } } } @@ -2233,13 +2276,13 @@ void DataChannelConnection::HandleNotification( HandleAdaptationIndication(&(notif->sn_adaptation_event)); break; case SCTP_AUTHENTICATION_EVENT: - LOG(("SCTP_AUTHENTICATION_EVENT")); + DC_DEBUG(("SCTP_AUTHENTICATION_EVENT")); break; case SCTP_SENDER_DRY_EVENT: - // LOG(("SCTP_SENDER_DRY_EVENT")); + // DC_DEBUG(("SCTP_SENDER_DRY_EVENT")); break; case SCTP_NOTIFICATIONS_STOPPED_EVENT: - LOG(("SCTP_NOTIFICATIONS_STOPPED_EVENT")); + DC_DEBUG(("SCTP_NOTIFICATIONS_STOPPED_EVENT")); break; case SCTP_PARTIAL_DELIVERY_EVENT: HandlePartialDeliveryEvent(&(notif->sn_pdapi_event)); @@ -2251,13 +2294,13 @@ void DataChannelConnection::HandleNotification( HandleStreamResetEvent(&(notif->sn_strreset_event)); break; case SCTP_ASSOC_RESET_EVENT: - LOG(("SCTP_ASSOC_RESET_EVENT")); + DC_DEBUG(("SCTP_ASSOC_RESET_EVENT")); break; case SCTP_STREAM_CHANGE_EVENT: HandleStreamChangeEvent(&(notif->sn_strchange_event)); break; default: - LOG(("unknown SCTP event: %u", (uint32_t)notif->sn_header.sn_type)); + DC_ERROR(("unknown SCTP event: %u", (uint32_t)notif->sn_header.sn_type)); break; } } @@ -2266,10 +2309,10 @@ int DataChannelConnection::ReceiveCallback(struct socket* sock, void* data, size_t datalen, struct sctp_rcvinfo rcv, int flags) { ASSERT_WEBRTC(!NS_IsMainThread()); - LOG(("In ReceiveCallback")); + DC_DEBUG(("In ReceiveCallback")); if (!data) { - LOG(("ReceiveCallback: SCTP has finished shutting down")); + DC_DEBUG(("ReceiveCallback: SCTP has finished shutting down")); } else { bool locked = false; if (!IsSTSThread()) { @@ -2300,13 +2343,22 @@ already_AddRefed DataChannelConnection::Open( const nsACString& label, const nsACString& protocol, Type type, bool inOrder, uint32_t prValue, DataChannelListener* aListener, nsISupports* aContext, bool aExternalNegotiated, uint16_t aStream) { + ASSERT_WEBRTC(NS_IsMainThread()); if (!aExternalNegotiated) { - // aStream == INVALID_STREAM to have the protocol allocate - aStream = INVALID_STREAM; + if (mAllocateEven.isSome()) { + aStream = FindFreeStream(); + if (aStream == INVALID_STREAM) { + return nullptr; + } + } else { + // We do not yet know whether we are client or server, and an id has not + // been chosen for us. We will need to choose later. + aStream = INVALID_STREAM; + } } uint16_t prPolicy = SCTP_PR_SCTP_NONE; - LOG( + DC_DEBUG( ("DC Open: label %s/%s, type %u, inorder %d, prValue %u, listener %p, " "context %p, external: %s, stream %u", PromiseFlatCString(label).get(), PromiseFlatCString(protocol).get(), @@ -2323,7 +2375,7 @@ already_AddRefed DataChannelConnection::Open( prPolicy = SCTP_PR_SCTP_TTL; break; default: - LOG(("ERROR: unsupported channel type: %u", type)); + DC_ERROR(("unsupported channel type: %u", type)); MOZ_ASSERT(false); return nullptr; } @@ -2331,10 +2383,8 @@ already_AddRefed DataChannelConnection::Open( return nullptr; } - // Don't look past currently-negotiated streams - if (aStream != INVALID_STREAM && aStream < mStreams.Length() && - mStreams[aStream]) { - LOG(("ERROR: external negotiation of already-open channel %u", aStream)); + if (aStream != INVALID_STREAM && mChannels.Get(aStream)) { + DC_ERROR(("external negotiation of already-open channel %u", aStream)); // XXX How do we indicate this up to the application? Probably the // caller's job, but we may need to return an error code. return nullptr; @@ -2343,6 +2393,7 @@ already_AddRefed DataChannelConnection::Open( RefPtr channel(new DataChannel( this, aStream, DataChannel::CONNECTING, label, protocol, prPolicy, prValue, inOrder, aExternalNegotiated, aListener, aContext)); + mChannels.Insert(channel); MutexAutoLock lock(mLock); // OpenFinish assumes this return OpenFinish(channel.forget()); @@ -2354,8 +2405,7 @@ already_AddRefed DataChannelConnection::OpenFinish( RefPtr channel(aChannel); // takes the reference passed in // Normally 1 reference if called from ::Open(), or 2 if called from // ProcessQueuedOpens() unless the DOMDataChannel was gc'd - uint16_t stream = channel->mStream; - bool queue = false; + const uint16_t stream = channel->mStream; mLock.AssertCurrentThreadOwns(); @@ -2382,61 +2432,20 @@ already_AddRefed DataChannelConnection::OpenFinish( // So the Open cases are basically the same // Not Open cases are simply queue for non-negotiated, and // either change the initial ask or possibly renegotiate after open. - - if (mState == OPEN) { - if (stream == INVALID_STREAM) { - stream = FindFreeStream(); // may be INVALID_STREAM if we need more - } - if (stream == INVALID_STREAM || stream >= mStreams.Length()) { + const auto readyState = GetReadyState(); + if (readyState != OPEN || stream >= mNegotiatedIdLimit) { + if (readyState == OPEN) { + MOZ_ASSERT(stream != INVALID_STREAM); // RequestMoreStreams() limits to MAX_NUM_STREAMS -- allocate extra // streams to avoid going back immediately for more if the ask to N, N+1, // etc - int32_t more_needed = (stream == INVALID_STREAM) - ? 16 - : (stream - ((int32_t)mStreams.Length())) + 16; + int32_t more_needed = stream - ((int32_t)mNegotiatedIdLimit) + 16; if (!RequestMoreStreams(more_needed)) { // Something bad happened... we're done goto request_error_cleanup; } - queue = true; - } - } else { - // not OPEN - if (stream != INVALID_STREAM && stream >= mStreams.Length() && - mState == CLOSED) { - // Update number of streams for init message - struct sctp_initmsg initmsg; - socklen_t len = sizeof(initmsg); - int32_t total_needed = stream + 16; - - memset(&initmsg, 0, sizeof(initmsg)); - if (usrsctp_getsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_INITMSG, - &initmsg, &len) < 0) { - LOG(("*** failed getsockopt SCTP_INITMSG")); - goto request_error_cleanup; - } - LOG(("Setting number of SCTP streams to %u, was %u/%u", total_needed, - initmsg.sinit_num_ostreams, initmsg.sinit_max_instreams)); - initmsg.sinit_num_ostreams = total_needed; - initmsg.sinit_max_instreams = MAX_NUM_STREAMS; - if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_INITMSG, - &initmsg, (socklen_t)sizeof(initmsg)) < 0) { - LOG(("*** failed setsockopt SCTP_INITMSG, errno %d", errno)); - goto request_error_cleanup; - } - - int32_t old_len = mStreams.Length(); - mStreams.AppendElements(total_needed - old_len); - for (int32_t i = old_len; i < total_needed; ++i) { - mStreams[i] = nullptr; - } } - // else if state is CONNECTING, we'll just re-negotiate when OpenFinish - // is called, if needed - queue = true; - } - if (queue) { - LOG(("Queuing channel %p (%u) to finish open", channel.get(), stream)); + DC_DEBUG(("Queuing channel %p (%u) to finish open", channel.get(), stream)); // Also serves to mark we told the app channel->mFlags |= DATA_CHANNEL_FLAGS_FINISH_OPEN; // we need a ref for the nsDeQue and one to return @@ -2447,30 +2456,26 @@ already_AddRefed DataChannelConnection::OpenFinish( } MOZ_ASSERT(stream != INVALID_STREAM); - // just allocated (& OPEN), or externally negotiated - mStreams[stream] = channel; // holds a reference - channel->mStream = stream; + MOZ_ASSERT(stream < mNegotiatedIdLimit); #ifdef TEST_QUEUED_DATA // It's painful to write a test for this... channel->AnnounceOpen(); - channel->mFlags |= DATA_CHANNEL_FLAGS_READY; SendDataMsgInternalOrBuffer(channel, "Help me!", 8, DATA_CHANNEL_PPID_DOMSTRING); #endif - if (channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED) { + if (!channel->mOrdered) { // Don't send unordered until this gets cleared channel->mFlags |= DATA_CHANNEL_FLAGS_WAITING_ACK; } - if (!(channel->mFlags & DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED)) { - int error = SendOpenRequestMessage( - channel->mLabel, channel->mProtocol, stream, - !!(channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED), - channel->mPrPolicy, channel->mPrValue); + if (!channel->mNegotiated) { + int error = SendOpenRequestMessage(channel->mLabel, channel->mProtocol, + stream, !channel->mOrdered, + channel->mPrPolicy, channel->mPrValue); if (error) { - LOG(("SendOpenRequest failed, error = %d", error)); + DC_ERROR(("SendOpenRequest failed, error = %d", error)); if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) { // We already returned the channel to the app. NS_ERROR("Failed to send open request"); @@ -2478,8 +2483,7 @@ already_AddRefed DataChannelConnection::OpenFinish( } // If we haven't returned the channel yet, it will get destroyed when we // exit this function. - mStreams[stream] = nullptr; - channel->mStream = INVALID_STREAM; + mChannels.Remove(channel); // we'll be destroying the channel return nullptr; /* NOTREACHED */ @@ -2487,7 +2491,6 @@ already_AddRefed DataChannelConnection::OpenFinish( } // Either externally negotiated or we sent Open - channel->mFlags |= DATA_CHANNEL_FLAGS_READY; // FIX? Move into DOMDataChannel? I don't think we can send it yet here channel->AnnounceOpen(); @@ -2551,13 +2554,13 @@ int DataChannelConnection::SendMsgInternal(OutgoingMsg& msg, size_t* aWritten) { if (aWritten) { *aWritten += written; } - LOG(("Sent buffer (written=%zu, len=%zu, left=%zu)", (size_t)written, - length, left - (size_t)written)); + DC_DEBUG(("Sent buffer (written=%zu, len=%zu, left=%zu)", (size_t)written, + length, left - (size_t)written)); // TODO: Remove once resolved // (https://github.com/sctplab/usrsctp/issues/132) if (written == 0) { - LOG(("@tuexen: usrsctp_sendv returned 0")); + DC_ERROR(("@tuexen: usrsctp_sendv returned 0")); error = EAGAIN; goto out; } @@ -2593,7 +2596,7 @@ int DataChannelConnection::SendMsgInternal(OutgoingMsg& msg, size_t* aWritten) { // Returns a POSIX error code directly instead of setting errno. // IMPORTANT: Ensure that the buffer passed is guarded by mLock! int DataChannelConnection::SendMsgInternalOrBuffer( - nsTArray>& buffer, OutgoingMsg& msg, + nsTArray>& buffer, OutgoingMsg& msg, bool& buffered, size_t* aWritten) { NS_WARNING_ASSERTION(msg.GetLength() > 0, "Length is 0?!"); @@ -2629,7 +2632,7 @@ int DataChannelConnection::SendMsgInternalOrBuffer( need_buffering = true; break; default: - LOG(("error %d on sending", error)); + DC_ERROR(("error %d on sending", error)); break; } } else { @@ -2641,8 +2644,8 @@ int DataChannelConnection::SendMsgInternalOrBuffer( // it is... auto* bufferedMsg = new BufferedOutgoingMsg(msg); // infallible malloc buffer.AppendElement(bufferedMsg); // owned by mBufferedData array - LOG(("Queued %zu buffers (left=%zu, total=%zu)", buffer.Length(), - msg.GetLeft(), msg.GetLength())); + DC_DEBUG(("Queued %zu buffers (left=%zu, total=%zu)", buffer.Length(), + msg.GetLeft(), msg.GetLength())); buffered = true; return 0; } @@ -2657,7 +2660,7 @@ int DataChannelConnection::SendDataMsgInternalOrBuffer(DataChannel& channel, const uint8_t* data, size_t len, uint32_t ppid) { - if (NS_WARN_IF(channel.mReadyState != OPEN)) { + if (NS_WARN_IF(channel.GetReadyState() != OPEN)) { return EINVAL; // TODO: Find a better error code } @@ -2671,12 +2674,12 @@ int DataChannelConnection::SendDataMsgInternalOrBuffer(DataChannel& channel, info.sendv_sndinfo.snd_flags = SCTP_EOR; info.sendv_sndinfo.snd_ppid = htonl(ppid); + MutexAutoLock lock(mLock); // Need to protect mFlags... :( // Unordered? // To avoid problems where an in-order OPEN is lost and an // out-of-order data message "beats" it, require data to be in-order // until we get an ACK. - if ((channel.mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED) && - !(channel.mFlags & DATA_CHANNEL_FLAGS_WAITING_ACK)) { + if (!channel.mOrdered && !(channel.mFlags & DATA_CHANNEL_FLAGS_WAITING_ACK)) { info.sendv_sndinfo.snd_flags |= SCTP_UNORDERED; } @@ -2689,7 +2692,6 @@ int DataChannelConnection::SendDataMsgInternalOrBuffer(DataChannel& channel, // Create message instance and send OutgoingMsg msg(info, data, len); - MutexAutoLock lock(mLock); bool buffered; size_t written = 0; mDeferSend = true; @@ -2724,8 +2726,8 @@ int DataChannelConnection::SendDataMsg(DataChannel& channel, // SendDataMsgInternalOrBuffer avoids blocking. if (mMaxMessageSize != 0 && len > mMaxMessageSize) { - LOG(("Message rejected, too large (%zu > %" PRIu64 ")", len, - mMaxMessageSize)); + DC_ERROR(("Message rejected, too large (%zu > %" PRIu64 ")", len, + mMaxMessageSize)); return EMSGSIZE; } @@ -2764,7 +2766,7 @@ class ReadBlobRunnable : public Runnable { // Returns a POSIX error code. int DataChannelConnection::SendBlob(uint16_t stream, nsIInputStream* aBlob) { - DataChannel* channel = mStreams[stream]; + RefPtr channel = mChannels.Get(stream); if (NS_WARN_IF(!channel)) { return EINVAL; // TODO: Find a better error code } @@ -2817,6 +2819,35 @@ class DataChannelBlobSendRunnable : public Runnable { uint16_t mStream; }; +static auto readyStateToCStr(const uint16_t state) -> const char* { + switch (state) { + case DataChannelConnection::CONNECTING: + return "CONNECTING"; + case DataChannelConnection::OPEN: + return "OPEN"; + case DataChannelConnection::CLOSING: + return "CLOSING"; + case DataChannelConnection::CLOSED: + return "CLOSED"; + default: { + MOZ_ASSERT(false); + return "UNKNOWW"; + } + } +}; + +void DataChannelConnection::SetReadyState(const uint16_t aState) { + mLock.AssertCurrentThreadOwns(); + + DC_DEBUG( + ("DataChannelConnection labeled %s (%p) switching connection state %s -> " + "%s", + mTransportId.c_str(), this, readyStateToCStr(mState), + readyStateToCStr(aState))); + + mState = aState; +} + void DataChannelConnection::ReadBlob( already_AddRefed aThis, uint16_t aStream, nsIInputStream* aBlob) { @@ -2850,15 +2881,6 @@ void DataChannelConnection::ReadBlob( Dispatch(runnable.forget()); } -void DataChannelConnection::GetStreamIds(std::vector* aStreamList) { - ASSERT_WEBRTC(NS_IsMainThread()); - for (uint32_t i = 0; i < mStreams.Length(); ++i) { - if (mStreams[i]) { - aStreamList->push_back(mStreams[i]->mStream); - } - } -} - // Returns a POSIX error code. int DataChannelConnection::SendDataMsgCommon(uint16_t stream, const nsACString& aMsg, @@ -2866,7 +2888,7 @@ int DataChannelConnection::SendDataMsgCommon(uint16_t stream, ASSERT_WEBRTC(NS_IsMainThread()); // We really could allow this from other threads, so long as we deal with // asynchronosity issues with channels closing, in particular access to - // mStreams, and issues with the association closing (access to mSocket). + // mChannels, and issues with the association closing (access to mSocket). const uint8_t* data = (const uint8_t*)aMsg.BeginReading(); uint32_t len = aMsg.Length(); @@ -2875,12 +2897,11 @@ int DataChannelConnection::SendDataMsgCommon(uint16_t stream, return EMSGSIZE; } #endif - DataChannel* channelPtr; - LOG(("Sending %sto stream %u: %u bytes", isBinary ? "binary " : "", stream, - len)); + DC_DEBUG(("Sending %sto stream %u: %u bytes", isBinary ? "binary " : "", + stream, len)); // XXX if we want more efficiency, translate flags once at open time - channelPtr = mStreams[stream]; + RefPtr channelPtr = mChannels.Get(stream); if (NS_WARN_IF(!channelPtr)) { return EINVAL; // TODO: Find a better error code } @@ -2913,31 +2934,35 @@ void DataChannelConnection::CloseInt(DataChannel* aChannel) { RefPtr channel(aChannel); // make sure it doesn't go away on us mLock.AssertCurrentThreadOwns(); - LOG(("Connection %p/Channel %p: Closing stream %u", - channel->mConnection.get(), channel.get(), channel->mStream)); + DC_DEBUG(("Connection %p/Channel %p: Closing stream %u", + channel->mConnection.get(), channel.get(), channel->mStream)); + + aChannel->mBufferedData.Clear(); + if (GetReadyState() == CLOSED) { + // If we're CLOSING, we might leave this in place until we can send a + // reset. + mChannels.Remove(channel); + } + + // This is supposed to only be accessed from Main thread, but this has + // been accessed here from the STS thread for a long time now. + // See Bug 1586475 + auto channelState = aChannel->mReadyState; // re-test since it may have closed before the lock was grabbed - if (aChannel->mReadyState == CLOSED || aChannel->mReadyState == CLOSING) { - LOG(("Channel already closing/closed (%u)", aChannel->mReadyState)); - if (mState == CLOSED && channel->mStream != INVALID_STREAM) { - // called from CloseAll() - // we're not going to hang around waiting any more - mStreams[channel->mStream] = nullptr; - } + if (channelState == CLOSED || channelState == CLOSING) { + DC_DEBUG(("Channel already closing/closed (%u)", channelState)); return; } - aChannel->mBufferedData.Clear(); + if (channel->mStream != INVALID_STREAM) { ResetOutgoingStream(channel->mStream); - if (mState == CLOSED) { // called from CloseAll() - // Let resets accumulate then send all at once in CloseAll() - // we're not going to hang around waiting - mStreams[channel->mStream] = nullptr; - } else { + if (GetReadyState() != CLOSED) { + // Individual channel is being closed, send reset now. SendOutgoingStreamReset(); } } - aChannel->mReadyState = CLOSING; - if (mState == CLOSED) { + aChannel->SetReadyState(CLOSING); + if (GetReadyState() == CLOSED) { // we're not going to hang around waiting channel->StreamClosedLocked(); } @@ -2946,41 +2971,101 @@ void DataChannelConnection::CloseInt(DataChannel* aChannel) { } void DataChannelConnection::CloseAll() { - LOG(("Closing all channels (connection %p)", (void*)this)); + DC_DEBUG(("Closing all channels (connection %p)", (void*)this)); // Don't need to lock here // Make sure no more channels will be opened { MutexAutoLock lock(mLock); - mState = CLOSED; + SetReadyState(CLOSED); } // Close current channels // If there are runnables, they hold a strong ref and keep the channel // and/or connection alive (even if in a CLOSED state) - bool closed_some = false; - for (uint32_t i = 0; i < mStreams.Length(); ++i) { - if (mStreams[i]) { - mStreams[i]->Close(); - closed_some = true; - } + for (auto& channel : mChannels.GetAll()) { + channel->Close(); } // Clean up any pending opens for channels RefPtr channel; while (nullptr != (channel = dont_AddRef( static_cast(mPending.PopFront())))) { - LOG(("closing pending channel %p, stream %u", channel.get(), - channel->mStream)); + DC_DEBUG(("closing pending channel %p, stream %u", channel.get(), + channel->mStream)); channel->Close(); // also releases the ref on each iteration - closed_some = true; } // It's more efficient to let the Resets queue in shutdown and then // SendOutgoingStreamReset() here. - if (closed_some) { - MutexAutoLock lock(mLock); - SendOutgoingStreamReset(); + MutexAutoLock lock(mLock); + SendOutgoingStreamReset(); +} + +bool DataChannelConnection::Channels::IdComparator::Equals( + const RefPtr& aChannel, uint16_t aId) const { + return aChannel->mStream == aId; +} + +bool DataChannelConnection::Channels::IdComparator::LessThan( + const RefPtr& aChannel, uint16_t aId) const { + return aChannel->mStream < aId; +} + +bool DataChannelConnection::Channels::IdComparator::Equals( + const RefPtr& a1, const RefPtr& a2) const { + return Equals(a1, a2->mStream); +} + +bool DataChannelConnection::Channels::IdComparator::LessThan( + const RefPtr& a1, const RefPtr& a2) const { + return LessThan(a1, a2->mStream); +} + +void DataChannelConnection::Channels::Insert( + const RefPtr& aChannel) { + DC_DEBUG(("Inserting channel %u : %p", aChannel->mStream, aChannel.get())); + MutexAutoLock lock(mMutex); + if (aChannel->mStream != INVALID_STREAM) { + MOZ_ASSERT(!mChannels.ContainsSorted(aChannel, IdComparator())); } + + MOZ_ASSERT(!mChannels.Contains(aChannel)); + + mChannels.InsertElementSorted(aChannel, IdComparator()); +} + +bool DataChannelConnection::Channels::Remove( + const RefPtr& aChannel) { + DC_DEBUG(("Removing channel %u : %p", aChannel->mStream, aChannel.get())); + MutexAutoLock lock(mMutex); + if (aChannel->mStream == INVALID_STREAM) { + return mChannels.RemoveElement(aChannel); + } + + return mChannels.RemoveElementSorted(aChannel, IdComparator()); +} + +RefPtr DataChannelConnection::Channels::Get(uint16_t aId) const { + MutexAutoLock lock(mMutex); + auto index = mChannels.BinaryIndexOf(aId, IdComparator()); + if (index == ChannelArray::NoIndex) { + return nullptr; + } + return mChannels[index]; +} + +RefPtr DataChannelConnection::Channels::GetNextChannel( + uint16_t aCurrentId) const { + MutexAutoLock lock(mMutex); + if (mChannels.IsEmpty()) { + return nullptr; + } + + auto index = mChannels.IndexOfFirstElementGt(aCurrentId, IdComparator()); + if (index == mChannels.Length()) { + index = 0; + } + return mChannels[index]; } DataChannel::~DataChannel() { @@ -3004,11 +3089,9 @@ void DataChannel::StreamClosedLocked() { mConnection->mLock.AssertCurrentThreadOwns(); ENSURE_DATACONNECTION; - LOG(("Destroying Data channel %u", mStream)); + DC_DEBUG(("Destroying Data channel %u", mStream)); MOZ_ASSERT_IF(mStream != INVALID_STREAM, !mConnection->FindChannelByStream(mStream)); - // Spec doesn't say to mess with the stream id... - mStream = INVALID_STREAM; AnnounceClosed(); // We leave mConnection live until the DOM releases us, to avoid races } @@ -3060,13 +3143,13 @@ void DataChannel::DecrementBufferedAmount(uint32_t aSize) { bool wasLow = mBufferedAmount <= mBufferedThreshold; mBufferedAmount -= aSize; if (!wasLow && mBufferedAmount <= mBufferedThreshold) { - LOG(("%s: sending BUFFER_LOW_THRESHOLD for %s/%s: %u", __FUNCTION__, - mLabel.get(), mProtocol.get(), mStream)); + DC_DEBUG(("%s: sending BUFFER_LOW_THRESHOLD for %s/%s: %u", + __FUNCTION__, mLabel.get(), mProtocol.get(), mStream)); mListener->OnBufferLow(mContext); } if (mBufferedAmount == 0) { - LOG(("%s: sending NO_LONGER_BUFFERED for %s/%s: %u", __FUNCTION__, - mLabel.get(), mProtocol.get(), mStream)); + DC_DEBUG(("%s: sending NO_LONGER_BUFFERED for %s/%s: %u", + __FUNCTION__, mLabel.get(), mProtocol.get(), mStream)); mListener->NotBuffered(mContext); } })); @@ -3075,12 +3158,13 @@ void DataChannel::DecrementBufferedAmount(uint32_t aSize) { void DataChannel::AnnounceOpen() { mMainThreadEventTarget->Dispatch(NS_NewRunnableFunction( "DataChannel::AnnounceOpen", [this, self = RefPtr(this)] { + auto state = GetReadyState(); // Special-case; spec says to put brand-new remote-created DataChannel // in "open", but queue the firing of the "open" event. - if (mReadyState != CLOSING && mReadyState != CLOSED && mListener) { - mReadyState = OPEN; - LOG(("%s: sending ON_CHANNEL_OPEN for %s/%s: %u", __FUNCTION__, - mLabel.get(), mProtocol.get(), mStream)); + if (state != CLOSING && state != CLOSED && mListener) { + SetReadyState(OPEN); + DC_DEBUG(("%s: sending ON_CHANNEL_OPEN for %s/%s: %u", __FUNCTION__, + mLabel.get(), mProtocol.get(), mStream)); mListener->OnChannelConnected(mContext); } })); @@ -3089,19 +3173,32 @@ void DataChannel::AnnounceOpen() { void DataChannel::AnnounceClosed() { mMainThreadEventTarget->Dispatch(NS_NewRunnableFunction( "DataChannel::AnnounceClosed", [this, self = RefPtr(this)] { - if (mReadyState == CLOSED) { + if (GetReadyState() == CLOSED) { return; } - mReadyState = CLOSED; + SetReadyState(CLOSED); mBufferedData.Clear(); if (mListener) { - LOG(("%s: sending ON_CHANNEL_CLOSED for %s/%s: %u", __FUNCTION__, - mLabel.get(), mProtocol.get(), mStream)); + DC_DEBUG(("%s: sending ON_CHANNEL_CLOSED for %s/%s: %u", __FUNCTION__, + mLabel.get(), mProtocol.get(), mStream)); mListener->OnChannelClosed(mContext); } })); } +// Set ready state +void DataChannel::SetReadyState(const uint16_t aState) { + MOZ_ASSERT(NS_IsMainThread()); + + DC_DEBUG( + ("DataChannelConnection labeled %s(%p) (stream %d) changing ready state " + "%s -> %s", + mLabel.get(), this, mStream, readyStateToCStr(mReadyState), + readyStateToCStr(aState))); + + mReadyState = aState; +} + void DataChannel::SendMsg(const nsACString& aMsg, ErrorResult& aRv) { if (!EnsureValidStream(aRv)) { return; diff --git a/netwerk/sctp/datachannel/DataChannel.h b/netwerk/sctp/datachannel/DataChannel.h index 0d63e88b4b..2dc43f3da2 100644 --- a/netwerk/sctp/datachannel/DataChannel.h +++ b/netwerk/sctp/datachannel/DataChannel.h @@ -15,6 +15,7 @@ #include #include "nsISupports.h" #include "nsCOMPtr.h" +#include "mozilla/UniquePtr.h" #include "mozilla/WeakPtr.h" #include "nsString.h" #include "nsThreadUtils.h" @@ -25,15 +26,13 @@ #include "DataChannelProtocol.h" #include "DataChannelListener.h" #include "mozilla/net/NeckoTargetHolder.h" +#include "DataChannelLog.h" + #ifdef SCTP_DTLS_SUPPORTED # include "mtransport/sigslot.h" # include "mtransport/transportlayer.h" // For TransportLayer::State #endif -#ifndef DATACHANNEL_LOG -# define DATACHANNEL_LOG(args) -#endif - #ifndef EALREADY # define EALREADY WSAEALREADY #endif @@ -157,12 +156,13 @@ class DataChannelConnection final : public net::NeckoTargetHolder #endif #ifdef SCTP_DTLS_SUPPORTED - bool ConnectToTransport(const std::string& aTransportId, bool aClient, - uint16_t localport, uint16_t remoteport); + bool ConnectToTransport(const std::string& aTransportId, const bool aClient, + const uint16_t aLocalPort, + const uint16_t aRemotePort); void TransportStateChange(const std::string& aTransportId, TransportLayer::State aState); void CompleteConnect(); - void SetSignals(const std::string& aTransportId, bool aClient); + void SetSignals(const std::string& aTransportId); #endif typedef enum { @@ -203,10 +203,6 @@ class DataChannelConnection final : public net::NeckoTargetHolder // Find out state enum { CONNECTING = 0U, OPEN = 1U, CLOSING = 2U, CLOSED = 3U }; - uint16_t GetReadyState() { - MutexAutoLock lock(mLock); - return mState; - } friend class DataChannel; Mutex mLock; @@ -214,8 +210,6 @@ class DataChannelConnection final : public net::NeckoTargetHolder void ReadBlob(already_AddRefed aThis, uint16_t aStream, nsIInputStream* aBlob); - void GetStreamIds(std::vector* aStreamList); - bool SendDeferredMessages(); #ifdef SCTP_DTLS_SUPPORTED @@ -239,6 +233,16 @@ class DataChannelConnection final : public net::NeckoTargetHolder bool Init(const uint16_t aLocalPort, const uint16_t aNumStreams, const Maybe& aMaxMessageSize); + // Caller must hold mLock + uint16_t GetReadyState() const { + mLock.AssertCurrentThreadOwns(); + + return mState; + } + + // Caller must hold mLock + void SetReadyState(const uint16_t aState); + #ifdef SCTP_DTLS_SUPPORTED static void DTLSConnectThread(void* data); void SendPacket(std::unique_ptr&& packet); @@ -256,10 +260,10 @@ class DataChannelConnection final : public net::NeckoTargetHolder const nsACString& protocol, uint16_t stream, bool unordered, uint16_t prPolicy, uint32_t prValue); - bool SendBufferedMessages(nsTArray>& buffer, + bool SendBufferedMessages(nsTArray>& buffer, size_t* aWritten); int SendMsgInternal(OutgoingMsg& msg, size_t* aWritten); - int SendMsgInternalOrBuffer(nsTArray>& buffer, + int SendMsgInternalOrBuffer(nsTArray>& buffer, OutgoingMsg& msg, bool& buffered, size_t* aWritten); int SendDataMsgInternalOrBuffer(DataChannel& channel, const uint8_t* data, @@ -312,25 +316,56 @@ class DataChannelConnection final : public net::NeckoTargetHolder } #endif + class Channels { + public: + Channels() : mMutex("DataChannelConnection::Channels::mMutex") {} + void Insert(const RefPtr& aChannel); + bool Remove(const RefPtr& aChannel); + RefPtr Get(uint16_t aId) const; + typedef AutoTArray, 16> ChannelArray; + ChannelArray GetAll() const { + MutexAutoLock lock(mMutex); + return mChannels; + } + RefPtr GetNextChannel(uint16_t aCurrentId) const; + + private: + struct IdComparator { + bool Equals(const RefPtr& aChannel, uint16_t aId) const; + bool LessThan(const RefPtr& aChannel, uint16_t aId) const; + bool Equals(const RefPtr& a1, + const RefPtr& a2) const; + bool LessThan(const RefPtr& a1, + const RefPtr& a2) const; + }; + mutable Mutex mMutex; + ChannelArray mChannels; + }; + bool mSendInterleaved = false; bool mMaxMessageSizeSet = false; uint64_t mMaxMessageSize = 0; - bool mAllocateEven = false; + // Main thread only + Maybe mAllocateEven; // Data: - // NOTE: while this array will auto-expand, increases in the number of + // NOTE: while this container will auto-expand, increases in the number of // channels available from the stack must be negotiated! - AutoTArray, 16> mStreams; + // Accessed from both main and sts, API is threadsafe + Channels mChannels; + // STS only uint32_t mCurrentStream = 0; nsDeque mPending; // Holds addref'ed DataChannel's -- careful! + // STS and main + size_t mNegotiatedIdLimit = 0; // GUARDED_BY(mConnection->mLock) uint8_t mPendingType = PENDING_NONE; // holds data that's come in before a channel is open - nsTArray> mQueuedData; + nsTArray> mQueuedData; // holds outgoing control messages - nsTArray> + nsTArray> mBufferedControl; // GUARDED_BY(mConnection->mLock) - // Streams pending reset - AutoTArray mStreamsResetting; + // Streams pending reset. Accessed from main and STS. + AutoTArray mStreamsResetting; // GUARDED_BY(mConnection->mLock) // accessed from STS thread struct socket* mMasterSocket = nullptr; // cloned from mMasterSocket on successful Connect on STS thread @@ -388,17 +423,10 @@ class DataChannel { mNegotiated(negotiated), mOrdered(ordered), mFlags(0), - mId(0), mIsRecvBinary(false), mBufferedThreshold(0), // default from spec mBufferedAmount(0), mMainThreadEventTarget(connection->GetNeckoTarget()) { - if (!ordered) { - mFlags |= DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED; - } - if (negotiated) { - mFlags |= DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED; - } NS_ASSERTION(mConnection, "NULL connection"); } @@ -464,11 +492,14 @@ class DataChannel { void AnnounceClosed(); // Find out state - uint16_t GetReadyState() { + uint16_t GetReadyState() const { MOZ_ASSERT(NS_IsMainThread()); return mReadyState; } + // Set ready state + void SetReadyState(const uint16_t aState); + void GetLabel(nsAString& aLabel) { CopyUTF8toUTF16(mLabel, aLabel); } void GetProtocol(nsAString& aProtocol) { CopyUTF8toUTF16(mProtocol, aProtocol); @@ -497,17 +528,17 @@ class DataChannel { uint16_t mStream; uint16_t mPrPolicy; uint32_t mPrValue; + // Accessed on main and STS const bool mNegotiated; const bool mOrdered; uint32_t mFlags; - uint32_t mId; bool mIsRecvBinary; size_t mBufferedThreshold; // Read/written on main only. Decremented via message-passing, because the // spec requires us to queue a task for this. size_t mBufferedAmount; nsCString mRecvBuffer; - nsTArray> + nsTArray> mBufferedData; // GUARDED_BY(mConnection->mLock) nsCOMPtr mMainThreadEventTarget; }; @@ -568,8 +599,8 @@ class DataChannelOnMessageAvailable : public Runnable { case ON_DATA_STRING: case ON_DATA_BINARY: if (!mChannel->mListener) { - DATACHANNEL_LOG(( - "DataChannelOnMessageAvailable (%d) with null Listener!", mType)); + DC_ERROR(("DataChannelOnMessageAvailable (%d) with null Listener!", + mType)); return NS_OK; } @@ -593,8 +624,8 @@ class DataChannelOnMessageAvailable : public Runnable { break; case ON_CHANNEL_CREATED: if (!mConnection->mListener) { - DATACHANNEL_LOG(( - "DataChannelOnMessageAvailable (%d) with null Listener!", mType)); + DC_ERROR(("DataChannelOnMessageAvailable (%d) with null Listener!", + mType)); return NS_OK; } diff --git a/netwerk/sctp/datachannel/DataChannelLog.h b/netwerk/sctp/datachannel/DataChannelLog.h index dbc9169b7a..343a53d261 100644 --- a/netwerk/sctp/datachannel/DataChannelLog.h +++ b/netwerk/sctp/datachannel/DataChannelLog.h @@ -12,8 +12,19 @@ namespace mozilla { extern mozilla::LazyLogModule gDataChannelLog; } -#undef LOG -#define LOG(args) \ +#define DC_ERROR(args) \ + MOZ_LOG(mozilla::gDataChannelLog, mozilla::LogLevel::Error, args) + +#define DC_WARN(args) \ + MOZ_LOG(mozilla::gDataChannelLog, mozilla::LogLevel::Warning, args) + +#define DC_INFO(args) \ + MOZ_LOG(mozilla::gDataChannelLog, mozilla::LogLevel::Info, args) + +#define DC_DEBUG(args) \ MOZ_LOG(mozilla::gDataChannelLog, mozilla::LogLevel::Debug, args) +#define DC_VERBOSE(args) \ + MOZ_LOG(mozilla::gDataChannelLog, mozilla::LogLevel::Verbose, args) + #endif diff --git a/netwerk/sctp/datachannel/DataChannelProtocol.h b/netwerk/sctp/datachannel/DataChannelProtocol.h index 244ed3da81..3a6ca98e0b 100644 --- a/netwerk/sctp/datachannel/DataChannelProtocol.h +++ b/netwerk/sctp/datachannel/DataChannelProtocol.h @@ -34,10 +34,7 @@ #define DATA_CHANNEL_MAX_BINARY_FRAGMENT 0x4000 -#define DATA_CHANNEL_FLAGS_READY 0x00000001 -#define DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED 0x00000002 #define DATA_CHANNEL_FLAGS_FINISH_OPEN 0x00000004 -#define DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED 0x00000008 #define DATA_CHANNEL_FLAGS_WAITING_ACK 0x00000010 #define DATA_CHANNEL_FLAGS_CLOSING_TOO_LARGE 0x00000020 diff --git a/netwerk/sctp/datachannel/moz.build b/netwerk/sctp/datachannel/moz.build index b6bcac49af..f599641e15 100644 --- a/netwerk/sctp/datachannel/moz.build +++ b/netwerk/sctp/datachannel/moz.build @@ -5,6 +5,7 @@ EXPORTS.mozilla.net += [ 'DataChannel.h', 'DataChannelListener.h', + 'DataChannelLog.h', 'DataChannelProtocol.h' ] diff --git a/netwerk/socket/nsISSLSocketControl.idl b/netwerk/socket/nsISSLSocketControl.idl index 9888e04834..67f456837f 100644 --- a/netwerk/socket/nsISSLSocketControl.idl +++ b/netwerk/socket/nsISSLSocketControl.idl @@ -167,14 +167,13 @@ interface nsISSLSocketControl : nsISupports { attribute ACString esniTxt; /** - * If the server certificate is present, serverCertIsBuiltInRoot is true if - * the root certificate for the server certificate is built in. + * True iff the connection was resumed using the resumption token. */ - readonly attribute boolean serverRootCertIsBuiltInRoot; + readonly attribute boolean resumed; /** - * True iff the connection was resumed using the resumption token. + * The id used to uniquely identify the connection to the peer. */ - readonly attribute boolean resumed; + readonly attribute ACString peerId; }; diff --git a/netwerk/socket/nsITransportSecurityInfo.idl b/netwerk/socket/nsITransportSecurityInfo.idl index 1b92f2edba..a0aa239ab8 100644 --- a/netwerk/socket/nsITransportSecurityInfo.idl +++ b/netwerk/socket/nsITransportSecurityInfo.idl @@ -5,7 +5,6 @@ #include "nsISupports.idl" interface nsIX509Cert; -interface nsIX509CertList; %{ C++ namespace IPC { @@ -32,12 +31,12 @@ interface nsITransportSecurityInfo : nsISupports { /** * If certificate verification failed, this will be the peer certificate * chain provided in the handshake, so it can be used for error reporting. - * If verification succeeded, this will be null. + * If verification succeeded, this will be empty. */ - readonly attribute nsIX509CertList failedCertChain; + readonly attribute Array failedCertChain; readonly attribute nsIX509Cert serverCert; - readonly attribute nsIX509CertList succeededCertChain; + readonly attribute Array succeededCertChain; [must_use] readonly attribute ACString cipherName; diff --git a/netwerk/socket/nsNamedPipeIOLayer.cpp b/netwerk/socket/nsNamedPipeIOLayer.cpp index 5de8ee4718..9f37bd5353 100644 --- a/netwerk/socket/nsNamedPipeIOLayer.cpp +++ b/netwerk/socket/nsNamedPipeIOLayer.cpp @@ -2,24 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsNamedPipeIOLayer.h" + #include #include + #include "mozilla/Atomics.h" #include "mozilla/DebugOnly.h" #include "mozilla/Logging.h" -#include "mozilla/Move.h" -#include "mozilla/net/DNS.h" #include "mozilla/RefPtr.h" #include "mozilla/Unused.h" -#include "nsNamedPipeService.h" +#include "mozilla/net/DNS.h" #include "nsISupportsImpl.h" -#include "nsNamedPipeIOLayer.h" +#include "nsNamedPipeService.h" #include "nsNetCID.h" -#include "nspr.h" #include "nsServiceManagerUtils.h" #include "nsSocketTransportService2.h" #include "nsString.h" #include "nsThreadUtils.h" +#include "nspr.h" #include "private/pprio.h" namespace mozilla { diff --git a/netwerk/socket/nsNamedPipeIOLayer.h b/netwerk/socket/nsNamedPipeIOLayer.h index 9727173f16..c7908c335b 100644 --- a/netwerk/socket/nsNamedPipeIOLayer.h +++ b/netwerk/socket/nsNamedPipeIOLayer.h @@ -6,6 +6,7 @@ #define mozilla_netwerk_socket_nsNamedPipeIOLayer_h #include "nscore.h" +#include "nsStringFwd.h" #include "prio.h" namespace mozilla { diff --git a/netwerk/streamconv/converters/ParseFTPList.cpp b/netwerk/streamconv/converters/ParseFTPList.cpp index 728c0445dc..1d70e0d844 100644 --- a/netwerk/streamconv/converters/ParseFTPList.cpp +++ b/netwerk/streamconv/converters/ParseFTPList.cpp @@ -687,8 +687,9 @@ int ParseFTPList(const char* line, struct list_state* state, } result->fe_type = 'f'; pos = toklen[2]; - while (pos > (sizeof(result->fe_size) - 1)) + if (pos > (sizeof(result->fe_size) - 1)) { pos = (sizeof(result->fe_size) - 1); + } memcpy(result->fe_size, tokens[2], pos); result->fe_size[pos] = '\0'; } else { diff --git a/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp b/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp index 8fb4051cdb..cf3928c1cb 100644 --- a/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp +++ b/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp @@ -1244,10 +1244,8 @@ nsresult MOZ_NewTXTToHTMLConv(mozTXTToHTMLConv** aConv) { MOZ_ASSERT(aConv != nullptr, "null ptr"); if (!aConv) return NS_ERROR_NULL_POINTER; - *aConv = new mozTXTToHTMLConv(); - if (!*aConv) return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(*aConv); + RefPtr conv = new mozTXTToHTMLConv(); + conv.forget(aConv); // return (*aConv)->Init(); return NS_OK; } diff --git a/netwerk/streamconv/converters/nsDirIndexParser.cpp b/netwerk/streamconv/converters/nsDirIndexParser.cpp index 746785d8b4..7315b9ed93 100644 --- a/netwerk/streamconv/converters/nsDirIndexParser.cpp +++ b/netwerk/streamconv/converters/nsDirIndexParser.cpp @@ -110,7 +110,7 @@ nsDirIndexParser::Field nsDirIndexParser::gFieldTable[] = { nsrefcnt nsDirIndexParser::gRefCntParser = 0; nsITextToSubURI* nsDirIndexParser::gTextToSubURI; -nsresult nsDirIndexParser::ParseFormat(const char* aFormatStr) { +void nsDirIndexParser::ParseFormat(const char* aFormatStr) { // Parse a "200" format line, and remember the fields and their // ordering in mFormat. Multiple 200 lines stomp on each other. unsigned int formatNum = 0; @@ -145,28 +145,25 @@ nsresult nsDirIndexParser::ParseFormat(const char* aFormatStr) { } } while (*aFormatStr && (formatNum < (ArrayLength(mFormat) - 1))); - - return NS_OK; } -nsresult nsDirIndexParser::ParseData(nsIDirIndex* aIdx, char* aDataStr, - int32_t aLineLen) { +void nsDirIndexParser::ParseData(nsIDirIndex* aIdx, char* aDataStr, + int32_t aLineLen) { // Parse a "201" data line, using the field ordering specified in // mFormat. if (mFormat[0] == -1) { // Ignore if we haven't seen a format yet. - return NS_OK; + return; } - nsresult rv = NS_OK; nsAutoCString filename; int32_t lineLen = aLineLen; for (int32_t i = 0; mFormat[i] != -1; ++i) { // If we've exhausted the data before we run out of fields, just bail. if (!*aDataStr || (lineLen < 1)) { - return NS_OK; + return; } while ((lineLen > 0) && nsCRT::IsAsciiSpace(*aDataStr)) { @@ -176,7 +173,7 @@ nsresult nsDirIndexParser::ParseData(nsIDirIndex* aIdx, char* aDataStr, if (lineLen < 1) { // invalid format, bail - return NS_OK; + return; } char* value = aDataStr; @@ -196,7 +193,7 @@ nsresult nsDirIndexParser::ParseData(nsIDirIndex* aIdx, char* aDataStr, if (!lineLen) { // invalid format, bail - return NS_OK; + return; } } else { // it's unquoted. snarf until we see whitespace. @@ -225,8 +222,8 @@ nsresult nsDirIndexParser::ParseData(nsIDirIndex* aIdx, char* aDataStr, if (gTextToSubURI) { nsAutoString result; - if (NS_SUCCEEDED(rv = gTextToSubURI->UnEscapeAndConvert( - mEncoding, filename, result))) { + if (NS_SUCCEEDED(gTextToSubURI->UnEscapeAndConvert( + mEncoding, filename, result))) { if (!result.IsEmpty()) { aIdx->SetLocation(filename); if (!mHasDescription) aIdx->SetDescription(result); @@ -288,8 +285,6 @@ nsresult nsDirIndexParser::ParseData(nsIDirIndex* aIdx, char* aDataStr, break; } } - - return NS_OK; } NS_IMETHODIMP @@ -336,7 +331,6 @@ nsresult nsDirIndexParser::ProcessData(nsIRequest* aRequest, mLineStart = eol + 1; if (lineLen >= 4) { - nsresult rv; const char* buf = line; if (buf[0] == '1') { @@ -361,19 +355,12 @@ nsresult nsDirIndexParser::ProcessData(nsIRequest* aRequest, if (buf[1] == '0') { if (buf[2] == '0' && buf[3] == ':') { // 200. Define field names - rv = ParseFormat(buf + 4); - if (NS_FAILED(rv)) { - return rv; - } + ParseFormat(buf + 4); } else if (buf[2] == '1' && buf[3] == ':') { // 201. Field data nsCOMPtr idx = new nsDirIndex(); - rv = ParseData(idx, ((char*)buf) + 4, lineLen - 4); - if (NS_FAILED(rv)) { - return rv; - } - + ParseData(idx, ((char*)buf) + 4, lineLen - 4); mListener->OnIndexAvailable(aRequest, aCtxt, idx); } } diff --git a/netwerk/streamconv/converters/nsDirIndexParser.h b/netwerk/streamconv/converters/nsDirIndexParser.h index 4f4f3a7684..95e3bb929b 100644 --- a/netwerk/streamconv/converters/nsDirIndexParser.h +++ b/netwerk/streamconv/converters/nsDirIndexParser.h @@ -57,8 +57,8 @@ class nsDirIndexParser : public nsIDirIndexParser { int mFormat[8]; nsresult ProcessData(nsIRequest* aRequest, nsISupports* aCtxt); - nsresult ParseFormat(const char* buf); - nsresult ParseData(nsIDirIndex* aIdx, char* aDataStr, int32_t lineLen); + void ParseFormat(const char* buf); + void ParseData(nsIDirIndex* aIdx, char* aDataStr, int32_t lineLen); struct Field { const char* mName; diff --git a/netwerk/streamconv/converters/nsFTPDirListingConv.cpp b/netwerk/streamconv/converters/nsFTPDirListingConv.cpp index df39bdb777..bb39277f5e 100644 --- a/netwerk/streamconv/converters/nsFTPDirListingConv.cpp +++ b/netwerk/streamconv/converters/nsFTPDirListingConv.cpp @@ -328,9 +328,7 @@ nsresult NS_NewFTPDirListingConv(nsFTPDirListingConv** aFTPDirListingConv) { MOZ_ASSERT(aFTPDirListingConv != nullptr, "null ptr"); if (!aFTPDirListingConv) return NS_ERROR_NULL_POINTER; - *aFTPDirListingConv = new nsFTPDirListingConv(); - if (!*aFTPDirListingConv) return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(*aFTPDirListingConv); + RefPtr conv = new nsFTPDirListingConv(); + conv.forget(aFTPDirListingConv); return NS_OK; } diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp index 5e2a916aab..acf85b2d5f 100644 --- a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp +++ b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp @@ -465,7 +465,7 @@ nsHTTPCompressConv::OnDataAvailable(nsIRequest* request, nsIInputStream* iStr, case HTTP_COMPRESS_BROTLI: { if (!mBrotli) { - mBrotli = new BrotliWrapper(); + mBrotli = MakeUnique(); } mBrotli->mRequest = request; diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.h b/netwerk/streamconv/converters/nsHTTPCompressConv.h index a92eb2cb2b..c35b279e9c 100644 --- a/netwerk/streamconv/converters/nsHTTPCompressConv.h +++ b/netwerk/streamconv/converters/nsHTTPCompressConv.h @@ -9,7 +9,6 @@ # include "nsICompressConvStats.h" # include "nsIThreadRetargetableStreamListener.h" # include "nsCOMPtr.h" -# include "nsAutoPtr.h" # include "mozilla/Atomics.h" # include "mozilla/Mutex.h" @@ -102,7 +101,7 @@ class nsHTTPCompressConv : public nsIStreamConverter, uint32_t mOutBufferLen; uint32_t mInpBufferLen; - nsAutoPtr mBrotli; + UniquePtr mBrotli; nsCOMPtr mStream; diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.cpp b/netwerk/streamconv/converters/nsMultiMixedConv.cpp index aa735182c1..dd7bf036a6 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp +++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp @@ -70,7 +70,7 @@ void nsPartChannel::SetContentDisposition( nsCOMPtr uri; GetURI(getter_AddRefs(uri)); NS_GetFilenameFromDisposition(mContentDispositionFilename, - mContentDispositionHeader, uri); + mContentDispositionHeader); mContentDisposition = NS_GetContentDispositionFromHeader(mContentDispositionHeader, this); } @@ -1008,10 +1008,8 @@ nsresult nsMultiMixedConv::ProcessHeader() { nsresult NS_NewMultiMixedConv(nsMultiMixedConv** aMultiMixedConv) { MOZ_ASSERT(aMultiMixedConv != nullptr, "null ptr"); - if (!aMultiMixedConv) return NS_ERROR_NULL_POINTER; - *aMultiMixedConv = new nsMultiMixedConv(); - - NS_ADDREF(*aMultiMixedConv); + RefPtr conv = new nsMultiMixedConv(); + conv.forget(aMultiMixedConv); return NS_OK; } diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.h b/netwerk/streamconv/converters/nsMultiMixedConv.h index 92387d4501..5e4a8c3745 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.h +++ b/netwerk/streamconv/converters/nsMultiMixedConv.h @@ -10,7 +10,6 @@ #include "nsCOMPtr.h" #include "nsIByteRangeRequest.h" #include "nsIMultiPartChannel.h" -#include "nsAutoPtr.h" #include "mozilla/Attributes.h" #include "mozilla/IncrementalTokenizer.h" #include "nsHttpResponseHead.h" @@ -45,8 +44,9 @@ class nsPartChannel final : public nsIChannel, /* SetContentDisposition expects the full value of the Content-Disposition * header */ void SetContentDisposition(const nsACString& aContentDispositionHeader); + // TODO(ER): This appears to be dead code void SetResponseHead(mozilla::net::nsHttpResponseHead* head) { - mResponseHead = head; + mResponseHead.reset(head); } NS_DECL_ISUPPORTS @@ -61,7 +61,7 @@ class nsPartChannel final : public nsIChannel, protected: nsCOMPtr mMultipartChannel; nsCOMPtr mListener; - nsAutoPtr mResponseHead; + UniquePtr mResponseHead; nsresult mStatus; nsLoadFlags mLoadFlags; diff --git a/netwerk/streamconv/nsStreamConverterService.cpp b/netwerk/streamconv/nsStreamConverterService.cpp index 93f0fee6c1..3904006590 100644 --- a/netwerk/streamconv/nsStreamConverterService.cpp +++ b/netwerk/streamconv/nsStreamConverterService.cpp @@ -5,7 +5,6 @@ #include "nsComponentManagerUtils.h" #include "nsStreamConverterService.h" #include "nsIComponentRegistrar.h" -#include "nsAutoPtr.h" #include "nsString.h" #include "nsAtom.h" #include "nsDeque.h" @@ -18,6 +17,7 @@ #include "nsTArray.h" #include "nsServiceManagerUtils.h" #include "nsISimpleEnumerator.h" +#include "mozilla/UniquePtr.h" /////////////////////////////////////////////////////////////////// // Breadth-First-Search (BFS) algorithm state classes and types. @@ -30,7 +30,7 @@ struct BFSTableData { nsCString key; BFScolors color; int32_t distance; - nsAutoPtr predecessor; + mozilla::UniquePtr predecessor; explicit BFSTableData(const nsACString& aKey) : key(aKey), color(white), distance(-1) {} @@ -250,7 +250,8 @@ nsresult nsStreamConverterService::FindConverter( if (white == curVertexState->color) { curVertexState->color = gray; curVertexState->distance = headVertexState->distance + 1; - curVertexState->predecessor = new nsCString(*currentHead); + curVertexState->predecessor = + mozilla::MakeUnique(*currentHead); grayQ.Push(curVertex); } else { delete curVertex; // if this vertex has already been discovered, we @@ -522,8 +523,8 @@ nsresult NS_NewStreamConv(nsStreamConverterService** aStreamConv) { MOZ_ASSERT(aStreamConv != nullptr, "null ptr"); if (!aStreamConv) return NS_ERROR_NULL_POINTER; - *aStreamConv = new nsStreamConverterService(); - NS_ADDREF(*aStreamConv); + RefPtr conv = new nsStreamConverterService(); + conv.forget(aStreamConv); return NS_OK; } diff --git a/netwerk/system/win32/nsNotifyAddrListener.cpp b/netwerk/system/win32/nsNotifyAddrListener.cpp index 3d77c20a96..1c0fa58ae1 100644 --- a/netwerk/system/win32/nsNotifyAddrListener.cpp +++ b/netwerk/system/win32/nsNotifyAddrListener.cpp @@ -27,7 +27,6 @@ #include "nsServiceManagerUtils.h" #include "nsNotifyAddrListener.h" #include "nsString.h" -#include "nsAutoPtr.h" #include "mozilla/Services.h" #include "nsCRT.h" #include "mozilla/Preferences.h" diff --git a/netwerk/test/TestCookie.cpp b/netwerk/test/TestCookie.cpp index 392ed51a5b..50bba651c0 100644 --- a/netwerk/test/TestCookie.cpp +++ b/netwerk/test/TestCookie.cpp @@ -13,7 +13,6 @@ #include "nsIChannel.h" #include "nsIPrincipal.h" #include "nsIScriptSecurityManager.h" -#include "nsISimpleEnumerator.h" #include "nsServiceManagerUtils.h" #include "nsNetCID.h" #include "nsIPrefBranch.h" @@ -70,7 +69,7 @@ void SetACookie(nsICookieService* aCookieService, const char* aSpec1, if (aSpec2) NS_NewURI(getter_AddRefs(uri2), aSpec2); nsresult rv = aCookieService->SetCookieStringFromHttp( - uri1, uri2, nullptr, nsDependentCString(aCookieString), + uri1, uri2, nsDependentCString(aCookieString), aServerTime ? nsDependentCString(aServerTime) : VoidCString(), nullptr); EXPECT_TRUE(NS_SUCCEEDED(rv)); } @@ -107,7 +106,7 @@ void SetASameSiteCookie(nsICookieService* aCookieService, const char* aSpec1, loadInfo->SetCookieSettings(cookieSettings); nsresult rv = aCookieService->SetCookieStringFromHttp( - uri1, uri2, nullptr, nsDependentCString(aCookieString), + uri1, uri2, nsDependentCString(aCookieString), aServerTime ? nsDependentCString(aServerTime) : VoidCString(), dummyChannel); EXPECT_TRUE(NS_SUCCEEDED(rv)); @@ -119,7 +118,7 @@ void SetACookieNoHttp(nsICookieService* aCookieService, const char* aSpec, NS_NewURI(getter_AddRefs(uri), aSpec); nsresult rv = aCookieService->SetCookieString( - uri, nullptr, nsDependentCString(aCookieString), nullptr); + uri, nsDependentCString(aCookieString), nullptr); EXPECT_TRUE(NS_SUCCEEDED(rv)); } @@ -342,7 +341,7 @@ TEST(TestCookie, TestCookieMain) SetACookie(cookieService, "http://path.net/path/file", nullptr, "test=path; path=/path/", nullptr); GetACookie(cookieService, "http://path.net/path", nullptr, cookie); - EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); GetACookie(cookieService, "http://path.net/path/", nullptr, cookie); EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); SetACookie(cookieService, "http://path.net/path/file", nullptr, @@ -358,7 +357,7 @@ TEST(TestCookie, TestCookieMain) GetACookie(cookieService, "http://path.net/path", nullptr, cookie); EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); GetACookie(cookieService, "http://path.net/foo", nullptr, cookie); - EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); SetACookie(cookieService, "http://path.net/path/file", nullptr, "test=path; path=/foo/; max-age=-1", nullptr); GetACookie(cookieService, "http://path.net/foo/", nullptr, cookie); @@ -880,28 +879,18 @@ TEST(TestCookie, TestCookieMain) &attrs, // originAttributes nsICookie::SAMESITE_UNSET))); // confirm using enumerator - nsCOMPtr enumerator; - EXPECT_TRUE( - NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator)))); - int32_t i = 0; - bool more; + nsTArray> cookies; + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies))); nsCOMPtr expiredCookie, newDomainCookie; - while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) { - nsCOMPtr cookie; - if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break; - ++i; - - // keep tabs on the second and third cookies, so we can check them later - nsCOMPtr cookie2(do_QueryInterface(cookie)); - if (!cookie2) break; + for (const auto& cookie : cookies) { nsAutoCString name; - cookie2->GetName(name); + cookie->GetName(name); if (name.EqualsLiteral("test2")) - expiredCookie = cookie2; + expiredCookie = cookie; else if (name.EqualsLiteral("test3")) - newDomainCookie = cookie2; + newDomainCookie = cookie; } - EXPECT_EQ(i, 3); + EXPECT_EQ(cookies.Length(), 3ul); // check the httpOnly attribute of the second cookie is honored GetACookie(cookieService, "http://cookiemgr.test/foo/", nullptr, cookie); EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test2=yes")); @@ -932,9 +921,9 @@ TEST(TestCookie, TestCookieMain) EXPECT_TRUE(found); // double-check RemoveAll() using the enumerator EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->RemoveAll())); - EXPECT_TRUE( - NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))) && - NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && !more); + cookies.SetLength(0); + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)) && + cookies.IsEmpty()); // *** eviction and creation ordering tests @@ -1001,18 +990,10 @@ TEST(TestCookie, TestCookieMain) SetASameSiteCookie(cookieService, "http://samesite.test", nullptr, "lax=yes; samesite=lax", nullptr, false); - EXPECT_TRUE( - NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator)))); - i = 0; - - // check the cookies for the required samesite value - while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) { - nsCOMPtr cookie; - if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break; - ++i; - } + cookies.SetLength(0); + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies))); - EXPECT_TRUE(i == 0); + EXPECT_TRUE(cookies.IsEmpty()); // Set cookies with various incantations of the samesite attribute: // No same site attribute present @@ -1034,23 +1015,15 @@ TEST(TestCookie, TestCookieMain) SetASameSiteCookie(cookieService, "http://samesite.test", nullptr, "lax=yes; samesite=lax", nullptr, true); - EXPECT_TRUE( - NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator)))); - i = 0; + cookies.SetLength(0); + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies))); // check the cookies for the required samesite value - while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) { - nsCOMPtr cookie; - if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break; - ++i; - - // keep tabs on the second and third cookies, so we can check them later - nsCOMPtr cookie2(do_QueryInterface(cookie)); - if (!cookie2) break; + for (const auto& cookie : cookies) { nsAutoCString name; - cookie2->GetName(name); + cookie->GetName(name); int32_t sameSiteAttr; - cookie2->GetSameSite(&sameSiteAttr); + cookie->GetSameSite(&sameSiteAttr); if (name.EqualsLiteral("unset")) { EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_UNSET); } else if (name.EqualsLiteral("unspecified")) { @@ -1066,7 +1039,7 @@ TEST(TestCookie, TestCookieMain) } } - EXPECT_TRUE(i == 6); + EXPECT_TRUE(cookies.Length() == 6); // *** SameSite attribute // Clear the cookies diff --git a/netwerk/test/httpserver/httpd.js b/netwerk/test/httpserver/httpd.js index 52dd3ffc37..9d26312be6 100644 --- a/netwerk/test/httpserver/httpd.js +++ b/netwerk/test/httpserver/httpd.js @@ -34,6 +34,7 @@ var EXPORTED_SYMBOLS = [ "HTTP_505", "HttpError", "HttpServer", + "NodeServer", ]; const CC = Components.Constructor; @@ -876,6 +877,98 @@ nsHttpServer.prototype = { var HttpServer = nsHttpServer; +class NodeServer { + // Executes command in the context of a node server. + // See handler in moz-http2.js + // + // Example use: + // let id = NodeServer.fork(); // id is a random string + // await NodeServer.execute(id, `"hello"`) + // > "hello" + // await NodeServer.execute(id, `(() => "hello")()`) + // > "hello" + // await NodeServer.execute(id, `(() => var_defined_on_server)()`) + // > "0" + // await NodeServer.execute(id, `var_defined_on_server`) + // > "0" + // function f(param) { if (param) return param; return "bla"; } + // await NodeServer.execute(id, f); // Defines the function on the server + // await NodeServer.execute(id, `f()`) // executes defined function + // > "bla" + // let result = await NodeServer.execute(id, `f("test")`); + // > "test" + // await NodeServer.kill(id); // shuts down the server + + // Forks a new node server using moz-http2-child.js as a starting point + static fork() { + return this.sendCommand("", "/fork"); + } + // Executes command in the context of the node server indicated by `id` + static execute(id, command) { + return this.sendCommand(command, `/execute/${id}`); + } + // Shuts down the server + static kill(id) { + return this.sendCommand("", `/kill/${id}`); + } + + // Issues a request to the node server (handler defined in moz-http2.js) + // This method should not be called directly. + static sendCommand(command, path) { + let env = Cc["@mozilla.org/process/environment;1"].getService( + Ci.nsIEnvironment + ); + let h2Port = env.get("MOZNODE_EXEC_PORT"); + if (!h2Port) { + throw new Error("Could not find MOZNODE_EXEC_PORT"); + } + + let req = new XMLHttpRequest(); + req.open("POST", `http://127.0.0.1:${h2Port}${path}`); + + // Passing a function to NodeServer.execute will define that function + // in node. It can be called in a later execute command. + let isFunction = function(obj) { + return !!(obj && obj.constructor && obj.call && obj.apply); + }; + let payload = command; + if (isFunction(command)) { + payload = `${command.name} = ${command.toString()};`; + } + + return new Promise((resolve, reject) => { + req.onload = () => { + let x = null; + + if (req.statusText != "OK") { + reject(`XHR request failed: ${req.statusText}`); + return; + } + + try { + x = JSON.parse(req.responseText); + } catch (e) { + reject(`Failed to parse ${req.responseText} - ${e}`); + return; + } + + if (x.error) { + let e = new Error(x.error, "", 0); + e.stack = x.errorStack; + reject(e); + return; + } + resolve(x.result); + }; + req.onerror = e => { + reject(e); + }; + + req.send(payload.toString()); + }); + } +} + // // RFC 2396 section 3.2.2: // diff --git a/netwerk/test/mochitests/file_chromecommon.js b/netwerk/test/mochitests/file_chromecommon.js index 2315b2d341..2ff87b63ce 100644 --- a/netwerk/test/mochitests/file_chromecommon.js +++ b/netwerk/test/mochitests/file_chromecommon.js @@ -2,7 +2,7 @@ let cs = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager); addMessageListener("getCookieCountAndClear", () => { let count = 0; - for (let cookie of cs.enumerator) { + for (let cookie of cs.cookies) { ++count; } cs.removeAll(); diff --git a/netwerk/test/mochitests/file_documentcookie_maxage_chromescript.js b/netwerk/test/mochitests/file_documentcookie_maxage_chromescript.js index b5e3785b40..72cdd5339a 100644 --- a/netwerk/test/mochitests/file_documentcookie_maxage_chromescript.js +++ b/netwerk/test/mochitests/file_documentcookie_maxage_chromescript.js @@ -4,7 +4,7 @@ function getCookieService() { function getCookies(cs) { let cookies = []; - for (let cookie of cs.enumerator) { + for (let cookie of cs.cookies) { cookies.push({ host: cookie.host, path: cookie.path, diff --git a/netwerk/test/mochitests/file_testloadflags_chromescript.js b/netwerk/test/mochitests/file_testloadflags_chromescript.js index 792035e3d8..523d4d1fd1 100644 --- a/netwerk/test/mochitests/file_testloadflags_chromescript.js +++ b/netwerk/test/mochitests/file_testloadflags_chromescript.js @@ -68,7 +68,7 @@ obs.prototype = { function getCookieCount(cs) { let count = 0; - for (let cookie of cs.enumerator) { + for (let cookie of cs.cookies) { info("cookie: " + cookie); info( "cookie host " + @@ -101,7 +101,7 @@ addMessageListener("init", ({ domain }) => { cs.removeAll(); cs.add( domain, - "", + "/", "oh", "hai", false, diff --git a/netwerk/test/mochitests/test_accept_header.html b/netwerk/test/mochitests/test_accept_header.html index 174c39805a..62e6eccc54 100644 --- a/netwerk/test/mochitests/test_accept_header.html +++ b/netwerk/test/mochitests/test_accept_header.html @@ -26,7 +26,7 @@ let ifr = document.createElement("iframe"); ifr.src = "test_accept_header.sjs?iframe"; ifr.onload = () => { - test_last_request_and_continue("iframe", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + test_last_request_and_continue("iframe", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"); }; document.body.appendChild(ifr); } diff --git a/netwerk/test/unit/head_cookies.js b/netwerk/test/unit/head_cookies.js index a00997d232..d309132f15 100644 --- a/netwerk/test/unit/head_cookies.js +++ b/netwerk/test/unit/head_cookies.js @@ -105,14 +105,7 @@ function do_load_profile(generator) { // Set a single session cookie using http and test the cookie count // against 'expected' function do_set_single_http_cookie(uri, channel, expected) { - Services.cookies.setCookieStringFromHttp( - uri, - null, - null, - "foo=bar", - null, - channel - ); + Services.cookies.setCookieStringFromHttp(uri, null, "foo=bar", null, channel); Assert.equal(Services.cookiemgr.countCookiesFromHost(uri.host), expected); } @@ -122,16 +115,15 @@ function do_set_cookies(uri, channel, session, expected) { let suffix = session ? "" : "; max-age=1000"; // without channel - Services.cookies.setCookieString(uri, null, "oh=hai" + suffix, null); + Services.cookies.setCookieString(uri, "oh=hai" + suffix, null); Assert.equal(Services.cookiemgr.countCookiesFromHost(uri.host), expected[0]); // with channel - Services.cookies.setCookieString(uri, null, "can=has" + suffix, channel); + Services.cookies.setCookieString(uri, "can=has" + suffix, channel); Assert.equal(Services.cookiemgr.countCookiesFromHost(uri.host), expected[1]); // without channel, from http Services.cookies.setCookieStringFromHttp( uri, null, - null, "cheez=burger" + suffix, null, null @@ -141,7 +133,6 @@ function do_set_cookies(uri, channel, session, expected) { Services.cookies.setCookieStringFromHttp( uri, null, - null, "hot=dog" + suffix, null, channel @@ -149,17 +140,8 @@ function do_set_cookies(uri, channel, session, expected) { Assert.equal(Services.cookiemgr.countCookiesFromHost(uri.host), expected[3]); } -function do_count_enumerator(enumerator) { - let i = 0; - for (let cookie of enumerator) { - void cookie; - ++i; - } - return i; -} - function do_count_cookies() { - return do_count_enumerator(Services.cookiemgr.enumerator); + return Services.cookiemgr.cookies.length; } // Helper object to store cookie data. diff --git a/netwerk/test/unit/test_altsvc.js b/netwerk/test/unit/test_altsvc.js index bb7116a4c4..5f77a47ae8 100644 --- a/netwerk/test/unit/test_altsvc.js +++ b/netwerk/test/unit/test_altsvc.js @@ -129,12 +129,7 @@ function h1ServerWK(metadata, response) { response.setHeader("Access-Control-Allow-Method", "GET", false); response.setHeader("Access-Control-Allow-Headers", "x-altsvc", false); - var body = - '{"http://foo.example.com:' + - h1Foo.identity.primaryPort + - '": { "tls-ports": [' + - h2Port + - "] }}"; + var body = '["http://foo.example.com:' + h1Foo.identity.primaryPort + '"]'; response.bodyOutputStream.write(body, body.length); } diff --git a/netwerk/test/unit/test_bug1177909.js b/netwerk/test/unit/test_bug1177909.js index 96b13679d0..223aaa623b 100644 --- a/netwerk/test/unit/test_bug1177909.js +++ b/netwerk/test/unit/test_bug1177909.js @@ -13,23 +13,21 @@ XPCOMUtils.defineLazyServiceGetter( XPCOMUtils.defineLazyGetter(this, "systemSettings", function() { return { - QueryInterface: function(iid) { - if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsISystemProxySettings)) { - return this; - } - throw Cr.NS_ERROR_NO_INTERFACE; - }, + QueryInterface: ChromeUtils.generateQI(["nsISystemProxySettings"]), mainThreadOnly: true, PACURI: null, - getProxyForURI: function(aSpec, aScheme, aHost, aPort) { + getProxyForURI(aSpec, aScheme, aHost, aPort) { if (aPort != -1) { return "SOCKS5 http://localhost:9050"; } - if (aScheme == "http" || aScheme == "https" || aScheme == "ftp") { + if (aScheme == "http" || aScheme == "ftp") { return "PROXY http://localhost:8080"; } + if (aScheme == "https") { + return "HTTPS https://localhost:8080"; + } return "DIRECT"; }, }; @@ -46,7 +44,7 @@ registerCleanupFunction(() => { function makeChannel(uri) { return NetUtil.newChannel({ - uri: uri, + uri, loadUsingSystemPrincipal: true, }); } @@ -84,7 +82,7 @@ add_task(async function testHttpsProxy() { let pi = await TestProxyTypeByURI("https://www.mozilla.org/"); equal(pi.host, "localhost", "Expected proxy host to be localhost"); equal(pi.port, 8080, "Expected proxy port to be 8080"); - equal(pi.type, "http", "Expected proxy type to be http"); + equal(pi.type, "https", "Expected proxy type to be https"); }); add_task(async function testFtpProxy() { @@ -142,6 +140,7 @@ add_task(async function testWebSocketProxy() { .finalize(); let proxyFlags = + Ci.nsIProtocolProxyService.RESOLVE_PREFER_SOCKS_PROXY | Ci.nsIProtocolProxyService.RESOLVE_PREFER_HTTPS_PROXY | Ci.nsIProtocolProxyService.RESOLVE_ALWAYS_TUNNEL; @@ -162,5 +161,32 @@ add_task(async function testWebSocketProxy() { let pi = await TestProxyType(chan, proxyFlags); equal(pi.host, "localhost", "Expected proxy host to be localhost"); equal(pi.port, 8080, "Expected proxy port to be 8080"); - equal(pi.type, "http", "Expected proxy type to be http"); + equal(pi.type, "https", "Expected proxy type to be https"); +}); + +add_task(async function testPreferHttpsProxy() { + let uri = Cc["@mozilla.org/network/standard-url-mutator;1"] + .createInstance(Ci.nsIURIMutator) + .setSpec("http://mozilla.org/") + .finalize(); + let proxyFlags = Ci.nsIProtocolProxyService.RESOLVE_PREFER_HTTPS_PROXY; + + let ioService = Cc["@mozilla.org/network/io-service;1"].getService( + Ci.nsIIOService + ); + let chan = ioService.newChannelFromURIWithProxyFlags( + uri, + null, + proxyFlags, + null, + Services.scriptSecurityManager.getSystemPrincipal(), + null, + Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, + Ci.nsIContentPolicy.TYPE_OTHER + ); + + let pi = await TestProxyType(chan, proxyFlags); + equal(pi.host, "localhost", "Expected proxy host to be localhost"); + equal(pi.port, 8080, "Expected proxy port to be 8080"); + equal(pi.type, "https", "Expected proxy type to be https"); }); diff --git a/netwerk/test/unit/test_bug248970_cache.js b/netwerk/test/unit/test_bug248970_cache.js index 5b8a269686..e8f2e13ef1 100644 --- a/netwerk/test/unit/test_bug248970_cache.js +++ b/netwerk/test/unit/test_bug248970_cache.js @@ -129,6 +129,9 @@ function run_test() { // Simulate a profile dir for xpcshell do_get_profile(); + Services.prefs.setBoolPref("browser.cache.offline.enable", true); + Services.prefs.setBoolPref("browser.cache.offline.storage.enable", true); + appCache = Cc["@mozilla.org/network/application-cache-service;1"] .getService(Ci.nsIApplicationCacheService) .getApplicationCache("fake-client-id|fake-group-id"); diff --git a/netwerk/test/unit/test_bug411952.js b/netwerk/test/unit/test_bug411952.js index fd8400f433..180b40b57a 100644 --- a/netwerk/test/unit/test_bug411952.js +++ b/netwerk/test/unit/test_bug411952.js @@ -19,7 +19,7 @@ function run_test() { const now = Math.floor(new Date().getTime() / 1000); var found = false; - for (let cookie of cm.enumerator) { + for (let cookie of cm.cookies) { if ( cookie.host == "example.com" && cookie.path == "/" && diff --git a/netwerk/test/unit/test_bug526789.js b/netwerk/test/unit/test_bug526789.js index aaf19d8d92..a7b594b517 100644 --- a/netwerk/test/unit/test_bug526789.js +++ b/netwerk/test/unit/test_bug526789.js @@ -136,7 +136,7 @@ function run_test() { var uri = NetUtil.newURI("http://baz.com/"); Assert.equal(uri.asciiHost, "baz.com"); - cs.setCookieString(uri, null, "foo=bar", null); + cs.setCookieString(uri, "foo=bar", null); Assert.equal(cs.getCookieString(uri, null), "foo=bar"); Assert.equal(cm.countCookiesFromHost(""), 0); @@ -147,8 +147,8 @@ function run_test() { cm.countCookiesFromHost(".."); }, Cr.NS_ERROR_ILLEGAL_VALUE); - var e = cm.getCookiesFromHost("", {}); - Assert.ok(!e.hasMoreElements()); + var cookies = cm.getCookiesFromHost("", {}); + Assert.ok(!cookies.length); do_check_throws(function() { cm.getCookiesFromHost(".", {}); }, Cr.NS_ERROR_ILLEGAL_VALUE); @@ -156,12 +156,11 @@ function run_test() { cm.getCookiesFromHost("..", {}); }, Cr.NS_ERROR_ILLEGAL_VALUE); - e = cm.getCookiesFromHost("baz.com", {}); - Assert.ok(e.hasMoreElements()); - Assert.equal(e.getNext().QueryInterface(Ci.nsICookie).name, "foo"); - Assert.ok(!e.hasMoreElements()); - e = cm.getCookiesFromHost("", {}); - Assert.ok(!e.hasMoreElements()); + cookies = cm.getCookiesFromHost("baz.com", {}); + Assert.equal(cookies.length, 1); + Assert.equal(cookies[0].name, "foo"); + cookies = cm.getCookiesFromHost("", {}); + Assert.ok(!cookies.length); do_check_throws(function() { cm.getCookiesFromHost(".", {}); }, Cr.NS_ERROR_ILLEGAL_VALUE); @@ -176,13 +175,13 @@ function run_test() { Assert.equal(emptyuri.asciiHost, ""); Assert.equal(NetUtil.newURI("file://./").asciiHost, ""); Assert.equal(NetUtil.newURI("file://foo.bar/").asciiHost, ""); - cs.setCookieString(emptyuri, null, "foo2=bar", null); + cs.setCookieString(emptyuri, "foo2=bar", null); Assert.equal(getCookieCount(), 1); - cs.setCookieString(emptyuri, null, "foo3=bar; domain=", null); + cs.setCookieString(emptyuri, "foo3=bar; domain=", null); Assert.equal(getCookieCount(), 2); - cs.setCookieString(emptyuri, null, "foo4=bar; domain=.", null); + cs.setCookieString(emptyuri, "foo4=bar; domain=.", null); Assert.equal(getCookieCount(), 2); - cs.setCookieString(emptyuri, null, "foo5=bar; domain=bar.com", null); + cs.setCookieString(emptyuri, "foo5=bar; domain=bar.com", null); Assert.equal(getCookieCount(), 2); Assert.equal(cs.getCookieString(emptyuri, null), "foo2=bar; foo3=bar"); @@ -193,14 +192,10 @@ function run_test() { cm.countCookiesFromHost("."); }, Cr.NS_ERROR_ILLEGAL_VALUE); - e = cm.getCookiesFromHost("baz.com", {}); - Assert.ok(!e.hasMoreElements()); - e = cm.getCookiesFromHost("", {}); - Assert.ok(e.hasMoreElements()); - e.getNext(); - Assert.ok(e.hasMoreElements()); - e.getNext(); - Assert.ok(!e.hasMoreElements()); + cookies = cm.getCookiesFromHost("baz.com", {}); + Assert.ok(!cookies.length); + cookies = cm.getCookiesFromHost("", {}); + Assert.equal(cookies.length, 2); do_check_throws(function() { cm.getCookiesFromHost(".", {}); }, Cr.NS_ERROR_ILLEGAL_VALUE); @@ -262,7 +257,7 @@ function run_test() { function getCookieCount() { var count = 0; var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager); - for (let cookie of cm.enumerator) { + for (let cookie of cm.cookies) { ++count; } return count; @@ -275,16 +270,16 @@ function testDomainCookie(uriString, domain) { cm.removeAll(); var uri = NetUtil.newURI(uriString); - cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null); - var e = cm.getCookiesFromHost(domain, {}); - Assert.ok(e.hasMoreElements()); - Assert.equal(e.getNext().QueryInterface(Ci.nsICookie).host, domain); + cs.setCookieString(uri, "foo=bar; domain=" + domain, null); + var cookies = cm.getCookiesFromHost(domain, {}); + Assert.ok(cookies.length); + Assert.equal(cookies[0].host, domain); cm.removeAll(); - cs.setCookieString(uri, null, "foo=bar; domain=." + domain, null); - e = cm.getCookiesFromHost(domain, {}); - Assert.ok(e.hasMoreElements()); - Assert.equal(e.getNext().QueryInterface(Ci.nsICookie).host, domain); + cs.setCookieString(uri, "foo=bar; domain=." + domain, null); + cookies = cm.getCookiesFromHost(domain, {}); + Assert.ok(cookies.length); + Assert.equal(cookies[0].host, domain); cm.removeAll(); } @@ -295,13 +290,13 @@ function testTrailingDotCookie(uriString, domain) { cm.removeAll(); var uri = NetUtil.newURI(uriString); - cs.setCookieString(uri, null, "foo=bar; domain=" + domain + ".", null); + cs.setCookieString(uri, "foo=bar; domain=" + domain + ".", null); Assert.equal(cm.countCookiesFromHost(domain), 0); Assert.equal(cm.countCookiesFromHost(domain + "."), 0); cm.removeAll(); uri = NetUtil.newURI(uriString + "."); - cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null); + cs.setCookieString(uri, "foo=bar; domain=" + domain, null); Assert.equal(cm.countCookiesFromHost(domain), 0); Assert.equal(cm.countCookiesFromHost(domain + "."), 0); cm.removeAll(); diff --git a/netwerk/test/unit/test_bug528292.js b/netwerk/test/unit/test_bug528292.js index 029b9a65d4..7202f2200b 100644 --- a/netwerk/test/unit/test_bug528292.js +++ b/netwerk/test/unit/test_bug528292.js @@ -80,7 +80,7 @@ function run_test() { var postRedirectURI = ioService.newURI(postRedirectURL); Cc["@mozilla.org/cookieService;1"] .getService(Ci.nsICookieService) - .setCookieString(postRedirectURI, null, sentCookieVal, chan); + .setCookieString(postRedirectURI, sentCookieVal, chan); // Load the pre-redirect URI. chan.asyncOpen(new ChannelListener(finish_test, null)); diff --git a/netwerk/test/unit/test_bug650995.js b/netwerk/test/unit/test_bug650995.js index ff47a92989..4e2f450e7d 100644 --- a/netwerk/test/unit/test_bug650995.js +++ b/netwerk/test/unit/test_bug650995.js @@ -167,6 +167,7 @@ function run_test() { httpserver.start(-1); prefService.setBoolPref("browser.cache.offline.enable", false); + prefService.setBoolPref("browser.cache.offline.storage.enable", false); prefService.setBoolPref("network.http.rcwn.enabled", false); nextTest(); diff --git a/netwerk/test/unit/test_bug667818.js b/netwerk/test/unit/test_bug667818.js index 4434be163b..90a18a5e40 100644 --- a/netwerk/test/unit/test_bug667818.js +++ b/netwerk/test/unit/test_bug667818.js @@ -12,17 +12,11 @@ function run_test() { // Try an expiration time before the epoch serv.setCookieString( uri, - null, "test=test; path=/; domain=example.com; expires=Sun, 31-Dec-1899 16:00:00 GMT;", null ); Assert.equal(serv.getCookieString(uri, null), ""); // Now sanity check - serv.setCookieString( - uri, - null, - "test2=test2; path=/; domain=example.com;", - null - ); + serv.setCookieString(uri, "test2=test2; path=/; domain=example.com;", null); Assert.equal(serv.getCookieString(uri, null), "test2=test2"); } diff --git a/netwerk/test/unit/test_bug767025.js b/netwerk/test/unit/test_bug767025.js index c30bf66ac8..d43f9cd832 100644 --- a/netwerk/test/unit/test_bug767025.js +++ b/netwerk/test/unit/test_bug767025.js @@ -74,6 +74,7 @@ function init_profile() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, diff --git a/netwerk/test/unit/test_cacheForOfflineUse_no-store.js b/netwerk/test/unit/test_cacheForOfflineUse_no-store.js index b2015c17ad..9d8c14d657 100644 --- a/netwerk/test/unit/test_cacheForOfflineUse_no-store.js +++ b/netwerk/test/unit/test_cacheForOfflineUse_no-store.js @@ -86,6 +86,12 @@ add_test(function test_noStore() { function run_test() { do_get_profile(); + var ps = Cc["@mozilla.org/preferences-service;1"].getService( + Ci.nsIPrefBranch + ); + ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); + httpServer = new HttpServer(); httpServer.registerPathHandler(basePath + normalEntry, normalHandler); httpServer.registerPathHandler(basePath + noStoreEntry, noStoreHandler); diff --git a/netwerk/test/unit/test_cache_204_response.js b/netwerk/test/unit/test_cache_204_response.js new file mode 100644 index 0000000000..2d2027b8a1 --- /dev/null +++ b/netwerk/test/unit/test_cache_204_response.js @@ -0,0 +1,61 @@ +/* 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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +Test if 204 response is cached. +1. Make first http request and return a 204 response. +2. Check if the first response is not cached. +3. Make second http request and check if the response is cached. + +*/ + +"use strict"; + +const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js"); + +function test_handler(metadata, response) { + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Cache-control", "max-age=9999", false); + response.setStatusLine(metadata.httpVersion, 204, "No Content"); +} + +function make_channel(url) { + let channel = NetUtil.newChannel({ + uri: url, + loadUsingSystemPrincipal: true, + }).QueryInterface(Ci.nsIHttpChannel); + return channel; +} + +async function get_response(channel, fromCache) { + return new Promise(resolve => { + channel.asyncOpen( + new ChannelListener((request, buffer, ctx, isFromCache) => { + ok(fromCache == isFromCache, `got response from cache = ${fromCache}`); + resolve(); + }) + ); + }); +} + +async function stop_server(httpserver) { + return new Promise(resolve => { + httpserver.stop(resolve); + }); +} + +add_task(async function() { + let httpserver = new HttpServer(); + httpserver.registerPathHandler("/testdir", test_handler); + httpserver.start(-1); + const PORT = httpserver.identity.primaryPort; + const URI = `http://localhost:${PORT}/testdir`; + + let response; + + await get_response(make_channel(URI, "GET"), false); + await get_response(make_channel(URI, "GET"), true); + + await stop_server(httpserver); +}); diff --git a/netwerk/test/unit/test_cookie_blacklist.js b/netwerk/test/unit/test_cookie_blacklist.js index 2bcd98e577..d80c833bff 100644 --- a/netwerk/test/unit/test_cookie_blacklist.js +++ b/netwerk/test/unit/test_cookie_blacklist.js @@ -11,7 +11,6 @@ function run_test() { cookieService.setCookieStringFromHttp( cookieURI, cookieURI, - null, "BadCookie1=\x01", null, null @@ -19,7 +18,6 @@ function run_test() { cookieService.setCookieStringFromHttp( cookieURI, cookieURI, - null, "BadCookie2=\v", null, null @@ -27,7 +25,6 @@ function run_test() { cookieService.setCookieStringFromHttp( cookieURI, cookieURI, - null, "Bad\x07Name=illegal", null, null @@ -35,7 +32,6 @@ function run_test() { cookieService.setCookieStringFromHttp( cookieURI, cookieURI, - null, GOOD_COOKIE, null, null @@ -43,7 +39,6 @@ function run_test() { cookieService.setCookieStringFromHttp( cookieURI, cookieURI, - null, SPACEY_COOKIE, null, null diff --git a/netwerk/test/unit/test_cookie_header.js b/netwerk/test/unit/test_cookie_header.js index 46d0beea67..c26dad1d46 100644 --- a/netwerk/test/unit/test_cookie_header.js +++ b/netwerk/test/unit/test_cookie_header.js @@ -98,7 +98,7 @@ function run_test_continued() { Ci.nsICookieService ); var cookie2 = "C2=V2"; - cookServ.setCookieString(chan.URI, null, cookie2, chan); + cookServ.setCookieString(chan.URI, cookie2, chan); chan.setRequestHeader("Cookie", cookieVal, false); // We expect that the setRequestHeader overrides the diff --git a/netwerk/test/unit/test_cookies_async_failure.js b/netwerk/test/unit/test_cookies_async_failure.js index 106f188119..cafa8e98f3 100644 --- a/netwerk/test/unit/test_cookies_async_failure.js +++ b/netwerk/test/unit/test_cookies_async_failure.js @@ -129,7 +129,7 @@ function do_corrupt_db(file) { function* run_test_1(generator) { // Load the profile and populate it. let uri = NetUtil.newURI("http://foo.com/"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); // Close the profile. do_close_profile(sub_generator); @@ -230,11 +230,10 @@ function* run_test_1(generator) { do_load_profile(); Assert.equal(Services.cookiemgr.countCookiesFromHost("foo.com"), 1); - let enumerator = Services.cookiemgr.getCookiesFromHost(cookie.host, {}); - Assert.ok(enumerator.hasMoreElements()); - let dbcookie = enumerator.getNext().QueryInterface(Ci.nsICookie); + let cookies = Services.cookiemgr.getCookiesFromHost(cookie.host, {}); + Assert.equal(cookies.length, 1); + let dbcookie = cookies[0]; Assert.equal(dbcookie.value, "hallo"); - Assert.ok(!enumerator.hasMoreElements()); // Close the profile. do_close_profile(sub_generator); @@ -254,7 +253,7 @@ function* run_test_2(generator) { Services.cookies.runInTransaction(_ => { for (let i = 0; i < 3000; ++i) { let uri = NetUtil.newURI("http://" + i + ".com/"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); } }); @@ -314,7 +313,6 @@ function* run_test_3(generator) { let uri = NetUtil.newURI("http://hither.com/"); Services.cookies.setCookieString( uri, - null, "oh" + i + "=hai; max-age=1000", null ); @@ -323,7 +321,6 @@ function* run_test_3(generator) { let uri = NetUtil.newURI("http://haithur.com/"); Services.cookies.setCookieString( uri, - null, "oh" + i + "=hai; max-age=1000", null ); @@ -396,7 +393,7 @@ function* run_test_4(generator) { Services.cookies.runInTransaction(_ => { for (let i = 0; i < 3000; ++i) { let uri = NetUtil.newURI("http://" + i + ".com/"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); } }); @@ -420,7 +417,7 @@ function* run_test_4(generator) { // Queue up an INSERT for the same base domain. This should also go into // memory and be written out during database rebuild. let uri = NetUtil.newURI("http://0.com/"); - Services.cookies.setCookieString(uri, null, "oh2=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh2=hai; max-age=1000", null); // At this point, the cookies should still be in memory. Assert.equal(Services.cookiemgr.countCookiesFromHost("0.com"), 1); @@ -456,15 +453,10 @@ function* run_test_5(generator) { do_load_profile(); Services.cookies.runInTransaction(_ => { let uri = NetUtil.newURI("http://bar.com/"); - Services.cookies.setCookieString( - uri, - null, - "oh=hai; path=/; max-age=1000", - null - ); + Services.cookies.setCookieString(uri, "oh=hai; path=/; max-age=1000", null); for (let i = 0; i < 3000; ++i) { let uri = NetUtil.newURI("http://" + i + ".com/"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); } }); diff --git a/netwerk/test/unit/test_cookies_privatebrowsing.js b/netwerk/test/unit/test_cookies_privatebrowsing.js index c6e5015874..4287f8b0f2 100644 --- a/netwerk/test/unit/test_cookies_privatebrowsing.js +++ b/netwerk/test/unit/test_cookies_privatebrowsing.js @@ -42,7 +42,7 @@ function* do_run_test() { let uri2 = NetUtil.newURI("http://bar.com/bar.html"); // Set a cookie for host 1. - Services.cookies.setCookieString(uri1, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri1, "oh=hai; max-age=1000", null); Assert.equal(Services.cookiemgr.countCookiesFromHost(uri1.host), 1); // Enter private browsing mode, set a cookie for host 2, and check the counts. @@ -54,7 +54,7 @@ function* do_run_test() { chan2.QueryInterface(Ci.nsIPrivateBrowsingChannel); chan2.setPrivate(true); - Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2); + Services.cookies.setCookieString(uri2, "oh=hai; max-age=1000", chan2); Assert.equal(Services.cookiemgr.getCookieString(uri1, chan1), ""); Assert.equal(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai"); @@ -63,7 +63,7 @@ function* do_run_test() { Assert.equal(Services.cookiemgr.getCookieString(uri1, chan1), ""); Assert.equal(Services.cookiemgr.getCookieString(uri2, chan2), ""); - Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2); + Services.cookies.setCookieString(uri2, "oh=hai; max-age=1000", chan2); Assert.equal(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai"); // Leave private browsing mode and check counts. @@ -83,7 +83,7 @@ function* do_run_test() { // Enter private browsing mode, set a cookie for host 2, and check the counts. Assert.equal(Services.cookiemgr.getCookieString(uri1, chan1), ""); Assert.equal(Services.cookiemgr.getCookieString(uri2, chan2), ""); - Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2); + Services.cookies.setCookieString(uri2, "oh=hai; max-age=1000", chan2); Assert.equal(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai"); // Fake a profile change. diff --git a/netwerk/test/unit/test_cookies_profile_close.js b/netwerk/test/unit/test_cookies_profile_close.js index 25a5976b3a..3e5756c651 100644 --- a/netwerk/test/unit/test_cookies_profile_close.js +++ b/netwerk/test/unit/test_cookies_profile_close.js @@ -29,11 +29,10 @@ function* do_run_test() { // Set a cookie. let uri = NetUtil.newURI("http://foo.com"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); - let enumerator = Services.cookiemgr.enumerator; - Assert.ok(enumerator.hasMoreElements()); - let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); - Assert.ok(!enumerator.hasMoreElements()); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); + let cookies = Services.cookiemgr.cookies; + Assert.ok(cookies.length == 1); + let cookie = cookies[0]; // Fire 'profile-before-change'. do_close_profile(); @@ -41,15 +40,8 @@ function* do_run_test() { // Check that the APIs behave appropriately. Assert.equal(Services.cookies.getCookieString(uri, null), ""); Assert.equal(Services.cookies.getCookieStringFromHttp(uri, null, null), ""); - Services.cookies.setCookieString(uri, null, "oh2=hai", null); - Services.cookies.setCookieStringFromHttp( - uri, - null, - null, - "oh3=hai", - null, - null - ); + Services.cookies.setCookieString(uri, "oh2=hai", null); + Services.cookies.setCookieStringFromHttp(uri, null, "oh3=hai", null, null); Assert.equal(Services.cookies.getCookieString(uri, null), ""); do_check_throws(function() { @@ -57,7 +49,7 @@ function* do_run_test() { }, Cr.NS_ERROR_NOT_AVAILABLE); do_check_throws(function() { - Services.cookiemgr.enumerator; + Services.cookiemgr.cookies; }, Cr.NS_ERROR_NOT_AVAILABLE); do_check_throws(function() { diff --git a/netwerk/test/unit/test_cookies_read.js b/netwerk/test/unit/test_cookies_read.js index 0bf6758a72..349714c102 100644 --- a/netwerk/test/unit/test_cookies_read.js +++ b/netwerk/test/unit/test_cookies_read.js @@ -27,8 +27,8 @@ function* do_run_test() { Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); // Start the cookieservice, to force creation of a database. - // Get the sessionEnumerator to join the initialization in cookie thread - Services.cookiemgr.sessionEnumerator; + // Get the sessionCookies to join the initialization in cookie thread + Services.cookiemgr.sessionCookies; // Open a database connection now, after synchronous initialization has // completed. We may not be able to open one later once asynchronous writing @@ -38,7 +38,7 @@ function* do_run_test() { for (let i = 0; i < CMAX; ++i) { let uri = NetUtil.newURI("http://" + i + ".com/"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); } Assert.equal(do_count_cookies(), CMAX); diff --git a/netwerk/test/unit/test_cookies_sync_failure.js b/netwerk/test/unit/test_cookies_sync_failure.js index 3aafcda5c1..0110d8c04c 100644 --- a/netwerk/test/unit/test_cookies_sync_failure.js +++ b/netwerk/test/unit/test_cookies_sync_failure.js @@ -166,7 +166,7 @@ function* run_test_1(generator) { // Load the profile and populate it. let uri = NetUtil.newURI("http://foo.com/"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); // Fake a profile change. do_close_profile(sub_generator); @@ -192,7 +192,7 @@ function* run_test_2(generator) { // Load the profile and populate it. do_load_profile(); let uri = NetUtil.newURI("http://foo.com/"); - Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); + Services.cookies.setCookieString(uri, "oh=hai; max-age=1000", null); // Fake a profile change. do_close_profile(sub_generator); diff --git a/netwerk/test/unit/test_domain_eviction.js b/netwerk/test/unit/test_domain_eviction.js index 60fcb8374a..ebeaf9d6e7 100644 --- a/netwerk/test/unit/test_domain_eviction.js +++ b/netwerk/test/unit/test_domain_eviction.js @@ -56,7 +56,7 @@ function* do_run_test() { setCookies("tasty.horse.radish", 50, futureExpiry); Assert.equal(countCookies("horse.radish", "horse.radish"), 50); - for (let cookie of Services.cookiemgr.enumerator) { + for (let cookie of Services.cookiemgr.cookies) { if (cookie.host == "horse.radish") { do_throw("cookies not evicted by lastAccessed order"); } @@ -125,15 +125,15 @@ function setCookies(aHost, aNumber, aExpiry) { // count how many cookies are within domain 'aBaseDomain', using three // independent interface methods on nsICookieManager: -// 1) 'enumerator', an enumerator of all cookies; +// 1) 'cookies', an array of all cookies; // 2) 'countCookiesFromHost', which returns the number of cookies within the // base domain of 'aHost', -// 3) 'getCookiesFromHost', which returns an enumerator of 2). +// 3) 'getCookiesFromHost', which returns an array of 2). function countCookies(aBaseDomain, aHost) { - // count how many cookies are within domain 'aBaseDomain' using the cookie - // enumerator. + // count how many cookies are within domain 'aBaseDomain' using the cookies + // array. let cookies = []; - for (let cookie of Services.cookiemgr.enumerator) { + for (let cookie of Services.cookiemgr.cookies) { if ( cookie.host.length >= aBaseDomain.length && cookie.host.slice(cookie.host.length - aBaseDomain.length) == aBaseDomain @@ -165,7 +165,7 @@ function countCookies(aBaseDomain, aHost) { } if (!found) { - do_throw("cookie " + cookie.name + " not found in master enumerator"); + do_throw("cookie " + cookie.name + " not found in master cookies"); } } else { do_throw( diff --git a/netwerk/test/unit/test_eviction.js b/netwerk/test/unit/test_eviction.js index 8b2c568285..8d12054016 100644 --- a/netwerk/test/unit/test_eviction.js +++ b/netwerk/test/unit/test_eviction.js @@ -222,9 +222,9 @@ function set_cookies(begin, end, expiry) { function get_creationTime(i) { let host = "eviction." + i + ".tests"; - let enumerator = Services.cookiemgr.getCookiesFromHost(host, {}); - Assert.ok(enumerator.hasMoreElements()); - let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); + let cookies = Services.cookiemgr.getCookiesFromHost(host, {}); + Assert.ok(cookies.length); + let cookie = cookies[0]; return cookie.creationTime; } @@ -235,7 +235,7 @@ function get_creationTime(i) { // + 10% are exceeded. function check_remaining_cookies(aNumberTotal, aNumberOld, aNumberToExpect) { let i = 0; - for (let cookie of Services.cookiemgr.enumerator) { + for (let cookie of Services.cookiemgr.cookies) { ++i; if (aNumberTotal != aNumberToExpect) { diff --git a/netwerk/test/unit/test_fallback_no-cache-entry_canceled.js b/netwerk/test/unit/test_fallback_no-cache-entry_canceled.js index 808af83314..66c11f796d 100644 --- a/netwerk/test/unit/test_fallback_no-cache-entry_canceled.js +++ b/netwerk/test/unit/test_fallback_no-cache-entry_canceled.js @@ -82,6 +82,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -89,7 +90,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. // In this test the randomURI doesn't exists diff --git a/netwerk/test/unit/test_fallback_no-cache-entry_passing.js b/netwerk/test/unit/test_fallback_no-cache-entry_passing.js index 4af2209004..0b263c9df0 100644 --- a/netwerk/test/unit/test_fallback_no-cache-entry_passing.js +++ b/netwerk/test/unit/test_fallback_no-cache-entry_passing.js @@ -82,6 +82,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -89,7 +90,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. // In this test the randomURI doesn't exists diff --git a/netwerk/test/unit/test_fallback_redirect-to-different-origin_canceled.js b/netwerk/test/unit/test_fallback_redirect-to-different-origin_canceled.js index df10b60a28..d2f45e3405 100644 --- a/netwerk/test/unit/test_fallback_redirect-to-different-origin_canceled.js +++ b/netwerk/test/unit/test_fallback_redirect-to-different-origin_canceled.js @@ -89,6 +89,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -96,7 +97,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. var chan = make_channel(randomURI); diff --git a/netwerk/test/unit/test_fallback_redirect-to-different-origin_passing.js b/netwerk/test/unit/test_fallback_redirect-to-different-origin_passing.js index fe3079dc92..30af425c5a 100644 --- a/netwerk/test/unit/test_fallback_redirect-to-different-origin_passing.js +++ b/netwerk/test/unit/test_fallback_redirect-to-different-origin_passing.js @@ -89,6 +89,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -96,7 +97,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. var chan = make_channel(randomURI); diff --git a/netwerk/test/unit/test_fallback_request-error_canceled.js b/netwerk/test/unit/test_fallback_request-error_canceled.js index 3b18213527..3175b69228 100644 --- a/netwerk/test/unit/test_fallback_request-error_canceled.js +++ b/netwerk/test/unit/test_fallback_request-error_canceled.js @@ -88,6 +88,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -95,7 +96,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. diff --git a/netwerk/test/unit/test_fallback_request-error_passing.js b/netwerk/test/unit/test_fallback_request-error_passing.js index 388405abe4..3ab2512bbd 100644 --- a/netwerk/test/unit/test_fallback_request-error_passing.js +++ b/netwerk/test/unit/test_fallback_request-error_passing.js @@ -89,6 +89,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -96,7 +97,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. var _x = randomURI; // doing this so the lazy value gets computed diff --git a/netwerk/test/unit/test_fallback_response-error_canceled.js b/netwerk/test/unit/test_fallback_response-error_canceled.js index a7b4bd5cca..4cc80e4c35 100644 --- a/netwerk/test/unit/test_fallback_response-error_canceled.js +++ b/netwerk/test/unit/test_fallback_response-error_canceled.js @@ -89,6 +89,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -96,7 +97,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. var chan = make_channel(randomURI); diff --git a/netwerk/test/unit/test_fallback_response-error_passing.js b/netwerk/test/unit/test_fallback_response-error_passing.js index 5673cc499e..313ca9dc4e 100644 --- a/netwerk/test/unit/test_fallback_response-error_passing.js +++ b/netwerk/test/unit/test_fallback_response-error_passing.js @@ -89,6 +89,7 @@ function run_test() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, @@ -96,7 +97,7 @@ function run_test() { ); cacheUpdateObserver = { - observe: function() { + observe() { dump("got offline-cache-update-completed\n"); // offline cache update completed. var chan = make_channel(randomURI); diff --git a/netwerk/test/unit/test_file_protocol.js b/netwerk/test/unit/test_file_protocol.js index 3ed4cdd629..62b89fb02e 100644 --- a/netwerk/test/unit/test_file_protocol.js +++ b/netwerk/test/unit/test_file_protocol.js @@ -59,23 +59,17 @@ FileStreamListener.prototype = { _got_onstoprequest: false, _contentLen: -1, - _isDir: function(request) { + _isDir(request) { request.QueryInterface(Ci.nsIFileChannel); return request.file.isDirectory(); }, - QueryInterface: function(iid) { - if ( - iid.equals(Ci.nsIStreamListener) || - iid.equals(Ci.nsIRequestObserver) || - iid.equals(Ci.nsISupports) - ) { - return this; - } - throw Cr.NS_ERROR_NO_INTERFACE; - }, + QueryInterface: ChromeUtils.generateQI([ + "nsIStreamListener", + "nsIRequestObserver" + ]), - onStartRequest: function(request) { + onStartRequest(request) { if (this._got_onstartrequest) { do_throw("Got second onStartRequest event!"); } @@ -90,7 +84,7 @@ FileStreamListener.prototype = { } }, - onDataAvailable: function(request, stream, offset, count) { + onDataAvailable(request, stream, offset, count) { if (!this._got_onstartrequest) { do_throw("onDataAvailable without onStartRequest event!"); } @@ -104,7 +98,7 @@ FileStreamListener.prototype = { this._buffer = this._buffer.concat(read_stream(stream, count)); }, - onStopRequest: function(request, status) { + onStopRequest(request, status) { if (!this._got_onstartrequest) { do_throw("onStopRequest without onStartRequest event!"); } @@ -286,7 +280,3 @@ function test_load_replace() { } run_next_test(); } - -function run_test() { - run_next_test(); -} diff --git a/netwerk/test/unit/test_http2-proxy.js b/netwerk/test/unit/test_http2-proxy.js index 3a04d0e368..7f57deaa96 100644 --- a/netwerk/test/unit/test_http2-proxy.js +++ b/netwerk/test/unit/test_http2-proxy.js @@ -20,9 +20,11 @@ */ const pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(); +const { NodeServer } = ChromeUtils.import("resource://testing-common/httpd.js"); let proxy_port; let server_port; +let filter; // See moz-http2 const proxy_auth = "authorization-token"; @@ -37,7 +39,12 @@ class ProxyFilter { this.QueryInterface = ChromeUtils.generateQI([Ci.nsIProtocolProxyFilter]); } applyFilter(pps, uri, pi, cb) { - if (uri.spec.match(/(\/proxy-session-counter)/)) { + if ( + uri.pathQueryRef.startsWith("/execute") || + uri.pathQueryRef.startsWith("/fork") || + uri.pathQueryRef.startsWith("/kill") + ) { + // So we allow NodeServer.execute to work cb.onProxyFilterResult(pi); return; } @@ -109,51 +116,202 @@ function get_response(channel, flags = CL_ALLOW_UNKNOWN_CL) { let initial_session_count = 0; +class http2ProxyCode { + static listen(server, envport) { + if (!server) { + return Promise.resolve(0); + } + + let portSelection = 0; + if (envport !== undefined) { + try { + portSelection = parseInt(envport, 10); + } catch (e) { + portSelection = -1; + } + } + return new Promise(resolve => { + server.listen(portSelection, "0.0.0.0", 2000, () => { + resolve(server.address().port); + }); + }); + } + + static startNewProxy() { + const fs = require("fs"); + const options = { + key: fs.readFileSync(__dirname + "/http2-cert.key"), + cert: fs.readFileSync(__dirname + "/http2-cert.pem"), + }; + const http2 = require("http2"); + global.proxy = http2.createSecureServer(options); + this.setupProxy(); + return http2ProxyCode.listen(proxy).then(port => { + return { port, success: true }; + }); + } + + static closeProxy() { + proxy.closeSockets(); + return new Promise(resolve => { + proxy.close(resolve); + }); + } + + static proxySessionCount() { + if (!proxy) { + return 0; + } + return proxy.proxy_session_count; + } + + static setupProxy() { + if (!proxy) { + throw new Error("proxy is null"); + } + proxy.proxy_session_count = 0; + proxy.on("session", () => { + ++proxy.proxy_session_count; + }); + + // We need to track active connections so we can forcefully close keep-alive + // connections when shutting down the proxy. + proxy.socketIndex = 0; + proxy.socketMap = {}; + proxy.on("connection", function(socket) { + let index = proxy.socketIndex++; + proxy.socketMap[index] = socket; + socket.on("close", function() { + delete proxy.socketMap[index]; + }); + }); + proxy.closeSockets = function() { + for (let i in proxy.socketMap) { + proxy.socketMap[i].destroy(); + } + }; + + proxy.on("stream", (stream, headers) => { + if (headers[":method"] !== "CONNECT") { + // Only accept CONNECT requests + stream.respond({ ":status": 405 }); + stream.end(); + return; + } + + const target = headers[":authority"]; + + const authorization_token = headers["proxy-authorization"]; + if ( + "authorization-token" != authorization_token || + target == "407.example.com:443" + ) { + stream.respond({ ":status": 407 }); + // Deliberately send no Proxy-Authenticate header + stream.end(); + return; + } + if (target == "404.example.com:443") { + // 404 Not Found, a response code that a proxy should return when the host can't be found + stream.respond({ ":status": 404 }); + stream.end(); + return; + } + if (target == "429.example.com:443") { + // 429 Too Many Requests, a response code that a proxy should return when receiving too many requests + stream.respond({ ":status": 429 }); + stream.end(); + return; + } + if (target == "502.example.com:443") { + // 502 Bad Gateway, a response code mostly resembling immediate connection error + stream.respond({ ":status": 502 }); + stream.end(); + return; + } + if (target == "504.example.com:443") { + // 504 Gateway Timeout, did not receive a timely response from an upstream server + stream.respond({ ":status": 504 }); + stream.end(); + return; + } + + const net = require("net"); + const socket = net.connect(serverPort, "127.0.0.1", () => { + try { + stream.respond({ ":status": 200 }); + socket.pipe(stream); + stream.pipe(socket); + } catch (exception) { + console.log(exception); + stream.close(); + } + }); + socket.on("error", error => { + throw `Unxpected error when conneting the HTTP/2 server from the HTTP/2 proxy during CONNECT handling: '${error}'`; + }); + }); + } +} + function proxy_session_counter() { return new Promise(async resolve => { - const channel = make_channel( - `https://localhost:${server_port}/proxy-session-counter` + let data = await NodeServer.execute( + processId, + `http2ProxyCode.proxySessionCount()` ); - const { data } = await get_response(channel); resolve(parseInt(data) - initial_session_count); }); } - +let processId; add_task(async function setup() { + // Set to allow the cert presented by our H2 server + do_get_profile(); + + // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem + // so add that cert to the trust list as a signing cert. + let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); + const env = Cc["@mozilla.org/process/environment;1"].getService( Ci.nsIEnvironment ); server_port = env.get("MOZHTTP2_PORT"); Assert.notEqual(server_port, null); - proxy_port = env.get("MOZHTTP2_PROXY_PORT"); + processId = await NodeServer.fork(); + await NodeServer.execute(processId, `serverPort = ${server_port}`); + await NodeServer.execute(processId, http2ProxyCode); + let proxy = await NodeServer.execute( + processId, + `http2ProxyCode.startNewProxy()` + ); + proxy_port = proxy.port; Assert.notEqual(proxy_port, null); - // Set to allow the cert presented by our H2 server - do_get_profile(); - Services.prefs.setBoolPref("network.http.spdy.enabled", true); Services.prefs.setBoolPref("network.http.spdy.enabled.http2", true); // make all native resolve calls "secretly" resolve localhost instead Services.prefs.setBoolPref("network.dns.native-is-localhost", true); - // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem - // so add that cert to the trust list as a signing cert. - let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( - Ci.nsIX509CertDB - ); - addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); - - pps.registerFilter(new ProxyFilter("https", "localhost", proxy_port, 0), 10); + filter = new ProxyFilter("https", "localhost", proxy_port, 0); + pps.registerFilter(filter, 10); initial_session_count = await proxy_session_counter(); info(`Initial proxy session count = ${initial_session_count}`); }); -registerCleanupFunction(() => { +registerCleanupFunction(async () => { Services.prefs.clearUserPref("network.http.spdy.enabled"); Services.prefs.clearUserPref("network.http.spdy.enabled.http2"); Services.prefs.clearUserPref("network.dns.native-is-localhost"); + + pps.unregisterFilter(filter); + + await NodeServer.execute(processId, `http2ProxyCode.closeProxy()`); + await NodeServer.kill(processId); }); /** diff --git a/netwerk/test/unit/test_http2.js b/netwerk/test/unit/test_http2.js index dc7ae526a2..c0ebc0e79d 100644 --- a/netwerk/test/unit/test_http2.js +++ b/netwerk/test/unit/test_http2.js @@ -782,12 +782,7 @@ function h1ServerWK(metadata, response) { response.setHeader("Access-Control-Allow-Origin", "*", false); response.setHeader("Access-Control-Allow-Method", "GET", false); - var body = - '{"http://foo.example.com:' + - httpserv.identity.primaryPort + - '": { "tls-ports": [' + - serverPort + - "] }}"; + var body = '["http://foo.example.com:' + httpserv.identity.primaryPort + '"]'; response.bodyOutputStream.write(body, body.length); } @@ -810,12 +805,7 @@ function h1ServerWK2(metadata, response) { response.setHeader("Access-Control-Allow-Origin", "*", false); response.setHeader("Access-Control-Allow-Method", "GET", false); - var body = - '{"http://foo.example.com:' + - httpserv2.identity.primaryPort + - '": { "tls-ports": [' + - serverPort + - "] }}"; + var body = '["http://foo.example.com:' + httpserv2.identity.primaryPort + '"]'; response.bodyOutputStream.write(body, body.length); } function test_http2_altsvc() { diff --git a/netwerk/test/unit/test_node_execute.js b/netwerk/test/unit/test_node_execute.js new file mode 100644 index 0000000000..d50b06b00b --- /dev/null +++ b/netwerk/test/unit/test_node_execute.js @@ -0,0 +1,88 @@ +// This test checks that the interaction between NodeServer.execute defined in +// httpd.js and the node server that we're interacting with defined in +// moz-http2.js is working properly. + +"use strict"; + +const { NodeServer } = ChromeUtils.import("resource://testing-common/httpd.js"); + +add_task(async function test_execute() { + function f() { + return "bla"; + } + let id = await NodeServer.fork(); + equal(await NodeServer.execute(id, `"hello"`), "hello"); + equal(await NodeServer.execute(id, `(() => "hello")()`), "hello"); + equal(await NodeServer.execute(id, `my_defined_var = 1;`), 1); + equal(await NodeServer.execute(id, `(() => my_defined_var)()`), 1); + equal(await NodeServer.execute(id, `my_defined_var`), 1); + + await NodeServer.execute(id, `not_defined_var`) + .then(() => { + ok(false, "should have thrown"); + }) + .catch(e => { + equal(e.message, "ReferenceError: not_defined_var is not defined"); + ok( + e.stack.includes("moz-http2-child.js"), + `stack should be coming from moz-http2-child.js - ${e.stack}` + ); + }); + await NodeServer.execute("definitely_wrong_id", `"hello"`) + .then(() => { + ok(false, "should have thrown"); + }) + .catch(e => { + equal(e.message, "Error: could not find id"); + ok( + e.stack.includes("moz-http2.js"), + `stack should be coming from moz-http2.js - ${e.stack}` + ); + }); + + // Defines f in the context of the node server. + // The implementation of NodeServer.execute prepends `functionName =` to the + // body of the function we pass so it gets attached to the global context + // in the server. + equal(await NodeServer.execute(id, f), undefined); + equal(await NodeServer.execute(id, `f()`), "bla"); + + class myClass { + static doStuff() { + return my_defined_var; + } + } + + equal(await NodeServer.execute(id, myClass), undefined); + equal(await NodeServer.execute(id, `myClass.doStuff()`), 1); + + equal(await NodeServer.kill(id), undefined); + await NodeServer.execute(id, `f()`) + .then(() => ok(false, "should throw")) + .catch(e => equal(e.message, "Error: could not find id")); + id = await NodeServer.fork(); + // Check that a child process dying during a call throws an error. + await NodeServer.execute(id, `process.exit()`) + .then(() => ok(false, "should throw")) + .catch(e => + equal(e.message, "child process exit closing code: 0 signal: null") + ); + + id = await NodeServer.fork(); + equal( + await NodeServer.execute( + id, + `setTimeout(function() { sendBackResponse(undefined) }, 0); 2` + ), + 2 + ); + await new Promise(resolve => do_timeout(10, resolve)); + await NodeServer.kill(id) + .then(() => ok(false, "should throw")) + .catch(e => + equal( + e.message, + `forked process without handler sent: {"error":"","errorStack":""}\n` + ) + ); +}); diff --git a/netwerk/test/unit/test_offlinecache_custom-directory.js b/netwerk/test/unit/test_offlinecache_custom-directory.js index 4ec7988d40..07494c8658 100644 --- a/netwerk/test/unit/test_offlinecache_custom-directory.js +++ b/netwerk/test/unit/test_offlinecache_custom-directory.js @@ -121,6 +121,7 @@ function run_test() { Ci.nsIPrefBranch ); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); // Set this pref to mimic the default browser behavior. ps.setComplexValue( "browser.cache.offline.parent_directory", diff --git a/netwerk/test/unit/test_pinned_app_cache.js b/netwerk/test/unit/test_pinned_app_cache.js index 9315506358..33bf031307 100644 --- a/netwerk/test/unit/test_pinned_app_cache.js +++ b/netwerk/test/unit/test_pinned_app_cache.js @@ -107,6 +107,7 @@ function init_profile() { ); dump(ps.getBoolPref("browser.cache.offline.enable")); ps.setBoolPref("browser.cache.offline.enable", true); + ps.setBoolPref("browser.cache.offline.storage.enable", true); ps.setComplexValue( "browser.cache.offline.parent_directory", Ci.nsIFile, diff --git a/netwerk/test/unit/test_post.js b/netwerk/test/unit/test_post.js index 755a470dbe..20c37bddba 100644 --- a/netwerk/test/unit/test_post.js +++ b/netwerk/test/unit/test_post.js @@ -36,28 +36,23 @@ const BUFFERSIZE = 4096; var correctOnProgress = false; var listenerCallback = { - QueryInterface: function(iid) { - if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIProgressEventSink)) { - return this; - } - throw Cr.NS_ERROR_NO_INTERFACE; - }, + QueryInterface: ChromeUtils.generateQI(["nsIProgressEventSink"]), - getInterface: function(iid) { + getInterface(iid) { if (iid.equals(Ci.nsIProgressEventSink)) { return this; } throw Cr.NS_ERROR_NO_INTERFACE; }, - onProgress: function(request, context, progress, progressMax) { + onProgress(request, progress, progressMax) { // this works because the response is 0 bytes and does not trigger onprogress if (progress === progressMax) { correctOnProgress = true; } }, - onStatus: function(request, context, status, statusArg) {}, + onStatus(request, status, statusArg) {}, }; function run_test() { diff --git a/netwerk/test/unit/test_private_cookie_changed.js b/netwerk/test/unit/test_private_cookie_changed.js index 71b0fdc5d5..4ce837044b 100644 --- a/netwerk/test/unit/test_private_cookie_changed.js +++ b/netwerk/test/unit/test_private_cookie_changed.js @@ -34,9 +34,9 @@ function run_test() { let uri = NetUtil.newURI("http://foo.com/"); let publicChan = makeChan(uri, false); let svc = Services.cookies.QueryInterface(Ci.nsICookieService); - svc.setCookieString(uri, null, "oh=hai", publicChan); + svc.setCookieString(uri, "oh=hai", publicChan); let privateChan = makeChan(uri, true); - svc.setCookieString(uri, null, "oh=hai", privateChan); + svc.setCookieString(uri, "oh=hai", privateChan); Assert.equal(publicNotifications, 1); Assert.equal(privateNotifications, 1); } diff --git a/netwerk/test/unit/test_progress.js b/netwerk/test/unit/test_progress.js index a27bebbb6f..0a071c5f02 100644 --- a/netwerk/test/unit/test_progress.js +++ b/netwerk/test/unit/test_progress.js @@ -26,19 +26,13 @@ var progressCallback = { _got_onstatus_after_onstartrequest: false, _last_callback_handled: null, - QueryInterface: function(iid) { - if ( - iid.equals(Ci.nsISupports) || - iid.equals(Ci.nsIProgressEventSink) || - iid.equals(Ci.nsIStreamListener) || - iid.equals(Ci.nsIRequestObserver) - ) { - return this; - } - throw Cr.NS_ERROR_NO_INTERFACE; - }, + QueryInterface: ChromeUtils.generateQI([ + "nsIProgressEventSink", + "nsIStreamListener", + "nsIRequestObserver" + ]), - getInterface: function(iid) { + getInterface(iid) { if ( iid.equals(Ci.nsIProgressEventSink) || iid.equals(Ci.nsIStreamListener) || @@ -49,7 +43,7 @@ var progressCallback = { throw Cr.NS_ERROR_NO_INTERFACE; }, - onStartRequest: function(request) { + onStartRequest(request) { Assert.equal(this._last_callback_handled, TYPE_ONSTATUS); this._got_onstartrequest = true; this._last_callback_handled = TYPE_ONSTARTREQUEST; @@ -58,14 +52,14 @@ var progressCallback = { this._listener.onStartRequest(request); }, - onDataAvailable: function(request, data, offset, count) { + onDataAvailable(request, data, offset, count) { Assert.equal(this._last_callback_handled, TYPE_ONPROGRESS); this._last_callback_handled = TYPE_ONDATAAVAILABLE; this._listener.onDataAvailable(request, data, offset, count); }, - onStopRequest: function(request, status) { + onStopRequest(request, status) { Assert.equal(this._last_callback_handled, TYPE_ONDATAAVAILABLE); Assert.ok(this._got_onstatus_after_onstartrequest); this._last_callback_handled = TYPE_ONSTOPREQUEST; @@ -74,7 +68,7 @@ var progressCallback = { delete this._listener; }, - onProgress: function(request, context, progress, progressMax) { + onProgress(request, progress, progressMax) { Assert.equal(this._last_callback_handled, TYPE_ONSTATUS); this._last_callback_handled = TYPE_ONPROGRESS; @@ -83,7 +77,7 @@ var progressCallback = { max = progressMax; }, - onStatus: function(request, context, status, statusArg) { + onStatus(request, status, statusArg) { if (!this._got_onstartrequest) { // Ensure that all messages before onStartRequest are onStatus if (this._last_callback_handled) { diff --git a/netwerk/test/unit/test_schema_2_migration.js b/netwerk/test/unit/test_schema_2_migration.js index e5221cdfc4..b6f64d8e52 100644 --- a/netwerk/test/unit/test_schema_2_migration.js +++ b/netwerk/test/unit/test_schema_2_migration.js @@ -23,8 +23,8 @@ function* do_run_test() { let profile = do_get_profile(); // Start the cookieservice, to force creation of a database. - // Get the sessionEnumerator to join the initialization in cookie thread - Services.cookiemgr.sessionEnumerator; + // Get the sessionCookies to join the initialization in cookie thread + Services.cookiemgr.sessionCookies; // Close the profile. do_close_profile(test_generator); @@ -161,8 +161,8 @@ function* do_run_test() { // 3) Only one cookie remains, and it's the one with the highest expiration // time. Assert.equal(Services.cookiemgr.countCookiesFromHost("baz.com"), 1); - let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com", {}); - let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); + let cookies = Services.cookiemgr.getCookiesFromHost("baz.com", {}); + let cookie = cookies[0]; Assert.equal(cookie.expiry, futureExpiry + 44); do_close_profile(test_generator); diff --git a/netwerk/test/unit/test_schema_3_migration.js b/netwerk/test/unit/test_schema_3_migration.js index acbfb2c07d..32d56687da 100644 --- a/netwerk/test/unit/test_schema_3_migration.js +++ b/netwerk/test/unit/test_schema_3_migration.js @@ -23,8 +23,8 @@ function* do_run_test() { let profile = do_get_profile(); // Start the cookieservice, to force creation of a database. - // Get the sessionEnumerator to join the initialization in cookie thread - Services.cookiemgr.sessionEnumerator; + // Get the sessionCookies to join the initialization in cookie thread + Services.cookiemgr.sessionCookies; // Close the profile. do_close_profile(test_generator); @@ -161,8 +161,8 @@ function* do_run_test() { // 3) Only one cookie remains, and it's the one with the highest expiration // time. Assert.equal(Services.cookiemgr.countCookiesFromHost("baz.com"), 1); - let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com", {}); - let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); + let cookies = Services.cookiemgr.getCookiesFromHost("baz.com", {}); + let cookie = cookies[0]; Assert.equal(cookie.expiry, futureExpiry + 44); do_close_profile(test_generator); @@ -199,8 +199,8 @@ function* do_run_test() { // Test the expected set of cookies. Assert.equal(Services.cookiemgr.countCookiesFromHost("cat.com"), 20); - enumerator = Services.cookiemgr.getCookiesFromHost("cat.com", {}); - cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); + cookies = Services.cookiemgr.getCookiesFromHost("cat.com", {}); + cookie = cookies[0]; Assert.equal(cookie.creationTime, 0); finish_test(); diff --git a/netwerk/test/unit/test_signature_extraction.js b/netwerk/test/unit/test_signature_extraction.js index 367a38c717..44970c12d0 100644 --- a/netwerk/test/unit/test_signature_extraction.js +++ b/netwerk/test/unit/test_signature_extraction.js @@ -178,24 +178,22 @@ add_task(async function test_signature() { saver.finish(Cr.NS_OK); await completionPromise; - // There's only one nsIX509CertList in the signature array. + // There's only one Array of certs(raw bytes) in the signature array. Assert.equal(1, saver.signatureInfo.length); - let certLists = saver.signatureInfo.enumerate(); - Assert.ok(certLists.hasMoreElements()); - let certList = certLists.getNext().QueryInterface(Ci.nsIX509CertList); - Assert.ok(!certLists.hasMoreElements()); - - // Check that it has 3 certs. - let certs = certList.getEnumerator(); - Assert.ok(certs.hasMoreElements()); - let signer = certs.getNext().QueryInterface(Ci.nsIX509Cert); - Assert.ok(certs.hasMoreElements()); - let issuer = certs.getNext().QueryInterface(Ci.nsIX509Cert); - Assert.ok(certs.hasMoreElements()); - let root = certs.getNext().QueryInterface(Ci.nsIX509Cert); - Assert.ok(!certs.hasMoreElements()); - - // Check that the certs have expected strings attached. + let certLists = saver.signatureInfo; + Assert.ok(certLists.length === 1); + + // Check that it has 3 certs(raw bytes). + let certs = certLists[0]; + Assert.ok(certs.length === 3); + + const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + let signer = certDB.constructX509(certs[0]); + let issuer = certDB.constructX509(certs[1]); + let root = certDB.constructX509(certs[2]); + let organization = "Microsoft Corporation"; Assert.equal("Microsoft Corporation", signer.commonName); Assert.equal(organization, signer.organization); diff --git a/netwerk/test/unit/test_stale-while-revalidate_loop.js b/netwerk/test/unit/test_stale-while-revalidate_loop.js new file mode 100644 index 0000000000..3c8b73cee2 --- /dev/null +++ b/netwerk/test/unit/test_stale-while-revalidate_loop.js @@ -0,0 +1,46 @@ +/* + +Tests the Cache-control: stale-while-revalidate response directive. + +Loads a HTTPS resource with the stale-while-revalidate and tries to load it +twice. + +*/ + +"use strict"; + +function make_channel(url) { + return NetUtil.newChannel({ + uri: url, + loadUsingSystemPrincipal: true, + }).QueryInterface(Ci.nsIHttpChannel); +} + +async function get_response(channel, fromCache) { + return new Promise(resolve => { + channel.asyncOpen( + new ChannelListener((request, buffer, ctx, isFromCache) => { + resolve(buffer); + }) + ); + }); +} + +add_task(async function() { + do_get_profile(); + let env = Cc["@mozilla.org/process/environment;1"].getService( + Ci.nsIEnvironment + ); + const PORT = env.get("MOZHTTP2_PORT"); + const URI = `https://localhost:${PORT}/stale-while-revalidate-loop-test`; + + let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); + + let response = await get_response(make_channel(URI), false); + ok(response == "1", "got response ver 1"); + response = await get_response(make_channel(URI), false); + ok(response == "1", "got response ver 1"); +}); diff --git a/netwerk/test/unit/test_stale-while-revalidate_positive.js b/netwerk/test/unit/test_stale-while-revalidate_positive.js index 69c75cf981..d39d96087b 100644 --- a/netwerk/test/unit/test_stale-while-revalidate_positive.js +++ b/netwerk/test/unit/test_stale-while-revalidate_positive.js @@ -25,10 +25,6 @@ and we hit it. const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js"); -function run_test() { - run_next_test(); -} - let max_age; let version; let generate_response = ver => `response version=${ver}`; diff --git a/netwerk/test/unit/test_synthesized_response.js b/netwerk/test/unit/test_synthesized_response.js index f4edcfaf85..ddd760cfc8 100644 --- a/netwerk/test/unit/test_synthesized_response.js +++ b/netwerk/test/unit/test_synthesized_response.js @@ -48,21 +48,21 @@ function make_channel(url, body, cb) { Ci.nsIInterfaceRequestor, Ci.nsIProgressEventSink, ]), - getInterface: function(iid) { + getInterface(iid) { return this.QueryInterface(iid); }, - onProgress: function(request, context, progress, progressMax) { + onProgress(request, progress, progressMax) { gotOnProgress = true; }, - onStatus: function(request, context, status, statusArg) { + onStatus(request, status, statusArg) { gotOnStatus = true; }, - shouldPrepareForIntercept: function() { + shouldPrepareForIntercept() { Assert.equal(this.numChecks, 0); this.numChecks++; return true; }, - channelIntercepted: function(channel) { + channelIntercepted(channel) { channel.QueryInterface(Ci.nsIInterceptedChannel); if (body) { var synthesized = Cc[ @@ -77,7 +77,7 @@ function make_channel(url, body, cb) { cb(channel); } return { - dispatch: function() {}, + dispatch() {} }; }, }; diff --git a/netwerk/test/unit/test_trr.js b/netwerk/test/unit/test_trr.js index 04199cc7cd..c89d93af20 100644 --- a/netwerk/test/unit/test_trr.js +++ b/netwerk/test/unit/test_trr.js @@ -1,5 +1,6 @@ "use strict"; +const { NodeServer } = ChromeUtils.import("resource://testing-common/httpd.js"); const dns = Cc["@mozilla.org/network/dns-service;1"].getService( Ci.nsIDNSService ); @@ -29,16 +30,21 @@ add_task(function setup() { // use the h2 server as DOH provider Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns` + `https://foo.example.com:${h2Port}/doh` ); // make all native resolve calls "secretly" resolve localhost instead Services.prefs.setBoolPref("network.dns.native-is-localhost", true); - // 0 - off, 1 - race, 2 TRR first, 3 TRR only, 4 shadow + // 0 - off, 1 - reserved, 2 - TRR first, 3 - TRR only, 4 - reserved Services.prefs.setIntPref("network.trr.mode", 2); // TRR first Services.prefs.setBoolPref("network.trr.wait-for-portal", false); + // By default wait for all responses before notifying the listeners. + Services.prefs.setBoolPref("network.trr.wait-for-A-and-AAAA", true); // don't confirm that TRR is working, just go! Services.prefs.setCharPref("network.trr.confirmationNS", "skip"); + // some tests rely on the cache not being cleared on pref change. + // we specifically test that this works + Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", false); // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem // so add that cert to the trust list as a signing cert. // the foo.example.com domain name. @@ -58,9 +64,16 @@ registerCleanupFunction(() => { Services.prefs.clearUserPref("network.trr.confirmationNS"); Services.prefs.clearUserPref("network.trr.bootstrapAddress"); Services.prefs.clearUserPref("network.trr.blacklist-duration"); - Services.prefs.clearUserPref("network.trr.request-timeout"); + Services.prefs.clearUserPref("network.trr.request_timeout_ms"); + Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms"); Services.prefs.clearUserPref("network.trr.disable-ECS"); + Services.prefs.clearUserPref("network.trr.early-AAAA"); + Services.prefs.clearUserPref("network.trr.skip-AAAA-when-not-supported"); + Services.prefs.clearUserPref("network.trr.wait-for-A-and-AAAA"); Services.prefs.clearUserPref("network.trr.excluded-domains"); + Services.prefs.clearUserPref("network.trr.builtin-excluded-domains"); + Services.prefs.clearUserPref("network.trr.clear-cache-on-pref-change"); + Services.prefs.clearUserPref("captivedetect.canonicalURL"); Services.prefs.clearUserPref("network.http.spdy.enabled"); Services.prefs.clearUserPref("network.http.spdy.enabled.http2"); @@ -86,7 +99,10 @@ class DNSListener { } onLookupComplete(inRequest, inRecord, inStatus) { - Assert.ok(inRequest == this.request); + Assert.ok( + inRequest == this.request, + "Checking that this is the correct callback" + ); // If we don't expect success here, just resolve and the caller will // decide what to do with the results. @@ -95,9 +111,13 @@ class DNSListener { return; } - Assert.equal(inStatus, Cr.NS_OK); + Assert.equal(inStatus, Cr.NS_OK, "Checking status"); let answer = inRecord.getNextAddrAsString(); - Assert.equal(answer, this.expectedAnswer); + Assert.equal( + answer, + this.expectedAnswer, + `Checking result for ${this.name}` + ); this.resolve([inRequest, inRecord, inStatus]); } @@ -114,6 +134,26 @@ class DNSListener { } } +Cu.importGlobalProperties(["fetch"]); + +add_task(async function test0_nodeExecute() { + // This test checks that moz-http2.js running in node is working. + // This should always be the first test in this file (except for setup) + // otherwise we may encounter random failures when the http2 server is down. + + let env = Cc["@mozilla.org/process/environment;1"].getService( + Ci.nsIEnvironment + ); + let execPort = env.get("MOZNODE_EXEC_PORT"); + await fetch(`http://127.0.0.1:${execPort}/test`) + .then(response => { + ok(true, "NodeServer is working"); + }) + .catch(e => { + ok(false, `There was an error ${e}`); + }); +}); + // verify basic A record add_task(async function test1() { dns.clearCache(true); @@ -138,6 +178,9 @@ add_task(async function test1b() { Services.prefs.setCharPref("network.dns.localDomains", "foo.example.com"); await new DNSListener("bar.example.com", "3.3.3.3"); + + Services.prefs.setCharPref("network.trr.bootstrapAddress", "127.0.0.1"); + Services.prefs.clearUserPref("network.dns.localDomains"); }); // verify that the name was put in cache - it works with bad DNS URI @@ -206,20 +249,118 @@ add_task(async function test5b() { "network.trr.uri", `https://foo.example.com:${h2Port}/404` ); - dump("test5b - resolve push.example.now please\n"); + dump("test5b - resolve push.example.org please\n"); - await new DNSListener("push.example.com", "2018::2018"); + await new DNSListener("push.example.org", "2018::2018"); }); // verify AAAA entry add_task(async function test6() { + Services.prefs.setBoolPref("network.trr.wait-for-A-and-AAAA", true); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", true); // ignored when wait-for-A-and-AAAA is true + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2020&delayIPv4=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2020"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", false); // ignored when wait-for-A-and-AAAA is true + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2030&delayIPv4=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2030"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", true); // ignored when wait-for-A-and-AAAA is true + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2020&delayIPv6=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2020"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", false); // ignored when wait-for-A-and-AAAA is true + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2030&delayIPv6=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2030"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", true); // ignored when wait-for-A-and-AAAA is true + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2020` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2020"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", false); // ignored when wait-for-A-and-AAAA is true + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2030` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2030"); + + Services.prefs.setBoolPref("network.trr.wait-for-A-and-AAAA", false); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref("network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2020&delayIPv4=100`); + await new DNSListener("aaaa.example.com", "2020:2020::2020"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", false); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2030&delayIPv4=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2030"); + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2020&delayIPv6=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2020"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", false); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2030&delayIPv6=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2030"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", true); Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only Services.prefs.setCharPref( "network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2020` ); await new DNSListener("aaaa.example.com", "2020:2020::2020"); + + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.early-AAAA", false); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2020:2020::2030&delayIPv4=100` + ); + await new DNSListener("aaaa.example.com", "2020:2020::2030"); + + Services.prefs.clearUserPref("network.trr.early-AAAA"); + Services.prefs.clearUserPref("network.trr.wait-for-A-and-AAAA"); }); // verify RFC1918 address from the server is rejected @@ -283,7 +424,6 @@ add_task(async function test9() { }); // confirmationNS set without confirmed NS yet -// NOTE: this requires test9 to run before, as the http2 server resets state there add_task(async function test10() { dns.clearCache(true); Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only @@ -291,7 +431,7 @@ add_task(async function test10() { Services.prefs.clearUserPref("network.trr.disable-ECS"); Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns-confirm` + `https://foo.example.com:${h2Port}/doh?responseIP=1::ffff` ); Services.prefs.setCharPref( "network.trr.confirmationNS", @@ -311,20 +451,15 @@ add_task(async function test10() { } catch (e) { await new Promise(resolve => do_timeout(200, resolve)); } -}); -// confirmationNS, retry until the confirmed NS works -add_task(async function test10b() { - dns.clearCache(true); + // confirmationNS, retry until the confirmed NS works let test_loops = 100; print("test confirmationNS, retry until the confirmed NS works"); - Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only - // same URI as in test10 // this test needs to resolve new names in every attempt since the DNS // will keep the negative resolved info while (test_loops > 0) { - print(`loops remaining: ${test_loops}`); + print(`loops remaining: ${test_loops}\n`); try { let [, inRecord, inStatus] = await new DNSListener( `10b-${test_loops}.example.com`, @@ -333,6 +468,8 @@ add_task(async function test10b() { ); if (inRecord) { Assert.equal(inStatus, Cr.NS_OK); + let answer = inRecord.getNextAddrAsString(); + Assert.equal(answer, "1::ffff"); break; } } catch (e) { @@ -354,7 +491,7 @@ add_task(async function test11() { "network.trr.uri", `https://foo.example.com:${h2Port}/dns-750ms` ); - Services.prefs.setIntPref("network.trr.request-timeout", 10); + Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10); let [, , inStatus] = await new DNSListener( "test11.example.com", undefined, @@ -366,16 +503,18 @@ add_task(async function test11() { ); }); -// gets an NS back from DOH +// gets an no answers back from DoH. Falls back to regular DNS add_task(async function test12() { dns.clearCache(true); Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first + Services.prefs.setIntPref("network.trr.request_timeout_ms", 10); Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns-ns` + `https://foo.example.com:${h2Port}/doh?responseIP=none` ); - Services.prefs.clearUserPref("network.trr.request-timeout"); - await new DNSListener("test12.example.com", "127.0.0.1"); + Services.prefs.clearUserPref("network.trr.request_timeout_ms"); + Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms"); + await new DNSListener("confirm.example.com", "127.0.0.1"); }); // TRR-first gets a 404 back from DOH @@ -389,27 +528,42 @@ add_task(async function test13() { await new DNSListener("test13.example.com", "127.0.0.1"); }); -// TRR-shadow gets a 404 back from DOH +// Test that MODE_RESERVED4 (previously MODE_SHADOW) is treated as TRR off. add_task(async function test14() { dns.clearCache(true); - Services.prefs.setIntPref("network.trr.mode", 4); // TRR-shadow + Services.prefs.setIntPref("network.trr.mode", 4); // MODE_RESERVED4. Interpreted as TRR off. Services.prefs.setCharPref( "network.trr.uri", `https://foo.example.com:${h2Port}/404` ); await new DNSListener("test14.example.com", "127.0.0.1"); + + Services.prefs.setIntPref("network.trr.mode", 4); // MODE_RESERVED4. Interpreted as TRR off. + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2` + ); + await new DNSListener("bar.example.com", "127.0.0.1"); }); -// TRR-shadow and timed out TRR +// Test that MODE_RESERVED4 (previously MODE_SHADOW) is treated as TRR off. add_task(async function test15() { dns.clearCache(true); - Services.prefs.setIntPref("network.trr.mode", 4); // TRR-shadow + Services.prefs.setIntPref("network.trr.mode", 4); // MODE_RESERVED4. Interpreted as TRR off. Services.prefs.setCharPref( "network.trr.uri", `https://foo.example.com:${h2Port}/dns-750ms` ); - Services.prefs.setIntPref("network.trr.request-timeout", 10); + Services.prefs.setIntPref("network.trr.request_timeout_ms", 10); + Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10); await new DNSListener("test15.example.com", "127.0.0.1"); + + Services.prefs.setIntPref("network.trr.mode", 4); // MODE_RESERVED4. Interpreted as TRR off. + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2` + ); + await new DNSListener("bar.example.com", "127.0.0.1"); }); // TRR-first and timed out TRR @@ -420,7 +574,8 @@ add_task(async function test16() { "network.trr.uri", `https://foo.example.com:${h2Port}/dns-750ms` ); - Services.prefs.setIntPref("network.trr.request-timeout", 10); + Services.prefs.setIntPref("network.trr.request_timeout_ms", 10); + Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10); await new DNSListener("test16.example.com", "127.0.0.1"); }); @@ -432,7 +587,8 @@ add_task(async function test17() { "network.trr.uri", `https://foo.example.com:${h2Port}/dns-cname` ); - Services.prefs.clearUserPref("network.trr.request-timeout"); + Services.prefs.clearUserPref("network.trr.request_timeout_ms"); + Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms"); await new DNSListener("cname.example.com", "99.88.77.66"); }); @@ -442,7 +598,7 @@ add_task(async function test18() { Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns-cname-loop` + `https://foo.example.com:${h2Port}/doh?responseIP=none&cnameloop=true` ); let [, , inStatus] = await new DNSListener( "test18.example.com", @@ -455,15 +611,22 @@ add_task(async function test18() { ); }); -// TRR-race and a CNAME loop +// Test that MODE_RESERVED1 (previously MODE_PARALLEL) is treated as TRR off. add_task(async function test19() { dns.clearCache(true); - Services.prefs.setIntPref("network.trr.mode", 1); // Race them! + Services.prefs.setIntPref("network.trr.mode", 1); // MODE_RESERVED1. Interpreted as TRR off. Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns-cname-loop` + `https://foo.example.com:${h2Port}/doh?responseIP=none&cnameloop=true` ); await new DNSListener("test19.example.com", "127.0.0.1"); + + Services.prefs.setIntPref("network.trr.mode", 1); // MODE_RESERVED1. Interpreted as TRR off. + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2` + ); + await new DNSListener("bar.example.com", "127.0.0.1"); }); // TRR-first and a CNAME loop @@ -472,20 +635,27 @@ add_task(async function test20() { Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns-cname-loop` + `https://foo.example.com:${h2Port}/doh?responseIP=none&cnameloop=true` ); await new DNSListener("test20.example.com", "127.0.0.1"); }); -// TRR-shadow and a CNAME loop +// Test that MODE_RESERVED4 (previously MODE_SHADOW) is treated as TRR off. add_task(async function test21() { dns.clearCache(true); - Services.prefs.setIntPref("network.trr.mode", 4); // shadow + Services.prefs.setIntPref("network.trr.mode", 4); // MODE_RESERVED4. Interpreted as TRR off. Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns-cname-loop` + `https://foo.example.com:${h2Port}/doh?responseIP=none&cnameloop=true` ); await new DNSListener("test21.example.com", "127.0.0.1"); + + Services.prefs.setIntPref("network.trr.mode", 4); // MODE_RESERVED4. Interpreted as TRR off. + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2` + ); + await new DNSListener("bar.example.com", "127.0.0.1"); }); // verify that basic A record name mismatch gets rejected. @@ -495,7 +665,7 @@ add_task(async function test22() { Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only to avoid native fallback Services.prefs.setCharPref( "network.trr.uri", - `https://foo.example.com:${h2Port}/dns` + `https://foo.example.com:${h2Port}/doh?hostname=bar.example.com` ); let [, , inStatus] = await new DNSListener( "mismatch.example.com", @@ -524,6 +694,7 @@ add_task(async function test24() { dns.clearCache(true); Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first Services.prefs.setCharPref("network.trr.excluded-domains", ""); + Services.prefs.setCharPref("network.trr.builtin-excluded-domains", ""); Services.prefs.setCharPref( "network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192` @@ -545,12 +716,85 @@ add_task(async function test24c() { await new DNSListener("bar.example.com", "127.0.0.1"); }); +// TRR-first check that DNS result is used if domain is part of the excluded-domains pref that contains things before it. +add_task(async function test24d() { + dns.clearCache(true); + Services.prefs.setCharPref( + "network.trr.excluded-domains", + "foo.test.com, bar.example.com" + ); + await new DNSListener("bar.example.com", "127.0.0.1"); +}); + +// TRR-first check that DNS result is used if domain is part of the excluded-domains pref that contains things after it. +add_task(async function test24e() { + dns.clearCache(true); + Services.prefs.setCharPref( + "network.trr.excluded-domains", + "bar.example.com, foo.test.com" + ); + await new DNSListener("bar.example.com", "127.0.0.1"); +}); + +// TRR-first check that captivedetect.canonicalURL is resolved via native DNS +add_task(async function test24f() { + dns.clearCache(true); + Services.prefs.setCharPref( + "captivedetect.canonicalURL", + "http://test.detectportal.com/success.txt" + ); + + await new DNSListener("test.detectportal.com", "127.0.0.1"); +}); + +// TRR-first check that DNS result is used if domain is part of the builtin-excluded-domains pref +add_task(async function test24h() { + dns.clearCache(true); + Services.prefs.setCharPref("network.trr.excluded-domains", ""); + Services.prefs.setCharPref( + "network.trr.builtin-excluded-domains", + "bar.example.com" + ); + await new DNSListener("bar.example.com", "127.0.0.1"); +}); + +// TRR-first check that DNS result is used if domain is part of the builtin-excluded-domains pref +add_task(async function test24i() { + dns.clearCache(true); + Services.prefs.setCharPref( + "network.trr.builtin-excluded-domains", + "example.com" + ); + await new DNSListener("bar.example.com", "127.0.0.1"); +}); + +// TRR-first check that DNS result is used if domain is part of the builtin-excluded-domains pref that contains things before it. +add_task(async function test24j() { + dns.clearCache(true); + Services.prefs.setCharPref( + "network.trr.builtin-excluded-domains", + "foo.test.com, bar.example.com" + ); + await new DNSListener("bar.example.com", "127.0.0.1"); +}); + +// TRR-first check that DNS result is used if domain is part of the builtin-excluded-domains pref that contains things after it. +add_task(async function test24k() { + dns.clearCache(true); + Services.prefs.setCharPref( + "network.trr.builtin-excluded-domains", + "bar.example.com, foo.test.com" + ); + await new DNSListener("bar.example.com", "127.0.0.1"); +}); + // TRR-only that resolving localhost with TRR-only mode will use the remote // resolver if it's not in the excluded domains add_task(async function test25() { dns.clearCache(true); Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only Services.prefs.setCharPref("network.trr.excluded-domains", ""); + Services.prefs.setCharPref("network.trr.builtin-excluded-domains", ""); Services.prefs.setCharPref( "network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192` @@ -600,3 +844,217 @@ add_task(async function test25d() { await new DNSListener("domain.other", "127.0.0.1"); }); + +// TRR-only check that captivedetect.canonicalURL is resolved via native DNS +add_task(async function test25e() { + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref( + "captivedetect.canonicalURL", + "http://test.detectportal.com/success.txt" + ); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192` + ); + + await new DNSListener("test.detectportal.com", "127.0.0.1"); +}); + +// TRR-only check that localhost goes directly to native lookup when in the builtin-excluded-domains +add_task(async function test25g() { + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref("network.trr.excluded-domains", ""); + Services.prefs.setCharPref( + "network.trr.builtin-excluded-domains", + "localhost" + ); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192` + ); + + await new DNSListener("localhost", "127.0.0.1"); +}); + +// TRR-only check that test.local is resolved via native DNS +add_task(async function test25h() { + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref( + "network.trr.builtin-excluded-domains", + "localhost,local" + ); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192` + ); + + await new DNSListener("test.local", "127.0.0.1"); +}); + +// TRR-only check that .other is resolved via native DNS when the pref is set +add_task(async function test25i() { + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref( + "network.trr.builtin-excluded-domains", + "localhost,local,other" + ); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192` + ); + + await new DNSListener("domain.other", "127.0.0.1"); +}); + +// Check that none of the requests have set any cookies. +add_task(async function count_cookies() { + let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager); + Assert.equal(cm.countCookiesFromHost("example.com"), 0); + Assert.equal(cm.countCookiesFromHost("foo.example.com."), 0); +}); + +add_task(async function test_connection_closed() { + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref("network.trr.excluded-domains", ""); + // We don't need to wait for 30 seconds for the request to fail + Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 500); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2` + ); + // bootstrap + Services.prefs.clearUserPref("network.dns.localDomains"); + Services.prefs.setCharPref("network.trr.bootstrapAddress", "127.0.0.1"); + + await new DNSListener("bar.example.com", "2.2.2.2"); + + // makes the TRR connection shut down. + let [, , inStatus] = await new DNSListener("closeme.com", undefined, false); + Assert.ok( + !Components.isSuccessCode(inStatus), + `${inStatus} should be an error code` + ); + await new DNSListener("bar2.example.com", "2.2.2.2"); +}); + +add_task(async function test_connection_closed_no_bootstrap() { + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref("network.trr.excluded-domains", "localhost,local"); + Services.prefs.setCharPref( + "network.trr.uri", + `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3` + ); + Services.prefs.setCharPref("network.dns.localDomains", "foo.example.com"); + Services.prefs.clearUserPref("network.trr.bootstrapAddress"); + + await new DNSListener("bar.example.com", "3.3.3.3"); + + // makes the TRR connection shut down. + let [, , inStatus] = await new DNSListener("closeme.com", undefined, false); + Assert.ok( + !Components.isSuccessCode(inStatus), + `${inStatus} should be an error code` + ); + await new DNSListener("bar2.example.com", "3.3.3.3"); +}); + +add_task(async function test_connection_closed_no_bootstrap_localhost() { + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref("network.trr.excluded-domains", "localhost"); + Services.prefs.setCharPref( + "network.trr.uri", + `https://localhost:${h2Port}/doh?responseIP=3.3.3.3` + ); + Services.prefs.clearUserPref("network.dns.localDomains"); + Services.prefs.clearUserPref("network.trr.bootstrapAddress"); + + await new DNSListener("bar.example.com", "3.3.3.3"); + + // makes the TRR connection shut down. + let [, , inStatus] = await new DNSListener("closeme.com", undefined, false); + Assert.ok( + !Components.isSuccessCode(inStatus), + `${inStatus} should be an error code` + ); + await new DNSListener("bar2.example.com", "3.3.3.3"); +}); + +add_task(async function test_connection_closed_no_bootstrap_no_excluded() { + // This test exists to document what happens when we're in TRR only mode + // and we don't set a bootstrap address. We use DNS to resolve the + // initial URI, but if the connection fails, we don't fallback to DNS + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only + Services.prefs.setCharPref("network.trr.excluded-domains", ""); + Services.prefs.setCharPref("network.trr.builtin-excluded-domains", ""); + Services.prefs.setCharPref( + "network.trr.uri", + `https://localhost:${h2Port}/doh?responseIP=3.3.3.3` + ); + Services.prefs.clearUserPref("network.dns.localDomains"); + Services.prefs.clearUserPref("network.trr.bootstrapAddress"); + + await new DNSListener("bar.example.com", "3.3.3.3"); + + // makes the TRR connection shut down. + let [, , inStatus] = await new DNSListener("closeme.com", undefined, false); + Assert.ok( + !Components.isSuccessCode(inStatus), + `${inStatus} should be an error code` + ); + [, , inStatus] = await new DNSListener("bar2.example.com", undefined, false); + Assert.ok( + !Components.isSuccessCode(inStatus), + `${inStatus} should be an error code` + ); +}); + +add_task(async function test_connection_closed_trr_first() { + // This test exists to document what happens when we're in TRR only mode + // and we don't set a bootstrap address. We use DNS to resolve the + // initial URI, but if the connection fails, we don't fallback to DNS + dns.clearCache(true); + Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first + Services.prefs.setCharPref( + "network.trr.uri", + `https://localhost:${h2Port}/doh?responseIP=9.9.9.9` + ); + Services.prefs.setCharPref("network.dns.localDomains", "closeme.com"); + Services.prefs.clearUserPref("network.trr.bootstrapAddress"); + + await new DNSListener("bar.example.com", "9.9.9.9"); + + // makes the TRR connection shut down. Should fallback to DNS + await new DNSListener("closeme.com", "127.0.0.1"); + // TRR should be back up again + await new DNSListener("bar2.example.com", "9.9.9.9"); +}); + +add_task(async function test_clearCacheOnURIChange() { + dns.clearCache(true); + Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", true); + Services.prefs.setIntPref("network.trr.mode", 2); // TRR-first + Services.prefs.setCharPref( + "network.trr.uri", + `https://localhost:${h2Port}/doh?responseIP=7.7.7.7` + ); + + await new DNSListener("bar.example.com", "7.7.7.7"); + + // The TRR cache should be cleared by this pref change. + Services.prefs.setCharPref( + "network.trr.uri", + `https://localhost:${h2Port}/doh?responseIP=8.8.8.8` + ); + + await new DNSListener("bar.example.com", "8.8.8.8"); + Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", false); +}); + diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index a4c3ee63b4..c96e37e5bb 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -447,11 +447,14 @@ skip-if = os == "android" # DNSv6 issues on android [test_bug1527293.js] [test_stale-while-revalidate_negative.js] [test_stale-while-revalidate_positive.js] +[test_stale-while-revalidate_loop.js] [test_stale-while-revalidate_max-age-0.js] [test_http1-proxy.js] [test_http2-proxy.js] run-sequentially = one http2 node proxy is used for all tests, this test is using global session counter -# so far has to be disabled until we update nodejs to at least 8.4+, then keep off on android (os == "android") -skip-if = true +skip-if = os == "android" [test_head_request_no_response_body.js] [test_disabled_ftp.js] +[test_cache_204_response.js] +[test_node_execute.js] +skip-if = os == "android" # node server doesn't run on android diff --git a/netwerk/url-classifier/UrlClassifierCommon.cpp b/netwerk/url-classifier/UrlClassifierCommon.cpp index a7c4c50766..21496c0f45 100644 --- a/netwerk/url-classifier/UrlClassifierCommon.cpp +++ b/netwerk/url-classifier/UrlClassifierCommon.cpp @@ -40,7 +40,7 @@ bool UrlClassifierCommon::AddonMayLoad(nsIChannel* aChannel, nsIURI* aURI) { // loadingPrincipal is used here to ensure we are loading into an // addon principal. This allows an addon, with explicit permission, to // call out to API endpoints that may otherwise get blocked. - nsIPrincipal* loadingPrincipal = channelLoadInfo->LoadingPrincipal(); + nsIPrincipal* loadingPrincipal = channelLoadInfo->GetLoadingPrincipal(); if (!loadingPrincipal) { return false; } diff --git a/netwerk/wifi/nsIWifiListener.idl b/netwerk/wifi/nsIWifiListener.idl index ffac02654e..49024f405f 100644 --- a/netwerk/wifi/nsIWifiListener.idl +++ b/netwerk/wifi/nsIWifiListener.idl @@ -16,7 +16,7 @@ interface nsIWifiListener : nsISupports * access points in view. */ - void onChange([array, size_is(aLen)] in nsIWifiAccessPoint accessPoints, in unsigned long aLen); + void onChange(in Array accessPoints); /* * Called when there is a problem with listening to wifi diff --git a/netwerk/wifi/nsWifiMonitor.cpp b/netwerk/wifi/nsWifiMonitor.cpp index 5bd2b61cb7..b886c3c318 100644 --- a/netwerk/wifi/nsWifiMonitor.cpp +++ b/netwerk/wifi/nsWifiMonitor.cpp @@ -43,7 +43,7 @@ nsWifiMonitor::Observe(nsISupports* subject, const char* topic, ReentrantMonitorAutoEnter mon(mReentrantMonitor); mKeepGoing = false; - mon.Signal(); + mon.Notify(); mThread = nullptr; } return NS_OK; @@ -81,7 +81,7 @@ NS_IMETHODIMP nsWifiMonitor::StartWatching(nsIWifiListener* aListener) { "nsIWifiListener", aListener))); // tell ourselves that we have a new watcher. - mon.Signal(); + mon.Notify(); return NS_OK; } @@ -104,20 +104,20 @@ NS_IMETHODIMP nsWifiMonitor::StopWatching(nsIWifiListener* aListener) { return NS_OK; } -typedef nsTArray > WifiListenerArray; +typedef nsTArray> WifiListenerArray; class nsPassErrorToWifiListeners final : public nsIRunnable { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIRUNNABLE - nsPassErrorToWifiListeners(nsAutoPtr aListeners, + nsPassErrorToWifiListeners(UniquePtr&& aListeners, nsresult aResult) - : mListeners(aListeners), mResult(aResult) {} + : mListeners(std::move(aListeners)), mResult(aResult) {} private: ~nsPassErrorToWifiListeners() = default; - nsAutoPtr mListeners; + UniquePtr mListeners; nsresult mResult; }; @@ -138,14 +138,14 @@ NS_IMETHODIMP nsWifiMonitor::Run() { LOG(("@@@@@ wifi monitor run::doscan complete %" PRIx32 "\n", static_cast(rv))); - nsAutoPtr currentListeners; + UniquePtr currentListeners; bool doError = false; { ReentrantMonitorAutoEnter mon(mReentrantMonitor); if (mKeepGoing && NS_FAILED(rv)) { doError = true; - currentListeners = new WifiListenerArray(mListeners.Length()); + currentListeners = MakeUnique(mListeners.Length()); for (uint32_t i = 0; i < mListeners.Length(); i++) currentListeners->AppendElement(mListeners[i].mListener); } @@ -157,7 +157,7 @@ NS_IMETHODIMP nsWifiMonitor::Run() { if (!target) return NS_ERROR_UNEXPECTED; nsCOMPtr runnable( - new nsPassErrorToWifiListeners(currentListeners, rv)); + new nsPassErrorToWifiListeners(std::move(currentListeners), rv)); if (!runnable) return NS_ERROR_OUT_OF_MEMORY; target->Dispatch(runnable, NS_DISPATCH_SYNC); @@ -172,23 +172,23 @@ class nsCallWifiListeners final : public nsIRunnable { NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIRUNNABLE - nsCallWifiListeners(nsAutoPtr aListeners, - nsAutoPtr > aAccessPoints) - : mListeners(aListeners), mAccessPoints(aAccessPoints) {} + nsCallWifiListeners(WifiListenerArray&& aListeners, + nsTArray>&& aAccessPoints) + : mListeners(std::move(aListeners)), + mAccessPoints(std::move(aAccessPoints)) {} private: ~nsCallWifiListeners() = default; - nsAutoPtr mListeners; - nsAutoPtr > mAccessPoints; + const WifiListenerArray mListeners; + const nsTArray> mAccessPoints; }; NS_IMPL_ISUPPORTS(nsCallWifiListeners, nsIRunnable) NS_IMETHODIMP nsCallWifiListeners::Run() { LOG(("About to send data to the wifi listeners\n")); - for (size_t i = 0; i < mListeners->Length(); i++) { - (*mListeners)[i]->OnChange(mAccessPoints->Elements(), - mAccessPoints->Length()); + for (auto& listener : mListeners) { + listener->OnChange(mAccessPoints); } return NS_OK; } @@ -196,34 +196,33 @@ NS_IMETHODIMP nsCallWifiListeners::Run() { nsresult nsWifiMonitor::CallWifiListeners( const nsCOMArray& aAccessPoints, bool aAccessPointsChanged) { - nsAutoPtr currentListeners; + WifiListenerArray currentListeners; { ReentrantMonitorAutoEnter mon(mReentrantMonitor); - currentListeners = new WifiListenerArray(mListeners.Length()); + currentListeners.SetCapacity(mListeners.Length()); - for (uint32_t i = 0; i < mListeners.Length(); i++) { - if (!mListeners[i].mHasSentData || aAccessPointsChanged) { - mListeners[i].mHasSentData = true; - currentListeners->AppendElement(mListeners[i].mListener); + for (auto& listener : mListeners) { + if (!listener.mHasSentData || aAccessPointsChanged) { + listener.mHasSentData = true; + currentListeners.AppendElement(listener.mListener); } } } - if (currentListeners->Length() > 0) { + if (!currentListeners.IsEmpty()) { uint32_t resultCount = aAccessPoints.Count(); - nsAutoPtr > accessPoints( - new nsTArray(resultCount)); - if (!accessPoints) return NS_ERROR_OUT_OF_MEMORY; + nsTArray> accessPoints(resultCount); - for (uint32_t i = 0; i < resultCount; i++) - accessPoints->AppendElement(aAccessPoints[i]); + for (uint32_t i = 0; i < resultCount; i++) { + accessPoints.AppendElement(aAccessPoints[i]); + } nsCOMPtr thread = do_GetMainThread(); if (!thread) return NS_ERROR_UNEXPECTED; - nsCOMPtr runnable( - new nsCallWifiListeners(currentListeners, accessPoints)); + nsCOMPtr runnable(new nsCallWifiListeners( + std::move(currentListeners), std::move(accessPoints))); if (!runnable) return NS_ERROR_OUT_OF_MEMORY; thread->Dispatch(runnable, NS_DISPATCH_SYNC); diff --git a/netwerk/wifi/nsWifiMonitor.h b/netwerk/wifi/nsWifiMonitor.h index 59401049c4..645600af33 100644 --- a/netwerk/wifi/nsWifiMonitor.h +++ b/netwerk/wifi/nsWifiMonitor.h @@ -7,7 +7,6 @@ #include "nsIWifiMonitor.h" #include "nsCOMPtr.h" -#include "nsAutoPtr.h" #include "nsProxyRelease.h" #include "nsIThread.h" #include "nsIRunnable.h" @@ -69,7 +68,7 @@ class nsWifiMonitor final : nsIRunnable, nsIWifiMonitor, nsIObserver { mozilla::ReentrantMonitor mReentrantMonitor; #ifdef XP_WIN - nsAutoPtr mWinWifiScanner; + mozilla::UniquePtr mWinWifiScanner; #endif }; diff --git a/netwerk/wifi/nsWifiScannerMac.cpp b/netwerk/wifi/nsWifiScannerMac.cpp index dab1335c43..4b8757fd10 100644 --- a/netwerk/wifi/nsWifiScannerMac.cpp +++ b/netwerk/wifi/nsWifiScannerMac.cpp @@ -8,7 +8,6 @@ #include "osx_wifi.h" -#include "nsAutoPtr.h" #include "nsCOMArray.h" #include "nsWifiMonitor.h" #include "nsWifiAccessPoint.h" diff --git a/netwerk/wifi/nsWifiScannerWin.cpp b/netwerk/wifi/nsWifiScannerWin.cpp index 3fa86fdec8..dba286f516 100644 --- a/netwerk/wifi/nsWifiScannerWin.cpp +++ b/netwerk/wifi/nsWifiScannerWin.cpp @@ -5,7 +5,6 @@ #include "nsWifiMonitor.h" // moz headers (alphabetical) -#include "nsAutoPtr.h" #include "nsCOMArray.h" #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" @@ -26,7 +25,7 @@ using namespace mozilla; */ nsresult nsWifiMonitor::DoScan() { if (!mWinWifiScanner) { - mWinWifiScanner = new WinWifiScanner(); + mWinWifiScanner = MakeUnique(); if (!mWinWifiScanner) { // TODO: Probably return OOM error return NS_ERROR_FAILURE; diff --git a/netwerk/wifi/osx_corewlan.mm b/netwerk/wifi/osx_corewlan.mm index 57b99e15a4..e526d98b9e 100644 --- a/netwerk/wifi/osx_corewlan.mm +++ b/netwerk/wifi/osx_corewlan.mm @@ -12,7 +12,6 @@ #include #include "nsObjCExceptions.h" -#include "nsAutoPtr.h" #include "nsCOMArray.h" #include "nsWifiMonitor.h" #include "nsWifiAccessPoint.h" diff --git a/netwerk/wifi/win_wifiScanner.cpp b/netwerk/wifi/win_wifiScanner.cpp index cc42cd414c..c9ebf4a192 100644 --- a/netwerk/wifi/win_wifiScanner.cpp +++ b/netwerk/wifi/win_wifiScanner.cpp @@ -64,7 +64,7 @@ WinWifiScanner::WinWifiScanner() { // and make our assumption incorrect. We opt to avoid making a bunch of // spurious LoadLibrary calls in the common case rather than load the // WLAN API in the edge case. - mWlanLibrary = WinWLANLibrary::Load(); + mWlanLibrary.reset(WinWLANLibrary::Load()); if (!mWlanLibrary) { NS_WARNING("Could not initialize Windows Wi-Fi scanner"); } @@ -91,7 +91,7 @@ nsresult WinWifiScanner::GetAccessPointsFromWLAN( } // This ensures we call WlanFreeMemory on interface_list - ScopedWLANObject scopedInterfaceList(mWlanLibrary, interface_list); + ScopedWLANObject scopedInterfaceList(*mWlanLibrary, interface_list); if (!interface_list->dwNumberOfItems) { return NS_OK; @@ -145,7 +145,7 @@ nsresult WinWifiScanner::GetAccessPointsFromWLAN( } // This ensures we call WlanFreeMemory on bss_list - ScopedWLANObject scopedBssList(mWlanLibrary, bss_list); + ScopedWLANObject scopedBssList(*mWlanLibrary, bss_list); // Store each discovered access point in our outparam for (int j = 0; j < static_cast(bss_list->dwNumberOfItems); ++j) { diff --git a/netwerk/wifi/win_wifiScanner.h b/netwerk/wifi/win_wifiScanner.h index 8c00a79f9f..d19bda6fc3 100644 --- a/netwerk/wifi/win_wifiScanner.h +++ b/netwerk/wifi/win_wifiScanner.h @@ -5,7 +5,7 @@ #pragma once // Moz headers (alphabetical) -#include "nsAutoPtr.h" +#include "mozilla/UniquePtr.h" #include "nsCOMArray.h" #include "win_wlanLibrary.h" @@ -28,5 +28,5 @@ class WinWifiScanner final { nsresult GetAccessPointsFromWLAN(nsCOMArray& accessPoints); private: - nsAutoPtr mWlanLibrary; + mozilla::UniquePtr mWlanLibrary; }; diff --git a/netwerk/wifi/win_wlanLibrary.h b/netwerk/wifi/win_wlanLibrary.h index c8b422eebc..b8aa71de39 100644 --- a/netwerk/wifi/win_wlanLibrary.h +++ b/netwerk/wifi/win_wlanLibrary.h @@ -41,12 +41,12 @@ class WinWLANLibrary { class ScopedWLANObject { public: - ScopedWLANObject(WinWLANLibrary* library, void* object) + ScopedWLANObject(const WinWLANLibrary& library, void* object) : mLibrary(library), mObject(object) {} - ~ScopedWLANObject() { (*(mLibrary->GetWlanFreeMemoryPtr()))(mObject); } + ~ScopedWLANObject() { (*(mLibrary.GetWlanFreeMemoryPtr()))(mObject); } private: - WinWLANLibrary* mLibrary; + const WinWLANLibrary& mLibrary; void* mObject; };