diff --git a/proxy/http.c b/proxy/http.c index 761abdf6..d4797171 100644 --- a/proxy/http.c +++ b/proxy/http.c @@ -670,9 +670,9 @@ static void proxy_http_process_queue(ProxyNegotiator *pn) /* 407 is Proxy Authentication Required, which we may be * able to do something about. */ if (s->connection_close) { - pn->error = dupprintf("HTTP proxy closed connection after " - "asking for authentication"); - crStopV; + /* If we got 407 + connection closed, reconnect before + * sending our next request. */ + pn->reconnect = true; } /* If the best we can do is report some kind of error from diff --git a/proxy/proxy.c b/proxy/proxy.c index 36105097..6bedcf9b 100644 --- a/proxy/proxy.c +++ b/proxy/proxy.c @@ -99,6 +99,7 @@ static void sk_proxy_close (Socket *s) ProxySocket *ps = container_of(s, ProxySocket, sock); sk_close(ps->sub_socket); + sk_addr_free(ps->proxy_addr); sk_addr_free(ps->remote_addr); proxy_negotiator_cleanup(ps); bufchain_clear(&ps->output_from_negotiator); @@ -223,6 +224,16 @@ static void proxy_negotiate(ProxySocket *ps) return; } + if (ps->pn->reconnect) { + sk_close(ps->sub_socket); + SockAddr *proxy_addr = sk_addr_dup(ps->proxy_addr); + ps->sub_socket = sk_new(proxy_addr, ps->proxy_port, + ps->proxy_privport, ps->proxy_oobinline, + ps->proxy_nodelay, ps->proxy_keepalive, + &ps->plugimpl); + ps->pn->reconnect = false; + } + while (bufchain_size(&ps->output_from_negotiator)) { ptrlen data = bufchain_prefix(&ps->output_from_negotiator); sk_write(ps->sub_socket, data.ptr, data.len); @@ -601,10 +612,16 @@ Socket *new_connection(SockAddr *addr, const char *hostname, /* create the actual socket we will be using, * connected to our proxy server and port. */ - ps->sub_socket = sk_new(proxy_addr, - conf_get_int(conf, CONF_proxy_port), - privport, oobinline, - nodelay, keepalive, &ps->plugimpl); + ps->proxy_addr = sk_addr_dup(proxy_addr); + ps->proxy_port = conf_get_int(conf, CONF_proxy_port); + ps->proxy_privport = privport; + ps->proxy_oobinline = oobinline; + ps->proxy_nodelay = nodelay; + ps->proxy_keepalive = keepalive; + ps->sub_socket = sk_new(proxy_addr, ps->proxy_port, + ps->proxy_privport, ps->proxy_oobinline, + ps->proxy_nodelay, ps->proxy_keepalive, + &ps->plugimpl); if (sk_socket_error(ps->sub_socket) != NULL) return &ps->sock; diff --git a/proxy/proxy.h b/proxy/proxy.h index ca4a293f..72d06d49 100644 --- a/proxy/proxy.h +++ b/proxy/proxy.h @@ -22,6 +22,11 @@ struct ProxySocket { SockAddr *remote_addr; int remote_port; + /* Parameters needed to make further connections to the proxy */ + SockAddr *proxy_addr; + int proxy_port; + bool proxy_privport, proxy_oobinline, proxy_nodelay, proxy_keepalive; + bufchain pending_output_data; bufchain pending_oob_output_data; bufchain pending_input_data; @@ -68,6 +73,11 @@ struct ProxyNegotiator { /* Set to report user abort during proxy negotiation. */ bool aborted; + + /* Set to request the centralised code to make a fresh connection + * to the proxy server, e.g. because an HTTP proxy slammed the + * connection shut after sending 407 Proxy Auth Required. */ + bool reconnect; }; struct ProxyNegotiatorVT {