15 #include "httpClient.h"
16 #include "httpChannel.h"
17 #include "config_downloader.h"
19 #include "config_express.h"
20 #include "virtualFileSystem.h"
21 #include "executionEnvironment.h"
22 #include "httpBasicAuthorization.h"
23 #include "httpDigestAuthorization.h"
24 #include "globPattern.h"
28 PT(HTTPClient) HTTPClient::_global_ptr;
35 trim_blanks(const
string &str) {
37 while (start < str.length() && isspace(str[start])) {
41 size_t end = str.length();
42 while (end > start && isspace(str[end - 1])) {
46 return str.substr(start, end - start);
62 tokenize(
const string &str, vector_string &words,
const string &delimiters) {
64 while (p < str.length()) {
65 size_t q = str.find_first_of(delimiters, p);
66 if (q == string::npos) {
67 words.push_back(str.substr(p));
70 words.push_back(str.substr(p, q - p));
73 words.push_back(
string());
85 PRC_DESC(
"Configure this true (the default) to insist on verifying all SSL "
86 "(e.g. https) servers against a known certificate, or false to allow "
87 "an unverified connection. This controls the default behavior; the "
88 "specific behavior for a particular HTTPClient can be adjusted at "
89 "runtime with set_verify_ssl()."));
92 (
"ssl-cipher-list",
"DEFAULT",
93 PRC_DESC(
"This is the default value for HTTPClient::set_cipher_list()."));
97 PRC_DESC(
"This specifies the default value for HTTPClient::set_proxy_spec(). "
98 "It is a semicolon-delimited list of proxies that we use to contact "
99 "all HTTP hosts that don't specify otherwise. See "
100 "set_proxy_spec() for more information."));
103 (
"http-direct-hosts",
"",
104 PRC_DESC(
"This specifies the default value for HTTPClient::set_direct_host_spec(). "
105 "It is a semicolon-delimited list of host names that do not require a "
106 "proxy. See set_direct_host_spec() for more information."));
109 (
"http-try-all-direct",
true,
110 PRC_DESC(
"This specifies the default value for HTTPClient::set_try_all_direct(). "
111 "If this is true, a direct connection will always be attempted after an "
112 "attempt to connect through a proxy fails."));
115 (
"http-proxy-username",
"",
116 PRC_DESC(
"This specifies a default username:password to pass to the proxy."));
120 PRC_DESC(
"Adds one or more username/password pairs to all HTTP clients. The client "
121 "will present this username/password when asked to authenticate a request "
122 "for a particular server and/or realm. The username is of the form "
123 "server:realm:username:password, where either or both of server and "
124 "realm may be empty, or just realm:username:password or username:password. "
125 "If the server or realm is empty, they will match anything."));
128 (
"http-client-certificate-filename",
"",
129 PRC_DESC(
"This provides a default client certificate to offer up should an "
130 "SSL server demand one. The file names a PEM-formatted file "
131 "that includes a public and private key specification. A "
132 "connection-specific certificate may also be specified at runtime on "
133 "the HTTPClient object, but this will require having a different "
134 "HTTPClient object for each differently-certificated connection."));
137 (
"http-client-certificate-passphrase",
"",
138 PRC_DESC(
"This specifies the passphrase to use to decode the certificate named "
139 "by http-client-certificate-filename."));
143 (
"http-preapproved-server-certificate-filename",
144 PRC_DESC(
"This specifies a server hostname:port combination, followed by "
145 "at least one space, and the name of a PEM file that contains "
146 "an SSL certificate that we expect this server to offer. If "
147 "it does, we will accept the cert without further question, "
148 "even if the cert does not match any known certificate "
149 "authorities. This option may appear multiple times."));
152 (
"http-preapproved-server-certificate-name",
153 PRC_DESC(
"This specifies a server hostname:port combination, followed by "
154 "at least one space, and a string describing the subject name "
155 "of an SSL certificate we expect this server to offer. If it "
156 "it does, we will accept the cert, but only if it also matches "
157 "a known certificate authority. This option may appear "
160 _http_version = HTTPEnum::HV_11;
161 _verify_ssl = verify_ssl ? VS_normal : VS_no_verify;
162 _ssl_ctx = (SSL_CTX *)NULL;
164 set_proxy_spec(http_proxy);
165 set_direct_host_spec(http_direct_hosts);
166 _try_all_direct = http_try_all_direct;
168 if (!http_proxy_username.empty()) {
169 set_username(
"*proxy",
"", http_proxy_username);
172 set_cipher_list(ssl_cipher_list);
176 int num_unique_values = http_username.get_num_unique_values();
177 for (
int i = 0; i < num_unique_values; i++) {
178 string username = http_username.get_unique_value(i);
179 add_http_username(username);
183 _client_certificate_filename = http_client_certificate_filename;
184 _client_certificate_passphrase = http_client_certificate_passphrase;
186 _client_certificate_loaded =
false;
187 _client_certificate_pub = NULL;
188 _client_certificate_priv = NULL;
190 int num_server_certs = http_preapproved_server_certificate_filename.get_num_unique_values();
192 for (si = 0; si < num_server_certs; si++) {
193 string cert_line = http_preapproved_server_certificate_filename.get_unique_value(si);
195 split_whitespace(a, b, cert_line);
196 add_preapproved_server_certificate_filename(
URLSpec(a,
true), b);
199 num_server_certs = http_preapproved_server_certificate_name.get_num_unique_values();
200 for (si = 0; si < num_server_certs; si++) {
201 string cert_line = http_preapproved_server_certificate_name.get_unique_value(si);
203 split_whitespace(a, b, cert_line);
204 add_preapproved_server_certificate_name(
URLSpec(a,
true), b);
209 OpenSSLWrapper::get_global_ptr();
218 HTTPClient(
const HTTPClient ©) {
219 _ssl_ctx = (SSL_CTX *)NULL;
230 operator = (
const HTTPClient ©) {
231 _proxies_by_scheme = copy._proxies_by_scheme;
232 _direct_hosts = copy._direct_hosts;
233 _try_all_direct = copy._try_all_direct;
234 _http_version = copy._http_version;
235 _verify_ssl = copy._verify_ssl;
236 _usernames = copy._usernames;
237 _cookies = copy._cookies;
250 if (_ssl_ctx != (SSL_CTX *)NULL) {
251 _ssl_ctx->cert_store = NULL;
252 SSL_CTX_free(_ssl_ctx);
255 unload_client_certificate();
278 OpenSSLWrapper::get_global_ptr();
296 set_proxy_spec(
const string &proxy_spec) {
299 string trim_proxy_spec = trim_blanks(proxy_spec);
302 if (!trim_proxy_spec.empty()) {
303 vector_string proxies;
304 tokenize(trim_proxy_spec, proxies,
";");
306 for (vector_string::const_iterator pi = proxies.begin();
309 const string &spec = (*pi);
314 size_t equals = spec.find(
'=');
315 if (equals == string::npos) {
317 proxy = trim_blanks(spec);
319 scheme = trim_blanks(spec.substr(0, equals));
320 proxy = trim_blanks(spec.substr(equals + 1));
323 if (proxy ==
"DIRECT" || proxy.empty()) {
326 add_proxy(scheme,
URLSpec(proxy,
true));
344 get_proxy_spec()
const {
347 ProxiesByScheme::const_iterator si;
348 for (si = _proxies_by_scheme.begin(); si != _proxies_by_scheme.end(); ++si) {
349 const string &scheme = (*si).first;
350 const Proxies &proxies = (*si).second;
351 Proxies::const_iterator pi;
352 for (pi = proxies.begin(); pi != proxies.end(); ++pi) {
354 if (!result.empty()) {
357 if (!scheme.empty()) {
381 set_direct_host_spec(
const string &direct_host_spec) {
386 tokenize(direct_host_spec, hosts,
";");
388 for (vector_string::const_iterator hi = hosts.begin();
391 string spec = trim_blanks(*hi);
397 add_direct_host(spec);
411 get_direct_host_spec()
const {
414 DirectHosts::const_iterator si;
415 for (si = _direct_hosts.begin(); si != _direct_hosts.end(); ++si) {
418 if (!result.empty()) {
436 _proxies_by_scheme.clear();
449 add_proxy(
const string &scheme,
const URLSpec &proxy) {
454 lc_scheme.reserve(scheme.length());
455 string::const_iterator si;
456 for (si = scheme.begin(); si != scheme.end(); ++si) {
457 lc_scheme += tolower(*si);
461 if (!lc_scheme.empty() && lc_scheme[lc_scheme.length() - 1] ==
':') {
462 lc_scheme = lc_scheme.substr(0, lc_scheme.length() - 1);
465 if (!proxy_url.empty()) {
471 if (lc_scheme ==
"socks") {
474 proxy_url.set_scheme(
"socks");
476 }
else if (!proxy_url.has_scheme()) {
479 proxy_url.set_scheme(
"http");
483 _proxies_by_scheme[lc_scheme].push_back(proxy_url);
495 clear_direct_host() {
496 _direct_hosts.clear();
508 add_direct_host(
const string &hostname) {
511 lc_hostname.reserve(hostname.length());
512 for (string::const_iterator si = hostname.begin();
513 si != hostname.end();
515 lc_hostname += tolower(*si);
541 if (!hostname.empty()) {
542 DirectHosts::const_iterator si;
543 for (si = _direct_hosts.begin(); si != _direct_hosts.end(); ++si) {
544 if ((*si).matches(hostname)) {
558 bool got_any =
false;
560 if (!scheme.empty()) {
562 if (get_proxies_for_scheme(scheme, temp_list)) {
567 if (!got_any && (scheme.empty() || url.
is_ssl())) {
572 if (get_proxies_for_scheme(
"socks", temp_list)) {
575 if (get_proxies_for_scheme(
"https", temp_list)) {
583 if (get_proxies_for_scheme(
"", temp_list)) {
588 if (_try_all_direct) {
590 temp_list.push_back(
URLSpec());
595 get_proxies_for_scheme(
"http", temp_list);
601 for (pi = temp_list.begin(); pi != temp_list.end(); ++pi) {
602 if (used.insert(*pi).second) {
604 proxies.push_back(*pi);
618 get_proxies_for_url(
const URLSpec &url)
const {
620 get_proxies_for_url(url, proxies);
623 if (!proxies.empty()) {
625 if ((*pi).get_url().empty()) {
628 result += (*pi).get_url();
632 while (pi != proxies.end()) {
634 if ((*pi).get_url().empty()) {
637 result += (*pi).get_url();
661 set_username(
const string &server,
const string &realm,
const string &username) {
662 string key = server +
":" + realm;
663 if (username.empty()) {
664 _usernames.erase(key);
666 _usernames[key] = username;
678 get_username(
const string &server,
const string &realm)
const {
679 string key = server +
":" + realm;
680 Usernames::const_iterator ui;
681 ui = _usernames.find(key);
682 if (ui != _usernames.end()) {
695 set_cookie(
const HTTPCookie &cookie) {
696 if (cookie.is_expired()) {
697 clear_cookie(cookie);
700 pair<Cookies::iterator, bool> result = _cookies.insert(cookie);
701 if (!result.second) {
704 const HTTPCookie &orig_cookie = *result.first;
705 ((HTTPCookie &)orig_cookie).update_from(cookie);
718 clear_cookie(
const HTTPCookie &cookie) {
719 Cookies::iterator ci = _cookies.find(cookie);
720 if (ci != _cookies.end()) {
734 clear_all_cookies() {
746 has_cookie(
const HTTPCookie &cookie)
const {
747 Cookies::const_iterator ci = _cookies.find(cookie);
748 return (ci != _cookies.end());
758 HTTPCookie HTTPClient::
759 get_cookie(
const HTTPCookie &cookie)
const {
760 Cookies::const_iterator ci = _cookies.find(cookie);
761 if (ci != _cookies.end()) {
777 copy_cookies_from(
const HTTPClient &other) {
778 Cookies::const_iterator ci;
779 for (ci = other._cookies.begin(); ci != other._cookies.end(); ++ci) {
793 write_cookies(ostream &out)
const {
794 Cookies::const_iterator ci;
795 for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) {
809 send_cookies(ostream &out,
const URLSpec &url) {
811 bool any_expired =
false;
812 bool first_cookie =
true;
814 Cookies::const_iterator ci;
815 for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) {
816 const HTTPCookie &cookie = (*ci);
817 if (cookie.is_expired(now)) {
820 }
else if (cookie.matches_url(url)) {
823 first_cookie =
false;
827 out << cookie.get_name() <<
"=" << cookie.get_value();
837 Cookies::const_iterator ci;
838 for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) {
839 const HTTPCookie &cookie = (*ci);
840 if (!cookie.is_expired(now)) {
841 new_cookies.insert(new_cookies.end(), cookie);
844 _cookies.swap(new_cookies);
861 load_client_certificate() {
862 if (!_client_certificate_loaded) {
863 _client_certificate_loaded =
true;
865 if (!_client_certificate_filename.empty()) {
866 _client_certificate_filename.set_text();
871 if (!vfs->
read_file(_client_certificate_filename,
872 _client_certificate_pem,
true)) {
874 downloader_cat.warning()
875 <<
"Could not read " << _client_certificate_filename <<
".\n";
880 if (!_client_certificate_pem.empty()) {
884 BIO *mbio = BIO_new_mem_buf((
void *)_client_certificate_pem.data(),
885 _client_certificate_pem.length());
888 _client_certificate_priv =
889 PEM_read_bio_PrivateKey(mbio, NULL, NULL,
890 (
char *)_client_certificate_passphrase.c_str());
897 _client_certificate_pub =
898 PEM_read_bio_X509(mbio, NULL, NULL, NULL);
903 NotifySeverity sev = NS_debug;
904 string source =
"memory";
905 if (!_client_certificate_filename.empty()) {
911 source = _client_certificate_filename;
914 if (downloader_cat.is_on(sev)) {
915 if (_client_certificate_priv != (EVP_PKEY *)NULL &&
916 _client_certificate_pub != (X509 *)NULL) {
917 downloader_cat.out(sev)
918 <<
"Read client certificate from " << source <<
"\n";
921 if (_client_certificate_priv == (EVP_PKEY *)NULL) {
922 downloader_cat.out(sev)
923 <<
"Could not read private key from " << source <<
"\n";
926 if (_client_certificate_pub == (X509 *)NULL) {
927 downloader_cat.out(sev)
928 <<
"Could not read public key from " << source <<
"\n";
935 return (_client_certificate_priv != (EVP_PKEY *)NULL &&
936 _client_certificate_pub != (X509 *)NULL);
958 add_preapproved_server_certificate_filename(
const URLSpec &url,
const Filename &filename) {
962 if (!vfs->
read_file(filename, pem,
true)) {
964 downloader_cat.warning()
965 <<
"Could not read " << filename <<
".\n";
969 return add_preapproved_server_certificate_pem(url, pem);
991 add_preapproved_server_certificate_pem(
const URLSpec &url,
const string &pem) {
995 BIO *mbio = BIO_new_mem_buf((
void *)pem.data(), pem.length());
998 X509 *cert = PEM_read_bio_X509(mbio, NULL, NULL, NULL);
1002 downloader_cat.warning()
1003 <<
"Could not parse PEM data\n";
1008 PreapprovedServerCerts::iterator psci =
1009 _preapproved_server_certs.insert(PreapprovedServerCerts::value_type(server_and_port, PreapprovedServerCert())).first;
1011 PreapprovedServerCert &psc = (*psci).second;
1012 psc._certs.push_back(cert);
1042 add_preapproved_server_certificate_name(
const URLSpec &url,
const string &name) {
1043 X509_NAME *cert_name = parse_x509_name(name);
1044 if (cert_name == NULL) {
1045 downloader_cat.warning()
1046 <<
"Could not parse certificate name " << name <<
"\n";
1051 PreapprovedServerCerts::iterator psci =
1052 _preapproved_server_certs.insert(PreapprovedServerCerts::value_type(server_and_port, PreapprovedServerCert())).first;
1054 PreapprovedServerCert &psc = (*psci).second;
1055 psc._cert_names.push_back(cert_name);
1067 clear_preapproved_server_certificates(
const URLSpec &url) {
1069 _preapproved_server_certs.erase(server_and_port);
1079 clear_all_preapproved_server_certificates() {
1080 _preapproved_server_certs.clear();
1090 get_http_version_string()
const {
1091 switch (_http_version) {
1092 case HTTPEnum::HV_09:
1095 case HTTPEnum::HV_10:
1098 case HTTPEnum::HV_11:
1101 case HTTPEnum::HV_other:
1117 HTTPEnum::HTTPVersion HTTPClient::
1118 parse_http_version_string(
const string &version) {
1119 if (version ==
"HTTP/1.0") {
1120 return HTTPEnum::HV_10;
1121 }
else if (version ==
"HTTP/1.1") {
1122 return HTTPEnum::HV_11;
1123 }
else if (version.substr(0, 6) ==
"HTTP/0") {
1124 return HTTPEnum::HV_09;
1126 return HTTPEnum::HV_other;
1140 load_certificates(
const Filename &filename) {
1141 OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
1142 return (sslw->load_certificates(filename) != 0);
1166 PT(HTTPChannel) HTTPClient::
1167 make_channel(
bool persistent_connection) {
1168 PT(HTTPChannel) doc = new HTTPChannel(this);
1169 doc->set_persistent_connection(persistent_connection);
1182 PT(HTTPChannel) HTTPClient::
1183 post_form(const
URLSpec &url, const
string &body) {
1184 PT(HTTPChannel) doc = new HTTPChannel(this);
1185 doc->post_form(url, body);
1198 PT(HTTPChannel) HTTPClient::
1199 get_document(const
URLSpec &url) {
1200 PT(HTTPChannel) doc = new HTTPChannel(this);
1201 doc->get_document(url);
1214 PT(HTTPChannel) HTTPClient::
1215 get_header(const
URLSpec &url) {
1216 PT(HTTPChannel) doc = new HTTPChannel(this);
1217 doc->get_header(url);
1226 HTTPClient *HTTPClient::
1228 if (_global_ptr == NULL) {
1229 _global_ptr =
new HTTPClient;
1241 SSL_CTX *HTTPClient::
1243 if (_ssl_ctx != (SSL_CTX *)NULL) {
1249 _ssl_ctx = SSL_CTX_new(SSLv23_client_method());
1251 #if defined(SSL_097) && !defined(NDEBUG)
1254 if (downloader_cat.is_debug()) {
1255 SSL_CTX_set_msg_callback(_ssl_ctx, ssl_msg_callback);
1260 OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
1261 sslw->notify_ssl_errors();
1263 SSL_CTX_set_cert_store(_ssl_ctx, sslw->get_x509_store());
1289 check_preapproved_server_certificate(
const URLSpec &url, X509 *cert,
1290 bool &cert_preapproved,
bool &cert_name_preapproved)
const {
1291 cert_preapproved =
false;
1292 cert_name_preapproved =
false;
1295 PreapprovedServerCerts::const_iterator psci =
1296 _preapproved_server_certs.find(server_and_port);
1298 if (psci == _preapproved_server_certs.end()) {
1303 const PreapprovedServerCert &psc = (*psci).second;
1306 ServerCerts::const_iterator sci;
1307 for (sci = psc._certs.begin(); sci != psc._certs.end(); ++sci) {
1308 if (X509_cmp(cert, *sci) == 0) {
1309 cert_preapproved =
true;
1310 cert_name_preapproved =
true;
1311 downloader_cat.info()
1312 <<
"Server certificate is pre-approved.\n";
1318 X509_NAME *subject = X509_get_subject_name(cert);
1319 ServerCertNames::const_iterator scni;
1320 for (scni = psc._cert_names.begin(); scni != psc._cert_names.end(); ++scni) {
1321 X509_NAME *cert_name = (*scni);
1322 if (x509_name_subset(cert_name, subject)) {
1323 downloader_cat.info()
1324 <<
"Server certificate name is pre-approved.\n";
1325 cert_name_preapproved =
true;
1342 get_proxies_for_scheme(
const string &scheme,
pvector<URLSpec> &proxies)
const {
1343 ProxiesByScheme::const_iterator si = _proxies_by_scheme.find(scheme);
1344 if (si == _proxies_by_scheme.end()) {
1347 const Proxies &scheme_proxies = (*si).second;
1348 if (scheme_proxies.empty()) {
1352 Proxies::const_iterator pi;
1353 for (pi = scheme_proxies.begin(); pi != scheme_proxies.end(); ++pi) {
1354 proxies.push_back(*pi);
1369 add_http_username(
const string &http_username) {
1370 size_t c1 = http_username.find(
':');
1371 if (c1 != string::npos) {
1372 size_t c2 = http_username.find(
':', c1 + 1);
1373 if (c2 != string::npos) {
1374 size_t c3 = http_username.find(
':', c2 + 1);
1375 if (c3 != string::npos) {
1376 size_t c4 = http_username.find(
':', c3 + 1);
1377 if (c4 != string::npos) {
1379 downloader_cat.error()
1380 <<
"Invalid http-username " << http_username <<
"\n";
1384 set_username(http_username.substr(0, c1),
1385 http_username.substr(c1 + 1, c2 - (c1 + 1)),
1386 http_username.substr(c2 + 1));
1391 set_username(
string(),
1392 http_username.substr(0, c1),
1393 http_username.substr(c1 + 1));
1397 set_username(
string(),
string(), http_username);
1401 downloader_cat.error()
1402 <<
"Invalid http-username " << http_username <<
"\n";
1413 select_username(
const URLSpec &url,
bool is_proxy,
const string &realm)
const {
1426 if (username.empty()) {
1428 username = get_username(
"*proxy", realm);
1430 if (username.empty()) {
1432 username = get_username(
"*proxy",
string());
1435 if (username.empty()) {
1437 username = get_username(url.
get_server(), realm);
1439 if (username.empty()) {
1441 username = get_username(url.
get_server(), string());
1443 if (username.empty()) {
1445 username = get_username(
string(), realm);
1447 if (username.empty()) {
1449 username = get_username(
string(),
string());
1462 HTTPAuthorization *HTTPClient::
1463 select_auth(
const URLSpec &url,
bool is_proxy,
const string &last_realm) {
1464 Domains &domains = is_proxy ? _proxy_domains : _www_domains;
1465 string canon = HTTPAuthorization::get_canonical_url(url).get_url();
1469 Domains::const_iterator best_di = domains.end();
1470 size_t longest_length = 0;
1471 Domains::const_iterator di;
1472 for (di = domains.begin(); di != domains.end(); ++di) {
1473 const string &domain = (*di).first;
1474 size_t length = domain.length();
1475 if (domain == canon.substr(0, length)) {
1477 if (length > longest_length) {
1479 longest_length = length;
1484 if (best_di != domains.end()) {
1486 if (downloader_cat.is_spam()) {
1487 downloader_cat.spam()
1488 <<
"Choosing domain " << (*best_di).first <<
" for " << url <<
"\n";
1490 const Realms &realms = (*best_di).second._realms;
1492 Realms::const_iterator ri;
1493 ri = realms.find(last_realm);
1494 if (ri != realms.end()) {
1495 return (*ri).second;
1498 if (!realms.empty()) {
1500 return (*realms.begin()).second;
1518 PT(HTTPAuthorization) HTTPClient::
1519 generate_auth(const
URLSpec &url,
bool is_proxy, const
string &challenge) {
1520 HTTPAuthorization::AuthenticationSchemes schemes;
1521 HTTPAuthorization::parse_authentication_schemes(schemes, challenge);
1523 PT(HTTPAuthorization) auth;
1524 HTTPAuthorization::AuthenticationSchemes::iterator si;
1526 si = schemes.find("digest");
1527 if (si != schemes.end()) {
1528 auth =
new HTTPDigestAuthorization((*si).second, url, is_proxy);
1531 if (auth == (HTTPAuthorization *)NULL || !auth->is_valid()) {
1532 si = schemes.find(
"basic");
1533 if (si != schemes.end()) {
1534 auth =
new HTTPBasicAuthorization((*si).second, url, is_proxy);
1538 if (auth == (HTTPAuthorization *)NULL || !auth->is_valid()) {
1539 downloader_cat.warning()
1540 <<
"Don't know how to use any of the server's available authorization schemes:\n";
1541 for (si = schemes.begin(); si != schemes.end(); ++si) {
1542 downloader_cat.warning() << (*si).first <<
"\n";
1548 Domains &domains = is_proxy ? _proxy_domains : _www_domains;
1549 const vector_string &domain = auth->get_domain();
1550 vector_string::const_iterator si;
1551 for (si = domain.begin(); si != domain.end(); ++si) {
1552 domains[(*si)]._realms[auth->get_realm()] = auth;
1567 unload_client_certificate() {
1568 if (_client_certificate_priv != (EVP_PKEY *)NULL) {
1569 EVP_PKEY_free(_client_certificate_priv);
1570 _client_certificate_priv = NULL;
1573 if (_client_certificate_pub != (X509 *)NULL) {
1574 X509_free(_client_certificate_pub);
1575 _client_certificate_pub = NULL;
1578 _client_certificate_loaded =
false;
1589 X509_NAME *HTTPClient::
1590 parse_x509_name(
const string &source) {
1591 X509_NAME *result = NULL;
1593 result = X509_NAME_new();
1594 bool added_any =
false;
1596 string::const_iterator si;
1597 si = source.begin();
1598 while (si != source.end()) {
1604 while (si != source.end() && (*si) !=
'=' && (*si) !=
'/') {
1605 if ((*si) ==
'\\') {
1607 if (si != source.end()) {
1617 int nid = OBJ_txt2nid((
char *)type.c_str());
1618 if (nid == NID_undef) {
1619 downloader_cat.info()
1620 <<
"Unknown type " << type <<
" in X509 name: " << source
1622 X509_NAME_free(result);
1628 if (si != source.end() && (*si) ==
'=') {
1630 while (si != source.end() && (*si) !=
'/') {
1631 if ((*si) ==
'\\') {
1633 if (si != source.end()) {
1644 if (!value.empty()) {
1646 X509_NAME_add_entry_by_NID(result, nid, V_ASN1_APP_CHOOSE,
1647 (
unsigned char *)value.c_str(), -1, -1, 0);
1649 downloader_cat.info()
1650 <<
"Unable to add " << type <<
"=" << value <<
" in X509 name: "
1652 X509_NAME_free(result);
1661 downloader_cat.info()
1662 <<
"Invalid empty X509 name: " << source <<
"\n";
1663 X509_NAME_free(result);
1678 x509_name_subset(X509_NAME *name_a, X509_NAME *name_b) {
1679 int count_a = X509_NAME_entry_count(name_a);
1680 for (
int ai = 0; ai < count_a; ai++) {
1681 X509_NAME_ENTRY *na = X509_NAME_get_entry(name_a, ai);
1683 int bi = X509_NAME_get_index_by_OBJ(name_b, na->object, -1);
1689 X509_NAME_ENTRY *nb = X509_NAME_get_entry(name_b, bi);
1690 if (na->value->length != nb->value->length ||
1691 memcmp(na->value->data, nb->value->data, na->value->length) != 0) {
1706 split_whitespace(
string &a,
string &b,
const string &c) {
1710 while (p < c.length() && isspace(c[p])) {
1716 while (p < c.length() && !isspace(c[p])) {
1720 a = c.substr(q, p - q);
1723 while (p < c.length() && isspace(c[p])) {
1729 #if defined(SSL_097) && !defined(NDEBUG)
1737 ssl_msg_callback(
int write_p,
int version,
int content_type,
1738 const void *,
size_t len, SSL *,
void *) {
1741 describe <<
"sent ";
1743 describe <<
"received ";
1747 describe <<
"SSL 2.0 ";
1751 describe <<
"SSL 3.0 ";
1755 describe <<
"TLS 1.0 ";
1759 describe <<
"unknown protocol ";
1762 describe <<
"message: ";
1764 if (version != SSL2_VERSION) {
1765 switch (content_type) {
1767 describe <<
"change cipher spec, ";
1771 describe <<
"alert, ";
1775 describe <<
"handshake, ";
1779 describe <<
"application data, ";
1783 describe <<
"unknown content type, ";
1787 describe << len <<
" bytes.\n";
1789 downloader_cat.debug() << describe.str();
1791 #endif // defined(SSL_097) && !defined(NDEBUG)
1798 HTTPClient::PreapprovedServerCert::
1799 ~PreapprovedServerCert() {
1800 ServerCerts::const_iterator sci;
1801 for (sci = _certs.begin(); sci != _certs.end(); ++sci) {
1805 ServerCertNames::const_iterator scni;
1806 for (scni = _cert_names.begin(); scni != _cert_names.end(); ++scni) {
1807 X509_NAME_free(*scni);
1811 #endif // HAVE_OPENSSL
bool has_username() const
Returns true if the URL specifies a username (and/or password), false otherwise.
A container for a URL, e.g.
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, even though the files may originate from several different sources that may not be related to the actual OS's file system.
This is a convenience class to specialize ConfigVariable as a boolean type.
bool is_ssl() const
Returns true if the URL's scheme specifies an SSL-secured protocol such as https, or false otherwise...
const string & get_pattern() const
Returns the pattern string that the GlobPattern object matches.
string read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns the entire contents of the indicated file as a string.
This class is similar to ConfigVariable, but it reports its value as a list of strings.
This is our own Panda specialization on the default STL vector.
The name of a file, such as a texture file or an Egg file.
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.
string get_scheme() const
Returns the scheme specified by the URL, or empty string if no scheme is specified.
static HTTPDate now()
Returns an HTTPDate that represents the current time and date.
const string & get_url() const
Returns the complete URL specification.
string get_server() const
Returns the server name specified by the URL, if any.
string get_username() const
Returns the username specified by the URL, if any.
string get_server_and_port() const
Returns a string consisting of the server name, followed by a colon, followed by the port number...
This is our own Panda specialization on the default STL set.
This class can be used to test for string matches against standard Unix-shell filename globbing conve...