diff --git a/panda/src/downloader/httpClient.I b/panda/src/downloader/httpClient.I index 8e69b55621..efaad11281 100644 --- a/panda/src/downloader/httpClient.I +++ b/panda/src/downloader/httpClient.I @@ -26,6 +26,7 @@ INLINE void HTTPClient:: set_proxy(const URLSpec &proxy) { _proxy = proxy; + _proxy_authorization = string(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/downloader/httpClient.cxx b/panda/src/downloader/httpClient.cxx index df6dc51d3e..9c3a8b39cd 100644 --- a/panda/src/downloader/httpClient.cxx +++ b/panda/src/downloader/httpClient.cxx @@ -626,32 +626,60 @@ establish_https_proxy(const URLSpec &url) { proxy_server << _proxy.get_server() << ":" << _proxy.get_port(); string proxy_server_str = proxy_server.str(); - BIO *bio = BIO_new_connect((char *)proxy_server_str.c_str()); - if (downloader_cat.is_debug()) { downloader_cat.debug() << "connecting to proxy " << proxy_server_str << "\n"; } - if (BIO_do_connect(bio) <= 0) { - downloader_cat.info() - << "Could not contact proxy " << proxy_server_str << "\n"; -#ifdef REPORT_SSL_ERRORS - ERR_print_errors_fp(stderr); -#endif - return NULL; - } ostringstream request; request << "CONNECT " << url.get_server() << ":" << url.get_port() << " " << get_http_version_string() << "\r\n"; + if (_http_version > HV_10) { + request + << "Host: " << url.get_server() << "\r\n"; + } string connect_header = request.str(); + BIO *bio = BIO_new_connect((char *)proxy_server_str.c_str()); + if (BIO_do_connect(bio) <= 0) { + downloader_cat.info() + << "Could not contact proxy " << proxy_server_str << ".\n"; +#ifdef REPORT_SSL_ERRORS + ERR_print_errors_fp(stderr); +#endif + return NULL; + } + // Create a temporary HTTPDocument to issue the request and read the // response from the proxy. { + string old_proxy_authorization = _proxy_authorization; PT(HTTPDocument) doc = new HTTPDocument(this, bio); - if (!doc->send_request(connect_header, string())) { + bool connected = doc->send_request(connect_header, string()); + if (!connected && doc->get_status_code() == 407 && + _proxy_authorization != old_proxy_authorization) { + // 407: Proxy Authentication Required. If this happened, maybe + // we got the authentication already (but the HTTPDocument was + // not allowed to try to reconnect automatically). Try it + // again, once. + BIO_free_all(bio); + BIO *bio = BIO_new_connect((char *)proxy_server_str.c_str()); + if (BIO_do_connect(bio) <= 0) { + downloader_cat.info() + << "Could not contact proxy " << proxy_server_str + << " a second time.\n"; +#ifdef REPORT_SSL_ERRORS + ERR_print_errors_fp(stderr); +#endif + return NULL; + } + + doc = new HTTPDocument(this, bio); + connected = doc->send_request(connect_header, string()); + } + + if (!connected) { downloader_cat.info() << "proxy would not open connection to " << url.get_authority() << ": " << doc->get_status_code() << " " @@ -712,7 +740,9 @@ make_https_connection(BIO *bio, const URLSpec &url) const { #ifdef REPORT_SSL_ERRORS ERR_print_errors_fp(stderr); #endif - BIO_free_all(sbio); + // It seems to be an error to free sbio at this point; perhaps + // it's already been freed? + BIO_free(bio); return NULL; } diff --git a/panda/src/downloader/httpClient.h b/panda/src/downloader/httpClient.h index c2759d7314..87a479921f 100644 --- a/panda/src/downloader/httpClient.h +++ b/panda/src/downloader/httpClient.h @@ -118,6 +118,7 @@ private: #endif URLSpec _proxy; + string _proxy_authorization; HTTPVersion _http_version; VerifySSL _verify_ssl; diff --git a/panda/src/downloader/httpDocument.cxx b/panda/src/downloader/httpDocument.cxx index bd49b0d210..e8c7ae880a 100644 --- a/panda/src/downloader/httpDocument.cxx +++ b/panda/src/downloader/httpDocument.cxx @@ -127,19 +127,31 @@ send_request(const string &method, const URLSpec &url, const string &body) { bool HTTPDocument:: send_request(const string &header, const string &body) { if (prepare_for_next()) { - issue_request(header, body); + // Tack on a proxy authorization if it is called for. Assume we + // can use the same authorization we used last time. + string proxy_auth_header = header; + if (!_proxy.empty() && !_client->_proxy_authorization.empty()) { + proxy_auth_header += "Proxy-Authorization: "; + proxy_auth_header += _client->_proxy_authorization; + proxy_auth_header += "\r\n"; + } + issue_request(proxy_auth_header, body); if (get_status_code() == 407 && !_proxy.empty()) { // 407: not authorized to proxy. Try to get the authorization. string authenticate_request = get_header_value("Proxy-Authenticate"); string authorization; if (get_authorization(authorization, authenticate_request, _proxy, true)) { - string new_header = header; - new_header += "Proxy-Authorization: "; - new_header += authorization; - new_header += "\r\n"; - if (prepare_for_next()) { - issue_request(new_header, body); + if (_client->_proxy_authorization != authorization) { + // Change the authorization. + _client->_proxy_authorization = authorization; + proxy_auth_header = header; + proxy_auth_header += "Proxy-Authorization: "; + proxy_auth_header += _client->_proxy_authorization; + proxy_auth_header += "\r\n"; + if (prepare_for_next()) { + issue_request(proxy_auth_header, body); + } } } } @@ -149,12 +161,12 @@ send_request(const string &header, const string &body) { string authenticate_request = get_header_value("WWW-Authenticate"); string authorization; if (get_authorization(authorization, authenticate_request, _url, false)) { - string new_header = header; - new_header += "Authorization: "; - new_header += authorization; - new_header += "\r\n"; + string web_auth_header = proxy_auth_header; + web_auth_header += "Authorization: "; + web_auth_header += authorization; + web_auth_header += "\r\n"; if (prepare_for_next()) { - issue_request(new_header, body); + issue_request(web_auth_header, body); } } } @@ -966,8 +978,9 @@ get_basic_authorization(string &authorization, const HTTPDocument::Tokens &token // Look in several places in order to find the matching username. - // Fist, if there's a username on the URL, that always wins. - if (url.has_username()) { + // Fist, if there's a username on the URL, that always wins (except + // when we are looking for a proxy username). + if (url.has_username() && !is_proxy) { username = url.get_username(); }