nsHttpConnectionInfo.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. // HttpLog.h should generally be included first
  6. #include "HttpLog.h"
  7. // Log on level :5, instead of default :4.
  8. #undef LOG
  9. #define LOG(args) LOG5(args)
  10. #undef LOG_ENABLED
  11. #define LOG_ENABLED() LOG5_ENABLED()
  12. #include "nsHttpConnectionInfo.h"
  13. #include "mozilla/net/DNS.h"
  14. #include "nsComponentManagerUtils.h"
  15. #include "nsICryptoHash.h"
  16. #include "nsIProtocolProxyService.h"
  17. #include "nsNetCID.h"
  18. #include "prnetdb.h"
  19. static nsresult
  20. SHA256(const char* aPlainText, nsAutoCString& aResult)
  21. {
  22. nsresult rv;
  23. nsCOMPtr<nsICryptoHash> hasher = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
  24. if (NS_FAILED(rv)) {
  25. LOG(("nsHttpDigestAuth: no crypto hash!\n"));
  26. return rv;
  27. }
  28. rv = hasher->Init(nsICryptoHash::SHA256);
  29. NS_ENSURE_SUCCESS(rv, rv);
  30. rv = hasher->Update((unsigned char*) aPlainText, strlen(aPlainText));
  31. NS_ENSURE_SUCCESS(rv, rv);
  32. return hasher->Finish(false, aResult);
  33. }
  34. namespace mozilla {
  35. namespace net {
  36. nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &originHost,
  37. int32_t originPort,
  38. const nsACString &npnToken,
  39. const nsACString &username,
  40. nsProxyInfo *proxyInfo,
  41. const NeckoOriginAttributes &originAttributes,
  42. bool endToEndSSL)
  43. : mRoutedPort(443)
  44. {
  45. Init(originHost, originPort, npnToken, username, proxyInfo, originAttributes, endToEndSSL);
  46. }
  47. nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &originHost,
  48. int32_t originPort,
  49. const nsACString &npnToken,
  50. const nsACString &username,
  51. nsProxyInfo *proxyInfo,
  52. const NeckoOriginAttributes &originAttributes,
  53. const nsACString &routedHost,
  54. int32_t routedPort)
  55. {
  56. mEndToEndSSL = true; // so DefaultPort() works
  57. mRoutedPort = routedPort == -1 ? DefaultPort() : routedPort;
  58. if (!originHost.Equals(routedHost) || (originPort != routedPort)) {
  59. mRoutedHost = routedHost;
  60. }
  61. Init(originHost, originPort, npnToken, username, proxyInfo, originAttributes, true);
  62. }
  63. void
  64. nsHttpConnectionInfo::Init(const nsACString &host, int32_t port,
  65. const nsACString &npnToken,
  66. const nsACString &username,
  67. nsProxyInfo* proxyInfo,
  68. const NeckoOriginAttributes &originAttributes,
  69. bool e2eSSL)
  70. {
  71. LOG(("Init nsHttpConnectionInfo @%p\n", this));
  72. mUsername = username;
  73. mProxyInfo = proxyInfo;
  74. mEndToEndSSL = e2eSSL;
  75. mUsingConnect = false;
  76. mNPNToken = npnToken;
  77. mOriginAttributes = originAttributes;
  78. mUsingHttpsProxy = (proxyInfo && proxyInfo->IsHTTPS());
  79. mUsingHttpProxy = mUsingHttpsProxy || (proxyInfo && proxyInfo->IsHTTP());
  80. if (mUsingHttpProxy) {
  81. mUsingConnect = mEndToEndSSL; // SSL always uses CONNECT
  82. uint32_t resolveFlags = 0;
  83. if (NS_SUCCEEDED(mProxyInfo->GetResolveFlags(&resolveFlags)) &&
  84. resolveFlags & nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL) {
  85. mUsingConnect = true;
  86. }
  87. }
  88. SetOriginServer(host, port);
  89. }
  90. void
  91. nsHttpConnectionInfo::SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId)
  92. {
  93. mNetworkInterfaceId = aNetworkInterfaceId;
  94. BuildHashKey();
  95. }
  96. void nsHttpConnectionInfo::BuildHashKey()
  97. {
  98. //
  99. // build hash key:
  100. //
  101. // the hash key uniquely identifies the connection type. two connections
  102. // are "equal" if they end up talking the same protocol to the same server
  103. // and are both used for anonymous or non-anonymous connection only;
  104. // anonymity of the connection is setup later from nsHttpChannel::AsyncOpen
  105. // where we know we use anonymous connection (LOAD_ANONYMOUS load flag)
  106. //
  107. const char *keyHost;
  108. int32_t keyPort;
  109. if (mUsingHttpProxy && !mUsingConnect) {
  110. keyHost = ProxyHost();
  111. keyPort = ProxyPort();
  112. } else {
  113. keyHost = Origin();
  114. keyPort = OriginPort();
  115. }
  116. // The hashkey has 4 fields followed by host connection info
  117. // byte 0 is P/T/. {P,T} for Plaintext/TLS Proxy over HTTP
  118. // byte 1 is S/. S is for end to end ssl such as https:// uris
  119. // byte 2 is A/. A is for an anonymous channel (no cookies, etc..)
  120. // byte 3 is P/. P is for a private browising channel
  121. // byte 4 is I/. I is for insecure scheme on TLS for http:// uris
  122. // byte 5 is X/. X is for disallow_spdy flag
  123. // byte 6 is C/. C is for be Conservative
  124. mHashKey.AssignLiteral(".......");
  125. mHashKey.Append(keyHost);
  126. if (!mNetworkInterfaceId.IsEmpty()) {
  127. mHashKey.Append('(');
  128. mHashKey.Append(mNetworkInterfaceId);
  129. mHashKey.Append(')');
  130. }
  131. mHashKey.Append(':');
  132. mHashKey.AppendInt(keyPort);
  133. if (!mUsername.IsEmpty()) {
  134. mHashKey.Append('[');
  135. mHashKey.Append(mUsername);
  136. mHashKey.Append(']');
  137. }
  138. if (mUsingHttpsProxy) {
  139. mHashKey.SetCharAt('T', 0);
  140. } else if (mUsingHttpProxy) {
  141. mHashKey.SetCharAt('P', 0);
  142. }
  143. if (mEndToEndSSL) {
  144. mHashKey.SetCharAt('S', 1);
  145. }
  146. // NOTE: for transparent proxies (e.g., SOCKS) we need to encode the proxy
  147. // info in the hash key (this ensures that we will continue to speak the
  148. // right protocol even if our proxy preferences change).
  149. //
  150. // NOTE: for SSL tunnels add the proxy information to the cache key.
  151. // We cannot use the proxy as the host parameter (as we do for non SSL)
  152. // because this is a single host tunnel, but we need to include the proxy
  153. // information so that a change in proxy config will mean this connection
  154. // is not reused
  155. // NOTE: Adding the username and the password provides a means to isolate
  156. // keep-alive to the URL bar domain as well: If the username is the URL bar
  157. // domain, keep-alive connections are not reused by resources bound to
  158. // different URL bar domains as the respective hash keys are not matching.
  159. if ((!mUsingHttpProxy && ProxyHost()) ||
  160. (mUsingHttpProxy && mUsingConnect)) {
  161. mHashKey.AppendLiteral(" (");
  162. mHashKey.Append(ProxyType());
  163. mHashKey.Append(':');
  164. mHashKey.Append(ProxyHost());
  165. mHashKey.Append(':');
  166. mHashKey.AppendInt(ProxyPort());
  167. mHashKey.Append(')');
  168. mHashKey.Append('[');
  169. mHashKey.Append(ProxyUsername());
  170. mHashKey.Append(':');
  171. const char* password = ProxyPassword();
  172. if (strlen(password) > 0) {
  173. nsAutoCString digestedPassword;
  174. nsresult rv = SHA256(password, digestedPassword);
  175. if (rv == NS_OK) {
  176. mHashKey.Append(digestedPassword);
  177. }
  178. }
  179. mHashKey.Append(']');
  180. }
  181. if(!mRoutedHost.IsEmpty()) {
  182. mHashKey.AppendLiteral(" <ROUTE-via ");
  183. mHashKey.Append(mRoutedHost);
  184. mHashKey.Append(':');
  185. mHashKey.AppendInt(mRoutedPort);
  186. mHashKey.Append('>');
  187. }
  188. if (!mNPNToken.IsEmpty()) {
  189. mHashKey.AppendLiteral(" {NPN-TOKEN ");
  190. mHashKey.Append(mNPNToken);
  191. mHashKey.AppendLiteral("}");
  192. }
  193. nsAutoCString originAttributes;
  194. mOriginAttributes.CreateSuffix(originAttributes);
  195. mHashKey.Append(originAttributes);
  196. }
  197. void
  198. nsHttpConnectionInfo::SetOriginServer(const nsACString &host, int32_t port)
  199. {
  200. mOrigin = host;
  201. mOriginPort = port == -1 ? DefaultPort() : port;
  202. BuildHashKey();
  203. }
  204. nsHttpConnectionInfo*
  205. nsHttpConnectionInfo::Clone() const
  206. {
  207. nsHttpConnectionInfo *clone;
  208. if (mRoutedHost.IsEmpty()) {
  209. clone = new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername, mProxyInfo,
  210. mOriginAttributes, mEndToEndSSL);
  211. } else {
  212. MOZ_ASSERT(mEndToEndSSL);
  213. clone = new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername, mProxyInfo,
  214. mOriginAttributes, mRoutedHost, mRoutedPort);
  215. }
  216. if (!mNetworkInterfaceId.IsEmpty()) {
  217. clone->SetNetworkInterfaceId(mNetworkInterfaceId);
  218. }
  219. // Make sure the anonymous, insecure-scheme, and private flags are transferred
  220. clone->SetAnonymous(GetAnonymous());
  221. clone->SetPrivate(GetPrivate());
  222. clone->SetInsecureScheme(GetInsecureScheme());
  223. clone->SetNoSpdy(GetNoSpdy());
  224. clone->SetBeConservative(GetBeConservative());
  225. MOZ_ASSERT(clone->Equals(this));
  226. return clone;
  227. }
  228. void
  229. nsHttpConnectionInfo::CloneAsDirectRoute(nsHttpConnectionInfo **outCI)
  230. {
  231. if (mRoutedHost.IsEmpty()) {
  232. *outCI = Clone();
  233. return;
  234. }
  235. RefPtr<nsHttpConnectionInfo> clone =
  236. new nsHttpConnectionInfo(mOrigin, mOriginPort,
  237. EmptyCString(), mUsername, mProxyInfo,
  238. mOriginAttributes, mEndToEndSSL);
  239. // Make sure the anonymous, insecure-scheme, and private flags are transferred
  240. clone->SetAnonymous(GetAnonymous());
  241. clone->SetPrivate(GetPrivate());
  242. clone->SetInsecureScheme(GetInsecureScheme());
  243. clone->SetNoSpdy(GetNoSpdy());
  244. clone->SetBeConservative(GetBeConservative());
  245. if (!mNetworkInterfaceId.IsEmpty()) {
  246. clone->SetNetworkInterfaceId(mNetworkInterfaceId);
  247. }
  248. clone.forget(outCI);
  249. }
  250. nsresult
  251. nsHttpConnectionInfo::CreateWildCard(nsHttpConnectionInfo **outParam)
  252. {
  253. // T???mozilla.org:443 (https:proxy.ducksong.com:3128) [specifc form]
  254. // TS??*:0 (https:proxy.ducksong.com:3128) [wildcard form]
  255. if (!mUsingHttpsProxy) {
  256. MOZ_ASSERT(false);
  257. return NS_ERROR_NOT_IMPLEMENTED;
  258. }
  259. RefPtr<nsHttpConnectionInfo> clone;
  260. clone = new nsHttpConnectionInfo(NS_LITERAL_CSTRING("*"), 0,
  261. mNPNToken, mUsername, mProxyInfo,
  262. mOriginAttributes, true);
  263. // Make sure the anonymous and private flags are transferred!
  264. clone->SetAnonymous(GetAnonymous());
  265. clone->SetPrivate(GetPrivate());
  266. clone.forget(outParam);
  267. return NS_OK;
  268. }
  269. bool
  270. nsHttpConnectionInfo::UsingProxy()
  271. {
  272. if (!mProxyInfo)
  273. return false;
  274. return !mProxyInfo->IsDirect();
  275. }
  276. bool
  277. nsHttpConnectionInfo::HostIsLocalIPLiteral() const
  278. {
  279. PRNetAddr prAddr;
  280. // If the host/proxy host is not an IP address literal, return false.
  281. if (ProxyHost()) {
  282. if (PR_StringToNetAddr(ProxyHost(), &prAddr) != PR_SUCCESS) {
  283. return false;
  284. }
  285. } else if (PR_StringToNetAddr(Origin(), &prAddr) != PR_SUCCESS) {
  286. return false;
  287. }
  288. NetAddr netAddr;
  289. PRNetAddrToNetAddr(&prAddr, &netAddr);
  290. return IsIPAddrLocal(&netAddr);
  291. }
  292. } // namespace net
  293. } // namespace mozilla