Browse Source

proxy authorization

David Rose 23 years ago
parent
commit
dba02d9705

+ 1 - 0
panda/src/downloader/httpClient.I

@@ -26,6 +26,7 @@
 INLINE void HTTPClient::
 set_proxy(const URLSpec &proxy) {
   _proxy = proxy;
+  _proxy_authorization = string();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 41 - 11
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";
   }
+
+  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";
+      << "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";
-  string connect_header = request.str();
-
   // 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;
   }
 

+ 1 - 0
panda/src/downloader/httpClient.h

@@ -118,6 +118,7 @@ private:
 #endif
 
   URLSpec _proxy;
+  string _proxy_authorization;
   HTTPVersion _http_version;
   VerifySSL _verify_ssl;
 

+ 27 - 14
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();
   }