@@ -1669,6 +1669,11 @@ class ClientImpl {
1669
1669
bool write_request (Stream &strm, Request &req, bool close_connection,
1670
1670
Error &error);
1671
1671
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);
1672
1677
bool handle_request (Stream &strm, Request &req, Response &res,
1673
1678
bool close_connection, Error &error);
1674
1679
std::unique_ptr<Response> send_with_content_provider (
@@ -8140,24 +8145,150 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
8140
8145
8141
8146
auto path = detail::decode_url (next_path, true ) + next_query;
8142
8147
8148
+ // Same host redirect - use current client
8143
8149
if (next_scheme == scheme && next_host == host_ && next_port == port_) {
8144
8150
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) {
8147
8181
#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);
8152
8214
#else
8153
- return false ;
8215
+ // SSL not supported - set appropriate error
8216
+ error = Error::SSLConnection;
8217
+ return false ;
8154
8218
#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_);
8159
8276
}
8277
+ #endif
8160
8278
}
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
8161
8292
}
8162
8293
8163
8294
inline bool ClientImpl::write_content_with_provider (Stream &strm,
@@ -9901,6 +10032,18 @@ inline bool SSLClient::connect_with_proxy(
9901
10032
!proxy_digest_auth_password_.empty ()) {
9902
10033
std::map<std::string, std::string> auth;
9903
10034
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
+
9904
10047
proxy_res = Response ();
9905
10048
if (!detail::process_client_socket (
9906
10049
socket.sock , read_timeout_sec_, read_timeout_usec_,
0 commit comments