Panda3D
httpClient.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file httpClient.cxx
10  * @author drose
11  * @date 2002-09-24
12  */
13 
14 #include "httpClient.h"
15 #include "httpChannel.h"
16 #include "config_downloader.h"
17 #include "filename.h"
18 #include "config_express.h"
19 #include "virtualFileSystem.h"
20 #include "executionEnvironment.h"
21 #include "httpBasicAuthorization.h"
23 #include "globPattern.h"
24 
25 #ifdef HAVE_OPENSSL
26 
27 #include "openSSLWrapper.h"
28 
29 using std::string;
30 
31 PT(HTTPClient) HTTPClient::_global_ptr;
32 
33 /**
34  *
35  */
36 static string
37 trim_blanks(const string &str) {
38  size_t start = 0;
39  while (start < str.length() && isspace(str[start])) {
40  start++;
41  }
42 
43  size_t end = str.length();
44  while (end > start && isspace(str[end - 1])) {
45  end--;
46  }
47 
48  return str.substr(start, end - start);
49 }
50 
51 /**
52  * Chops the source string up into pieces delimited by any of the characters
53  * specified in delimiters. Repeated delimiter characters represent zero-
54  * length tokens.
55  *
56  * It is the user's responsibility to ensure the output vector is cleared
57  * before calling this function; the results will simply be appended to the
58  * end of the vector.
59  */
60 static void
61 tokenize(const string &str, vector_string &words, const string &delimiters) {
62  size_t p = 0;
63  while (p < str.length()) {
64  size_t q = str.find_first_of(delimiters, p);
65  if (q == string::npos) {
66  words.push_back(str.substr(p));
67  return;
68  }
69  words.push_back(str.substr(p, q - p));
70  p = q + 1;
71  }
72  words.push_back(string());
73 }
74 
75 #ifndef NDEBUG
76 /**
77  * This method is attached as a callback for SSL messages only when debug
78  * output is enabled.
79  */
80 static void
81 ssl_msg_callback(int write_p, int version, int content_type,
82  const void *, size_t len, SSL *, void *) {
83  std::ostringstream describe;
84  if (write_p) {
85  describe << "sent ";
86  } else {
87  describe << "received ";
88  }
89  switch (version) {
90  case SSL2_VERSION:
91  describe << "SSL 2.0 ";
92  break;
93 
94  case SSL3_VERSION:
95  describe << "SSL 3.0 ";
96  break;
97 
98  case TLS1_VERSION:
99  describe << "TLS 1.0 ";
100  break;
101 
102  default:
103  describe << "unknown protocol ";
104  }
105 
106  describe << "message: ";
107 
108  if (version != SSL2_VERSION) {
109  switch (content_type) {
110  case 20:
111  describe << "change cipher spec, ";
112  break;
113 
114  case 21:
115  describe << "alert, ";
116  break;
117 
118  case 22:
119  describe << "handshake, ";
120  break;
121 
122  case 23:
123  describe << "application data, ";
124  break;
125 
126  default:
127  describe << "unknown content type, ";
128  }
129  }
130 
131  describe << len << " bytes.\n";
132 
133  downloader_cat.debug() << describe.str();
134 }
135 #endif // !defined(NDEBUG)
136 
137 /**
138  *
139  */
140 HTTPClient::
141 HTTPClient() {
142  ConfigVariableBool verify_ssl
143  ("verify-ssl", true,
144  PRC_DESC("Configure this true (the default) to insist on verifying all SSL "
145  "(e.g. https) servers against a known certificate, or false to allow "
146  "an unverified connection. This controls the default behavior; the "
147  "specific behavior for a particular HTTPClient can be adjusted at "
148  "runtime with set_verify_ssl()."));
149 
150  ConfigVariableString ssl_cipher_list
151  ("ssl-cipher-list", "DEFAULT",
152  PRC_DESC("This is the default value for HTTPClient::set_cipher_list()."));
153 
154  ConfigVariableString http_proxy
155  ("http-proxy", "",
156  PRC_DESC("This specifies the default value for HTTPClient::set_proxy_spec(). "
157  "It is a semicolon-delimited list of proxies that we use to contact "
158  "all HTTP hosts that don't specify otherwise. See "
159  "set_proxy_spec() for more information."));
160 
161  ConfigVariableString http_direct_hosts
162  ("http-direct-hosts", "",
163  PRC_DESC("This specifies the default value for HTTPClient::set_direct_host_spec(). "
164  "It is a semicolon-delimited list of host names that do not require a "
165  "proxy. See set_direct_host_spec() for more information."));
166 
167  ConfigVariableBool http_try_all_direct
168  ("http-try-all-direct", true,
169  PRC_DESC("This specifies the default value for HTTPClient::set_try_all_direct(). "
170  "If this is true, a direct connection will always be attempted after an "
171  "attempt to connect through a proxy fails."));
172 
173  ConfigVariableString http_proxy_username
174  ("http-proxy-username", "",
175  PRC_DESC("This specifies a default username:password to pass to the proxy."));
176 
177  ConfigVariableList http_username
178  ("http-username",
179  PRC_DESC("Adds one or more username/password pairs to all HTTP clients. The client "
180  "will present this username/password when asked to authenticate a request "
181  "for a particular server and/or realm. The username is of the form "
182  "server:realm:username:password, where either or both of server and "
183  "realm may be empty, or just realm:username:password or username:password. "
184  "If the server or realm is empty, they will match anything."));
185 
186  ConfigVariableFilename http_client_certificate_filename
187  ("http-client-certificate-filename", "",
188  PRC_DESC("This provides a default client certificate to offer up should an "
189  "SSL server demand one. The file names a PEM-formatted file "
190  "that includes a public and private key specification. A "
191  "connection-specific certificate may also be specified at runtime on "
192  "the HTTPClient object, but this will require having a different "
193  "HTTPClient object for each differently-certificated connection."));
194 
195  ConfigVariableString http_client_certificate_passphrase
196  ("http-client-certificate-passphrase", "",
197  PRC_DESC("This specifies the passphrase to use to decode the certificate named "
198  "by http-client-certificate-filename."));
199 
200 
201  ConfigVariableList http_preapproved_server_certificate_filename
202  ("http-preapproved-server-certificate-filename",
203  PRC_DESC("This specifies a server hostname:port combination, followed by "
204  "at least one space, and the name of a PEM file that contains "
205  "an SSL certificate that we expect this server to offer. If "
206  "it does, we will accept the cert without further question, "
207  "even if the cert does not match any known certificate "
208  "authorities. This option may appear multiple times."));
209 
210  ConfigVariableList http_preapproved_server_certificate_name
211  ("http-preapproved-server-certificate-name",
212  PRC_DESC("This specifies a server hostname:port combination, followed by "
213  "at least one space, and a string describing the subject name "
214  "of an SSL certificate we expect this server to offer. If it "
215  "it does, we will accept the cert, but only if it also matches "
216  "a known certificate authority. This option may appear "
217  "multiple times."));
218 
219  _http_version = HTTPEnum::HV_11;
220  _verify_ssl = verify_ssl ? VS_normal : VS_no_verify;
221  _ssl_ctx = nullptr;
222 
223  set_proxy_spec(http_proxy);
224  set_direct_host_spec(http_direct_hosts);
225  _try_all_direct = http_try_all_direct;
226 
227  if (!http_proxy_username.empty()) {
228  set_username("*proxy", "", http_proxy_username);
229  }
230 
231  set_cipher_list(ssl_cipher_list);
232 
233  {
234  // Also load in the general usernames.
235  int num_unique_values = http_username.get_num_unique_values();
236  for (int i = 0; i < num_unique_values; i++) {
237  string username = http_username.get_unique_value(i);
238  add_http_username(username);
239  }
240  }
241 
242  _client_certificate_filename = http_client_certificate_filename;
243  _client_certificate_passphrase = http_client_certificate_passphrase;
244 
245  _client_certificate_loaded = false;
246  _client_certificate_pub = nullptr;
247  _client_certificate_priv = nullptr;
248 
249  int num_server_certs = http_preapproved_server_certificate_filename.get_num_unique_values();
250  int si;
251  for (si = 0; si < num_server_certs; si++) {
252  string cert_line = http_preapproved_server_certificate_filename.get_unique_value(si);
253  string a, b;
254  split_whitespace(a, b, cert_line);
255  add_preapproved_server_certificate_filename(URLSpec(a, true), b);
256  }
257 
258  num_server_certs = http_preapproved_server_certificate_name.get_num_unique_values();
259  for (si = 0; si < num_server_certs; si++) {
260  string cert_line = http_preapproved_server_certificate_name.get_unique_value(si);
261  string a, b;
262  split_whitespace(a, b, cert_line);
263  add_preapproved_server_certificate_name(URLSpec(a, true), b);
264  }
265 
266  // The first time we create an HTTPClient, we must initialize the OpenSSL
267  // library. The OpenSSLWrapper object does that.
268  OpenSSLWrapper::get_global_ptr();
269 }
270 
271 /**
272  *
273  */
274 HTTPClient::
275 HTTPClient(const HTTPClient &copy) {
276  _ssl_ctx = nullptr;
277 
278  (*this) = copy;
279 }
280 
281 /**
282  *
283  */
284 void HTTPClient::
285 operator = (const HTTPClient &copy) {
286  _proxies_by_scheme = copy._proxies_by_scheme;
287  _direct_hosts = copy._direct_hosts;
288  _try_all_direct = copy._try_all_direct;
289  _http_version = copy._http_version;
290  _verify_ssl = copy._verify_ssl;
291  _usernames = copy._usernames;
292  _cookies = copy._cookies;
293 }
294 
295 /**
296  *
297  */
298 HTTPClient::
299 ~HTTPClient() {
300  if (_ssl_ctx != nullptr) {
301 #if OPENSSL_VERSION_NUMBER < 0x10100000
302  // Before we can free the context, we must remove the X509_STORE pointer
303  // from it, so it won't be destroyed along with it (this object is shared
304  // among all contexts).
305  _ssl_ctx->cert_store = nullptr;
306 #endif
307  SSL_CTX_free(_ssl_ctx);
308  }
309 
310  unload_client_certificate();
311 }
312 
313 /**
314  * This may be called once, presumably at the beginning of an application, to
315  * initialize OpenSSL's random seed. On Windows, it is particularly important
316  * to call this at startup if you are going to be performing any https
317  * operations or otherwise use encryption, since the Windows algorithm for
318  * getting a random seed takes 2-3 seconds at startup, but can take 30 seconds
319  * or more after you have opened a 3-D graphics window and started rendering.
320  *
321  * There is no harm in calling this method multiple times, or in not calling
322  * it at all.
323  */
324 void HTTPClient::
325 init_random_seed() {
326  // Creating the global OpenSSLWrapper object is nowadays sufficient to
327  // ensure that OpenSSL and its random seed have been initialized.
328  OpenSSLWrapper::get_global_ptr();
329 }
330 
331 /**
332  * Specifies the complete set of proxies to use for all schemes. This is
333  * either a semicolon-delimited set of hostname:ports, or a semicolon-
334  * delimited set of pairs of the form "scheme=hostname:port", or a
335  * combination. Use the keyword DIRECT, or an empty string, to represent a
336  * direct connection. A particular scheme and/or proxy host may be listed
337  * more than once. This is a convenience function that can be used in place
338  * of explicit calls to add_proxy() for each scheme/proxy pair.
339  */
340 void HTTPClient::
341 set_proxy_spec(const string &proxy_spec) {
342  clear_proxy();
343 
344  string trim_proxy_spec = trim_blanks(proxy_spec);
345 
346  // Tokenize the string based on the semicolons.
347  if (!trim_proxy_spec.empty()) {
348  vector_string proxies;
349  tokenize(trim_proxy_spec, proxies, ";");
350 
351  for (vector_string::const_iterator pi = proxies.begin();
352  pi != proxies.end();
353  ++pi) {
354  const string &spec = (*pi);
355 
356  // Divide out the scheme and the hostname.
357  string scheme;
358  string proxy;
359  size_t equals = spec.find('=');
360  if (equals == string::npos) {
361  scheme = "";
362  proxy = trim_blanks(spec);
363  } else {
364  scheme = trim_blanks(spec.substr(0, equals));
365  proxy = trim_blanks(spec.substr(equals + 1));
366  }
367 
368  if (proxy == "DIRECT" || proxy.empty()) {
369  add_proxy(scheme, URLSpec());
370  } else {
371  add_proxy(scheme, URLSpec(proxy, true));
372  }
373  }
374  }
375 }
376 
377 /**
378  * Returns the complete set of proxies to use for all schemes. This is a
379  * string of the form specified by set_proxy_spec(), above. Note that the
380  * string returned by this function may not be exactly the same as the string
381  * passed into set_proxy_spec(), since the string is regenerated from the
382  * internal storage structures and may therefore be reordered.
383  */
384 string HTTPClient::
385 get_proxy_spec() const {
386  string result;
387 
388  ProxiesByScheme::const_iterator si;
389  for (si = _proxies_by_scheme.begin(); si != _proxies_by_scheme.end(); ++si) {
390  const string &scheme = (*si).first;
391  const Proxies &proxies = (*si).second;
392  Proxies::const_iterator pi;
393  for (pi = proxies.begin(); pi != proxies.end(); ++pi) {
394  const URLSpec &url = (*pi);
395  if (!result.empty()) {
396  result += ";";
397  }
398  if (!scheme.empty()) {
399  result += scheme;
400  result += "=";
401  }
402  if (url.empty()) {
403  result += "DIRECT";
404  } else {
405  result += url.get_url();
406  }
407  }
408  }
409 
410  return result;
411 }
412 
413 /**
414  * Specifies the set of hosts that should be connected to directly, without
415  * using a proxy. This is a semicolon-separated list of hostnames that may
416  * contain wildcard characters ("*").
417  */
418 void HTTPClient::
419 set_direct_host_spec(const string &direct_host_spec) {
420  clear_direct_host();
421 
422  // Tokenize the string based on the semicolons.
423  vector_string hosts;
424  tokenize(direct_host_spec, hosts, ";");
425 
426  for (vector_string::const_iterator hi = hosts.begin();
427  hi != hosts.end();
428  ++hi) {
429  string spec = trim_blanks(*hi);
430 
431  // We should be careful to avoid adding any empty hostnames to the list.
432  // In particular, we will get one empty hostname if the direct_host_spec
433  // is empty.
434  if (!spec.empty()) {
435  add_direct_host(spec);
436  }
437  }
438 }
439 
440 /**
441  * Returns the set of hosts that should be connected to directly, without
442  * using a proxy, as a semicolon-separated list of hostnames that may contain
443  * wildcard characters ("*").
444  */
445 string HTTPClient::
446 get_direct_host_spec() const {
447  string result;
448 
449  DirectHosts::const_iterator si;
450  for (si = _direct_hosts.begin(); si != _direct_hosts.end(); ++si) {
451  const GlobPattern &host = (*si);
452 
453  if (!result.empty()) {
454  result += ";";
455  }
456  result += host.get_pattern();
457  }
458 
459  return result;
460 }
461 
462 /**
463  * Resets the proxy spec to empty. Subsequent calls to add_proxy() may be
464  * made to build up the set of proxy servers.
465  */
466 void HTTPClient::
467 clear_proxy() {
468  _proxies_by_scheme.clear();
469 }
470 
471 /**
472  * Adds the indicated proxy host as a proxy for communications on the given
473  * scheme. Usually the scheme is "http" or "https". It may be the empty
474  * string to indicate a general proxy. The proxy string may be the empty URL
475  * to indicate a direct connection.
476  */
477 void HTTPClient::
478 add_proxy(const string &scheme, const URLSpec &proxy) {
479  URLSpec proxy_url(proxy);
480 
481  // The scheme is always converted to lowercase.
482  string lc_scheme;
483  lc_scheme.reserve(scheme.length());
484  string::const_iterator si;
485  for (si = scheme.begin(); si != scheme.end(); ++si) {
486  lc_scheme += tolower(*si);
487  }
488 
489  // Remove the trailing colon, if there is one.
490  if (!lc_scheme.empty() && lc_scheme[lc_scheme.length() - 1] == ':') {
491  lc_scheme = lc_scheme.substr(0, lc_scheme.length() - 1);
492  }
493 
494  if (!proxy_url.empty()) {
495  // Enforce the scheme that we use to communicate to the proxy itself.
496  // This is not the same as lc_scheme, which is the scheme of the requested
497  // connection. Generally, all proxies speak HTTP, except for Socks
498  // proxies.
499 
500  if (lc_scheme == "socks") {
501  // Scheme "socks" implies we talk to the proxy via the "socks" scheme,
502  // no matter what scheme the user actually specified.
503  proxy_url.set_scheme("socks");
504 
505  } else if (!proxy_url.has_scheme()) {
506  // Otherwise, if the user didn't specify a scheme to talk to the proxy,
507  // the default is "http".
508  proxy_url.set_scheme("http");
509  }
510  }
511 
512  _proxies_by_scheme[lc_scheme].push_back(proxy_url);
513 }
514 
515 /**
516  * Resets the set of direct hosts to empty. Subsequent calls to
517  * add_direct_host() may be made to build up the list of hosts that do not
518  * require a proxy connection.
519  */
520 void HTTPClient::
521 clear_direct_host() {
522  _direct_hosts.clear();
523 }
524 
525 /**
526  * Adds the indicated name to the set of hostnames that are connected to
527  * directly, without using a proxy. This name may be either a DNS name or an
528  * IP address, and it may include the * as a wildcard character.
529  */
530 void HTTPClient::
531 add_direct_host(const string &hostname) {
532  // The hostname is always converted to lowercase.
533  string lc_hostname;
534  lc_hostname.reserve(hostname.length());
535  for (string::const_iterator si = hostname.begin();
536  si != hostname.end();
537  ++si) {
538  lc_hostname += tolower(*si);
539  }
540 
541  _direct_hosts.push_back(GlobPattern(lc_hostname));
542 }
543 
544 /**
545  * Fills up the indicated vector with the list of URLSpec objects, in the
546  * order in which they should be tried, that are appropriate proxies to try
547  * for the indicated URL. The empty URL is returned for a direct connection.
548  *
549  * It is the user's responsibility to empty this vector before calling this
550  * method; otherwise, the proxy URL's will simply be appended to the existing
551  * list.
552  */
553 void HTTPClient::
554 get_proxies_for_url(const URLSpec &url, pvector<URLSpec> &proxies) const {
555  // First, check if the hostname matches any listed in direct_hosts.
556  string hostname = url.get_server();
557 
558  // If the hostname is empty, treat it as a special case: we don't match any
559  // of the hostnames listed in direct_hosts (even "*").
560  if (!hostname.empty()) {
561  DirectHosts::const_iterator si;
562  for (si = _direct_hosts.begin(); si != _direct_hosts.end(); ++si) {
563  if ((*si).matches(hostname)) {
564  // It matches, so don't use any proxies.
565  proxies.push_back(URLSpec());
566  return;
567  }
568  }
569  }
570 
571  // Build our list of proxies into a temporary vector, so we can pull out
572  // duplicates later.
573  pvector<URLSpec> temp_list;
574 
575  // Now choose the appropriate proxy based on the scheme.
576  string scheme = url.get_scheme();
577  bool got_any = false;
578 
579  if (!scheme.empty()) {
580  // If we have a scheme, try to match it.
581  if (get_proxies_for_scheme(scheme, temp_list)) {
582  got_any = true;
583  }
584  }
585 
586  if (!got_any && (scheme.empty() || url.is_ssl())) {
587  // An empty scheme (or an ssl-style scheme) implies we will need to make a
588  // direct connection, so fallback to a socks-style andor https-style
589  // scheme.
590 
591  if (get_proxies_for_scheme("socks", temp_list)) {
592  got_any = true;
593  }
594  if (get_proxies_for_scheme("https", temp_list)) {
595  got_any = true;
596  }
597  }
598 
599  if (!got_any) {
600  // If we didn't find our scheme of choice, fall back to the default proxy
601  // type, if we've got one.
602  if (get_proxies_for_scheme("", temp_list)) {
603  got_any = true;
604  }
605  }
606 
607  if (_try_all_direct) {
608  // We may try a direct connection if all else fails.
609  temp_list.push_back(URLSpec());
610  }
611 
612  // Finally, as a very last resort, fall back to the HTTP proxy.
613  if (!got_any) {
614  get_proxies_for_scheme("http", temp_list);
615  }
616 
617  // Now remove duplicate entries as we copy the resulting list out.
619  pset<URLSpec> used;
620  for (pi = temp_list.begin(); pi != temp_list.end(); ++pi) {
621  if (used.insert(*pi).second) {
622  // This is a unique one.
623  proxies.push_back(*pi);
624  }
625  }
626 }
627 
628 /**
629  * Returns a semicolon-delimited list of proxies, in the order in which they
630  * should be tried, that are appropriate for the indicated URL. The keyword
631  * DIRECT indicates a direct connection should be tried.
632  */
633 string HTTPClient::
634 get_proxies_for_url(const URLSpec &url) const {
635  pvector<URLSpec> proxies;
636  get_proxies_for_url(url, proxies);
637 
638  string result;
639  if (!proxies.empty()) {
640  pvector<URLSpec>::const_iterator pi = proxies.begin();
641  if ((*pi).get_url().empty()) {
642  result += "DIRECT";
643  } else {
644  result += (*pi).get_url();
645  }
646  ++pi;
647 
648  while (pi != proxies.end()) {
649  result += ";";
650  if ((*pi).get_url().empty()) {
651  result += "DIRECT";
652  } else {
653  result += (*pi).get_url();
654  }
655  ++pi;
656  }
657  }
658 
659  return result;
660 }
661 
662 /**
663  * Specifies the username:password string corresponding to a particular server
664  * and/or realm, when demanded by the server. Either or both of the server or
665  * realm may be empty; if so, they match anything. Also, the server may be
666  * set to the special string "*proxy", which will match any proxy server.
667  *
668  * If the username is set to the empty string, this clears the password for
669  * the particular server/realm pair.
670  */
671 void HTTPClient::
672 set_username(const string &server, const string &realm, const string &username) {
673  string key = server + ":" + realm;
674  if (username.empty()) {
675  _usernames.erase(key);
676  } else {
677  _usernames[key] = username;
678  }
679 }
680 
681 /**
682  * Returns the username:password string set for this server/realm pair, or
683  * empty string if nothing has been set. See set_username().
684  */
685 string HTTPClient::
686 get_username(const string &server, const string &realm) const {
687  string key = server + ":" + realm;
688  Usernames::const_iterator ui;
689  ui = _usernames.find(key);
690  if (ui != _usernames.end()) {
691  return (*ui).second;
692  }
693  return string();
694 }
695 
696 /**
697  * Stores the indicated cookie in the client's list of cookies, as if it had
698  * been received from a server.
699  */
700 void HTTPClient::
701 set_cookie(const HTTPCookie &cookie) {
702  if (cookie.is_expired()) {
703  clear_cookie(cookie);
704 
705  } else {
706  std::pair<Cookies::iterator, bool> result = _cookies.insert(cookie);
707  if (!result.second) {
708  // We already had a cookie matching the supplied domainpathname, so
709  // replace it.
710  const HTTPCookie &orig_cookie = *result.first;
711  ((HTTPCookie &)orig_cookie).update_from(cookie);
712  }
713  }
714 }
715 
716 /**
717  * Removes the cookie with the matching domain/path/name from the client's
718  * list of cookies. Returns true if it was removed, false if the cookie was
719  * not matched.
720  */
721 bool HTTPClient::
722 clear_cookie(const HTTPCookie &cookie) {
723  Cookies::iterator ci = _cookies.find(cookie);
724  if (ci != _cookies.end()) {
725  _cookies.erase(ci);
726  return true;
727  }
728 
729  return false;
730 }
731 
732 /**
733  * Removes the all stored cookies from the client.
734  */
735 void HTTPClient::
736 clear_all_cookies() {
737  _cookies.clear();
738 }
739 
740 /**
741  * Returns true if there is a cookie in the client matching the given cookie's
742  * domain/path/name, false otherwise.
743  */
744 bool HTTPClient::
745 has_cookie(const HTTPCookie &cookie) const {
746  Cookies::const_iterator ci = _cookies.find(cookie);
747  return (ci != _cookies.end());
748 }
749 
750 /**
751  * Looks up and returns the cookie in the client matching the given cookie's
752  * domain/path/name. If there is no matching cookie, returns an empty cookie.
753  */
754 HTTPCookie HTTPClient::
755 get_cookie(const HTTPCookie &cookie) const {
756  Cookies::const_iterator ci = _cookies.find(cookie);
757  if (ci != _cookies.end()) {
758  return (*ci);
759  }
760 
761  return HTTPCookie();
762 }
763 
764 /**
765  * Copies all the cookies from the indicated HTTPClient into this one.
766  * Existing cookies in this client are not affected, unless they are shadowed
767  * by the new cookies.
768  */
769 void HTTPClient::
770 copy_cookies_from(const HTTPClient &other) {
771  Cookies::const_iterator ci;
772  for (ci = other._cookies.begin(); ci != other._cookies.end(); ++ci) {
773  set_cookie(*ci);
774  }
775 }
776 
777 /**
778  * Outputs the complete list of cookies stored on the client, for all domains,
779  * including the expired cookies (which will normally not be sent back to a
780  * host).
781  */
782 void HTTPClient::
783 write_cookies(std::ostream &out) const {
784  Cookies::const_iterator ci;
785  for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) {
786  out << *ci << "\n";
787  }
788 }
789 
790 /**
791  * Writes to the indicated ostream a "Cookie" header line for sending the
792  * cookies appropriate to the indicated URL along with an HTTP request. This
793  * also removes expired cookies.
794  */
795 void HTTPClient::
796 send_cookies(std::ostream &out, const URLSpec &url) {
797  HTTPDate now = HTTPDate::now();
798  bool any_expired = false;
799  bool first_cookie = true;
800 
801  Cookies::const_iterator ci;
802  for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) {
803  const HTTPCookie &cookie = (*ci);
804  if (cookie.is_expired(now)) {
805  any_expired = true;
806 
807  } else if (cookie.matches_url(url)) {
808  if (first_cookie) {
809  out << "Cookie: ";
810  first_cookie = false;
811  } else {
812  out << "; ";
813  }
814  out << cookie.get_name() << "=" << cookie.get_value();
815  }
816  }
817 
818  if (!first_cookie) {
819  out << "\r\n";
820  }
821 
822  if (any_expired) {
823  Cookies new_cookies;
824  Cookies::const_iterator ci;
825  for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) {
826  const HTTPCookie &cookie = (*ci);
827  if (!cookie.is_expired(now)) {
828  new_cookies.insert(new_cookies.end(), cookie);
829  }
830  }
831  _cookies.swap(new_cookies);
832  }
833 }
834 
835 /**
836  * Attempts to load the certificate named by set_client_certificate_filename()
837  * immediately, and returns true if successful, false otherwise.
838  *
839  * Normally this need not be explicitly called, since it will be called
840  * automatically if the server requests a certificate, but it may be useful to
841  * determine ahead of time if the certificate can be loaded correctly.
842  */
843 bool HTTPClient::
844 load_client_certificate() {
845  if (!_client_certificate_loaded) {
846  _client_certificate_loaded = true;
847 
848  if (!_client_certificate_filename.empty()) {
849  _client_certificate_filename.set_text();
850 
851  // First, read the complete file into memory.
853 
854  if (!vfs->read_file(_client_certificate_filename,
855  _client_certificate_pem, true)) {
856  // Could not find or read file.
857  downloader_cat.warning()
858  << "Could not read " << _client_certificate_filename << ".\n";
859  return false;
860  }
861  }
862 
863  if (!_client_certificate_pem.empty()) {
864  // Create an in-memory BIO to read the "file" from the memory buffer,
865  // and call the low-level routines to read the keys from the BIO.
866  BIO *mbio = BIO_new_mem_buf((void *)_client_certificate_pem.data(),
867  _client_certificate_pem.length());
868 
869  ERR_clear_error();
870  _client_certificate_priv =
871  PEM_read_bio_PrivateKey(mbio, nullptr, nullptr,
872  (char *)_client_certificate_passphrase.c_str());
873 
874  // Rewind the "file" to the beginning in order to read the public key
875  // (which might appear first in the file).
876  (void)BIO_reset(mbio);
877 
878  ERR_clear_error();
879  _client_certificate_pub =
880  PEM_read_bio_X509(mbio, nullptr, nullptr, nullptr);
881 
882  BIO_free(mbio);
883 
884 
885  NotifySeverity sev = NS_debug;
886  string source = "memory";
887  if (!_client_certificate_filename.empty()) {
888  // Only report status to "info" severity if we have read the
889  // certificate from a file. If it came from an in-memory image, a
890  // failure will presumably be handled by whoever set the image.
891  sev = NS_info;
892  source = _client_certificate_filename;
893  }
894 
895  if (downloader_cat.is_on(sev)) {
896  if (_client_certificate_priv != nullptr &&
897  _client_certificate_pub != nullptr) {
898  downloader_cat.out(sev)
899  << "Read client certificate from " << source << "\n";
900 
901  } else {
902  if (_client_certificate_priv == nullptr) {
903  downloader_cat.out(sev)
904  << "Could not read private key from " << source << "\n";
905  }
906 
907  if (_client_certificate_pub == nullptr) {
908  downloader_cat.out(sev)
909  << "Could not read public key from " << source << "\n";
910  }
911  }
912  }
913  }
914  }
915 
916  return (_client_certificate_priv != nullptr &&
917  _client_certificate_pub != nullptr);
918 }
919 
920 /**
921  * Adds the certificate defined in the indicated PEM filename as a "pre-
922  * approved" certificate for the indicated server, defined by the hostname and
923  * port (only) from the given URL.
924  *
925  * If the server offers this particular certificate on a secure connection, it
926  * will be accepted without question. This is particularly useful for
927  * communicating with a server using a known self-signed certificate.
928  *
929  * See also the similar add_preapproved_server_certificate_pem(), and the
930  * weaker add_preapproved_server_certificate_name().
931  */
932 bool HTTPClient::
933 add_preapproved_server_certificate_filename(const URLSpec &url, const Filename &filename) {
935  string pem;
936 
937  if (!vfs->read_file(filename, pem, true)) {
938  // Could not find or read file.
939  downloader_cat.warning()
940  << "Could not read " << filename << ".\n";
941  return false;
942  }
943 
944  return add_preapproved_server_certificate_pem(url, pem);
945 }
946 
947 /**
948  * Adds the certificate defined in the indicated data string, formatted as a
949  * PEM block, as a "pre-approved" certificate for the indicated server,
950  * defined by the hostname and port (only) from the given URL.
951  *
952  * If the server offers this particular certificate on a secure connection, it
953  * will be accepted without question. This is particularly useful for
954  * communicating with a server using a known self-signed certificate.
955  *
956  * See also the similar add_preapproved_server_certificate_filename(), and the
957  * weaker add_preapproved_server_certificate_name().
958  */
959 bool HTTPClient::
960 add_preapproved_server_certificate_pem(const URLSpec &url, const string &pem) {
961  // Create an in-memory BIO to read the "file" from the memory buffer, and
962  // call the low-level routine to read the cert from the BIO.
963  BIO *mbio = BIO_new_mem_buf((void *)pem.data(), pem.length());
964 
965  ERR_clear_error();
966  X509 *cert = PEM_read_bio_X509(mbio, nullptr, nullptr, nullptr);
967  BIO_free(mbio);
968 
969  if (cert == nullptr) {
970  downloader_cat.warning()
971  << "Could not parse PEM data\n";
972  return false;
973  }
974 
975  string server_and_port = url.get_server_and_port();
976  PreapprovedServerCerts::iterator psci =
977  _preapproved_server_certs.insert(PreapprovedServerCerts::value_type(server_and_port, PreapprovedServerCert())).first;
978 
979  PreapprovedServerCert &psc = (*psci).second;
980  psc._certs.push_back(cert);
981 
982  return true;
983 }
984 
985 /**
986  * Adds the certificate *name* only, as a "pre-approved" certificate name for
987  * the indicated server, defined by the hostname and port (only) from the
988  * given URL.
989  *
990  * This is a weaker function than
991  * add_preapproved_server_certificate_filename(). This checks only the
992  * subject name of the certificate, without checking for a particular
993  * certificate by key. This means that a variety of server certificates may
994  * match the indicated name.
995  *
996  * Because this is a weaker verification, it only applies to server
997  * certificates that are signed by a recognized certificate authority. Thus,
998  * it cannot be used to pre-approve self-signed certificates, but it can be
999  * used to accept a server certificate offered by a different hostname than
1000  * the one in the cert itself.
1001  *
1002  * The certificate name should be formatted in the form
1003  * type0=value0/type1=value1/type2=...
1004  */
1005 bool HTTPClient::
1006 add_preapproved_server_certificate_name(const URLSpec &url, const string &name) {
1007  X509_NAME *cert_name = parse_x509_name(name);
1008  if (cert_name == nullptr) {
1009  downloader_cat.warning()
1010  << "Could not parse certificate name " << name << "\n";
1011  return false;
1012  }
1013 
1014  string server_and_port = url.get_server_and_port();
1015  PreapprovedServerCerts::iterator psci =
1016  _preapproved_server_certs.insert(PreapprovedServerCerts::value_type(server_and_port, PreapprovedServerCert())).first;
1017 
1018  PreapprovedServerCert &psc = (*psci).second;
1019  psc._cert_names.push_back(cert_name);
1020 
1021  return true;
1022 }
1023 
1024 /**
1025  * Removes all preapproved server certificates for the indicated server and
1026  * port.
1027  */
1028 void HTTPClient::
1029 clear_preapproved_server_certificates(const URLSpec &url) {
1030  string server_and_port = url.get_server_and_port();
1031  _preapproved_server_certs.erase(server_and_port);
1032 }
1033 
1034 /**
1035  * Removes all preapproved server certificates for all servers.
1036  */
1037 void HTTPClient::
1038 clear_all_preapproved_server_certificates() {
1039  _preapproved_server_certs.clear();
1040 }
1041 
1042 /**
1043  * Returns the current HTTP version setting as a string, e.g. "HTTP/1.0" or
1044  * "HTTP/1.1".
1045  */
1046 string HTTPClient::
1047 get_http_version_string() const {
1048  switch (_http_version) {
1049  case HTTPEnum::HV_09:
1050  return "HTTP/0.9";
1051 
1052  case HTTPEnum::HV_10:
1053  return "HTTP/1.0";
1054 
1055  case HTTPEnum::HV_11:
1056  return "HTTP/1.1";
1057 
1058  case HTTPEnum::HV_other:
1059  // Report the best we can do.
1060  return "HTTP/1.1";
1061  }
1062 
1063  return "unknown";
1064 }
1065 
1066 /**
1067  * Matches the string representing a particular HTTP version against any of
1068  * the known versions and returns the appropriate enumerated value, or
1069  * HV_other if the version is unknown.
1070  */
1071 HTTPEnum::HTTPVersion HTTPClient::
1072 parse_http_version_string(const string &version) {
1073  if (version == "HTTP/1.0") {
1074  return HTTPEnum::HV_10;
1075  } else if (version == "HTTP/1.1") {
1076  return HTTPEnum::HV_11;
1077  } else if (version.substr(0, 6) == "HTTP/0") {
1078  return HTTPEnum::HV_09;
1079  } else {
1080  return HTTPEnum::HV_other;
1081  }
1082 }
1083 
1084 /**
1085  * Reads the certificate(s) (delimited by -----BEGIN CERTIFICATE----- and
1086  * -----END CERTIFICATE-----) from the indicated file and makes them known as
1087  * trusted public keys for validating future connections. Returns true on
1088  * success, false otherwise.
1089  */
1090 bool HTTPClient::
1091 load_certificates(const Filename &filename) {
1092  OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
1093  return (sslw->load_certificates(filename) != 0);
1094 }
1095 
1096 /**
1097  * Returns a new HTTPChannel object that may be used for reading multiple
1098  * documents using the same connection, for greater network efficiency than
1099  * calling HTTPClient::get_document() repeatedly (which would force a new
1100  * connection for each document).
1101  *
1102  * Also, HTTPChannel has some additional, less common interface methods than
1103  * the basic interface methods that exist on HTTPClient; if you wish to call
1104  * any of these methods you must first obtain an HTTPChannel.
1105  *
1106  * Pass true for persistent_connection to gain this network efficiency. If,
1107  * on the other hand, your intention is to use the channel to retrieve only
1108  * one document, then pass false to inform the server that we will be dropping
1109  * the connection after the first document.
1110  */
1111 PT(HTTPChannel) HTTPClient::
1112 make_channel(bool persistent_connection) {
1113  PT(HTTPChannel) doc = new HTTPChannel(this);
1114  doc->set_persistent_connection(persistent_connection);
1115  return doc;
1116 }
1117 
1118 /**
1119  * Posts form data to a particular URL and retrieves the response. Returns a
1120  * new HTTPChannel object whether the document is successfully read or not;
1121  * you can test is_valid() and get_return_code() to determine whether the
1122  * document was retrieved.
1123  */
1124 PT(HTTPChannel) HTTPClient::
1125 post_form(const URLSpec &url, const string &body) {
1126  PT(HTTPChannel) doc = new HTTPChannel(this);
1127  doc->post_form(url, body);
1128  return doc;
1129 }
1130 
1131 /**
1132  * Opens the named document for reading. Returns a new HTTPChannel object
1133  * whether the document is successfully read or not; you can test is_valid()
1134  * and get_return_code() to determine whether the document was retrieved.
1135  */
1136 PT(HTTPChannel) HTTPClient::
1137 get_document(const URLSpec &url) {
1138  PT(HTTPChannel) doc = new HTTPChannel(this);
1139  doc->get_document(url);
1140  return doc;
1141 }
1142 
1143 /**
1144  * Like get_document(), except only the header associated with the document is
1145  * retrieved. This may be used to test for existence of the document; it
1146  * might also return the size of the document (if the server gives us this
1147  * information).
1148  */
1149 PT(HTTPChannel) HTTPClient::
1150 get_header(const URLSpec &url) {
1151  PT(HTTPChannel) doc = new HTTPChannel(this);
1152  doc->get_header(url);
1153  return doc;
1154 }
1155 
1156 /**
1157  * Returns the default global HTTPClient.
1158  */
1159 HTTPClient *HTTPClient::
1160 get_global_ptr() {
1161  if (_global_ptr == nullptr) {
1162  _global_ptr = new HTTPClient;
1163  }
1164  return _global_ptr;
1165 }
1166 
1167 
1168 /**
1169  * Returns the OpenSSL context object, creating it first if needed.
1170  */
1171 SSL_CTX *HTTPClient::
1172 get_ssl_ctx() {
1173  if (_ssl_ctx != nullptr) {
1174  return _ssl_ctx;
1175  }
1176 
1177  init_random_seed();
1178 
1179  _ssl_ctx = SSL_CTX_new(SSLv23_client_method());
1180 
1181 #ifndef NDEBUG
1182  // If we have debugging enabled, set a callback that allows us to report the
1183  // SSL messages as they are sent and received.
1184  if (downloader_cat.is_debug()) {
1185  SSL_CTX_set_msg_callback(_ssl_ctx, ssl_msg_callback);
1186  }
1187 #endif
1188 
1189  // Make sure the error strings are loaded.
1190  OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
1191  sslw->notify_ssl_errors();
1192 
1193  X509_STORE *store = sslw->get_x509_store();
1194 #if OPENSSL_VERSION_NUMBER >= 0x10100000
1195  if (store != nullptr) {
1196  X509_STORE_up_ref(store);
1197  }
1198 #endif
1199  SSL_CTX_set_cert_store(_ssl_ctx, store);
1200 
1201  return _ssl_ctx;
1202 }
1203 
1204 /**
1205  * Checks to see if the indicated certificate is on the pre-approved list for
1206  * the indicated server's URL.
1207  *
1208  * If the full cert itself (including its key) is on the pre-approved list,
1209  * sets both cert_preapproved and cert_name_preapproved to true.
1210  *
1211  * If the full cert is not on the pre-approved list, but its name matches a
1212  * name on the pre-approved list, sets cert_name_preapproved to true, and
1213  * cert_preapproved to false.
1214  *
1215  * Otherwise, sets both values to false. This doesn't mean the cert is
1216  * necessarily invalid, just that it wasn't on the pre-approved list (which is
1217  * usually empty anyway).
1218  */
1219 void HTTPClient::
1220 check_preapproved_server_certificate(const URLSpec &url, X509 *cert,
1221  bool &cert_preapproved, bool &cert_name_preapproved) const {
1222  cert_preapproved = false;
1223  cert_name_preapproved = false;
1224 
1225  string server_and_port = url.get_server_and_port();
1226  PreapprovedServerCerts::const_iterator psci =
1227  _preapproved_server_certs.find(server_and_port);
1228 
1229  if (psci == _preapproved_server_certs.end()) {
1230  // No preapproved certs defined for this server.
1231  return;
1232  }
1233 
1234  const PreapprovedServerCert &psc = (*psci).second;
1235 
1236  // See if we have an exact match on the cert itself.
1237  ServerCerts::const_iterator sci;
1238  for (sci = psc._certs.begin(); sci != psc._certs.end(); ++sci) {
1239  if (X509_cmp(cert, *sci) == 0) {
1240  cert_preapproved = true;
1241  cert_name_preapproved = true;
1242  downloader_cat.info()
1243  << "Server certificate is pre-approved.\n";
1244  return;
1245  }
1246  }
1247 
1248  // OK, look for a match on the cert's name only.
1249  X509_NAME *subject = X509_get_subject_name(cert);
1250  ServerCertNames::const_iterator scni;
1251  for (scni = psc._cert_names.begin(); scni != psc._cert_names.end(); ++scni) {
1252  X509_NAME *cert_name = (*scni);
1253  if (x509_name_subset(cert_name, subject)) {
1254  downloader_cat.info()
1255  << "Server certificate name is pre-approved.\n";
1256  cert_name_preapproved = true;
1257  return;
1258  }
1259  }
1260 
1261  // Didn't find any match.
1262  return;
1263 }
1264 
1265 /**
1266  * Adds the proxy servers associated with the indicated scheme, if any, to the
1267  * list. Returns true if any were added, false otherwise.
1268  */
1269 bool HTTPClient::
1270 get_proxies_for_scheme(const string &scheme, pvector<URLSpec> &proxies) const {
1271  ProxiesByScheme::const_iterator si = _proxies_by_scheme.find(scheme);
1272  if (si == _proxies_by_scheme.end()) {
1273  return false;
1274  }
1275  const Proxies &scheme_proxies = (*si).second;
1276  if (scheme_proxies.empty()) {
1277  return false;
1278  }
1279 
1280  Proxies::const_iterator pi;
1281  for (pi = scheme_proxies.begin(); pi != scheme_proxies.end(); ++pi) {
1282  proxies.push_back(*pi);
1283  }
1284 
1285  return true;
1286 }
1287 
1288 /**
1289  * Handles a Config definition for http-username as
1290  * server:realm:username:password, where either or both of server and realm
1291  * may be empty, or just server:username:password or username:password.
1292  */
1293 void HTTPClient::
1294 add_http_username(const string &http_username) {
1295  size_t c1 = http_username.find(':');
1296  if (c1 != string::npos) {
1297  size_t c2 = http_username.find(':', c1 + 1);
1298  if (c2 != string::npos) {
1299  size_t c3 = http_username.find(':', c2 + 1);
1300  if (c3 != string::npos) {
1301  size_t c4 = http_username.find(':', c3 + 1);
1302  if (c4 != string::npos) {
1303  // Oops, we have five? Problem.
1304  downloader_cat.error()
1305  << "Invalid http-username " << http_username << "\n";
1306 
1307  } else {
1308  // Ok, we have four.
1309  set_username(http_username.substr(0, c1),
1310  http_username.substr(c1 + 1, c2 - (c1 + 1)),
1311  http_username.substr(c2 + 1));
1312  }
1313 
1314  } else {
1315  // We have only three.
1316  set_username(string(),
1317  http_username.substr(0, c1),
1318  http_username.substr(c1 + 1));
1319  }
1320  } else {
1321  // We have only two.
1322  set_username(string(), string(), http_username);
1323  }
1324  } else {
1325  // We have only one? Problem.
1326  downloader_cat.error()
1327  << "Invalid http-username " << http_username << "\n";
1328  }
1329 }
1330 
1331 /**
1332  * Chooses a suitable username:password string for the given URL and realm.
1333  */
1334 string HTTPClient::
1335 select_username(const URLSpec &url, bool is_proxy, const string &realm) const {
1336  string username;
1337 
1338  // Look in several places in order to find the matching username.
1339 
1340  // Fist, if there's a username on the URL, that always wins (except when we
1341  // are looking for a proxy username).
1342  if (url.has_username() && !is_proxy) {
1343  username = url.get_username();
1344  }
1345 
1346  // Otherwise, start looking on the HTTPClient.
1347  if (is_proxy) {
1348  if (username.empty()) {
1349  // Try the *proxyrealm.
1350  username = get_username("*proxy", realm);
1351  }
1352  if (username.empty()) {
1353  // Then, try *proxyany realm.
1354  username = get_username("*proxy", string());
1355  }
1356  }
1357  if (username.empty()) {
1358  // Try the specific serverrealm.
1359  username = get_username(url.get_server(), realm);
1360  }
1361  if (username.empty()) {
1362  // Then, try the specific serverany realm.
1363  username = get_username(url.get_server(), string());
1364  }
1365  if (username.empty()) {
1366  // Then, try any server with this realm.
1367  username = get_username(string(), realm);
1368  }
1369  if (username.empty()) {
1370  // Then, take the general password.
1371  username = get_username(string(), string());
1372  }
1373 
1374  return username;
1375 }
1376 
1377 /**
1378  * Chooses a suitable pre-computed authorization for the indicated URL.
1379  * Returns NULL if no authorization matches.
1380  */
1381 HTTPAuthorization *HTTPClient::
1382 select_auth(const URLSpec &url, bool is_proxy, const string &last_realm) {
1383  Domains &domains = is_proxy ? _proxy_domains : _www_domains;
1384  string canon = HTTPAuthorization::get_canonical_url(url).get_url();
1385 
1386  // Look for the longest domain string that is a prefix of our canonical URL.
1387  // We have to make a linear scan through the list.
1388  Domains::const_iterator best_di = domains.end();
1389  size_t longest_length = 0;
1390  Domains::const_iterator di;
1391  for (di = domains.begin(); di != domains.end(); ++di) {
1392  const string &domain = (*di).first;
1393  size_t length = domain.length();
1394  if (domain == canon.substr(0, length)) {
1395  // This domain string matches. Is it the longest?
1396  if (length > longest_length) {
1397  best_di = di;
1398  longest_length = length;
1399  }
1400  }
1401  }
1402 
1403  if (best_di != domains.end()) {
1404  // Ok, we found a matching domain. Use it.
1405  if (downloader_cat.is_spam()) {
1406  downloader_cat.spam()
1407  << "Choosing domain " << (*best_di).first << " for " << url << "\n";
1408  }
1409  const Realms &realms = (*best_di).second._realms;
1410  // First, try our last realm.
1411  Realms::const_iterator ri;
1412  ri = realms.find(last_realm);
1413  if (ri != realms.end()) {
1414  return (*ri).second;
1415  }
1416 
1417  if (!realms.empty()) {
1418  // Oh well, just return the first realm.
1419  return (*realms.begin()).second;
1420  }
1421  }
1422 
1423  // No matching domains.
1424  return nullptr;
1425 }
1426 
1427 /**
1428  * Generates a new authorization entry in response to a 401 or 407 challenge
1429  * from the server or proxy. The new authorization entry is stored for future
1430  * connections to the same server (or, more precisely, the same domain, which
1431  * may be a subset of the server, or it may include multiple servers).
1432  */
1433 PT(HTTPAuthorization) HTTPClient::
1434 generate_auth(const URLSpec &url, bool is_proxy, const string &challenge) {
1435  HTTPAuthorization::AuthenticationSchemes schemes;
1436  HTTPAuthorization::parse_authentication_schemes(schemes, challenge);
1437 
1438  PT(HTTPAuthorization) auth;
1439  HTTPAuthorization::AuthenticationSchemes::iterator si;
1440 
1441  si = schemes.find("digest");
1442  if (si != schemes.end()) {
1443  auth = new HTTPDigestAuthorization((*si).second, url, is_proxy);
1444  }
1445 
1446  if (auth == nullptr || !auth->is_valid()) {
1447  si = schemes.find("basic");
1448  if (si != schemes.end()) {
1449  auth = new HTTPBasicAuthorization((*si).second, url, is_proxy);
1450  }
1451  }
1452 
1453  if (auth == nullptr || !auth->is_valid()) {
1454  downloader_cat.warning()
1455  << "Don't know how to use any of the server's available authorization schemes:\n";
1456  for (si = schemes.begin(); si != schemes.end(); ++si) {
1457  downloader_cat.warning() << (*si).first << "\n";
1458  }
1459 
1460  } else {
1461  // Now that we've got an authorization, store it under under each of its
1462  // suggested domains for future use.
1463  Domains &domains = is_proxy ? _proxy_domains : _www_domains;
1464  const vector_string &domain = auth->get_domain();
1465  vector_string::const_iterator si;
1466  for (si = domain.begin(); si != domain.end(); ++si) {
1467  domains[(*si)]._realms[auth->get_realm()] = auth;
1468  }
1469  }
1470 
1471  return auth;
1472 }
1473 
1474 /**
1475  * Frees the resources allocated by a previous call to
1476  * load_client_certificate(), and marks the certificate unloaded.
1477  */
1478 void HTTPClient::
1479 unload_client_certificate() {
1480  if (_client_certificate_priv != nullptr) {
1481  EVP_PKEY_free(_client_certificate_priv);
1482  _client_certificate_priv = nullptr;
1483  }
1484 
1485  if (_client_certificate_pub != nullptr) {
1486  X509_free(_client_certificate_pub);
1487  _client_certificate_pub = nullptr;
1488  }
1489 
1490  _client_certificate_loaded = false;
1491 }
1492 
1493 /**
1494  * Parses a string of the form type0=value0/type1=value1/type2=... into a
1495  * newly allocated X509_NAME object. Returns NULL if the string is invalid.
1496  */
1497 X509_NAME *HTTPClient::
1498 parse_x509_name(const string &source) {
1499  X509_NAME *result = nullptr;
1500 
1501  result = X509_NAME_new();
1502  bool added_any = false;
1503 
1504  string::const_iterator si;
1505  si = source.begin();
1506  while (si != source.end()) {
1507  if ((*si) == '/') {
1508  // Skip a slash delimiter.
1509  ++si;
1510  } else {
1511  string type;
1512  while (si != source.end() && (*si) != '=' && (*si) != '/') {
1513  if ((*si) == '\\') {
1514  ++si;
1515  if (si != source.end()) {
1516  type += (*si);
1517  ++si;
1518  }
1519  } else {
1520  type += (*si);
1521  ++si;
1522  }
1523  }
1524 
1525  int nid = OBJ_txt2nid((char *)type.c_str());
1526  if (nid == NID_undef) {
1527  downloader_cat.info()
1528  << "Unknown type " << type << " in X509 name: " << source
1529  << "\n";
1530  X509_NAME_free(result);
1531  return nullptr;
1532  }
1533 
1534  string value;
1535 
1536  if (si != source.end() && (*si) == '=') {
1537  ++si;
1538  while (si != source.end() && (*si) != '/') {
1539  if ((*si) == '\\') {
1540  ++si;
1541  if (si != source.end()) {
1542  value += (*si);
1543  ++si;
1544  }
1545  } else {
1546  value += (*si);
1547  ++si;
1548  }
1549  }
1550  }
1551 
1552  if (!value.empty()) {
1553  int add_result =
1554  X509_NAME_add_entry_by_NID(result, nid, V_ASN1_APP_CHOOSE,
1555  (unsigned char *)value.c_str(), -1, -1, 0);
1556  if (!add_result) {
1557  downloader_cat.info()
1558  << "Unable to add " << type << "=" << value << " in X509 name: "
1559  << source << "\n";
1560  X509_NAME_free(result);
1561  return nullptr;
1562  }
1563  added_any = true;
1564  }
1565  }
1566  }
1567 
1568  if (!added_any) {
1569  downloader_cat.info()
1570  << "Invalid empty X509 name: " << source << "\n";
1571  X509_NAME_free(result);
1572  return nullptr;
1573  }
1574 
1575  return result;
1576 }
1577 
1578 /**
1579  * Returns true if name_a is a subset of name_b: each property of name_a is
1580  * defined in name_b, and the defined value is equivalent to that of name_a.
1581  */
1582 bool HTTPClient::
1583 x509_name_subset(X509_NAME *name_a, X509_NAME *name_b) {
1584  int count_a = X509_NAME_entry_count(name_a);
1585  for (int ai = 0; ai < count_a; ai++) {
1586  X509_NAME_ENTRY *na = X509_NAME_get_entry(name_a, ai);
1587 
1588  int bi = X509_NAME_get_index_by_OBJ(name_b, X509_NAME_ENTRY_get_object(na), -1);
1589  if (bi < 0) {
1590  // This entry in name_a is not defined in name_b.
1591  return false;
1592  }
1593 
1594  X509_NAME_ENTRY *nb = X509_NAME_get_entry(name_b, bi);
1595  ASN1_STRING *na_value = X509_NAME_ENTRY_get_data(na);
1596  ASN1_STRING *nb_value = X509_NAME_ENTRY_get_data(nb);
1597  if (na_value->length != nb_value->length ||
1598  memcmp(na_value->data, nb_value->data, na_value->length) != 0) {
1599  // This entry in name_a doesn't match that of name_b.
1600  return false;
1601  }
1602  }
1603  return true;
1604 }
1605 
1606 /**
1607  * Puts the first word of c into a, and the remainder into b.
1608  */
1609 void HTTPClient::
1610 split_whitespace(string &a, string &b, const string &c) {
1611  size_t p = 0;
1612 
1613  // Skip initial whitespace
1614  while (p < c.length() && isspace(c[p])) {
1615  ++p;
1616  }
1617 
1618  // Find the length of the first word
1619  size_t q = p;
1620  while (p < c.length() && !isspace(c[p])) {
1621  ++p;
1622  }
1623 
1624  a = c.substr(q, p - q);
1625 
1626  // Skip whitespace between words
1627  while (p < c.length() && isspace(c[p])) {
1628  ++p;
1629  }
1630  b = c.substr(p);
1631 }
1632 
1633 /**
1634  *
1635  */
1636 HTTPClient::PreapprovedServerCert::
1637 ~PreapprovedServerCert() {
1638  ServerCerts::const_iterator sci;
1639  for (sci = _certs.begin(); sci != _certs.end(); ++sci) {
1640  X509_free(*sci);
1641  }
1642 
1643  ServerCertNames::const_iterator scni;
1644  for (scni = _cert_names.begin(); scni != _cert_names.end(); ++scni) {
1645  X509_NAME_free(*scni);
1646  }
1647 }
1648 
1649 #endif // HAVE_OPENSSL
is_ssl
Returns true if the URL's scheme specifies an SSL-secured protocol such as https, or false otherwise.
Definition: urlSpec.h:101
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for a URL, e.g.
Definition: urlSpec.h:28
This is a convenience class to specialize ConfigVariable as a Filename type.
A hierarchy of directories and files that appears to be one continuous file system,...
This is a convenience class to specialize ConfigVariable as a boolean type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_username() const
Returns true if the URL specifies a username (and/or password), false otherwise.
Definition: urlSpec.I:77
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool empty() const
Returns false if the URLSpec is valid (not empty), or true if it is an empty string.
Definition: urlSpec.I:209
This class is similar to ConfigVariable, but it reports its value as a list of strings.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
get_scheme
Returns the scheme specified by the URL, or empty string if no scheme is specified.
Definition: urlSpec.h:93
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
This is a convenience class to specialize ConfigVariable as a string type.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
A container for an HTTP-legal time/date indication.
Definition: httpDate.h:27
static HTTPDate now()
Returns an HTTPDate that represents the current time and date.
Definition: httpDate.I:47
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_pattern
Returns the pattern string that the GlobPattern object matches.
Definition: globPattern.h:44
void tokenize(const string &str, vector_string &words, const string &delimiters, bool discard_repeated_delimiters)
Chops the source string up into pieces delimited by any of the characters specified in delimiters.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const std::string & get_url() const
Returns the complete URL specification.
Definition: urlSpec.I:184
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_server
Returns the server name specified by the URL, if any.
Definition: urlSpec.h:96
get_username
Returns the username specified by the URL, if any.
Definition: urlSpec.h:95
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_server_and_port
Returns a string consisting of the server name, followed by a colon, followed by the port number.
Definition: urlSpec.h:98
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition: globPattern.h:32