diff options
Diffstat (limited to 'netwerk/protocol/http/HSTSPrimerListener.cpp')
-rw-r--r-- | netwerk/protocol/http/HSTSPrimerListener.cpp | 273 |
1 files changed, 0 insertions, 273 deletions
diff --git a/netwerk/protocol/http/HSTSPrimerListener.cpp b/netwerk/protocol/http/HSTSPrimerListener.cpp deleted file mode 100644 index 8c9d28d36..000000000 --- a/netwerk/protocol/http/HSTSPrimerListener.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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 "nsHttp.h" - -#include "HSTSPrimerListener.h" -#include "nsIHstsPrimingCallback.h" -#include "nsIPrincipal.h" -#include "nsSecurityHeaderParser.h" -#include "nsISiteSecurityService.h" -#include "nsISocketProvider.h" -#include "nsISSLStatus.h" -#include "nsISSLStatusProvider.h" -#include "nsStreamUtils.h" -#include "nsHttpChannel.h" -#include "LoadInfo.h" - -namespace mozilla { -namespace net { - -using namespace mozilla; - -NS_IMPL_ISUPPORTS(HSTSPrimingListener, nsIStreamListener, - nsIRequestObserver, nsIInterfaceRequestor) - -NS_IMETHODIMP -HSTSPrimingListener::GetInterface(const nsIID & aIID, void **aResult) -{ - return QueryInterface(aIID, aResult); -} - -NS_IMETHODIMP -HSTSPrimingListener::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) -{ - nsresult primingResult = CheckHSTSPrimingRequestStatus(aRequest); - nsCOMPtr<nsIHstsPrimingCallback> callback(mCallback); - mCallback = nullptr; - - nsCOMPtr<nsITimedChannel> timingChannel = - do_QueryInterface(callback); - if (timingChannel) { - TimeStamp channelCreationTime; - nsresult rv = timingChannel->GetChannelCreation(&channelCreationTime); - if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) { - PRUint32 interval = - (PRUint32) (TimeStamp::Now() - channelCreationTime).ToMilliseconds(); - Telemetry::Accumulate(Telemetry::HSTS_PRIMING_REQUEST_DURATION, - (NS_SUCCEEDED(primingResult)) ? NS_LITERAL_CSTRING("success") - : NS_LITERAL_CSTRING("failure"), - interval); - } - } - - if (NS_FAILED(primingResult)) { - LOG(("HSTS Priming Failed (request was not approved)")); - return callback->OnHSTSPrimingFailed(primingResult, false); - } - - LOG(("HSTS Priming Succeeded (request was approved)")); - return callback->OnHSTSPrimingSucceeded(false); -} - -NS_IMETHODIMP -HSTSPrimingListener::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aStatus) -{ - return NS_OK; -} - -nsresult -HSTSPrimingListener::CheckHSTSPrimingRequestStatus(nsIRequest* aRequest) -{ - nsresult status; - nsresult rv = aRequest->GetStatus(&status); - NS_ENSURE_SUCCESS(rv, rv); - if (NS_FAILED(status)) { - return NS_ERROR_CONTENT_BLOCKED; - } - - // Test that things worked on a HTTP level - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest); - NS_ENSURE_STATE(httpChannel); - nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest); - NS_ENSURE_STATE(internal); - - bool succeedded; - rv = httpChannel->GetRequestSucceeded(&succeedded); - if (NS_FAILED(rv) || !succeedded) { - // If the request did not return a 2XX response, don't process it - return NS_ERROR_CONTENT_BLOCKED; - } - - bool synthesized = false; - nsHttpChannel* rawHttpChannel = static_cast<nsHttpChannel*>(httpChannel.get()); - rv = rawHttpChannel->GetResponseSynthesized(&synthesized); - NS_ENSURE_SUCCESS(rv, rv); - if (synthesized) { - // Don't consider synthesized responses - return NS_ERROR_CONTENT_BLOCKED; - } - - // check to see if the HSTS cache was updated - nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIURI> uri; - rv = httpChannel->GetURI(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(uri, NS_ERROR_CONTENT_BLOCKED); - - bool hsts; - rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, nullptr, &hsts); - NS_ENSURE_SUCCESS(rv, rv); - - if (hsts) { - // An HSTS upgrade was found - return NS_OK; - } - - // There is no HSTS upgrade available - return NS_ERROR_CONTENT_BLOCKED; -} - -/** nsIStreamListener methods **/ - -NS_IMETHODIMP -HSTSPrimingListener::OnDataAvailable(nsIRequest *aRequest, - nsISupports *ctxt, - nsIInputStream *inStr, - uint64_t sourceOffset, - uint32_t count) -{ - uint32_t totalRead; - return inStr->ReadSegments(NS_DiscardSegment, nullptr, count, &totalRead); -} - -// static -nsresult -HSTSPrimingListener::StartHSTSPriming(nsIChannel* aRequestChannel, - nsIHstsPrimingCallback* aCallback) -{ - - nsCOMPtr<nsIURI> finalChannelURI; - nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(finalChannelURI)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIURI> uri; - rv = NS_GetSecureUpgradedURI(finalChannelURI, getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv,rv); - - // check the HSTS cache - bool hsts; - bool cached; - nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, &cached, &hsts); - NS_ENSURE_SUCCESS(rv, rv); - - if (hsts) { - // already saw this host and will upgrade if allowed by preferences - return aCallback->OnHSTSPrimingSucceeded(true); - } - - if (cached) { - // there is a non-expired entry in the cache that doesn't allow us to - // upgrade, so go ahead and fail early. - return aCallback->OnHSTSPrimingFailed(NS_ERROR_CONTENT_BLOCKED, true); - } - - // Either it wasn't cached or the cached result has expired. Build a - // channel for the HEAD request. - - nsCOMPtr<nsILoadInfo> originalLoadInfo = aRequestChannel->GetLoadInfo(); - MOZ_ASSERT(originalLoadInfo, "can not perform HSTS priming without a loadInfo"); - if (!originalLoadInfo) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr<nsILoadInfo> loadInfo = static_cast<mozilla::LoadInfo*> - (originalLoadInfo.get())->CloneForNewRequest(); - - // the LoadInfo must have a security flag set in order to pass through priming - // if none of these security flags are set, go ahead and fail now instead of - // crashing in nsContentSecurityManager::ValidateSecurityFlags - nsSecurityFlags securityMode = loadInfo->GetSecurityMode(); - if (securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS && - securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED && - securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS && - securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL && - securityMode != nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) { - return aCallback->OnHSTSPrimingFailed(NS_ERROR_CONTENT_BLOCKED, true); - } - - nsCOMPtr<nsILoadGroup> loadGroup; - rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup)); - NS_ENSURE_SUCCESS(rv, rv); - - nsLoadFlags loadFlags; - rv = aRequestChannel->GetLoadFlags(&loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - - loadFlags &= HttpBaseChannel::INHIBIT_CACHING | - HttpBaseChannel::INHIBIT_PERSISTENT_CACHING | - HttpBaseChannel::LOAD_BYPASS_CACHE | - HttpBaseChannel::LOAD_FROM_CACHE | - HttpBaseChannel::VALIDATE_ALWAYS; - // Priming requests should never be intercepted by service workers and - // are always anonymous. - loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER | - nsIRequest::LOAD_ANONYMOUS; - - // Create a new channel to send the priming request - nsCOMPtr<nsIChannel> primingChannel; - rv = NS_NewChannelInternal(getter_AddRefs(primingChannel), - uri, - loadInfo, - loadGroup, - nullptr, // aCallbacks are set later - loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - - // Set method and headers - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(primingChannel); - if (!httpChannel) { - NS_ERROR("HSTSPrimingListener: Failed to QI to nsIHttpChannel!"); - return NS_ERROR_FAILURE; - } - - // Currently using HEAD per the draft, but under discussion to change to GET - // with credentials so if the upgrade is approved the result is already cached. - rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD")); - NS_ENSURE_SUCCESS(rv, rv); - - rv = httpChannel-> - SetRequestHeader(NS_LITERAL_CSTRING("Upgrade-Insecure-Requests"), - NS_LITERAL_CSTRING("1"), false); - NS_ENSURE_SUCCESS(rv, rv); - - // attempt to set the class of service flags on the new channel - nsCOMPtr<nsIClassOfService> requestClass = do_QueryInterface(aRequestChannel); - if (!requestClass) { - NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService"); - return NS_ERROR_FAILURE; - } - nsCOMPtr<nsIClassOfService> primingClass = do_QueryInterface(httpChannel); - if (!primingClass) { - NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService"); - return NS_ERROR_FAILURE; - } - - uint32_t classFlags = 0; - rv = requestClass ->GetClassFlags(&classFlags); - NS_ENSURE_SUCCESS(rv, rv); - rv = primingClass->SetClassFlags(classFlags); - NS_ENSURE_SUCCESS(rv, rv); - - // Set up listener which will start the original channel - nsCOMPtr<nsIStreamListener> primingListener(new HSTSPrimingListener(aCallback)); - - // Start priming - rv = primingChannel->AsyncOpen2(primingListener); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -} // namespace net -} // namespace mozilla |