diff --git a/src/ndi/+ndi/+cloud/+api/+files/putFiles.m b/src/ndi/+ndi/+cloud/+api/+files/putFiles.m index fe40e9f79..4f9105d9f 100644 --- a/src/ndi/+ndi/+cloud/+api/+files/putFiles.m +++ b/src/ndi/+ndi/+cloud/+api/+files/putFiles.m @@ -14,8 +14,10 @@ % Name-Value Pairs: % 'useCurl' (logical) - If true, the function will use a system call % to the `curl` command-line tool to perform the -% upload. This can be a robust fallback if the native -% MATLAB HTTP client fails. Defaults to false. +% upload. Defaults to true so every upload path +% stores objects in S3 with consistent headers +% (the MATLAB HTTP client can tag objects +% differently, producing flaky downloads). % % Outputs: % b - True if the upload succeeded (HTTP 200), false otherwise. @@ -39,7 +41,7 @@ arguments preSignedURL (1,1) string filePath (1,1) string {mustBeFile} - options.useCurl (1,1) logical = false + options.useCurl (1,1) logical = true end % 1. Create an instance of the implementation class, passing the options. api_call = ndi.cloud.api.implementation.files.PutFiles(... @@ -51,4 +53,3 @@ [b, answer, apiResponse, apiURL] = api_call.execute(); end - diff --git a/src/ndi/+ndi/+cloud/+api/+implementation/+files/PutFiles.m b/src/ndi/+ndi/+cloud/+api/+implementation/+files/PutFiles.m index ef5c4b487..af21029eb 100644 --- a/src/ndi/+ndi/+cloud/+api/+implementation/+files/PutFiles.m +++ b/src/ndi/+ndi/+cloud/+api/+implementation/+files/PutFiles.m @@ -16,7 +16,7 @@ arguments args.preSignedURL (1,1) string args.filePath (1,1) string {mustBeFile} - args.useCurl (1,1) logical = false + args.useCurl (1,1) logical = true end this.preSignedURL = args.preSignedURL; this.filePath = args.filePath; @@ -62,9 +62,16 @@ % Implementation using a system call to curl b = false; apiURL = this.preSignedURL; % Return the URL as a string - - command = sprintf('curl -X PUT --upload-file "%s" "%s"', this.filePath, this.preSignedURL); - + + % -f so HTTP errors (403/404 on a stale signed URL, etc.) surface + % as a non-zero exit. Pin Content-Type to application/octet-stream + % and Accept-Encoding to identity so the object metadata stored in + % S3 is predictable regardless of the client's environment. + command = sprintf(['curl -fsSL -X PUT --upload-file "%s" ' ... + '-H "Content-Type: application/octet-stream" ' ... + '-H "Accept-Encoding: identity" ' ... + '"%s"'], this.filePath, this.preSignedURL); + [status, result] = system(command); b = (status == 0); @@ -75,4 +82,3 @@ end end end - diff --git a/src/ndi/+ndi/+cloud/uploadSingleFile.m b/src/ndi/+ndi/+cloud/uploadSingleFile.m index f52f0edb3..3af119d6f 100644 --- a/src/ndi/+ndi/+cloud/uploadSingleFile.m +++ b/src/ndi/+ndi/+cloud/uploadSingleFile.m @@ -40,7 +40,7 @@ error(['Could not get file collection upload URL: ' url_or_error.message]); end - [b_put, put_or_error] = ndi.cloud.api.files.putFiles(url_or_error, zip_file); + [b_put, put_or_error] = ndi.cloud.api.files.putFiles(url_or_error, zip_file, 'useCurl', options.useCurl); if ~b_put error(['Could not upload zip file: ' put_or_error.message]); end