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 "mozilla/DataStorage.h" 27 #include "nsRefPtrHashtable.h" 28 #include "nsString.h" 29 #include "nsIInterfaceRequestor.h" 30 #include "nsIStreamListener.h" 31 #include "nsISpeculativeConnect.h" 32 #include "mozilla/BasePrincipal.h" 33 #include "SpeculativeTransaction.h" 34 35 class nsILoadInfo; 36 37 namespace mozilla { 38 namespace net { 39 40 class nsProxyInfo; 41 class nsHttpConnectionInfo; 42 class nsHttpTransaction; 43 class nsHttpChannel; 44 class WellKnownChecker; 45 46 class AltSvcMapping { 47 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AltSvcMapping) 48 49 private: // ctor from ProcessHeader 50 AltSvcMapping(DataStorage* storage, int32_t storageEpoch, 51 const nsACString& originScheme, const nsACString& originHost, 52 int32_t originPort, const nsACString& username, 53 bool privateBrowsing, uint32_t expiresAt, 54 const nsACString& alternateHost, int32_t alternatePort, 55 const nsACString& npnToken, 56 const OriginAttributes& originAttributes, bool aIsHttp3); 57 58 public: 59 AltSvcMapping(DataStorage* storage, int32_t storageEpoch, 60 const nsCString& str); 61 62 static void ProcessHeader( 63 const nsCString& buf, const nsCString& originScheme, 64 const nsCString& originHost, int32_t originPort, 65 const nsACString& username, bool privateBrowsing, 66 nsIInterfaceRequestor* callbacks, nsProxyInfo* proxyInfo, uint32_t caps, 67 const OriginAttributes& originAttributes, 68 bool aDontValidate = false); // aDontValidate is only used for testing! 69 70 // AcceptableProxy() decides whether a particular proxy configuration (pi) is 71 // suitable for use with Alt-Svc. No proxy (including a null pi) is suitable. 72 static bool AcceptableProxy(nsProxyInfo* proxyInfo); 73 AlternateHost()74 const nsCString& AlternateHost() const { return mAlternateHost; } OriginHost()75 const nsCString& OriginHost() const { return mOriginHost; } OriginPort()76 uint32_t OriginPort() const { return mOriginPort; } HashKey()77 const nsCString& HashKey() const { return mHashKey; } AlternatePort()78 uint32_t AlternatePort() const { return mAlternatePort; } Validated()79 bool Validated() { return mValidated; } GetExpiresAt()80 int32_t GetExpiresAt() { return mExpiresAt; } 81 bool RouteEquals(AltSvcMapping* map); HTTPS()82 bool HTTPS() { return mHttps; } 83 84 void GetConnectionInfo(nsHttpConnectionInfo** outCI, nsProxyInfo* pi, 85 const OriginAttributes& originAttributes); 86 87 int32_t TTL(); StorageEpoch()88 int32_t StorageEpoch() { return mStorageEpoch; } Private()89 bool Private() { return mPrivate; } 90 91 void SetValidated(bool val); 92 void SetMixedScheme(bool val); 93 void SetExpiresAt(int32_t val); 94 void SetExpired(); 95 void Sync(); SetSyncOnlyOnSuccess(bool aSOOS)96 void SetSyncOnlyOnSuccess(bool aSOOS) { mSyncOnlyOnSuccess = aSOOS; } 97 98 static void MakeHashKey(nsCString& outKey, const nsACString& originScheme, 99 const nsACString& originHost, int32_t originPort, 100 bool privateBrowsing, 101 const OriginAttributes& originAttributes, 102 bool aHttp3); 103 IsHttp3()104 bool IsHttp3() { return mIsHttp3; } NPNToken()105 const nsCString& NPNToken() const { return mNPNToken; } 106 107 private: 108 virtual ~AltSvcMapping() = default; 109 void SyncString(const nsCString& str); 110 RefPtr<DataStorage> mStorage; 111 int32_t mStorageEpoch; 112 void Serialize(nsCString& out); 113 114 nsCString mHashKey; 115 116 // If you change any of these members, update Serialize() 117 nsCString mAlternateHost; 118 int32_t mAlternatePort{-1}; 119 120 nsCString mOriginHost; 121 int32_t mOriginPort{-1}; 122 123 nsCString mUsername; 124 bool mPrivate{false}; 125 126 // alt-svc mappping 127 uint32_t mExpiresAt{0}; 128 129 bool mValidated{false}; 130 // origin is https:// 131 MOZ_INIT_OUTSIDE_CTOR bool mHttps{false}; 132 // .wk allows http and https on same con 133 MOZ_INIT_OUTSIDE_CTOR bool mMixedScheme{false}; 134 135 nsCString mNPNToken; 136 137 OriginAttributes mOriginAttributes; 138 139 bool mSyncOnlyOnSuccess{false}; 140 bool mIsHttp3{false}; 141 }; 142 143 class AltSvcOverride : public nsIInterfaceRequestor, 144 public nsISpeculativeConnectionOverrider { 145 public: 146 NS_DECL_THREADSAFE_ISUPPORTS 147 NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER 148 NS_DECL_NSIINTERFACEREQUESTOR 149 AltSvcOverride(nsIInterfaceRequestor * aRequestor)150 explicit AltSvcOverride(nsIInterfaceRequestor* aRequestor) 151 : mCallbacks(aRequestor) {} 152 153 private: 154 virtual ~AltSvcOverride() = default; 155 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; 156 }; 157 158 class TransactionObserver final : public nsIStreamListener { 159 public: 160 NS_DECL_THREADSAFE_ISUPPORTS 161 NS_DECL_NSISTREAMLISTENER 162 NS_DECL_NSIREQUESTOBSERVER 163 164 TransactionObserver(nsHttpChannel* channel, WellKnownChecker* checker); 165 void Complete(bool versionOK, bool authOK, nsresult reason); 166 167 private: 168 friend class WellKnownChecker; 169 virtual ~TransactionObserver() = default; 170 171 nsCOMPtr<nsISupports> mChannelRef; 172 nsHttpChannel* mChannel; 173 WellKnownChecker* mChecker; 174 nsCString mWKResponse; 175 176 bool mRanOnce; 177 bool mStatusOK; // HTTP Status 200 178 // These two values could be accessed on sts thread. 179 Atomic<bool> mAuthOK; // confirmed no TLS failure 180 Atomic<bool> mVersionOK; // connection h2 181 }; 182 183 class AltSvcCache { 184 public: 185 AltSvcCache() = default; 186 virtual ~AltSvcCache() = default; 187 void UpdateAltServiceMapping( 188 AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*, 189 uint32_t caps, 190 const OriginAttributes& originAttributes); // main thread 191 void UpdateAltServiceMappingWithoutValidation( 192 AltSvcMapping* map, nsProxyInfo* pi, nsIInterfaceRequestor*, 193 uint32_t caps, 194 const OriginAttributes& originAttributes); // main thread 195 already_AddRefed<AltSvcMapping> GetAltServiceMapping( 196 const nsACString& scheme, const nsACString& host, int32_t port, 197 bool privateBrowsing, const OriginAttributes& originAttributes, 198 bool aHttp2Allowed, bool aHttp3Allowed); 199 void ClearAltServiceMappings(); 200 void ClearHostMapping(const nsACString& host, int32_t port, 201 const OriginAttributes& originAttributes); 202 void ClearHostMapping(nsHttpConnectionInfo* ci); GetStoragePtr()203 DataStorage* GetStoragePtr() { return mStorage.get(); } StorageEpoch()204 int32_t StorageEpoch() { return mStorageEpoch; } 205 nsresult GetAltSvcCacheKeys(nsTArray<nsCString>& value); 206 207 private: 208 void EnsureStorageInited(); 209 already_AddRefed<AltSvcMapping> LookupMapping(const nsCString& key, 210 bool privateBrowsing); 211 RefPtr<DataStorage> mStorage; 212 int32_t mStorageEpoch{0}; 213 }; 214 215 // This class is used to write the validated result to AltSvcMapping when the 216 // AltSvcTransaction is closed and destroyed. 217 class AltSvcMappingValidator final { 218 public: 219 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AltSvcMappingValidator) 220 221 explicit AltSvcMappingValidator(AltSvcMapping* aMap); 222 223 void OnTransactionDestroy(bool aValidateResult); 224 225 void OnTransactionClose(bool aValidateResult); 226 227 protected: 228 virtual ~AltSvcMappingValidator() = default; 229 230 RefPtr<AltSvcMapping> mMapping; 231 }; 232 233 // This is the asynchronous null transaction used to validate 234 // an alt-svc advertisement only for https:// 235 // When http over socket process is enabled, this class should live only in 236 // socket process. 237 template <class Validator> 238 class AltSvcTransaction final : public SpeculativeTransaction { 239 public: 240 AltSvcTransaction(nsHttpConnectionInfo* ci, nsIInterfaceRequestor* callbacks, 241 uint32_t caps, Validator* aValidator, bool aIsHttp3); 242 243 ~AltSvcTransaction() override; 244 245 // AltSvcTransaction is used to validate the alt-svc record, so we don't want 246 // to fetch HTTPS RR for this. FetchHTTPSRR()247 virtual nsresult FetchHTTPSRR() override { return NS_ERROR_NOT_IMPLEMENTED; } 248 249 private: 250 // check on alternate route. 251 // also evaluate 'reasonable assurances' for opportunistic security 252 bool MaybeValidate(nsresult reason); 253 254 public: 255 void Close(nsresult reason) override; 256 nsresult ReadSegments(nsAHttpSegmentReader* reader, uint32_t count, 257 uint32_t* countRead) override; 258 259 private: 260 RefPtr<Validator> mValidator; 261 uint32_t mIsHttp3 : 1; 262 uint32_t mRunning : 1; 263 uint32_t mTriedToValidate : 1; 264 uint32_t mTriedToWrite : 1; 265 uint32_t mValidatedResult : 1; 266 }; 267 268 } // namespace net 269 } // namespace mozilla 270 271 #endif // include guard 272