@@ -1669,6 +1669,11 @@ class ClientImpl {
16691669 bool write_request (Stream &strm, Request &req, bool close_connection,
16701670 Error &error);
16711671 bool redirect (Request &req, Response &res, Error &error);
1672+ bool create_redirect_client (const std::string &scheme,
1673+ const std::string &host, int port, Request &req,
1674+ Response &res, const std::string &path,
1675+ const std::string &location, Error &error);
1676+ template <typename ClientType> void setup_redirect_client (ClientType &client);
16721677 bool handle_request (Stream &strm, Request &req, Response &res,
16731678 bool close_connection, Error &error);
16741679 std::unique_ptr<Response> send_with_content_provider (
@@ -8140,24 +8145,150 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
81408145
81418146 auto path = detail::decode_url (next_path, true ) + next_query;
81428147
8148+ // Same host redirect - use current client
81438149 if (next_scheme == scheme && next_host == host_ && next_port == port_) {
81448150 return detail::redirect (*this , req, res, path, location, error);
8145- } else {
8146- if (next_scheme == " https" ) {
8151+ }
8152+
8153+ // Cross-host/scheme redirect - create new client with robust setup
8154+ return create_redirect_client (next_scheme, next_host, next_port, req, res,
8155+ path, location, error);
8156+ }
8157+
8158+ // New method for robust redirect client creation
8159+ inline bool ClientImpl::create_redirect_client (
8160+ const std::string &scheme, const std::string &host, int port, Request &req,
8161+ Response &res, const std::string &path, const std::string &location,
8162+ Error &error) {
8163+ // Determine if we need SSL
8164+ auto need_ssl = (scheme == " https" );
8165+
8166+ // Clean up request headers that are host/client specific
8167+ // Remove headers that should not be carried over to new host
8168+ auto headers_to_remove =
8169+ std::vector<std::string>{" Host" , " Proxy-Authorization" , " Authorization" };
8170+
8171+ for (const auto &header_name : headers_to_remove) {
8172+ auto it = req.headers .find (header_name);
8173+ while (it != req.headers .end ()) {
8174+ it = req.headers .erase (it);
8175+ it = req.headers .find (header_name);
8176+ }
8177+ }
8178+
8179+ // Create appropriate client type and handle redirect
8180+ if (need_ssl) {
81478181#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8148- SSLClient cli (next_host, next_port);
8149- cli.copy_settings (*this );
8150- if (ca_cert_store_) { cli.set_ca_cert_store (ca_cert_store_); }
8151- return detail::redirect (cli, req, res, path, location, error);
8182+ // Create SSL client for HTTPS redirect
8183+ SSLClient redirect_client (host, port);
8184+
8185+ // Setup basic client configuration first
8186+ setup_redirect_client (redirect_client);
8187+
8188+ // SSL-specific configuration for proxy environments
8189+ if (!proxy_host_.empty () && proxy_port_ != -1 ) {
8190+ // Critical: Disable SSL verification for proxy environments
8191+ redirect_client.enable_server_certificate_verification (false );
8192+ redirect_client.enable_server_hostname_verification (false );
8193+ } else {
8194+ // For direct SSL connections, copy SSL verification settings
8195+ redirect_client.enable_server_certificate_verification (
8196+ server_certificate_verification_);
8197+ redirect_client.enable_server_hostname_verification (
8198+ server_hostname_verification_);
8199+ }
8200+
8201+ // Handle CA certificate store and paths if available
8202+ if (ca_cert_store_) { redirect_client.set_ca_cert_store (ca_cert_store_); }
8203+ if (!ca_cert_file_path_.empty ()) {
8204+ redirect_client.set_ca_cert_path (ca_cert_file_path_, ca_cert_dir_path_);
8205+ }
8206+
8207+ // Client certificates are set through constructor for SSLClient
8208+ // NOTE: SSLClient constructor already takes client_cert_path and
8209+ // client_key_path so we need to create it properly if client certs are
8210+ // needed
8211+
8212+ // Execute the redirect
8213+ return detail::redirect (redirect_client, req, res, path, location, error);
81528214#else
8153- return false ;
8215+ // SSL not supported - set appropriate error
8216+ error = Error::SSLConnection;
8217+ return false ;
81548218#endif
8155- } else {
8156- ClientImpl cli (next_host, next_port);
8157- cli.copy_settings (*this );
8158- return detail::redirect (cli, req, res, path, location, error);
8219+ } else {
8220+ // HTTP redirect
8221+ ClientImpl redirect_client (host, port);
8222+
8223+ // Setup client with robust configuration
8224+ setup_redirect_client (redirect_client);
8225+
8226+ // Execute the redirect
8227+ return detail::redirect (redirect_client, req, res, path, location, error);
8228+ }
8229+ }
8230+
8231+ // New method for robust client setup (based on basic_manual_redirect.cpp logic)
8232+ template <typename ClientType>
8233+ inline void ClientImpl::setup_redirect_client (ClientType &client) {
8234+ // Copy basic settings first
8235+ client.set_connection_timeout (connection_timeout_sec_);
8236+ client.set_read_timeout (read_timeout_sec_, read_timeout_usec_);
8237+ client.set_write_timeout (write_timeout_sec_, write_timeout_usec_);
8238+ client.set_keep_alive (keep_alive_);
8239+ client.set_follow_location (
8240+ true ); // Enable redirects to handle multi-step redirects
8241+ client.set_url_encode (url_encode_);
8242+ client.set_compress (compress_);
8243+ client.set_decompress (decompress_);
8244+
8245+ // Copy authentication settings BEFORE proxy setup
8246+ if (!basic_auth_username_.empty ()) {
8247+ client.set_basic_auth (basic_auth_username_, basic_auth_password_);
8248+ }
8249+ if (!bearer_token_auth_token_.empty ()) {
8250+ client.set_bearer_token_auth (bearer_token_auth_token_);
8251+ }
8252+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8253+ if (!digest_auth_username_.empty ()) {
8254+ client.set_digest_auth (digest_auth_username_, digest_auth_password_);
8255+ }
8256+ #endif
8257+
8258+ // Setup proxy configuration (CRITICAL ORDER - proxy must be set
8259+ // before proxy auth)
8260+ if (!proxy_host_.empty () && proxy_port_ != -1 ) {
8261+ // First set proxy host and port
8262+ client.set_proxy (proxy_host_, proxy_port_);
8263+
8264+ // Then set proxy authentication (order matters!)
8265+ if (!proxy_basic_auth_username_.empty ()) {
8266+ client.set_proxy_basic_auth (proxy_basic_auth_username_,
8267+ proxy_basic_auth_password_);
8268+ }
8269+ if (!proxy_bearer_token_auth_token_.empty ()) {
8270+ client.set_proxy_bearer_token_auth (proxy_bearer_token_auth_token_);
8271+ }
8272+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8273+ if (!proxy_digest_auth_username_.empty ()) {
8274+ client.set_proxy_digest_auth (proxy_digest_auth_username_,
8275+ proxy_digest_auth_password_);
81598276 }
8277+ #endif
81608278 }
8279+
8280+ // Copy network and socket settings
8281+ client.set_address_family (address_family_);
8282+ client.set_tcp_nodelay (tcp_nodelay_);
8283+ client.set_ipv6_v6only (ipv6_v6only_);
8284+ if (socket_options_) { client.set_socket_options (socket_options_); }
8285+ if (!interface_.empty ()) { client.set_interface (interface_); }
8286+
8287+ // Copy logging and headers
8288+ if (logger_) { client.set_logger (logger_); }
8289+
8290+ // NOTE: DO NOT copy default_headers_ as they may contain stale Host headers
8291+ // Each new client should generate its own headers based on its target host
81618292}
81628293
81638294inline bool ClientImpl::write_content_with_provider (Stream &strm,
@@ -9901,6 +10032,18 @@ inline bool SSLClient::connect_with_proxy(
990110032 !proxy_digest_auth_password_.empty ()) {
990210033 std::map<std::string, std::string> auth;
990310034 if (detail::parse_www_authenticate (proxy_res, auth, true )) {
10035+ // Close the current socket and create a new one for the authenticated
10036+ // request
10037+ shutdown_ssl (socket, true );
10038+ shutdown_socket (socket);
10039+ close_socket (socket);
10040+
10041+ // Create a new socket for the authenticated CONNECT request
10042+ if (!create_and_connect_socket (socket, error)) {
10043+ success = false ;
10044+ return false ;
10045+ }
10046+
990410047 proxy_res = Response ();
990510048 if (!detail::process_client_socket (
990610049 socket.sock , read_timeout_sec_, read_timeout_usec_,
0 commit comments