1 /* -*- Mode: C++; tab-width: 8; 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 #ifndef nsHttpConnectionInfo_h__
8 #define nsHttpConnectionInfo_h__
9 
10 #include "nsHttp.h"
11 #include "nsProxyInfo.h"
12 #include "nsCOMPtr.h"
13 #include "nsStringFwd.h"
14 #include "mozilla/Logging.h"
15 #include "mozilla/BasePrincipal.h"
16 #include "mozilla/AlreadyAddRefed.h"
17 #include "ARefBase.h"
18 #include "nsIRequest.h"
19 
20 //-----------------------------------------------------------------------------
21 // nsHttpConnectionInfo - holds the properties of a connection
22 //-----------------------------------------------------------------------------
23 
24 // http:// uris through a proxy will all share the same CI, because they can
25 // all use the same connection. (modulo pb and anonymous flags). They just use
26 // the proxy as the origin host name.
27 // however, https:// uris tunnel through the proxy so they will have different
28 // CIs - the CI reflects both the proxy and the origin.
29 // however, proxy conenctions made with http/2 (or spdy) can tunnel to the
30 // origin and multiplex non tunneled transactions at the same time, so they have
31 // a special wildcard CI that accepts all origins through that proxy.
32 
33 class nsISVCBRecord;
34 
35 namespace mozilla {
36 namespace net {
37 
38 extern LazyLogModule gHttpLog;
39 class HttpConnectionInfoCloneArgs;
40 class nsHttpTransaction;
41 
42 class nsHttpConnectionInfo final : public ARefBase {
43  public:
44   nsHttpConnectionInfo(const nsACString& originHost, int32_t originPort,
45                        const nsACString& npnToken, const nsACString& username,
46                        nsProxyInfo* proxyInfo,
47                        const OriginAttributes& originAttributes,
48                        bool endToEndSSL = false, bool aIsHttp3 = false);
49 
50   // this version must use TLS and you may supply separate
51   // connection (aka routing) information than the authenticated
52   // origin information
53   nsHttpConnectionInfo(const nsACString& originHost, int32_t originPort,
54                        const nsACString& npnToken, const nsACString& username,
55                        nsProxyInfo* proxyInfo,
56                        const OriginAttributes& originAttributes,
57                        const nsACString& routedHost, int32_t routedPort,
58                        bool aIsHttp3);
59 
60   static void SerializeHttpConnectionInfo(nsHttpConnectionInfo* aInfo,
61                                           HttpConnectionInfoCloneArgs& aArgs);
62   static already_AddRefed<nsHttpConnectionInfo>
63   DeserializeHttpConnectionInfoCloneArgs(
64       const HttpConnectionInfoCloneArgs& aInfoArgs);
65 
66  private:
~nsHttpConnectionInfo()67   virtual ~nsHttpConnectionInfo() {
68     MOZ_LOG(gHttpLog, LogLevel::Debug,
69             ("Destroying nsHttpConnectionInfo @%p\n", this));
70   }
71 
72   void BuildHashKey();
73   void RebuildHashKey();
74 
75   // See comments in nsHttpConnectionInfo::BuildHashKey for the meaning of each
76   // field.
77   enum class HashKeyIndex : uint32_t {
78     Proxy = 0,
79     EndToEndSSL,
80     Anonymous,
81     Private,
82     InsecureScheme,
83     NoSpdy,
84     BeConservative,
85     AnonymousAllowClientCert,
86     FallbackConnection,
87     End,
88   };
UnderlyingIndex(HashKeyIndex aIndex)89   constexpr inline auto UnderlyingIndex(HashKeyIndex aIndex) const {
90     return std::underlying_type_t<HashKeyIndex>(aIndex);
91   }
92 
93  public:
HashKey()94   const nsCString& HashKey() const { return mHashKey; }
95 
GetOrigin()96   const nsCString& GetOrigin() const { return mOrigin; }
Origin()97   const char* Origin() const { return mOrigin.get(); }
OriginPort()98   int32_t OriginPort() const { return mOriginPort; }
99 
GetRoutedHost()100   const nsCString& GetRoutedHost() const { return mRoutedHost; }
RoutedHost()101   const char* RoutedHost() const { return mRoutedHost.get(); }
RoutedPort()102   int32_t RoutedPort() const { return mRoutedPort; }
103 
104   // OK to treat these as an infalible allocation
105   already_AddRefed<nsHttpConnectionInfo> Clone() const;
106   // This main prupose of this function is to clone this connection info, but
107   // replace mRoutedHost with SvcDomainName in the given SVCB record. Note that
108   // if SvcParamKeyPort and SvcParamKeyAlpn are presented in the SVCB record,
109   // mRoutedPort and mNPNToken will be replaced as well.
110   already_AddRefed<nsHttpConnectionInfo> CloneAndAdoptHTTPSSVCRecord(
111       nsISVCBRecord* aRecord) const;
112   void CloneAsDirectRoute(nsHttpConnectionInfo** outCI);
113   [[nodiscard]] nsresult CreateWildCard(nsHttpConnectionInfo** outParam);
114 
ProxyHost()115   const char* ProxyHost() const {
116     return mProxyInfo ? mProxyInfo->Host().get() : nullptr;
117   }
ProxyPort()118   int32_t ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
ProxyType()119   const char* ProxyType() const {
120     return mProxyInfo ? mProxyInfo->Type() : nullptr;
121   }
ProxyUsername()122   const char* ProxyUsername() const {
123     return mProxyInfo ? mProxyInfo->Username().get() : nullptr;
124   }
ProxyPassword()125   const char* ProxyPassword() const {
126     return mProxyInfo ? mProxyInfo->Password().get() : nullptr;
127   }
128 
ProxyAuthorizationHeader()129   const nsCString& ProxyAuthorizationHeader() const {
130     return mProxyInfo ? mProxyInfo->ProxyAuthorizationHeader() : EmptyCString();
131   }
ConnectionIsolationKey()132   const nsCString& ConnectionIsolationKey() const {
133     return mProxyInfo ? mProxyInfo->ConnectionIsolationKey() : EmptyCString();
134   }
135 
136   // Compare this connection info to another...
137   // Two connections are 'equal' if they end up talking the same
138   // protocol to the same server. This is needed to properly manage
139   // persistent connections to proxies
140   // Note that we don't care about transparent proxies -
141   // it doesn't matter if we're talking via socks or not, since
142   // a request will end up at the same host.
Equals(const nsHttpConnectionInfo * info)143   bool Equals(const nsHttpConnectionInfo* info) {
144     return mHashKey.Equals(info->HashKey());
145   }
146 
Username()147   const char* Username() const { return mUsername.get(); }
ProxyInfo()148   nsProxyInfo* ProxyInfo() const { return mProxyInfo; }
DefaultPort()149   int32_t DefaultPort() const {
150     return mEndToEndSSL ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT;
151   }
SetAnonymous(bool anon)152   void SetAnonymous(bool anon) {
153     SetHashCharAt(anon ? 'A' : '.', HashKeyIndex::Anonymous);
154   }
GetAnonymous()155   bool GetAnonymous() const {
156     return GetHashCharAt(HashKeyIndex::Anonymous) == 'A';
157   }
SetPrivate(bool priv)158   void SetPrivate(bool priv) {
159     SetHashCharAt(priv ? 'P' : '.', HashKeyIndex::Private);
160   }
GetPrivate()161   bool GetPrivate() const {
162     return GetHashCharAt(HashKeyIndex::Private) == 'P';
163   }
SetInsecureScheme(bool insecureScheme)164   void SetInsecureScheme(bool insecureScheme) {
165     SetHashCharAt(insecureScheme ? 'I' : '.', HashKeyIndex::InsecureScheme);
166   }
GetInsecureScheme()167   bool GetInsecureScheme() const {
168     return GetHashCharAt(HashKeyIndex::InsecureScheme) == 'I';
169   }
170 
SetNoSpdy(bool aNoSpdy)171   void SetNoSpdy(bool aNoSpdy) {
172     SetHashCharAt(aNoSpdy ? 'X' : '.', HashKeyIndex::NoSpdy);
173     if (aNoSpdy && mNPNToken == "h2"_ns) {
174       mNPNToken.Truncate();
175       RebuildHashKey();
176     }
177   }
GetNoSpdy()178   bool GetNoSpdy() const { return GetHashCharAt(HashKeyIndex::NoSpdy) == 'X'; }
179 
SetBeConservative(bool aBeConservative)180   void SetBeConservative(bool aBeConservative) {
181     SetHashCharAt(aBeConservative ? 'C' : '.', HashKeyIndex::BeConservative);
182   }
GetBeConservative()183   bool GetBeConservative() const {
184     return GetHashCharAt(HashKeyIndex::BeConservative) == 'C';
185   }
186 
SetAnonymousAllowClientCert(bool anon)187   void SetAnonymousAllowClientCert(bool anon) {
188     SetHashCharAt(anon ? 'B' : '.', HashKeyIndex::AnonymousAllowClientCert);
189   }
GetAnonymousAllowClientCert()190   bool GetAnonymousAllowClientCert() const {
191     return GetHashCharAt(HashKeyIndex::AnonymousAllowClientCert) == 'B';
192   }
193 
SetFallbackConnection(bool aFallback)194   void SetFallbackConnection(bool aFallback) {
195     SetHashCharAt(aFallback ? 'F' : '.', HashKeyIndex::FallbackConnection);
196   }
GetFallbackConnection()197   bool GetFallbackConnection() const {
198     return GetHashCharAt(HashKeyIndex::FallbackConnection) == 'F';
199   }
200 
201   void SetTlsFlags(uint32_t aTlsFlags);
GetTlsFlags()202   uint32_t GetTlsFlags() const { return mTlsFlags; }
203 
204   // IsTrrServiceChannel means that this connection is used to send TRR requests
205   // over
SetIsTrrServiceChannel(bool aIsTRRChannel)206   void SetIsTrrServiceChannel(bool aIsTRRChannel) {
207     mIsTrrServiceChannel = aIsTRRChannel;
208   }
GetIsTrrServiceChannel()209   bool GetIsTrrServiceChannel() const { return mIsTrrServiceChannel; }
210 
211   void SetTRRMode(nsIRequest::TRRMode aTRRMode);
GetTRRMode()212   nsIRequest::TRRMode GetTRRMode() const { return mTRRMode; }
213 
214   void SetIPv4Disabled(bool aNoIPv4);
GetIPv4Disabled()215   bool GetIPv4Disabled() const { return mIPv4Disabled; }
216 
217   void SetIPv6Disabled(bool aNoIPv6);
GetIPv6Disabled()218   bool GetIPv6Disabled() const { return mIPv6Disabled; }
219 
GetNPNToken()220   const nsCString& GetNPNToken() { return mNPNToken; }
GetUsername()221   const nsCString& GetUsername() { return mUsername; }
222 
GetOriginAttributes()223   const OriginAttributes& GetOriginAttributes() { return mOriginAttributes; }
224 
225   // Returns true for any kind of proxy (http, socks, https, etc..)
226   bool UsingProxy();
227 
228   // Returns true when proxying over HTTP or HTTPS
UsingHttpProxy()229   bool UsingHttpProxy() const { return mUsingHttpProxy || mUsingHttpsProxy; }
230 
231   // Returns true when proxying over HTTPS
UsingHttpsProxy()232   bool UsingHttpsProxy() const { return mUsingHttpsProxy; }
233 
234   // Returns true when a resource is in SSL end to end (e.g. https:// uri)
EndToEndSSL()235   bool EndToEndSSL() const { return mEndToEndSSL; }
236 
237   // Returns true when at least first hop is SSL (e.g. proxy over https or https
238   // uri)
FirstHopSSL()239   bool FirstHopSSL() const { return mEndToEndSSL || mUsingHttpsProxy; }
240 
241   // Returns true when CONNECT is used to tunnel through the proxy (e.g.
242   // https:// or ws://)
UsingConnect()243   bool UsingConnect() const { return mUsingConnect; }
244 
245   // Returns true when origin/proxy is an RFC1918 literal.
246   bool HostIsLocalIPLiteral() const;
247 
GetLessThanTls13()248   bool GetLessThanTls13() const { return mLessThanTls13; }
SetLessThanTls13(bool aLessThanTls13)249   void SetLessThanTls13(bool aLessThanTls13) {
250     mLessThanTls13 = aLessThanTls13;
251   }
252 
IsHttp3()253   bool IsHttp3() const { return mIsHttp3; }
254 
SetHasIPHintAddress(bool aHasIPHint)255   void SetHasIPHintAddress(bool aHasIPHint) { mHasIPHintAddress = aHasIPHint; }
HasIPHintAddress()256   bool HasIPHintAddress() const { return mHasIPHintAddress; }
257 
SetEchConfig(const nsACString & aEchConfig)258   void SetEchConfig(const nsACString& aEchConfig) { mEchConfig = aEchConfig; }
GetEchConfig()259   const nsCString& GetEchConfig() const { return mEchConfig; }
260 
261  private:
262   void Init(const nsACString& host, int32_t port, const nsACString& npnToken,
263             const nsACString& username, nsProxyInfo* proxyInfo,
264             const OriginAttributes& originAttributes, bool e2eSSL,
265             bool aIsHttp3);
266   void SetOriginServer(const nsACString& host, int32_t port);
GetHashCharAt(HashKeyIndex aIndex)267   nsCString::char_type GetHashCharAt(HashKeyIndex aIndex) const {
268     return mHashKey.CharAt(UnderlyingIndex(aIndex));
269   }
SetHashCharAt(nsCString::char_type aValue,HashKeyIndex aIndex)270   void SetHashCharAt(nsCString::char_type aValue, HashKeyIndex aIndex) {
271     mHashKey.SetCharAt(aValue, UnderlyingIndex(aIndex));
272   }
273 
274   nsCString mOrigin;
275   int32_t mOriginPort = 0;
276   nsCString mRoutedHost;
277   int32_t mRoutedPort;
278 
279   nsCString mHashKey;
280   nsCString mUsername;
281   nsCOMPtr<nsProxyInfo> mProxyInfo;
282   bool mUsingHttpProxy = false;
283   bool mUsingHttpsProxy = false;
284   bool mEndToEndSSL = false;
285   // if will use CONNECT with http proxy
286   bool mUsingConnect = false;
287   nsCString mNPNToken;
288   OriginAttributes mOriginAttributes;
289   nsIRequest::TRRMode mTRRMode;
290 
291   uint32_t mTlsFlags = 0;
292   uint16_t mIsTrrServiceChannel : 1;
293   uint16_t mIPv4Disabled : 1;
294   uint16_t mIPv6Disabled : 1;
295 
296   bool mLessThanTls13;  // This will be set to true if we negotiate less than
297                         // tls1.3. If the tls version is till not know or it
298                         // is 1.3 or greater the value will be false.
299   bool mIsHttp3 = false;
300 
301   bool mHasIPHintAddress = false;
302   nsCString mEchConfig;
303 
304   // for RefPtr
305   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpConnectionInfo, override)
306 };
307 
308 }  // namespace net
309 }  // namespace mozilla
310 
311 #endif  // nsHttpConnectionInfo_h__
312