summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/AlternateServices.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--netwerk/protocol/http/AlternateServices.h271
1 files changed, 271 insertions, 0 deletions
diff --git a/netwerk/protocol/http/AlternateServices.h b/netwerk/protocol/http/AlternateServices.h
new file mode 100644
index 0000000000..4de5a281c0
--- /dev/null
+++ b/netwerk/protocol/http/AlternateServices.h
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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/. */
+
+/*
+Alt-Svc allows separation of transport routing from the origin host without
+using a proxy. See https://httpwg.github.io/http-extensions/alt-svc.html and
+https://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-06
+
+ Nice To Have Future Enhancements::
+ * flush on network change event when we have an indicator
+ * use established https channel for http instead separate of conninfo hash
+ * pin via http-tls header
+ * clear based on origin when a random fail happens not just 421
+ * upon establishment of channel, cancel and retry trans that have not yet
+ written anything
+ * persistent storage (including private browsing filter)
+ * memory reporter for cache, but this is rather tiny
+*/
+
+#ifndef mozilla_net_AlternateServices_h
+#define mozilla_net_AlternateServices_h
+
+#include "nsRefPtrHashtable.h"
+#include "nsString.h"
+#include "nsIDataStorage.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIStreamListener.h"
+#include "nsISpeculativeConnect.h"
+#include "mozilla/BasePrincipal.h"
+#include "SpeculativeTransaction.h"
+
+class nsILoadInfo;
+
+namespace mozilla {
+namespace net {
+
+class nsProxyInfo;
+class nsHttpConnectionInfo;
+class nsHttpTransaction;
+class nsHttpChannel;
+class WellKnownChecker;
+
+class AltSvcMapping {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AltSvcMapping)
+
+ private: // ctor from ProcessHeader
+ AltSvcMapping(nsIDataStorage* storage, int32_t storageEpoch,
+ const nsACString& originScheme, const nsACString& originHost,
+ int32_t originPort, const nsACString& username,
+ bool privateBrowsing, uint32_t expiresAt,
+ const nsACString& alternateHost, int32_t alternatePort,
+ const nsACString& npnToken,
+ const OriginAttributes& originAttributes, bool aIsHttp3);
+
+ public:
+ AltSvcMapping(nsIDataStorage* storage, int32_t storageEpoch,
+ const nsCString& str);
+
+ static void ProcessHeader(
+ const nsCString& buf, const nsCString& originScheme,
+ const nsCString& originHost, int32_t originPort,
+ const nsACString& username, bool privateBrowsing,
+ nsIInterfaceRequestor* callbacks, nsProxyInfo* proxyInfo, uint32_t caps,
+ const OriginAttributes& originAttributes,
+ bool aDontValidate = false); // aDontValidate is only used for testing!
+
+ // AcceptableProxy() decides whether a particular proxy configuration (pi) is
+ // suitable for use with Alt-Svc. No proxy (including a null pi) is suitable.
+ static bool AcceptableProxy(nsProxyInfo* proxyInfo);
+
+ const nsCString& AlternateHost() const { return mAlternateHost; }
+ const nsCString& OriginHost() const { return mOriginHost; }
+ uint32_t OriginPort() const { return mOriginPort; }
+ const nsCString& HashKey() const { return mHashKey; }
+ uint32_t AlternatePort() const { return mAlternatePort; }
+ bool Validated() { return mValidated; }
+ int32_t GetExpiresAt() { return mExpiresAt; }
+ bool RouteEquals(AltSvcMapping* map);
+ bool HTTPS() { return mHttps; }
+
+ void GetConnectionInfo(nsHttpConnectionInfo** outCI, nsProxyInfo* pi,
+ const OriginAttributes& originAttributes);
+
+ int32_t TTL();
+ int32_t StorageEpoch() { return mStorageEpoch; }
+ bool Private() { return mPrivate; }
+
+ void SetValidated(bool val);
+ void SetMixedScheme(bool val);
+ void SetExpiresAt(int32_t val);
+ void SetExpired();
+ void Sync();
+ void SetSyncOnlyOnSuccess(bool aSOOS) { mSyncOnlyOnSuccess = aSOOS; }
+
+ static void MakeHashKey(nsCString& outKey, const nsACString& originScheme,
+ const nsACString& originHost, int32_t originPort,
+ bool privateBrowsing,
+ const OriginAttributes& originAttributes,
+ bool aHttp3);
+
+ bool IsHttp3() { return mIsHttp3; }
+ const nsCString& NPNToken() const { return mNPNToken; }
+
+ private:
+ virtual ~AltSvcMapping() = default;
+ void SyncString(const nsCString& str);
+ nsCOMPtr<nsIDataStorage> mStorage;
+ int32_t mStorageEpoch;
+ void Serialize(nsCString& out);
+
+ nsCString mHashKey;
+
+ // If you change any of these members, update Serialize()
+ nsCString mAlternateHost;
+ int32_t mAlternatePort{-1};
+
+ nsCString mOriginHost;
+ int32_t mOriginPort{-1};
+
+ nsCString mUsername;
+ bool mPrivate{false};
+
+ // alt-svc mappping
+ uint32_t mExpiresAt{0};
+
+ bool mValidated{false};
+ // origin is https://
+ MOZ_INIT_OUTSIDE_CTOR bool mHttps{false};
+ // .wk allows http and https on same con
+ MOZ_INIT_OUTSIDE_CTOR bool mMixedScheme{false};
+
+ nsCString mNPNToken;
+
+ OriginAttributes mOriginAttributes;
+
+ bool mSyncOnlyOnSuccess{false};
+ bool mIsHttp3{false};
+};
+
+class AltSvcOverride : public nsIInterfaceRequestor,
+ public nsISpeculativeConnectionOverrider {
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+ explicit AltSvcOverride(nsIInterfaceRequestor* aRequestor)
+ : mCallbacks(aRequestor) {}
+
+ private:
+ virtual ~AltSvcOverride() = default;
+ nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
+};
+
+class TransactionObserver final : public nsIStreamListener {
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSISTREAMLISTENER
+ NS_DECL_NSIREQUESTOBSERVER
+
+ TransactionObserver(nsHttpChannel* channel, WellKnownChecker* checker);
+ void Complete(bool versionOK, bool authOK, nsresult reason);
+
+ private:
+ friend class WellKnownChecker;
+ virtual ~TransactionObserver() = default;
+
+ nsCOMPtr<nsISupports> mChannelRef;
+ nsHttpChannel* mChannel;
+ WellKnownChecker* mChecker;
+ nsCString mWKResponse;
+
+ bool mRanOnce;
+ bool mStatusOK; // HTTP Status 200
+ // These two values could be accessed on sts thread.
+ Atomic<bool> mAuthOK; // confirmed no TLS failure
+ Atomic<bool> mVersionOK; // connection h2
+};
+
+class AltSvcCache {
+ public:
+ AltSvcCache() = default;
+ virtual ~AltSvcCache() = default;
+ void UpdateAltServiceMapping(
+ AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*,
+ uint32_t caps,
+ const OriginAttributes& originAttributes); // main thread
+ void UpdateAltServiceMappingWithoutValidation(
+ AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*,
+ uint32_t caps,
+ const OriginAttributes& originAttributes); // main thread
+ already_AddRefed<AltSvcMapping> GetAltServiceMapping(
+ const nsACString& scheme, const nsACString& host, int32_t port,
+ bool privateBrowsing, const OriginAttributes& originAttributes,
+ bool aHttp2Allowed, bool aHttp3Allowed);
+ void ClearAltServiceMappings();
+ void ClearHostMapping(const nsACString& host, int32_t port,
+ const OriginAttributes& originAttributes);
+ void ClearHostMapping(nsHttpConnectionInfo* ci);
+ nsIDataStorage* GetStoragePtr() { return mStorage.get(); }
+ int32_t StorageEpoch() { return mStorageEpoch; }
+ nsresult GetAltSvcCacheKeys(nsTArray<nsCString>& value);
+
+ private:
+ void EnsureStorageInited();
+ already_AddRefed<AltSvcMapping> LookupMapping(const nsCString& key,
+ bool privateBrowsing);
+ nsCOMPtr<nsIDataStorage> mStorage;
+ int32_t mStorageEpoch{0};
+};
+
+// This class is used to write the validated result to AltSvcMapping when the
+// AltSvcTransaction is closed and destroyed.
+class AltSvcMappingValidator final {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AltSvcMappingValidator)
+
+ explicit AltSvcMappingValidator(AltSvcMapping* aMap);
+
+ void OnTransactionDestroy(bool aValidateResult);
+
+ void OnTransactionClose(bool aValidateResult);
+
+ protected:
+ virtual ~AltSvcMappingValidator() = default;
+
+ RefPtr<AltSvcMapping> mMapping;
+};
+
+// This is the asynchronous null transaction used to validate
+// an alt-svc advertisement only for https://
+// When http over socket process is enabled, this class should live only in
+// socket process.
+template <class Validator>
+class AltSvcTransaction final : public SpeculativeTransaction {
+ public:
+ AltSvcTransaction(nsHttpConnectionInfo* ci, nsIInterfaceRequestor* callbacks,
+ uint32_t caps, Validator* aValidator, bool aIsHttp3);
+
+ ~AltSvcTransaction() override;
+
+ // AltSvcTransaction is used to validate the alt-svc record, so we don't want
+ // to fetch HTTPS RR for this.
+ virtual nsresult FetchHTTPSRR() override { return NS_ERROR_NOT_IMPLEMENTED; }
+
+ private:
+ // check on alternate route.
+ // also evaluate 'reasonable assurances' for opportunistic security
+ bool MaybeValidate(nsresult reason);
+
+ public:
+ void Close(nsresult reason) override;
+ nsresult ReadSegments(nsAHttpSegmentReader* reader, uint32_t count,
+ uint32_t* countRead) override;
+
+ private:
+ RefPtr<Validator> mValidator;
+ uint32_t mIsHttp3 : 1;
+ uint32_t mRunning : 1;
+ uint32_t mTriedToValidate : 1;
+ uint32_t mTriedToWrite : 1;
+ uint32_t mValidatedResult : 1;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // include guard