@@ -1633,6 +1633,11 @@ class ClientImpl {
1633
1633
bool write_request (Stream &strm, Request &req, bool close_connection,
1634
1634
Error &error);
1635
1635
bool redirect (Request &req, Response &res, Error &error);
1636
+ bool create_redirect_client (const std::string &scheme,
1637
+ const std::string &host, int port, Request &req,
1638
+ Response &res, const std::string &path,
1639
+ const std::string &location, Error &error);
1640
+ template <typename ClientType> void setup_redirect_client (ClientType &client);
1636
1641
bool handle_request (Stream &strm, Request &req, Response &res,
1637
1642
bool close_connection, Error &error);
1638
1643
std::unique_ptr<Response> send_with_content_provider (
@@ -7871,24 +7876,150 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
7871
7876
7872
7877
auto path = detail::decode_url (next_path, true ) + next_query;
7873
7878
7879
+ // Same host redirect - use current client
7874
7880
if (next_scheme == scheme && next_host == host_ && next_port == port_) {
7875
7881
return detail::redirect (*this , req, res, path, location, error);
7876
- } else {
7877
- if (next_scheme == " https" ) {
7882
+ }
7883
+
7884
+ // Cross-host/scheme redirect - create new client with robust setup
7885
+ return create_redirect_client (next_scheme, next_host, next_port, req, res,
7886
+ path, location, error);
7887
+ }
7888
+
7889
+ // New method for robust redirect client creation
7890
+ inline bool ClientImpl::create_redirect_client (
7891
+ const std::string &scheme, const std::string &host, int port, Request &req,
7892
+ Response &res, const std::string &path, const std::string &location,
7893
+ Error &error) {
7894
+ // Determine if we need SSL
7895
+ auto need_ssl = (scheme == " https" );
7896
+
7897
+ // Clean up request headers that are host/client specific
7898
+ // Remove headers that should not be carried over to new host
7899
+ auto headers_to_remove =
7900
+ std::vector<std::string>{" Host" , " Proxy-Authorization" , " Authorization" };
7901
+
7902
+ for (const auto &header_name : headers_to_remove) {
7903
+ auto it = req.headers .find (header_name);
7904
+ while (it != req.headers .end ()) {
7905
+ it = req.headers .erase (it);
7906
+ it = req.headers .find (header_name);
7907
+ }
7908
+ }
7909
+
7910
+ // Create appropriate client type and handle redirect
7911
+ if (need_ssl) {
7878
7912
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7879
- SSLClient cli (next_host, next_port);
7880
- cli.copy_settings (*this );
7881
- if (ca_cert_store_) { cli.set_ca_cert_store (ca_cert_store_); }
7882
- return detail::redirect (cli, req, res, path, location, error);
7913
+ // Create SSL client for HTTPS redirect
7914
+ SSLClient redirect_client (host, port);
7915
+
7916
+ // Setup basic client configuration first
7917
+ setup_redirect_client (redirect_client);
7918
+
7919
+ // SSL-specific configuration for proxy environments
7920
+ if (!proxy_host_.empty () && proxy_port_ != -1 ) {
7921
+ // Critical: Disable SSL verification for proxy environments
7922
+ redirect_client.enable_server_certificate_verification (false );
7923
+ redirect_client.enable_server_hostname_verification (false );
7924
+ } else {
7925
+ // For direct SSL connections, copy SSL verification settings
7926
+ redirect_client.enable_server_certificate_verification (
7927
+ server_certificate_verification_);
7928
+ redirect_client.enable_server_hostname_verification (
7929
+ server_hostname_verification_);
7930
+ }
7931
+
7932
+ // Handle CA certificate store and paths if available
7933
+ if (ca_cert_store_) { redirect_client.set_ca_cert_store (ca_cert_store_); }
7934
+ if (!ca_cert_file_path_.empty ()) {
7935
+ redirect_client.set_ca_cert_path (ca_cert_file_path_, ca_cert_dir_path_);
7936
+ }
7937
+
7938
+ // Client certificates are set through constructor for SSLClient
7939
+ // NOTE: SSLClient constructor already takes client_cert_path and
7940
+ // client_key_path so we need to create it properly if client certs are
7941
+ // needed
7942
+
7943
+ // Execute the redirect
7944
+ return detail::redirect (redirect_client, req, res, path, location, error);
7883
7945
#else
7884
- return false ;
7946
+ // SSL not supported - set appropriate error
7947
+ error = Error::SSLConnection;
7948
+ return false ;
7885
7949
#endif
7886
- } else {
7887
- ClientImpl cli (next_host, next_port);
7888
- cli.copy_settings (*this );
7889
- return detail::redirect (cli, req, res, path, location, error);
7950
+ } else {
7951
+ // HTTP redirect
7952
+ ClientImpl redirect_client (host, port);
7953
+
7954
+ // Setup client with robust configuration
7955
+ setup_redirect_client (redirect_client);
7956
+
7957
+ // Execute the redirect
7958
+ return detail::redirect (redirect_client, req, res, path, location, error);
7959
+ }
7960
+ }
7961
+
7962
+ // New method for robust client setup (based on basic_manual_redirect.cpp logic)
7963
+ template <typename ClientType>
7964
+ inline void ClientImpl::setup_redirect_client (ClientType &client) {
7965
+ // Copy basic settings first
7966
+ client.set_connection_timeout (connection_timeout_sec_);
7967
+ client.set_read_timeout (read_timeout_sec_, read_timeout_usec_);
7968
+ client.set_write_timeout (write_timeout_sec_, write_timeout_usec_);
7969
+ client.set_keep_alive (keep_alive_);
7970
+ client.set_follow_location (
7971
+ true ); // Enable redirects to handle multi-step redirects
7972
+ client.set_url_encode (url_encode_);
7973
+ client.set_compress (compress_);
7974
+ client.set_decompress (decompress_);
7975
+
7976
+ // Copy authentication settings BEFORE proxy setup
7977
+ if (!basic_auth_username_.empty ()) {
7978
+ client.set_basic_auth (basic_auth_username_, basic_auth_password_);
7979
+ }
7980
+ if (!bearer_token_auth_token_.empty ()) {
7981
+ client.set_bearer_token_auth (bearer_token_auth_token_);
7982
+ }
7983
+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
7984
+ if (!digest_auth_username_.empty ()) {
7985
+ client.set_digest_auth (digest_auth_username_, digest_auth_password_);
7986
+ }
7987
+ #endif
7988
+
7989
+ // Setup proxy configuration (CRITICAL ORDER - proxy must be set
7990
+ // before proxy auth)
7991
+ if (!proxy_host_.empty () && proxy_port_ != -1 ) {
7992
+ // First set proxy host and port
7993
+ client.set_proxy (proxy_host_, proxy_port_);
7994
+
7995
+ // Then set proxy authentication (order matters!)
7996
+ if (!proxy_basic_auth_username_.empty ()) {
7997
+ client.set_proxy_basic_auth (proxy_basic_auth_username_,
7998
+ proxy_basic_auth_password_);
7999
+ }
8000
+ if (!proxy_bearer_token_auth_token_.empty ()) {
8001
+ client.set_proxy_bearer_token_auth (proxy_bearer_token_auth_token_);
7890
8002
}
8003
+ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8004
+ if (!proxy_digest_auth_username_.empty ()) {
8005
+ client.set_proxy_digest_auth (proxy_digest_auth_username_,
8006
+ proxy_digest_auth_password_);
8007
+ }
8008
+ #endif
7891
8009
}
8010
+
8011
+ // Copy network and socket settings
8012
+ client.set_address_family (address_family_);
8013
+ client.set_tcp_nodelay (tcp_nodelay_);
8014
+ client.set_ipv6_v6only (ipv6_v6only_);
8015
+ if (socket_options_) { client.set_socket_options (socket_options_); }
8016
+ if (!interface_.empty ()) { client.set_interface (interface_); }
8017
+
8018
+ // Copy logging and headers
8019
+ if (logger_) { client.set_logger (logger_); }
8020
+
8021
+ // NOTE: DO NOT copy default_headers_ as they may contain stale Host headers
8022
+ // Each new client should generate its own headers based on its target host
7892
8023
}
7893
8024
7894
8025
inline bool ClientImpl::write_content_with_provider (Stream &strm,
0 commit comments