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