akka-http icon indicating copy to clipboard operation
akka-http copied to clipboard

Allow HttpRequest entity content-type without parameters.

Open devsprint opened this issue 8 years ago • 6 comments

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.

devsprint avatar Dec 26 '16 22:12 devsprint

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 avatar Dec 29 '16 11:12 jrudolph

@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.

devsprint avatar Dec 29 '16 12:12 devsprint

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 avatar Dec 29 '16 12:12 jrudolph

@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.

devsprint avatar Dec 29 '16 12:12 devsprint

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.

jrudolph avatar Dec 29 '16 13:12 jrudolph

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

bblfish avatar Jan 17 '22 10:01 bblfish