@@ -62,7 +62,12 @@ static HTTPHeaders create_s3_header(string url, string query, string host, strin
6262 res[" x-amz-server-side-encryption-aws-kms-key-id" ] = auth_params.kms_key_id ;
6363 }
6464
65- string signed_headers = " " ;
65+ bool use_requester_pays = auth_params.requester_pays ;
66+ if (use_requester_pays) {
67+ res[" x-amz-request-payer" ] = " requester" ;
68+ }
69+
70+ string signed_headers = " " ;
6671 hash_bytes canonical_request_hash;
6772 hash_str canonical_request_hash_str;
6873 if (content_type.length () > 0 ) {
@@ -75,7 +80,10 @@ static HTTPHeaders create_s3_header(string url, string query, string host, strin
7580 if (use_sse_kms) {
7681 signed_headers += " ;x-amz-server-side-encryption;x-amz-server-side-encryption-aws-kms-key-id" ;
7782 }
78- auto canonical_request = method + " \n " + S3FileSystem::UrlEncode (url) + " \n " + query;
83+ if (use_requester_pays) {
84+ signed_headers += " ;x-amz-request-payer" ;
85+ }
86+ auto canonical_request = method + " \n " + S3FileSystem::UrlEncode (url) + " \n " + query;
7987 if (content_type.length () > 0 ) {
8088 canonical_request += " \n content-type:" + content_type;
8189 }
@@ -87,6 +95,9 @@ static HTTPHeaders create_s3_header(string url, string query, string host, strin
8795 canonical_request += " \n x-amz-server-side-encryption:aws:kms" ;
8896 canonical_request += " \n x-amz-server-side-encryption-aws-kms-key-id:" + auth_params.kms_key_id ;
8997 }
98+ if (use_requester_pays) {
99+ canonical_request += " \n x-amz-request-payer:requester" ;
100+ }
90101
91102 canonical_request += " \n\n " + signed_headers + " \n " + payload_hash;
92103 sha256 (canonical_request.c_str (), canonical_request.length (), canonical_request_hash);
@@ -143,6 +154,7 @@ void AWSEnvironmentCredentialsProvider::SetAll() {
143154 this ->SetExtensionOptionValue (" s3_endpoint" , DUCKDB_ENDPOINT_ENV_VAR);
144155 this ->SetExtensionOptionValue (" s3_use_ssl" , DUCKDB_USE_SSL_ENV_VAR);
145156 this ->SetExtensionOptionValue (" s3_kms_key_id" , DUCKDB_KMS_KEY_ID_ENV_VAR);
157+ this ->SetExtensionOptionValue (" s3_requester_pays" , DUCKDB_REQUESTER_PAYS_ENV_VAR);
146158}
147159
148160S3AuthParams AWSEnvironmentCredentialsProvider::CreateParams () {
@@ -156,6 +168,7 @@ S3AuthParams AWSEnvironmentCredentialsProvider::CreateParams() {
156168 params.endpoint = DUCKDB_ENDPOINT_ENV_VAR;
157169 params.kms_key_id = DUCKDB_KMS_KEY_ID_ENV_VAR;
158170 params.use_ssl = DUCKDB_USE_SSL_ENV_VAR;
171+ params.requester_pays = DUCKDB_REQUESTER_PAYS_ENV_VAR;
159172
160173 return params;
161174}
@@ -181,6 +194,8 @@ S3AuthParams S3AuthParams::ReadFrom(optional_ptr<FileOpener> opener, FileOpenerI
181194 secret_reader.TryGetSecretKeyOrSetting (" kms_key_id" , " s3_kms_key_id" , result.kms_key_id );
182195 secret_reader.TryGetSecretKeyOrSetting (" s3_url_compatibility_mode" , " s3_url_compatibility_mode" ,
183196 result.s3_url_compatibility_mode );
197+ secret_reader.TryGetSecretKeyOrSetting (" requester_pays" , " s3_requester_pays" ,
198+ result.requester_pays );
184199
185200 // Endpoint and url style are slightly more complex and require special handling for gcs and r2
186201 auto endpoint_result = secret_reader.TryGetSecretKeyOrSetting (" endpoint" , " s3_endpoint" , result.endpoint );
@@ -219,6 +234,7 @@ unique_ptr<KeyValueSecret> CreateSecret(vector<string> &prefix_paths_p, string &
219234 return_value->secret_map [" use_ssl" ] = params.use_ssl ;
220235 return_value->secret_map [" kms_key_id" ] = params.kms_key_id ;
221236 return_value->secret_map [" s3_url_compatibility_mode" ] = params.s3_url_compatibility_mode ;
237+ return_value->secret_map [" requester_pays" ] = params.requester_pays ;
222238
223239 // ! Set redact keys
224240 return_value->redact_keys = {" secret" , " session_token" };
@@ -531,9 +547,21 @@ void S3FileSystem::ReadQueryParams(const string &url_query_param, S3AuthParams &
531547 }
532548 query_params.erase (found_param);
533549 }
550+ auto found_requester_pays_param = query_params.find (" s3_requester_pays" );
551+ if (found_requester_pays_param != query_params.end ()) {
552+ if (found_requester_pays_param->second == " true" ) {
553+ params.requester_pays = true ;
554+ } else if (found_requester_pays_param->second == " false" ) {
555+ params.requester_pays = false ;
556+ } else {
557+ throw IOException (" Incorrect setting found for s3_requester_pays, allowed values are: 'true' or 'false'" );
558+ }
559+ query_params.erase (found_requester_pays_param);
560+ }
534561 if (!query_params.empty ()) {
535562 throw IOException (" Invalid query parameters found. Supported parameters are:\n 's3_region', 's3_access_key_id', "
536- " 's3_secret_access_key', 's3_session_token',\n 's3_endpoint', 's3_url_style', 's3_use_ssl'" );
563+ " 's3_secret_access_key', 's3_session_token',\n 's3_endpoint', 's3_url_style', 's3_use_ssl', "
564+ " 's3_requester_pays'" );
537565 }
538566}
539567
0 commit comments