I solved this myself. The Content-Type
header was the culprit. In total despair I tested my code with a very small text file and got 403 as the HTTP status code from S3. No timeout. Such progress. I also got a very informative error message:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><StringToSignBytes>...</StringToSignBytes><RequestId>...</RequestId><HostId>...</HostId><SignatureProvided>...</SignatureProvided>
<StringToSign>PUT
text/plain
1391784394
KEYNAME</StringToSign>
<AWSAccessKeyId>...</AWSAccessKeyId>
</Error>
Obviously the content type string (text/plain
in this case) is expected in the string-to-sign if it is provided as an HTTP header from the client. Don't ask me why this causes a timeout with large (5.5MB?) files. I hope this will save someone else a few hours of life time.
The easiest fix is to just remove the line
[request setValue:@"..." forHTTPHeaderField:@"Content-Type"];
If you know the content type when you create the pre-signed URL you can of course add the string to the string-to-sign then.