Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

Can't change content type of PUT file from octet/stream to image/jpeg #91

Closed
ransomweaver opened this issue May 29, 2015 · 4 comments
Closed

Comments

@ransomweaver
Copy link

I'm sending images to s3 like this:

[[[VS3 sharedVS3] s3Manager]
     putObjectWithFile:fileName
     destinationPath:remotePath
     parameters:nil
     progress:nil

and this works, but the files seem to be the default octet/stream on s3, which is not desirable.
so we try to set the Content-type header to image/jpeg like this:

[[[VS3 sharedVS3] s3Manager]
     putObjectWithFile:fileName
     destinationPath:remotePath
     parameters:@{@"Content-Type":@"image/jpeg"}
     progress:nil

and that works (to set the header), but now we get 403 from s3:

The request signature we calculated does not match the signature you provided. 
Check your key and signing method

<StringToSign>PUT

image/jpeg
Fri, 29 May 2015 06:03:06 GMT
/vnimages/uploads/2015/05/29/11/E29128D6-FD26-4B0E-9268-BB3A04B13173.jpg</StringToSign>

Seems like the Content-Type parameter is missing from the signing of the request?

I see in AFAmazonS3Manager::putObjectWithFile that it does this to get the signed request:

request = [self.requestSerializer requestWithMethod:method URLString:[[self.baseURL URLByAppendingPathComponent:destinationPath] absoluteString] parameters:nil error:nil];

which shows that the parameters passed to putObjectWithFile never get to requestBySettingAuthorizationHeadersForRequest in the requestSerializer. But, changing that nil to parameters doesn't fix it for me.

@mattt
Copy link
Contributor

mattt commented May 29, 2015

Content-Type is a header, not a parameter. The correct MIME type should be automatically provided if the file extension is .jpg or .jpeg. If not, the request serializer can override this.

@mattt mattt closed this as completed May 29, 2015
@ransomweaver
Copy link
Author

You are sure this is the case for PUT, not POST? The code in AFAmazonS3Manager is this:

 NSData *data = [NSURLConnection sendSynchronousRequest:fileRequest returningResponse:&response error:&fileError];

If I log the mimetype:

NSLog(@"mimetype is %@", [response MIMEType]); // for me this shows "image/jpeg" for the local file

then POST OR PUT:

POST uses

[formData appendPartWithFileData:data name:@"file" 
fileName:[filePath lastPathComponent] mimeType:[response MIMEType]];

but PUT does

request = [self.requestSerializer requestWithMethod:method URLString:[[self.baseURL URLByAppendingPathComponent:destinationPath] absoluteString] parameters:nil error:nil];

    // S3 expects parameters as headers for PUT requests
    if (parameters != nil) {
        for (id key in parameters) {
            [request setValue:[parameters objectForKey:key] forHTTPHeaderField:key];
        }
    }

    request.HTTPBody = data;

The ".jpg" is at the end of destinationPath...is that how the request serializer is supposed to figure out the mime type? A custom request serializer is required here?

@btrimble
Copy link

This seems like a bug or a lack of functionality. putObject doesn't allow for setting headers that factor into the auth signature because the headers (passed as parameters) are set on the request after the auth signature is generated. This leads to a 403 from S3.

You can subclass the request serializer but it ends up duplicating code. Even then you can only set headers that are derived from information that's in the request like Content-Type from file extension or an MD5 hash. You can't specify 'x-amz-acl' header for instance.

@chrisallick
Copy link

Would love for this to be fixed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants