浏览代码

Issue 2213: Support for "Requester pays" S3 buckets

https://winscp.net/tracker/2213

Source commit: b9cc8e854b82d3c0a94e0481e16fa6b0f1e82c4a
Martin Prikryl 1 年之前
父节点
当前提交
068128f522

+ 2 - 0
libs/libs3/inc/libs3.h

@@ -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,

+ 1 - 0
libs/libs3/inc/request_context.h

@@ -52,6 +52,7 @@ struct S3RequestContext
     void *sslCallbackData;
     S3ResponseDataCallback *responseDataCallback;
     void *responseDataCallbackData;
+    int requesterPays;
 #else
     CURLM *curlm;
     S3CurlMode curl_mode;

+ 15 - 3
libs/libs3/src/request.c

@@ -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;
@@ -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
@@ -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;
 
@@ -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;
     }
@@ -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);
     }
 

+ 6 - 1
libs/libs3/src/request_context.c

@@ -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;
@@ -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)

+ 2 - 0
source/core/S3FileSystem.cpp

@@ -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
   {

+ 9 - 0
source/core/SessionData.cpp

@@ -297,6 +297,7 @@ void __fastcall TSessionData::DefaultSettings()
   S3UrlStyle = s3usVirtualHost;
   S3MaxKeys = asAuto;
   S3CredentialsEnv = false;
+  S3RequesterPays = false;
 
   // SFTP
   SftpServer = L"";
@@ -463,6 +464,7 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(S3UrlStyle); \
   PROPERTY(S3MaxKeys); \
   PROPERTY(S3CredentialsEnv); \
+  PROPERTY(S3RequesterPays); \
   \
   PROPERTY(ProxyMethod); \
   PROPERTY(ProxyHost); \
@@ -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)
@@ -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);
@@ -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);

+ 3 - 0
source/core/SessionData.h

@@ -234,6 +234,7 @@ private:
   TS3UrlStyle FS3UrlStyle;
   TAutoSwitch FS3MaxKeys;
   bool FS3CredentialsEnv;
+  bool FS3RequesterPays;
   bool FIsWorkspace;
   UnicodeString FLink;
   UnicodeString FNameOverride;
@@ -426,6 +427,7 @@ private:
   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);
@@ -710,6 +712,7 @@ public:
   __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 };

+ 2 - 0
source/forms/SiteAdvanced.cpp

@@ -225,6 +225,7 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
     {
       S3UrlStyleCombo->ItemIndex = 0;
     }
+    S3RequesterPaysCheck->Checked = FSessionData->S3RequesterPays;
 
     UnicodeString S3SessionToken = FSessionData->S3SessionToken;
     if (FSessionData->HasAutoCredentials())
@@ -635,6 +636,7 @@ void __fastcall TSiteAdvancedDialog::SaveSession(TSessionData * SessionData)
   {
     SessionData->S3UrlStyle = s3usVirtualHost;
   }
+  FSessionData->S3RequesterPays = S3RequesterPaysCheck->Checked;
   if (SessionData->HasAutoCredentials())
   {
     SessionData->S3SessionToken = EmptyStr;

+ 11 - 3
source/forms/SiteAdvanced.dfm

@@ -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
@@ -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]

+ 1 - 0
source/forms/SiteAdvanced.h

@@ -283,6 +283,7 @@ __published:
   TComboBox *SFTPRealPathCombo;
   TLabel *DetachedCertificateLabel;
   TFilenameEdit *DetachedCertificateEdit;
+  TCheckBox *S3RequesterPaysCheck;
   void __fastcall DataChange(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall PageControlChange(TObject *Sender);