AlternateServices.h (9449B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 ts=8 et tw=80 : */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 Alt-Svc allows separation of transport routing from the origin host without 9 using a proxy. See https://httpwg.github.io/http-extensions/alt-svc.html and 10 https://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-06 11 12 Nice To Have Future Enhancements:: 13 * flush on network change event when we have an indicator 14 * use established https channel for http instead separate of conninfo hash 15 * pin via http-tls header 16 * clear based on origin when a random fail happens not just 421 17 * upon establishment of channel, cancel and retry trans that have not yet 18 written anything 19 * persistent storage (including private browsing filter) 20 * memory reporter for cache, but this is rather tiny 21 */ 22 23 #ifndef mozilla_net_AlternateServices_h 24 #define mozilla_net_AlternateServices_h 25 26 #include "nsHttp.h" 27 #include "nsRefPtrHashtable.h" 28 #include "nsString.h" 29 #include "nsIDataStorage.h" 30 #include "nsIInterfaceRequestor.h" 31 #include "nsIStreamListener.h" 32 #include "nsISpeculativeConnect.h" 33 #include "mozilla/BasePrincipal.h" 34 #include "SpeculativeTransaction.h" 35 36 class nsILoadInfo; 37 38 namespace mozilla { 39 namespace net { 40 41 class nsProxyInfo; 42 class nsHttpConnectionInfo; 43 class nsHttpTransaction; 44 class nsHttpChannel; 45 class WellKnownChecker; 46 47 class AltSvcMapping { 48 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AltSvcMapping) 49 50 private: // ctor from ProcessHeader 51 AltSvcMapping(nsIDataStorage* storage, int32_t storageEpoch, 52 const nsACString& originScheme, const nsACString& originHost, 53 int32_t originPort, const nsACString& username, 54 bool privateBrowsing, uint32_t expiresAt, 55 const nsACString& alternateHost, int32_t alternatePort, 56 const nsACString& npnToken, 57 const OriginAttributes& originAttributes, bool aIsHttp3, 58 SupportedAlpnRank aRank); 59 60 public: 61 AltSvcMapping(nsIDataStorage* storage, int32_t storageEpoch, 62 const nsCString& str); 63 64 static void ProcessHeader( 65 const nsCString& buf, const nsCString& originScheme, 66 const nsCString& originHost, int32_t originPort, 67 const nsACString& username, bool privateBrowsing, 68 nsIInterfaceRequestor* callbacks, nsProxyInfo* proxyInfo, uint32_t caps, 69 const OriginAttributes& originAttributes, 70 nsHttpConnectionInfo* aTransConnInfo, 71 bool aDontValidate = false); // aDontValidate is only used for testing! 72 73 // AcceptableProxy() decides whether a particular proxy configuration (pi) is 74 // suitable for use with Alt-Svc. No proxy (including a null pi) is suitable. 75 static bool AcceptableProxy(nsProxyInfo* proxyInfo); 76 77 const nsCString& AlternateHost() const { return mAlternateHost; } 78 const nsCString& OriginHost() const { return mOriginHost; } 79 uint32_t OriginPort() const { return mOriginPort; } 80 const nsCString& HashKey() const { return mHashKey; } 81 uint32_t AlternatePort() const { return mAlternatePort; } 82 bool Validated() { return mValidated; } 83 int32_t GetExpiresAt() { return mExpiresAt; } 84 bool RouteEquals(AltSvcMapping* map); 85 bool HTTPS() { return mHttps; } 86 87 void GetConnectionInfo(nsHttpConnectionInfo** outCI, nsProxyInfo* pi, 88 const OriginAttributes& originAttributes); 89 90 int32_t TTL(); 91 int32_t StorageEpoch() { return mStorageEpoch; } 92 bool Private() { return mPrivate; } 93 94 void SetValidated(bool val); 95 void SetMixedScheme(bool val); 96 void SetExpiresAt(int32_t val); 97 void SetExpired(); 98 void Sync(); 99 void SetSyncOnlyOnSuccess(bool aSOOS) { mSyncOnlyOnSuccess = aSOOS; } 100 101 static void MakeHashKey(nsCString& outKey, const nsACString& originScheme, 102 const nsACString& originHost, int32_t originPort, 103 bool privateBrowsing, 104 const OriginAttributes& originAttributes, 105 bool aHttp3); 106 107 bool IsHttp3() { return mIsHttp3; } 108 const nsCString& NPNToken() const { return mNPNToken; } 109 SupportedAlpnRank AlpnRank() const { return mAlpnRank; } 110 111 private: 112 virtual ~AltSvcMapping() = default; 113 void SyncString(const nsCString& str); 114 nsCOMPtr<nsIDataStorage> mStorage; 115 int32_t mStorageEpoch; 116 void Serialize(nsCString& out); 117 118 nsCString mHashKey; 119 120 // If you change any of these members, update Serialize() 121 nsCString mAlternateHost; 122 int32_t mAlternatePort{-1}; 123 124 nsCString mOriginHost; 125 int32_t mOriginPort{-1}; 126 127 nsCString mUsername; 128 bool mPrivate{false}; 129 130 // alt-svc mappping 131 uint32_t mExpiresAt{0}; 132 133 bool mValidated{false}; 134 // origin is https:// 135 MOZ_INIT_OUTSIDE_CTOR bool mHttps{false}; 136 // .wk allows http and https on same con 137 MOZ_INIT_OUTSIDE_CTOR bool mMixedScheme{false}; 138 139 nsCString mNPNToken; 140 141 OriginAttributes mOriginAttributes; 142 143 bool mSyncOnlyOnSuccess{false}; 144 bool mIsHttp3{false}; 145 SupportedAlpnRank mAlpnRank{SupportedAlpnRank::NOT_SUPPORTED}; 146 }; 147 148 class AltSvcOverride : public nsIInterfaceRequestor, 149 public nsISpeculativeConnectionOverrider { 150 public: 151 NS_DECL_THREADSAFE_ISUPPORTS 152 NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER 153 NS_DECL_NSIINTERFACEREQUESTOR 154 155 explicit AltSvcOverride(nsIInterfaceRequestor* aRequestor) 156 : mCallbacks(aRequestor) {} 157 158 private: 159 virtual ~AltSvcOverride() = default; 160 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; 161 }; 162 163 class TransactionObserver final : public nsIStreamListener { 164 public: 165 NS_DECL_THREADSAFE_ISUPPORTS 166 NS_DECL_NSISTREAMLISTENER 167 NS_DECL_NSIREQUESTOBSERVER 168 169 TransactionObserver(nsHttpChannel* channel, WellKnownChecker* checker); 170 void Complete(bool versionOK, bool authOK, nsresult reason); 171 172 private: 173 friend class WellKnownChecker; 174 virtual ~TransactionObserver() = default; 175 176 nsCOMPtr<nsISupports> mChannelRef; 177 nsHttpChannel* mChannel; 178 WellKnownChecker* mChecker; 179 nsCString mWKResponse; 180 181 bool mRanOnce; 182 bool mStatusOK; // HTTP Status 200 183 // These two values could be accessed on sts thread. 184 Atomic<bool> mAuthOK; // confirmed no TLS failure 185 Atomic<bool> mVersionOK; // connection h2 186 }; 187 188 class AltSvcCache { 189 public: 190 AltSvcCache() = default; 191 virtual ~AltSvcCache() = default; 192 void UpdateAltServiceMapping( 193 AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*, 194 uint32_t caps, 195 const OriginAttributes& originAttributes); // main thread 196 void UpdateAltServiceMappingWithoutValidation( 197 AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*, 198 uint32_t caps, 199 const OriginAttributes& originAttributes); // main thread 200 already_AddRefed<AltSvcMapping> GetAltServiceMapping( 201 const nsACString& scheme, const nsACString& host, int32_t port, 202 bool privateBrowsing, const OriginAttributes& originAttributes, 203 bool aHttp2Allowed, bool aHttp3Allowed); 204 void ClearAltServiceMappings(); 205 void ClearHostMapping(const nsACString& host, int32_t port, 206 const OriginAttributes& originAttributes); 207 void ClearHostMapping(nsHttpConnectionInfo* ci); 208 nsIDataStorage* GetStoragePtr() { return mStorage.get(); } 209 int32_t StorageEpoch() { return mStorageEpoch; } 210 nsresult GetAltSvcCacheKeys(nsTArray<nsCString>& value); 211 212 private: 213 void EnsureStorageInited(); 214 already_AddRefed<AltSvcMapping> LookupMapping(const nsCString& key, 215 bool privateBrowsing); 216 nsCOMPtr<nsIDataStorage> mStorage; 217 int32_t mStorageEpoch{0}; 218 }; 219 220 // This class is used to write the validated result to AltSvcMapping when the 221 // AltSvcTransaction is closed and destroyed. 222 class AltSvcMappingValidator final { 223 public: 224 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AltSvcMappingValidator) 225 226 explicit AltSvcMappingValidator(AltSvcMapping* aMap); 227 228 void OnTransactionDestroy(bool aValidateResult); 229 230 void OnTransactionClose(bool aValidateResult); 231 232 protected: 233 virtual ~AltSvcMappingValidator() = default; 234 235 RefPtr<AltSvcMapping> mMapping; 236 }; 237 238 // This is the asynchronous null transaction used to validate 239 // an alt-svc advertisement only for https:// 240 // When http over socket process is enabled, this class should live only in 241 // socket process. 242 template <class Validator> 243 class AltSvcTransaction final : public SpeculativeTransaction { 244 public: 245 AltSvcTransaction(nsHttpConnectionInfo* ci, nsIInterfaceRequestor* callbacks, 246 uint32_t caps, Validator* aValidator, bool aIsHttp3); 247 248 ~AltSvcTransaction() override; 249 250 // AltSvcTransaction is used to validate the alt-svc record, so we don't want 251 // to fetch HTTPS RR for this. 252 virtual nsresult FetchHTTPSRR() override { return NS_ERROR_NOT_IMPLEMENTED; } 253 254 private: 255 // check on alternate route. 256 // also evaluate 'reasonable assurances' for opportunistic security 257 bool MaybeValidate(nsresult reason); 258 259 public: 260 void Close(nsresult reason) override; 261 nsresult ReadSegments(nsAHttpSegmentReader* reader, uint32_t count, 262 uint32_t* countRead) override; 263 264 private: 265 RefPtr<Validator> mValidator; 266 uint32_t mIsHttp3 : 1; 267 uint32_t mRunning : 1; 268 uint32_t mTriedToValidate : 1; 269 uint32_t mTriedToWrite : 1; 270 uint32_t mValidatedResult : 1; 271 }; 272 273 } // namespace net 274 } // namespace mozilla 275 276 #endif // include guard