Allow HttpRequest entity content-type without parameters.
According to the HTTP specification section 3.7, older HTTP clients/server may not be able to handle Media Type definition with parameters. While implementing the test suite for AWS Signature 4, I did not found a way to build a HttpRequest, with body's content-type (media type) without parameters. It is this possible with current implementation?
So, if I build a HttpRequest as:
HttpRequest(HttpMethods.getForKey(rawMethod.trim).getOrElse(HttpMethods.CONNECT), encodeIfRequired(rawUri), headers, HttpEntity(body), HttpProtocols.getForKey(rawProtocol).getOrElse(HttpProtocols.HTTP/1.1))
And headers variable already contains a Content-Type header, then I'm expecting that this header will not be overwritten by HttpRequest implementation when the HttpEntity is created.
The latest spec, RFC7231, doesn't seem to contain that paragraph any more. Also, the previous version also didn't say anywhere that you can or should remove required parameters. Also, it isn't clear how this relates to AWS signatures? AFAIU, AWS doesn't state anywhere that you need to strip parameters off? In fact, it shows a request including media type parameters in the documentation.
In any case, putting the Content-Type into the headers is the wrong place. You need to change the media type inside the HttpEntity.
@jrudolph I have find this issue implementing the test suite provided for AWS Signature 4 from Amazon. Their test data contains a scenario where the input data looks like:
POST / HTTP/1.1
Content-Type:application/x-www-form-urlencoded
Host:example.amazonaws.com
X-Amz-Date:20150830T123600Z
Param1=value1
and the expected result is:
POST
/
content-type:application/x-www-form-urlencoded
host:example.amazonaws.com
x-amz-date:20150830T123600Z
content-type;host;x-amz-date
9095672bbd1f56dfc5b65f3e153adc8731a4a654192329106275f4c7b24d0b6e
When I have implemented this I did not found a way to be able to get a result without media type parameter out of a HttpRequest. Anyway, I'm aware that is not quite in line with the spec, but I just made people aware that because of this I'm not able to cover one scenario suggested by Amazon.
AWS do no state anywhere that the parameters should be strip off. Their examples contains the media type parameter information, but only this particular scenario is not inline with that.
Hmm, this example does not include any media-type parameters, so I seem to be missing something :)
The canonicalization procedure required by AWS signing is basically a function HttpRequest => String, so the only important thing is that you get all the required information out of an existing HttpRequest object, not that you actually change the request (aside from adding the signature headers).
@jrudolph their data scenarios are in that form, the last part "Param1=value1" is basically the body content. The implementation of the AWS Signature 4 in alpakka is based on HttpRequest. So basically, to be able to use the test scenarios, I had to build a HttpRequest, pass to signature implementation, retrieve the data from HttpRequest after signature and compare it with the expected results (as string). This is why I found this issue and the other one related to Uri.
From my point of view, this is just an issue with the test suite provided by Amazon, and is not a problem with current implementation of signature in alpakka. @agolubev asked me to log these 2 issues to get more feedback (I guess) on this.
First of all, thanks for improving the test coverage for s3, @devsprint. I think I understand the problem now. It seems indeed be a problem with the test data. The failing test assumes that akka-http would send a request like the one defined in post-x-www-form-urlencoded-parameters.req:
POST / HTTP/1.1
Content-Type:application/x-www-form-urlencoded; charset=utf8
Host:example.amazonaws.com
X-Amz-Date:20150830T123600Z
Param1=value1
However, that will never happen as akka-http has its own "canonical representation" for charset parameters, so that utf8 will always be rendered as UTF-8. So, it doesn't really make sense to run this test through akka-http.
In fact, your fixes will actually even break signing because you sign something else than what akka-http will actually send. I will also comment on your PR.
I think AWS-Signature is now the IETF HTTP-Bis spec "Signing Http Messages" which is at version 07. I have an implementation of that here for Akka. https://github.com/bblfish/httpSig