Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignatureDoesNotMatch error when Content-type is 'text/*' using TAmazonStorageService.UploadObject

Using the following Delphi XE2 (update 4) code:

var
  ConInfo: TAmazonConnectionInfo;
  RespInfo: TCloudResponseInfo;
  Service: TAmazonStorageService;
  Content: TBytes;
  Headers: TStringList;
begin
  ConInfo:=TAmazonConnectionInfo.Create(self);
  ConInfo.AccountName:='YOUR ACCOUNT NAME';
  ConInfo.AccountKey:='YOUR ACCOUNT KEY';
  ConInfo.Protocol:='http';

  Service:=TAmazonStorageService.Create(ConInfo);
  RespInfo:=TCloudResponseInfo.Create;

  SetLength(Content, 128);
  FillMemory(@Content[0], 128, Byte('x'));

  Headers:=TStringList.Create;
  Headers.Values['Content-type']:='text/plain';
  if not Service.UploadObject('YOUR BUCKET', 'test.txt', Content, TRUE, nil, Headers, amzbaPrivate, RespInfo) then
    ShowMessage('Failed:' + RespInfo.StatusMessage);

I always get an error on the call to UploadObject:

Failed:HTTP/1.1 403 Forbidden - The request signature we calculated does not match the signature you provided. Check your key and signing method. (SignatureDoesNotMatch)

This only happens when the Content-type is set to 'text/plain', 'text/html', or text anything. Using exactly the same code, if you just change the content-type to any other content-type, e.g. 'video/3gpp', then it works as expected and without error. The actual content of the object being uploaded isn't relevant and has no bearing on getting the error or not.

I've traced through the Indy code in Delphi, but I'm stumped as to why the text content type always gives this error.

Any ideas?

like image 467
Mick Avatar asked Apr 26 '12 08:04

Mick


1 Answers

If you append "; charset=ISO-8859-1" to the Content-Type string, then it works:

Headers.Values['Content-type']:='text/plain; charset=ISO-8859-1';

Stepping through the code I see the Content-Type is being changed in TIdEntityHeaderInfo.SetHeaders (IdHTTPHeaderInfo.pas) which is called from TIdHTTPProtocol.BuildAndSendRequest (IdHTTP.pas).

Ultimately, it looks like the problem is that TIdEntityHeaderInfo.SetContentType (IdHTTPHeaderInfo.pas) is appending a character set to the content type if it is 'text' and it doesn't already have one. It shouldn't be changing the content type in these situations because the content type is part of the string to be signed, so changing it after the signing makes the signature invalid.

like image 145
Mick Avatar answered Sep 20 '22 16:09

Mick