You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficserver.apache.org by "Dimitry Andric (JIRA)" <ji...@apache.org> on 2014/03/05 14:43:43 UTC
[jira] [Updated] (TS-2616) Multiple Transfer-Encoding: chunked
headers are not sanitized
[ https://issues.apache.org/jira/browse/TS-2616?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Dimitry Andric updated TS-2616:
-------------------------------
Attachment: fix-ts-2616-1.diff
> Multiple Transfer-Encoding: chunked headers are not sanitized
> -------------------------------------------------------------
>
> Key: TS-2616
> URL: https://issues.apache.org/jira/browse/TS-2616
> Project: Traffic Server
> Issue Type: Bug
> Components: HTTP
> Reporter: Dimitry Andric
> Attachments: fix-ts-2616-1.diff
>
>
> I encountered an origin server which sometimes sends multiple copies of the same header. Obviously, this origin server is buggy, but I cannot touch it, or modify it in any way. An example of such a request:
> {noformat}
> CLIENT> GET /example/request?token=12345678 HTTP/1.1
> CLIENT> Host: 192.168.42.42:8080
> CLIENT> Accept-Encoding: deflate, gzip
> CLIENT> User-Agent: Mozilla/5.0 (Mac OS X; en-us) AppleWebKit/535.7.0 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/535.7.0
> CLIENT> Accept: application/json
> CLIENT> Referer: http://example.com/
> CLIENT> Client-ip: 127.0.0.1
> CLIENT> X-Forwarded-For: 127.0.0.1
> CLIENT> Via: http/1.1 trafficserver.localdomain[FF000000000000000000000000000011] (ApacheTrafficServer/4.0.2)
> CLIENT>
> SERVER> HTTP/1.1 200 OK
> SERVER> Access-Control-Allow-Origin: *
> SERVER> Access-Control-Allow-Headers : Content-Type
> SERVER> Access-Control-Allow-Methods : GET, PUT, POST, DELETE
> SERVER> Server: Apache-Coyote/1.1
> SERVER> Transfer-Encoding: chunked
> SERVER> Content-Encoding: gzip
> SERVER> Vary: Accept-Encoding
> SERVER> Date: Tue, 04 Feb 2014 13:55:56 GMT
> SERVER> Transfer-Encoding: chunked
> SERVER>
> SERVER> 14
> SERVER> ....................
> SERVER> 0
> {noformat}
> When this request is initially passed through by TrafficServer, the client sees at least one "Transfer-Encoding: chunked" header, and assumes a chunked transfer. Everything works fine.
> After TrafficServer has cached the request, subsequent requests from the client will receive a non-chunked transfer. However, while TrafficServer has coalesced multiple headers into one, it removes only *one* instance of the "chunked" value:
> {noformat}
> CLIENT> GET http://192.168.42.42:8080/example/request?token=12345678 HTTP/1.1
> CLIENT> Host: 192.168.42.42
> CLIENT> Accept-Encoding: deflate, gzip
> CLIENT> Proxy-Connection: Keep-Alive
> CLIENT> User-Agent: User-Agent: Mozilla/5.0 (Mac OS X; en-us) AppleWebKit/535.7.0 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/535.7.0
> CLIENT> Accept: application/json
> CLIENT> Referer: http://example.com/
> CLIENT>
> SERVER> HTTP/1.1 200 OK
> SERVER> Access-Control-Allow-Origin: *
> SERVER> Access-Control-Allow-Headers : Content-Type
> SERVER> Access-Control-Allow-Methods : GET, PUT, POST, DELETE
> SERVER> Server: ATS/4.0.2
> SERVER> Content-Encoding: gzip
> SERVER> Vary: Accept-Encoding
> SERVER> Date: Tue, 04 Feb 2014 13:57:36 GMT
> SERVER> Transfer-Encoding: chunked
> SERVER> Age: 1546
> SERVER> Content-Length: 20
> SERVER> Proxy-Connection: keep-alive
> SERVER>
> SERVER> ....................
> {noformat}
> Now the client sees both a "Content-Length: 20" and "Transfer-Encoding: chunked" header, which should not happen. When e.g. curl is used as a client, it will assume the transfer is chunked, and it attempts to parse the initial bytes as a hexadecimal size line. Of course this fails, since there is no real chunked transfer, and curl will abort the transfer with an error, after reading approximately 256 kiB.
> The problem is due to a piece of code in HttpTransact::initialize_state_variables_from_response(), which scans the Transfer-Encoding: headers, coalesces them, and removes any "chunked" value from them. However, it does not handle multiple "chunked" values, as explicitly noticed in a comment on line 5795:
> {noformat}
> 5720 void
> 5721 HttpTransact::initialize_state_variables_from_response(State* s, HTTPHdr* incoming_response)
> 5722 {
> ...
> 5785 if (incoming_response->presence(MIME_PRESENCE_TRANSFER_ENCODING)) {
> 5786 MIMEField *field = incoming_response->field_find(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING);
> ...
> 5792 while (enc_value) {
> 5793 const char *wks_value = hdrtoken_string_to_wks(enc_value, enc_val_len);
> 5794
> 5795 // FIX ME: What is chunked appears more than once? Old
> 5796 // code didn't deal with this so I don't either
> 5797 if (wks_value == HTTP_VALUE_CHUNKED) {
> ...
> 5813 // Loop over the all the values in existing Trans-enc header and
> 5814 // copy the ones that aren't our chunked value to a new field
> 5815 while (new_enc_val) {
> 5816 if (new_enc_val != enc_value) {
> 5817 if (new_enc_field) {
> 5818 new_enc_field->value_append(incoming_response->m_heap, incoming_response->m_mime, new_enc_val, new_enc_len, true);
> 5819 } else {
> 5820 new_enc_field = incoming_response->field_create();
> 5821 incoming_response->field_value_set(new_enc_field, new_enc_val, new_enc_len);
> 5822 }
> 5823 }
> 5824
> 5825 new_enc_val = new_enc_iter.get_next(&new_enc_len);
> 5826 }
> {noformat}
> The comparison on line 5816 compares the char pointers new_enc_val and enc_value, to pluck out any non-"chunked" values, while it should really compare the *contents* of the strings. Although it is probably better to just re-use hdrtoken_string_to_wks(), and compare the result with the special HTTP_VALUE_CHUNKED value, e.g.:
> {noformat}
> 5813 // Loop over the all the values in existing Trans-enc header and
> 5814 // copy the ones that aren't our chunked value to a new field
> 5815 while (new_enc_val) {
> 5816 const char *new_wks_val = hdrtoken_string_to_wks(new_enc_val, new_enc_len);
> 5817 if (new_wks_val != HTTP_VALUE_CHUNKED) {
> 5818 if (new_enc_field) {
> 5819 new_enc_field->value_append(incoming_response->m_heap, incoming_response->m_mime, new_enc_val, new_enc_len, true);
> 5820 } else {
> 5821 new_enc_field = incoming_response->field_create();
> 5822 incoming_response->field_value_set(new_enc_field, new_enc_val, new_enc_len);
> 5823 }
> 5824 }
> 5825
> 5826 new_enc_val = new_enc_iter.get_next(&new_enc_len);
> 5827 }
> {noformat}
> After locally modifying my copy of TrafficServer 4.0.2 in the above fashion, I have successfully used it to sanitize the multiple Transfer-Encoding: headers from the origin server.
> Please review the patch I will attach to this issue, which modifies proxy/http/HttpTransact.cc as shown above.
--
This message was sent by Atlassian JIRA
(v6.2#6252)