New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 696967 link

Starred by 3 users

Issue metadata

Status: Fixed
Owner:
Closed: May 2017
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 2
Type: Bug



Sign in to add a comment

Inconsistent handling of Content-Disposition header starting with a semicolon

Reported by t...@adblockplus.org, Feb 28 2017

Issue description

UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0) Gecko/20100101 Firefox/50.0 Bugcrowd/1.0

Example URL:
http://chrome-navigation-tester.kzar.co.uk/

Steps to reproduce the problem:
1. Go to http://chrome-navigation-tester.kzar.co.uk/
2. Enter ";foo" for "Content-disposition header" (without quotation marks). Other values to test are ";;;;;attachment", ";inline" or ";foo?"
3. Click Submit and watch Chrome handle the server response containing this Content-Disposition header.

What is the expected behavior?
With an RFC 2183 compliant parser, all values listed in step 2 have an empty disposition type. So all of them should be treated like "Content-Disposition: inline" and the browser should navigate to the result page. This is the behavior I see in Firefox 51 for example.

What went wrong?
In Chrome (versions 55, 56 and 58 tested) only "Content-Disposition: ;inline" and "Content-Disposition: ;foo?" result in navigation, other values listed cause the request to be ignored entirely - it shows up in Developer Tools but doesn't even trigger a download.

Did this work before? N/A 

Chrome version: 55.0.2883.87  Channel: stable
OS Version: Ubuntu 16.10 (64-bit)
Flash Version: 

The handling of Content-Disposition header seems to be inconsistent internally. For purposes of downloads (function MimeSniffingResourceHandler::MustDownload()) the header is treated correctly which is why none of these headers trigger a download. The handling for purposes of navigation ignores leading semicolons however so that "Content-Disposition: ;foo" is considered equivalent to "Content-Disposition: foo" and doesn't result in navigation (unrecognized disposition types are treated like "attachment"). This is also why "Content-Disposition: ;inline" and "Content-Disposition: ;foo?" still result in navigation, the former because disposition type is considered to be "inline" and the latter because "foo?" isn't a valid HTTP token so it is rejected as disposition type.

 

Comment 1 by nrav...@samsung.com, Feb 28 2017

I tried to check this on firefox and IE, I could see the result page having webcontent "letsgo" . I hope this is the expected behavior.
Well yes you should see the "letsgo" page if navigation occurred (without a redirection.)

Comment 3 by nrav...@samsung.com, Feb 28 2017

Alright. Am a newbie to Chromium and I'd like to check debug this issue :).

Comment 4 by jri@chromium.org, Mar 2 2017

Cc: rsleevi@chromium.org rdsmith@chromium.org mmenke@chromium.org
Components: -Internals>Network Internals>Network>HTTP
mmenke, rdsmith, rsleevi: Can one of you take a look?
Cc: asanka@chromium.org
Adding in Asanka as well, since I suspect he's familiar with C-D from the downloads work.


Comment 6 by mmenke@google.com, Mar 2 2017

I'm going to go ahead and WontFix this - the report both misunderstandings how Content-Dispositions work, and the spec.

First off, per RFC 2183, the value before the first semi-colon in the content-disposition line is disposition-type, everything after that is a disposition-parm.  (Note that this is indicated by the use of semi-colon.  HTTP headers with lists of the same type of objects generally use a comma separator.  Ones where the first value is the main value, and the others are parameters generally use semi-colons).

Secondly, per the RFC, unrecognized content-disposition types should be treated as attachment, not inline (See section 2.8 of the RFC), and the empty string is not a recognized content-disposition.
Status: WontFix (was: Unconfirmed)
Friendly reminder: reading bug description before replying helps.

I am reporting bogus handling of invalid Content-Disposition headers, namely those starting with one or multiple semicolons. The disposition type is empty in this case which should result in it being treated like inline - it's not an unknown disposition type but rather a missing one. You can look up that logic in HttpContentDisposition::ConsumeDispositionType() in the Chromium code base, and that's how such responses are being treated by Firefox.

However, it seems that there is a second code path within Chromium that I wasn't able to find yet, one that ignores leading semicolons. This second code path causes the strange behavior described in this report. And I am pretty sure that ignoring leading semicolons isn't in line with the RFC.

