diff options
Diffstat (limited to 'netwerk/protocol/http/InterceptedChannel.cpp')
-rw-r--r-- | netwerk/protocol/http/InterceptedChannel.cpp | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/netwerk/protocol/http/InterceptedChannel.cpp b/netwerk/protocol/http/InterceptedChannel.cpp new file mode 100644 index 0000000000..09a0f701ee --- /dev/null +++ b/netwerk/protocol/http/InterceptedChannel.cpp @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: -*- */ +/* vim:set expandtab ts=2 sw=2 sts=2 cin: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "HttpLog.h" + +#include "InterceptedChannel.h" +#include "nsInputStreamPump.h" +#include "nsITimedChannel.h" +#include "nsHttpChannel.h" +#include "HttpChannelChild.h" +#include "nsHttpResponseHead.h" +#include "nsNetUtil.h" +#include "mozilla/ConsoleReportCollector.h" +#include "mozilla/dom/ChannelInfo.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace net { + +extern nsresult DoUpdateExpirationTime(nsHttpChannel* aSelf, + nsICacheEntry* aCacheEntry, + nsHttpResponseHead* aResponseHead, + uint32_t& aExpirationTime); +extern nsresult DoAddCacheEntryHeaders(nsHttpChannel* self, + nsICacheEntry* entry, + nsHttpRequestHead* requestHead, + nsHttpResponseHead* responseHead, + nsISupports* securityInfo); + +NS_IMPL_ISUPPORTS(InterceptedChannelBase, nsIInterceptedChannel) + +InterceptedChannelBase::InterceptedChannelBase( + nsINetworkInterceptController* aController) + : mController(aController), + mReportCollector(new ConsoleReportCollector()), + mClosed(false), + mSynthesizedOrReset(Invalid) {} + +void InterceptedChannelBase::EnsureSynthesizedResponse() { + if (mSynthesizedResponseHead.isNothing()) { + mSynthesizedResponseHead.emplace(new nsHttpResponseHead()); + } +} + +void InterceptedChannelBase::DoNotifyController() { + nsresult rv = NS_OK; + + if (NS_WARN_IF(!mController)) { + rv = ResetInterception(); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to resume intercepted network request"); + CancelInterception(rv); + } + return; + } + + rv = mController->ChannelIntercepted(this); + if (NS_WARN_IF(NS_FAILED(rv))) { + rv = ResetInterception(); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to resume intercepted network request"); + CancelInterception(rv); + } + } + mController = nullptr; +} + +void InterceptedChannelBase::DoSynthesizeStatus(uint16_t aStatus, + const nsACString& aReason) { + EnsureSynthesizedResponse(); + + // Always assume HTTP 1.1 for synthesized responses. + nsAutoCString statusLine; + statusLine.AppendLiteral("HTTP/1.1 "); + statusLine.AppendInt(aStatus); + statusLine.AppendLiteral(" "); + statusLine.Append(aReason); + + (*mSynthesizedResponseHead)->ParseStatusLine(statusLine); +} + +nsresult InterceptedChannelBase::DoSynthesizeHeader(const nsACString& aName, + const nsACString& aValue) { + EnsureSynthesizedResponse(); + + nsAutoCString header = aName + ": "_ns + aValue; + // Overwrite any existing header. + return (*mSynthesizedResponseHead)->ParseHeaderLine(header); +} + +NS_IMETHODIMP +InterceptedChannelBase::GetConsoleReportCollector( + nsIConsoleReportCollector** aCollectorOut) { + MOZ_ASSERT(aCollectorOut); + nsCOMPtr<nsIConsoleReportCollector> ref = mReportCollector; + ref.forget(aCollectorOut); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedChannelBase::SetReleaseHandle(nsISupports* aHandle) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mReleaseHandle); + MOZ_ASSERT(aHandle); + + // We need to keep it and mChannel alive until destructor clear it up. + mReleaseHandle = aHandle; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedChannelBase::SaveTimeStamps() { + MOZ_ASSERT(NS_IsMainThread()); + + // If we were not able to start the fetch event for some reason (like + // corrupted scripts), then just do nothing here. + if (mHandleFetchEventStart.IsNull()) { + return NS_OK; + } + + nsCOMPtr<nsIChannel> underlyingChannel; + nsresult rv = GetChannel(getter_AddRefs(underlyingChannel)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(underlyingChannel); + MOZ_ASSERT(timedChannel); + + rv = timedChannel->SetLaunchServiceWorkerStart(mLaunchServiceWorkerStart); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + rv = timedChannel->SetLaunchServiceWorkerEnd(mLaunchServiceWorkerEnd); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + rv = timedChannel->SetDispatchFetchEventStart(mDispatchFetchEventStart); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + rv = timedChannel->SetDispatchFetchEventEnd(mDispatchFetchEventEnd); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + rv = timedChannel->SetHandleFetchEventStart(mHandleFetchEventStart); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + rv = timedChannel->SetHandleFetchEventEnd(mHandleFetchEventEnd); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + nsCOMPtr<nsIChannel> channel; + GetChannel(getter_AddRefs(channel)); + if (NS_WARN_IF(!channel)) { + return NS_ERROR_FAILURE; + } + + bool isNonSubresourceRequest = + nsContentUtils::IsNonSubresourceRequest(channel); + nsCString navigationOrSubresource = + isNonSubresourceRequest ? "navigation"_ns : "subresource"_ns; + + nsAutoCString subresourceKey(""_ns); + GetSubresourceTimeStampKey(channel, subresourceKey); + + // We may have null timestamps if the fetch dispatch runnable was cancelled + // and we defaulted to resuming the request. + if (!mFinishResponseStart.IsNull() && !mFinishResponseEnd.IsNull()) { + MOZ_ASSERT(mSynthesizedOrReset != Invalid); + + Telemetry::HistogramID id = + (mSynthesizedOrReset == Synthesized) + ? Telemetry:: + SERVICE_WORKER_FETCH_EVENT_FINISH_SYNTHESIZED_RESPONSE_MS + : Telemetry::SERVICE_WORKER_FETCH_EVENT_CHANNEL_RESET_MS; + Telemetry::Accumulate( + id, navigationOrSubresource, + static_cast<uint32_t>( + (mFinishResponseEnd - mFinishResponseStart).ToMilliseconds())); + if (!isNonSubresourceRequest && !subresourceKey.IsEmpty()) { + Telemetry::Accumulate( + id, subresourceKey, + static_cast<uint32_t>( + (mFinishResponseEnd - mFinishResponseStart).ToMilliseconds())); + } + } + + Telemetry::Accumulate( + Telemetry::SERVICE_WORKER_FETCH_EVENT_DISPATCH_MS, + navigationOrSubresource, + static_cast<uint32_t>((mHandleFetchEventStart - mDispatchFetchEventStart) + .ToMilliseconds())); + + if (!isNonSubresourceRequest && !subresourceKey.IsEmpty()) { + Telemetry::Accumulate(Telemetry::SERVICE_WORKER_FETCH_EVENT_DISPATCH_MS, + subresourceKey, + static_cast<uint32_t>((mHandleFetchEventStart - + mDispatchFetchEventStart) + .ToMilliseconds())); + } + + if (!mFinishResponseEnd.IsNull()) { + Telemetry::Accumulate( + Telemetry::SERVICE_WORKER_FETCH_INTERCEPTION_DURATION_MS, + navigationOrSubresource, + static_cast<uint32_t>( + (mFinishResponseEnd - mDispatchFetchEventStart).ToMilliseconds())); + if (!isNonSubresourceRequest && !subresourceKey.IsEmpty()) { + Telemetry::Accumulate( + Telemetry::SERVICE_WORKER_FETCH_INTERCEPTION_DURATION_MS, + subresourceKey, + static_cast<uint32_t>((mFinishResponseEnd - mDispatchFetchEventStart) + .ToMilliseconds())); + } + } + + return rv; +} + +/* static */ +already_AddRefed<nsIURI> InterceptedChannelBase::SecureUpgradeChannelURI( + nsIChannel* aChannel) { + nsCOMPtr<nsIURI> uri; + nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, nullptr); + + nsCOMPtr<nsIURI> upgradedURI; + rv = NS_GetSecureUpgradedURI(uri, getter_AddRefs(upgradedURI)); + NS_ENSURE_SUCCESS(rv, nullptr); + + return upgradedURI.forget(); +} + +} // namespace net +} // namespace mozilla |