diff options
Diffstat (limited to 'netwerk/protocol/http/nsHttpActivityDistributor.cpp')
-rw-r--r-- | netwerk/protocol/http/nsHttpActivityDistributor.cpp | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/netwerk/protocol/http/nsHttpActivityDistributor.cpp b/netwerk/protocol/http/nsHttpActivityDistributor.cpp new file mode 100644 index 0000000000..702ecfa713 --- /dev/null +++ b/netwerk/protocol/http/nsHttpActivityDistributor.cpp @@ -0,0 +1,198 @@ +/* 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<nsIHttpActivityObserver> ObserverHolder; +typedef nsMainThreadPtrHandle<nsIHttpActivityObserver> 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<nsHttpActivityDistributor> 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<nsIHttpChannel> channel = do_QueryReferent(weakPtr)) { + Unused << self->ObserveActivity(channel, aActivityType, + aActivitySubtype, aTimestamp, + aExtraSizeData, extraStringData); + } + } else if (args.type() == HttpActivityArgs::THttpActivity) { + nsCOMPtr<nsIURI> 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<NullHttpChannel> channel = new NullHttpChannel(); + rv = channel->Init(uri, 0, nullptr, 0, nullptr); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + Unused << self->ObserveActivity( + nsCOMPtr<nsISupports>(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 |