For reference, we discovered that bug when we tried to "predict" in Adblock Plus whether a particular HTTP response will result in navigation.

Comment 9 by mmenke@chromium.org, Mar 10 2017

Components: -Internals>Network>HTTP Internals>Network
Status: Untriaged (was: WontFix)
Re-opening this, per above comment (Sorry, put this on my todo list, but never got back to thinking about it).
I tried to ignore the leading semicolons and it works fine and we get the same behavior as we see in firefox or IE
Cc: csharrison@chromium.org
Hey, Charles, can I take advantage of your blink expertise? After a bit of source code digging, I spun up a local instance of Chrome and tried to track what happened in ResourceLoader, and it looks like it is successfully completing a GET to "http://chrome-navigation-tester.kzar.co.uk/letsgo/0.338618?statuscode=200&content-type=&location=&content-disposition=%3Bfoo" and handing that over to the AsyncResourceHandler.  Which I think means the problem is further up the loader stack.  Do you know if/where in blink the Content-Disposition header is evaluated?


Exactly, this looks like the other Content-Disposition parser I was looking for. The logic is similar to HttpContentDisposition but not identical. From what I understand, the problematic line is this one:

  contentDisposition.split(';', parameters);

This implicitly sets allowEmptyEntries parameter to false, so the split will ignore empty strings. Changing it to contentDisposition.split(';', true, parameters) should fix the issue reported here. From the look of it, otherwise the result should be identical to HttpContentDisposition.
Cc: tyoshino@chromium.org
Components: Blink>Loader
Thanks for taking a look trev. To Blink>Loader for assignment, and cc tyoshino, is this in your wheelhouse?
Should we use the same code in net/ and blink/ to parse the header, now that we can?
Components: -Internals>Network
Removing network label, as it seems this is a blink issue.
Owner: yhirano@chromium.org
Status: Assigned (was: Untriaged)
> #8
> The disposition type is empty in this case which should result in it being treated like inline

Sorry, can you tell me where it is specified? I skimmed RFC 2183, but failed to find the description.
That's the logic I saw in both Chrome and Firefox code, but I didn't see this case mentioned explicitly in RFC. I guess the idea is that an empty disposition type is the same as no disposition type - meaning that the default behavior applies.
Thanks, hopefully https://codereview.chromium.org/2844353003/ will fix the issue.
Project Member

Comment 21 by bugdroid1@chromium.org, Apr 28 2017

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/a397826c00c0873475842d7f9d9d03038015dcdf

commit a397826c00c0873475842d7f9d9d03038015dcdf
Author: yhirano <yhirano@chromium.org>
Date: Fri Apr 28 13:30:46 2017

Use net::HttpContentTypeDisposition in blink

This CL replaces blink::GetContentDispositionType implementation by
net::HttpContentTypeDisposition. There are some behavior differences between
these two implementations, but because the former is used only to see if
the disposition type is attachement, there is only one difference that matters.
The former returns kAttachement for empty content disposition type (e.g.,
";foo"), but the latter returns kInline. It looks the former is intended to
return kNone, but it returns kAttachment due to misuse of confusing
WTFString::Split interface.

Hence this CL adds IsContentDispositionAttachment and makes it return false
when a value with an empty content disposition type is given.

BUG= 696967 

Review-Url: https://codereview.chromium.org/2844353003
Cr-Commit-Position: refs/heads/master@{#467977}

[add] https://crrev.com/a397826c00c0873475842d7f9d9d03038015dcdf/third_party/WebKit/LayoutTests/http/tests/loading/empty-content-disposition-type.html
[add] https://crrev.com/a397826c00c0873475842d7f9d9d03038015dcdf/third_party/WebKit/LayoutTests/http/tests/loading/resources/empty-content-disposition-type.php
[modify] https://crrev.com/a397826c00c0873475842d7f9d9d03038015dcdf/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
[modify] https://crrev.com/a397826c00c0873475842d7f9d9d03038015dcdf/third_party/WebKit/Source/platform/network/HTTPParsers.cpp
[modify] https://crrev.com/a397826c00c0873475842d7f9d9d03038015dcdf/third_party/WebKit/Source/platform/network/HTTPParsers.h

Status: Fixed (was: Assigned)

Sign in to add a comment