Issues with Digital Oceans Spaces presigned url with content type and ACL public-read

August 4, 2019 301 views
Object Storage DigitalOcean

So I’m building this platform that will allow file uploads and I will be using Digital Oceans Spaces because it’s more affordable for my project. I encountered 2 problems so far when uploading files with presigned url. One is independent from the other. Here’s the code that generates the url:

$spaces = \Storage::disk('spaces');
$client = $spaces->getDriver()->getAdapter()->getClient();
$expiry = "+60 minutes";
$filename = time() .'.jpeg';
$command = $client->getCommand('PutObject', [
   'Bucket' => 'jgb',
   'Key'            => "images/$filename",
   'ACL'            => 'public-read',
   'ContentType' => 'application/octet-stream',
]);

$request = $client->createPresignedRequest($command, $expiry);

return (string) $request->getUri();

and it works fine for file uploads using Postman except that I’m getting 2 problems:

  • I can’t get the content type for files for the files and I get a weird type such as
multipart/form-data; boundary=--------------------------532068335149033986173029

when testing with Postman.

  • I am getting “SignatureDoesNotMatch” error when when presigned url is generated with ACL set to “public-read” to allow access to everyone.

I’ve googled around and couldn’t find anything related to that. I’m thinking maybe Digital Ocean Spaces just lacks some of the features of S3.

Any help is welcome. Thanks!

1 Answer

Hi, Spaces Engineering team member here.

This looks mostly like the AWS PHP SDK v3 you’re using, please do correct me if I’m wrong.

Based on the multipart/form-data string, I think you might be doing a request with the POST HTTP method rather than a PUT HTTP method.

If this is the case, you need to either do a PUT method for the actual upload (be sure to specify the headers & fields per your signed request), or instead generate a signed POST request to use.

The public-read you have specified is a constraint on what permissions should be present on the object AFTER it’s uploaded. Similarly for the content-type.

The SDK does provide explicit methods to ensure you get this correct:

  • $request->getMethod();
  • $request->getHeaders();

If you read the URI string closely, you should see a parameter that shows which headers were signed. Those will need to be preserved if any.

Have another answer? Share your knowledge.