Skip to content

Commit

Permalink
Issue 2213: Support for "Requester pays" S3 buckets
Browse files Browse the repository at this point in the history
https://winscp.net/tracker/2213

Source commit: b9cc8e854b82d3c0a94e0481e16fa6b0f1e82c4a
  • Loading branch information
martinprikryl committed Nov 15, 2023
1 parent 22eac2a commit 068128f
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 7 deletions.
2 changes: 2 additions & 0 deletions libs/libs3/inc/libs3.h
Expand Up @@ -1701,6 +1701,8 @@ typedef void (S3ResponseDataCallback)(const char *data, size_t size, void *callb
void S3_set_request_context_response_data_callback(S3RequestContext *requestContext,
S3ResponseDataCallback responseDataCallback,
void * responseDataCallbackData);

void S3_set_request_context_requester_pays(S3RequestContext *requestContext, int requesterPays);
#else
/**
* Runs the S3RequestContext until all requests within it have completed,
Expand Down
1 change: 1 addition & 0 deletions libs/libs3/inc/request_context.h
Expand Up @@ -52,6 +52,7 @@ struct S3RequestContext
void *sslCallbackData;
S3ResponseDataCallback *responseDataCallback;
void *responseDataCallbackData;
int requesterPays;
#else
CURLM *curlm;
S3CurlMode curl_mode;
Expand Down
18 changes: 15 additions & 3 deletions libs/libs3/src/request.c
Expand Up @@ -346,6 +346,7 @@ static S3Status append_amz_header(RequestComputedValues *values,
// to be the count of the total number of x-amz- headers thus created).
static S3Status compose_amz_headers(const RequestParams *params,
int forceUnsignedPayload,
int requesterPays, // WINSCP
RequestComputedValues *values)
{
const S3PutProperties *properties = params->putProperties;
Expand Down Expand Up @@ -427,6 +428,16 @@ static S3Status compose_amz_headers(const RequestParams *params,
params->bucketContext.securityToken);
}

// WINSCP
if (requesterPays
&& (params->httpRequestType == HttpRequestTypeDELETE
|| params->httpRequestType == HttpRequestTypeGET
|| params->httpRequestType == HttpRequestTypeHEAD
|| params->httpRequestType == HttpRequestTypePOST
|| params->httpRequestType == HttpRequestTypePUT)) {
append_amz_header(values, 0, "x-amz-request-payer", "requester");
}

if (!forceUnsignedPayload
&& (params->httpRequestType == HttpRequestTypeGET
|| params->httpRequestType == HttpRequestTypeCOPY
Expand Down Expand Up @@ -1519,7 +1530,8 @@ void request_api_deinitialize()

static S3Status setup_request(const RequestParams *params,
RequestComputedValues *computed,
int forceUnsignedPayload)
int forceUnsignedPayload,
int requesterPays) // WINSCP
{
S3Status status;

Expand Down Expand Up @@ -1550,7 +1562,7 @@ static S3Status setup_request(const RequestParams *params,
"%Y%m%dT%H%M%SZ", &gmt);

// Compose the amz headers
if ((status = compose_amz_headers(params, forceUnsignedPayload, computed))
if ((status = compose_amz_headers(params, forceUnsignedPayload, requesterPays, computed)) // WINSCP
!= S3StatusOK) {
return status;
}
Expand Down Expand Up @@ -1604,7 +1616,7 @@ void request_perform(const RequestParams *params, S3RequestContext *context)
// These will hold the computed values
RequestComputedValues computed;

if ((status = setup_request(params, &computed, 0)) != S3StatusOK) {
if ((status = setup_request(params, &computed, 0, context->requesterPays)) != S3StatusOK) { // WINSCP
return_status(status);
}

Expand Down
7 changes: 6 additions & 1 deletion libs/libs3/src/request_context.c
Expand Up @@ -54,7 +54,7 @@ S3Status S3_create_request_context_ex(S3RequestContext **requestContextReturn,
}

#ifdef WINSCP
(*requestContextReturn)->sslCallback = NULL;
memset(*requestContextReturn, 0, sizeof(S3RequestContext));
#else
if (curlm) {
(*requestContextReturn)->curlm = curlm;
Expand Down Expand Up @@ -136,6 +136,11 @@ void S3_set_request_context_response_data_callback(S3RequestContext *requestCont
requestContext->responseDataCallbackData = responseDataCallbackData;
}

void S3_set_request_context_requester_pays(S3RequestContext *requestContext, int requesterPays)
{
requestContext->requesterPays = requesterPays;
}

#else

S3Status S3_runall_request_context(S3RequestContext *requestContext)
Expand Down
2 changes: 2 additions & 0 deletions source/core/S3FileSystem.cpp
Expand Up @@ -419,6 +419,8 @@ void __fastcall TS3FileSystem::Open()
FTerminal->LogEvent(L"Google Cloud detected.");
}

S3_set_request_context_requester_pays(FRequestContext, FTerminal->SessionData->S3RequesterPays);

FActive = false;
try
{
Expand Down
9 changes: 9 additions & 0 deletions source/core/SessionData.cpp
Expand Up @@ -297,6 +297,7 @@ void __fastcall TSessionData::DefaultSettings()
S3UrlStyle = s3usVirtualHost;
S3MaxKeys = asAuto;
S3CredentialsEnv = false;
S3RequesterPays = false;

// SFTP
SftpServer = L"";
Expand Down Expand Up @@ -463,6 +464,7 @@ void __fastcall TSessionData::NonPersistant()
PROPERTY(S3UrlStyle); \
PROPERTY(S3MaxKeys); \
PROPERTY(S3CredentialsEnv); \
PROPERTY(S3RequesterPays); \
\
PROPERTY(ProxyMethod); \
PROPERTY(ProxyHost); \
Expand Down Expand Up @@ -810,6 +812,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
S3UrlStyle = (TS3UrlStyle)Storage->ReadInteger(L"S3UrlStyle", S3UrlStyle);
S3MaxKeys = Storage->ReadEnum(L"S3MaxKeys", S3MaxKeys, AutoSwitchMapping);
S3CredentialsEnv = Storage->ReadBool(L"S3CredentialsEnv", S3CredentialsEnv);
S3RequesterPays = Storage->ReadBool(L"S3RequesterPays", S3RequesterPays);

// PuTTY defaults to TcpNoDelay, but the psftp/pscp ignores this preference, and always set this to off (what is our default too)
if (!PuttyImport)
Expand Down Expand Up @@ -1137,6 +1140,7 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
WRITE_DATA(Integer, S3UrlStyle);
WRITE_DATA(Integer, S3MaxKeys);
WRITE_DATA(Bool, S3CredentialsEnv);
WRITE_DATA(Bool, S3RequesterPays);
WRITE_DATA(Integer, SendBuf);
WRITE_DATA(String, SourceAddress);
WRITE_DATA(String, ProtocolFeatures);
Expand Down Expand Up @@ -4562,6 +4566,11 @@ void __fastcall TSessionData::SetS3CredentialsEnv(bool value)
SET_SESSION_PROPERTY(S3CredentialsEnv);
}
//---------------------------------------------------------------------
void __fastcall TSessionData::SetS3RequesterPays(bool value)
{
SET_SESSION_PROPERTY(S3RequesterPays);
}
//---------------------------------------------------------------------
void __fastcall TSessionData::SetIsWorkspace(bool value)
{
SET_SESSION_PROPERTY(IsWorkspace);
Expand Down
3 changes: 3 additions & 0 deletions source/core/SessionData.h
Expand Up @@ -234,6 +234,7 @@ friend class TStoredSessionList;
TS3UrlStyle FS3UrlStyle;
TAutoSwitch FS3MaxKeys;
bool FS3CredentialsEnv;
bool FS3RequesterPays;
bool FIsWorkspace;
UnicodeString FLink;
UnicodeString FNameOverride;
Expand Down Expand Up @@ -426,6 +427,7 @@ friend class TStoredSessionList;
void __fastcall SetS3UrlStyle(TS3UrlStyle value);
void __fastcall SetS3MaxKeys(TAutoSwitch value);
void __fastcall SetS3CredentialsEnv(bool value);
void __fastcall SetS3RequesterPays(bool value);
void __fastcall SetLogicalHostName(UnicodeString value);
void __fastcall SetIsWorkspace(bool value);
void __fastcall SetLink(UnicodeString value);
Expand Down Expand Up @@ -710,6 +712,7 @@ friend class TStoredSessionList;
__property TS3UrlStyle S3UrlStyle = { read = FS3UrlStyle, write = SetS3UrlStyle };
__property TAutoSwitch S3MaxKeys = { read = FS3MaxKeys, write = SetS3MaxKeys };
__property bool S3CredentialsEnv = { read = FS3CredentialsEnv, write = SetS3CredentialsEnv };
__property bool S3RequesterPays = { read = FS3RequesterPays, write = SetS3RequesterPays };
__property bool IsWorkspace = { read = FIsWorkspace, write = SetIsWorkspace };
__property UnicodeString Link = { read = FLink, write = SetLink };
__property UnicodeString NameOverride = { read = FNameOverride, write = SetNameOverride };
Expand Down
2 changes: 2 additions & 0 deletions source/forms/SiteAdvanced.cpp
Expand Up @@ -225,6 +225,7 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
{
S3UrlStyleCombo->ItemIndex = 0;
}
S3RequesterPaysCheck->Checked = FSessionData->S3RequesterPays;

UnicodeString S3SessionToken = FSessionData->S3SessionToken;
if (FSessionData->HasAutoCredentials())
Expand Down Expand Up @@ -635,6 +636,7 @@ void __fastcall TSiteAdvancedDialog::SaveSession(TSessionData * SessionData)
{
SessionData->S3UrlStyle = s3usVirtualHost;
}
FSessionData->S3RequesterPays = S3RequesterPaysCheck->Checked;
if (SessionData->HasAutoCredentials())
{
SessionData->S3SessionToken = EmptyStr;
Expand Down
14 changes: 11 additions & 3 deletions source/forms/SiteAdvanced.dfm
Expand Up @@ -1017,13 +1017,13 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
Left = 0
Top = 6
Width = 393
Height = 70
Height = 97
Anchors = [akLeft, akTop, akRight]
Caption = 'Protocol options'
TabOrder = 0
DesignSize = (
393
70)
97)
object Label27: TLabel
Left = 12
Top = 20
Expand Down Expand Up @@ -1099,10 +1099,18 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
'Virtual Host'
'Path')
end
object S3RequesterPaysCheck: TCheckBox
Left = 12
Top = 68
Width = 369
Height = 17
Caption = 'Requester &pays'
TabOrder = 2
end
end
object S3AuthenticationGroup: TGroupBox
Left = 1
Top = 82
Top = 109
Width = 393
Height = 143
Anchors = [akLeft, akTop, akRight]
Expand Down
1 change: 1 addition & 0 deletions source/forms/SiteAdvanced.h
Expand Up @@ -283,6 +283,7 @@ class TSiteAdvancedDialog : public TForm
TComboBox *SFTPRealPathCombo;
TLabel *DetachedCertificateLabel;
TFilenameEdit *DetachedCertificateEdit;
TCheckBox *S3RequesterPaysCheck;
void __fastcall DataChange(TObject *Sender);
void __fastcall FormShow(TObject *Sender);
void __fastcall PageControlChange(TObject *Sender);
Expand Down

0 comments on commit 068128f

Please sign in to comment.