/* 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/. */ // HttpLog.h should generally be included first #include "HttpLog.h" #include "mozilla/net/SocketProcessChild.h" #include "mozilla/net/SocketProcessParent.h" #include "nsHttpActivityDistributor.h" #include "nsHttpHandler.h" #include "nsCOMPtr.h" #include "nsIOService.h" #include "nsNetUtil.h" #include "nsQueryObject.h" #include "nsThreadUtils.h" #include "NullHttpChannel.h" namespace mozilla { namespace net { typedef nsMainThreadPtrHolder ObserverHolder; typedef nsMainThreadPtrHandle ObserverHandle; NS_IMPL_ISUPPORTS(nsHttpActivityDistributor, nsIHttpActivityDistributor, nsIHttpActivityObserver) nsHttpActivityDistributor::nsHttpActivityDistributor() : mLock("nsHttpActivityDistributor.mLock"), mActivated(false) {} NS_IMETHODIMP nsHttpActivityDistributor::ObserveActivity(nsISupports* aHttpChannel, uint32_t aActivityType, uint32_t aActivitySubtype, PRTime aTimestamp, uint64_t aExtraSizeData, const nsACString& aExtraStringData) { MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread()); for (size_t i = 0; i < mObservers.Length(); i++) { Unused << mObservers[i]->ObserveActivity(aHttpChannel, aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData, aExtraStringData); } return NS_OK; } NS_IMETHODIMP nsHttpActivityDistributor::ObserveActivityWithArgs( const HttpActivityArgs& aArgs, uint32_t aActivityType, uint32_t aActivitySubtype, PRTime aTimestamp, uint64_t aExtraSizeData, const nsACString& aExtraStringData) { HttpActivityArgs args(aArgs); nsCString extraStringData(aExtraStringData); if (XRE_IsSocketProcess()) { auto task = [args{std::move(args)}, aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData, extraStringData{std::move(extraStringData)}]() { SocketProcessChild::GetSingleton()->SendObserveHttpActivity( args, aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData, extraStringData); }; if (!NS_IsMainThread()) { return NS_DispatchToMainThread(NS_NewRunnableFunction( "net::nsHttpActivityDistributor::ObserveActivityWithArgs", task)); } task(); return NS_OK; } MOZ_ASSERT(XRE_IsParentProcess()); RefPtr self = this; auto task = [args{std::move(args)}, aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData, extraStringData{std::move(extraStringData)}, self{std::move(self)}]() { if (args.type() == HttpActivityArgs::Tuint64_t) { nsWeakPtr weakPtr = gHttpHandler->GetWeakHttpChannel(args.get_uint64_t()); if (nsCOMPtr channel = do_QueryReferent(weakPtr)) { Unused << self->ObserveActivity(channel, aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData, extraStringData); } } else if (args.type() == HttpActivityArgs::THttpActivity) { nsCOMPtr uri; nsAutoCString portStr(""_ns); int32_t port = args.get_HttpActivity().port(); bool endToEndSSL = args.get_HttpActivity().endToEndSSL(); if (port != -1 && ((endToEndSSL && port != 443) || (!endToEndSSL && port != 80))) { portStr.AppendInt(port); } nsresult rv = NS_NewURI(getter_AddRefs(uri), (endToEndSSL ? "https://"_ns : "http://"_ns) + args.get_HttpActivity().host() + portStr); if (NS_FAILED(rv)) { return; } RefPtr channel = new NullHttpChannel(); rv = channel->Init(uri, 0, nullptr, 0, nullptr); MOZ_ASSERT(NS_SUCCEEDED(rv)); Unused << self->ObserveActivity( nsCOMPtr(do_QueryObject(channel)), aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData, extraStringData); } }; if (!NS_IsMainThread()) { return NS_DispatchToMainThread(NS_NewRunnableFunction( "net::nsHttpActivityDistributor::ObserveActivityWithArgs", task)); } task(); return NS_OK; } NS_IMETHODIMP nsHttpActivityDistributor::GetIsActive(bool* isActive) { NS_ENSURE_ARG_POINTER(isActive); MutexAutoLock lock(mLock); if (XRE_IsSocketProcess()) { *isActive = mActivated; return NS_OK; } *isActive = !!mObservers.Length(); return NS_OK; } NS_IMETHODIMP nsHttpActivityDistributor::SetIsActive(bool aActived) { MOZ_RELEASE_ASSERT(XRE_IsSocketProcess()); mActivated = aActived; return NS_OK; } NS_IMETHODIMP nsHttpActivityDistributor::AddObserver(nsIHttpActivityObserver* aObserver) { MOZ_ASSERT(XRE_IsParentProcess()); ObserverHandle observer( new ObserverHolder("nsIHttpActivityObserver", aObserver)); bool wasEmpty = false; { MutexAutoLock lock(mLock); wasEmpty = mObservers.IsEmpty(); // XXX(Bug 1631371) Check if this should use a fallible operation as it // pretended earlier. mObservers.AppendElement(observer); } if (nsIOService::UseSocketProcess() && wasEmpty) { auto task = []() { SocketProcessParent* parent = SocketProcessParent::GetSingleton(); if (parent && parent->CanSend()) { Unused << parent->SendOnHttpActivityDistributorActivated(true); } }; gIOService->CallOrWaitForSocketProcess(task); } return NS_OK; } NS_IMETHODIMP nsHttpActivityDistributor::RemoveObserver(nsIHttpActivityObserver* aObserver) { MOZ_ASSERT(XRE_IsParentProcess()); ObserverHandle observer( new ObserverHolder("nsIHttpActivityObserver", aObserver)); bool isEmpty = false; { MutexAutoLock lock(mLock); if (!mObservers.RemoveElement(observer)) return NS_ERROR_FAILURE; isEmpty = mObservers.IsEmpty(); } if (nsIOService::UseSocketProcess() && isEmpty) { auto task = []() { SocketProcessParent* parent = SocketProcessParent::GetSingleton(); if (parent && parent->CanSend()) { Unused << parent->SendOnHttpActivityDistributorActivated(false); } }; gIOService->CallOrWaitForSocketProcess(task); } return NS_OK; } } // namespace net } // namespace mozilla