<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://www.w3.org/Bugs/Public/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4"
          urlbase="https://www.w3.org/Bugs/Public/"
          
          maintainer="sysbot+bugzilla@w3.org"
>

    <bug>
          <bug_id>20322</bug_id>
          
          <creation_ts>2012-12-10 10:21:53 +0000</creation_ts>
          <short_desc>Upload progress events vs CORS</short_desc>
          <delta_ts>2016-08-11 14:01:21 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebAppsWG</product>
          <component>XHR</component>
          <version>unspecified</version>
          <rep_platform>PC</rep_platform>
          <op_sys>All</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P2</priority>
          <bug_severity>normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Anne">annevk</reporter>
          <assigned_to name="Anne">annevk</assigned_to>
          <cc>bugs</cc>
    
    <cc>hsteen</cc>
    
    <cc>jonas</cc>
    
    <cc>mike</cc>
    
    <cc>odinho</cc>
    
    <cc>public-webapps</cc>
    
    <cc>travil</cc>
    
    <cc>tyoshino</cc>
          
          <qa_contact>public-webapps-bugzilla</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>79820</commentid>
    <comment_count>0</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2012-12-10 10:21:53 +0000</bug_when>
    <thetext>It would be good to add some details here. The main thing it prevents detecting I think is the existence of another server, but whether that&apos;s useful given that you can already discover it via &lt;img&gt; I&apos;m not sure, and we might be able to address it in a better way?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>95953</commentid>
    <comment_count>1</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-07 14:33:39 +0000</bug_when>
    <thetext>Anne, what was this bug about? I&apos;m not entirely sure what the context is. Can it be closed?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96046</commentid>
    <comment_count>2</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2013-11-08 22:31:16 +0000</bug_when>
    <thetext>What is unclear about the title plus summary? It cannot be closed.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96050</commentid>
    <comment_count>3</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-08 22:45:32 +0000</bug_when>
    <thetext>XHR spec mentions:

force preflight flag
    Set if the upload events flag is set. 

Force preflight flag links to Fetch: 
http://fetch.spec.whatwg.org/#force-preflight-flag
where it is defined. I assume that you want to add more text about it in the XHR spec since you want this bug to remain open? (Of course using non-trivial HTTP verbs or custom headers also should trigger the preflight - but that logic is in Fetch already..) Anyway - up to you, since you know what you want to get done here :-)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96051</commentid>
    <comment_count>4</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2013-11-08 22:47:14 +0000</bug_when>
    <thetext>This bug is mostly about figuring out whether the &quot;upload events flag&quot; makes sense and by extension the &quot;force preflight flag&quot; which was introduced for XMLHttpRequest.

People kept asking why it was needed and I don&apos;t remember.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96141</commentid>
    <comment_count>5</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-11 21:14:21 +0000</bug_when>
    <thetext>Thanks for explaining this a bit more..

So yeah, why do we need a preflight if XHR sends some data and has registered upload event listeners? Well, I presume there&apos;s a concern about cross-origin information leakage if some upload event listeners fire. Stuff like intranet port/host sniffing might be possible?

So we should  add something like:

&lt;p class=&quot;note&quot;&gt;Firing upload events for cross-origin requests requires a preflight because otherwise, information about the existence of sites and services might leak across origins.&lt;/p&gt;

..although it also seems feasible to just kill the &quot;upload events flag&quot; and do it this way:
https://github.com/whatwg/xhr/pull/15</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96166</commentid>
    <comment_count>6</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2013-11-12 06:30:15 +0000</bug_when>
    <thetext>It seems there is a bug in the specification. We should not be dispatching upload progress events unless that flag is set. Otherwise event listeners registered after send() is invoked will still get events.

It&apos;s not entirely clear to me how you cannot figure out the server exists with just &lt;img&gt;, but I guess it makes timing attacks even easier maybe? Still feels somewhat sketchy.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96181</commentid>
    <comment_count>7</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-12 12:06:34 +0000</bug_when>
    <thetext>No, whether to fire events is controlled by the &quot;upload complete&quot; flag. That works fine as far as I can tell, so there should be no reason to keep the &quot;upload events flag&quot;.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96182</commentid>
    <comment_count>8</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-12 12:10:26 +0000</bug_when>
    <thetext>(Though I note that I agree with your comment about server/port detection via &lt;IMG&gt; and I&apos;m still unsure why you need to enforce a preflight at all)

(Anoter note - to self - is that if we keep the &quot;force preflight flag&quot; it needs a test or two written.)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96197</commentid>
    <comment_count>9</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-12 20:13:34 +0000</bug_when>
    <thetext>Anne&apos;s last comment had some details I didn&apos;t really respond to above.

&gt; Otherwise event listeners registered after send() is invoked will
&gt; still get events.

Hm.. If xhr is an async request object, and a script does his:

xhr.send(data)
xhr.upload.onloadend = function(){...}

it sounds like you&apos;re saying the loadend listener should not fire - ? Why not?

&gt; It&apos;s not entirely clear to me how you cannot figure out the 
&gt; server exists with just &lt;img&gt;, but I guess it makes timing
&gt; attacks even easier maybe? Still feels somewhat sketchy.

http://xhr.spec.whatwg.org/#security-considerations has a useful statement about reading information like size of resources with progress events. That&apos;s certainly sufficient reason to require a preflight here.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96425</commentid>
    <comment_count>10</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2013-11-18 13:56:45 +0000</bug_when>
    <thetext>It should not fire if we want to require a preflight for that case and no preflight was made.

And those security considerations are for a response, not a request (of which you already know the size).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96426</commentid>
    <comment_count>11</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2013-11-18 14:14:07 +0000</bug_when>
    <thetext>x.open(&quot;POST&quot;, &quot;...&quot;)
x.send(&quot;test&quot;)

should not send a preflight and should not allow for late registration of upload event listeners.

x.open(&quot;POST&quot;, &quot;...&quot;)
x.setRequestHeader(&quot;test&quot;, &quot;test&quot;)
x.send(&quot;test&quot;)

should send a preflight and should probably allow for late registration of upload event listeners therefore.

So I guess what we want is keep track in Fetch of whether a preflight happened and if a preflight happened we dispatch events and otherwise we do not.

(It&apos;s also somewhat icky we look for event listeners for a certain event name here but there&apos;s no API to do that in the platform. We should maybe define some kind of hook...)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96506</commentid>
    <comment_count>12</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-19 11:11:24 +0000</bug_when>
    <thetext>&gt; x.open(&quot;POST&quot;, &quot;...&quot;)
&gt; x.send(&quot;test&quot;)
&gt; should not send a preflight and should not allow
&gt; for late registration of upload event listeners.

&gt; x.open(&quot;POST&quot;, &quot;...&quot;)
&gt; x.setRequestHeader(&quot;test&quot;, &quot;test&quot;)
&gt; x.send(&quot;test&quot;)
&gt; should send a preflight and should probably allow
&gt; for late registration of upload event listeners therefore.

Anne, I can see the logic - sort of - but I think the usability of this is going to suck. What you&apos;re suggesting is to introduce some secret state in the API which the JS author can&apos;t inspect or know about (&apos;force_preflight&apos;) that will depend on side effects of whether specific methods like setRequestHeader() were called with specific arguments - and this secret state will determine whether my upload event listeners fire?

Are you really, really sure?

Because it sure seems like a much simpler option to just say &quot;OK, you want to listen to upload events? Righty, doing that will take a preflight request but the events you expect will fire&quot;. That to some extent goes against the norm that adding event listeners should not have side effects - but the API seems much more usable that way.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96777</commentid>
    <comment_count>13</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-25 16:12:40 +0000</bug_when>
    <thetext>So.. tried to write a test case for this to see how current browsers behave. This should be a valid test:
https://github.com/w3c/web-platform-tests/commit/5fd7fd9b759d12006d2ecba5e26d0026521343d6

Story right now is that:

* Firefox implements what Anne and (apparently) the spec says is correct: don&apos;t fire upload events for &quot;simple&quot; requests, fire for &quot;not simple&quot; requests (preflighted).

* Opera (Presto) fires all the events, whether the request was &quot;preflighted&quot; or not.

* Chromium fires none of those events, again regardless of preflight status.

(Can&apos;t test in a modern IE right now - it would be a pretty sweet mess if they did the opposite of Firefox - so we had all possible behaviours covered among the main four engines..)

Note: the data being sent in the above test case is only 1000 characters - well, 999 to be precise - maybe sending a more complex payload might change the way some implementations behave? Thinking of Chrome in particular. I tried to send a larger payload but at some point it seemed to hit some configured limit for the python serve.py script..

IMO this mess indicates that this specific corner of the spec isn&apos;t relied upon by authors yet, and we could do a bit of cleanup. I&apos;m not sure how exactly it should work though - given that it&apos;s too late to make sure a preflight request happens after send() is called, maybe Chromium&apos;s &quot;ignore events registered after send()&quot; model is best?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96827</commentid>
    <comment_count>14</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2013-11-26 13:10:44 +0000</bug_when>
    <thetext>So Chrome only dispatches events if the &quot;upload events flag&quot; is set? That would be okay with me.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>96829</commentid>
    <comment_count>15</comment_count>
    <who name="Hallvord R. M. Steen">hsteen</who>
    <bug_when>2013-11-26 14:30:37 +0000</bug_when>
    <thetext>Seems correct. I agree this is reasonable.

(Also I&apos;d like browsers to issue warnings when authors register listeners that will never fire, but I guess that&apos;s an implementation detail)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>113461</commentid>
    <comment_count>16</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-10-20 16:01:25 +0000</bug_when>
    <thetext>Okay. So it sounds like what we want to do here is require events listeners to be added to XMLHttpRequest&apos;s associated XMLHttpRequestUpload object before send() is invoked.

Do we do this even for same-origin fetches? Since due to redirects they might be hard to distinguish.


Hallvord, I did not get this by the way from comment 13 upon rereading this bug:

&gt; given that it&apos;s too late to make sure a preflight request happens 
&gt; after send() is called</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>113511</commentid>
    <comment_count>17</comment_count>
    <who name="Jonas Sicking (Not reading bugmail)">jonas</who>
    <bug_when>2014-10-20 23:13:41 +0000</bug_when>
    <thetext>Gecko does not force a preflight for sameorigin requests if there&apos;s a progress listener. Doing so would likely break a lot of existing content that was written before CORS existed.

However gecko does not support redirecting to cross-origin in that case since we generally don&apos;t support redirects when a preflight is required. Both because this used to be what the spec required, and because doing anything else used to be impossible due to the design of Gecko&apos;s network library.

And yes, I believe the force-preflight flag was added to avoid making it possible to detect servers. I agree it&apos;s doubtful if that&apos;s really useful. Feel free to reach out to the mozilla security team to see if they feel comfortable removing this restriction. Obviously other browser vendors might have the same concern.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>113519</commentid>
    <comment_count>18</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-10-21 07:05:44 +0000</bug_when>
    <thetext>I did not mean forcing a preflight for same-origin content. I meant requiring that listeners are added in advance. I believe Chrome is doing that.

(Note that I don&apos;t believe you&apos;re right about the specification having changed. I think same-origin -&gt; cross-origin has always been there.)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>113520</commentid>
    <comment_count>19</comment_count>
    <who name="Jonas Sicking (Not reading bugmail)">jonas</who>
    <bug_when>2014-10-21 07:23:34 +0000</bug_when>
    <thetext>What&apos;s the advantage to requiring that listeners are added before the .send() call? Why not instead treat listeners added before .send() as setting the &quot;force preflight&quot;. And if we&apos;re not preflighting a cross-origin request, then no progress events are fired.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>113522</commentid>
    <comment_count>20</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-10-21 07:30:28 +0000</bug_when>
    <thetext>That requires an awful lot of coordination between the API and the Fetch layer due to e.g. same-origin requests redirecting to cross-origin requests. Whether a preflight was made for a cross-origin request. I&apos;m not sure we want to have that kind of back-and-forth between those layers. Seems cumbersome.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>113525</commentid>
    <comment_count>21</comment_count>
    <who name="Jonas Sicking (Not reading bugmail)">jonas</who>
    <bug_when>2014-10-21 09:15:28 +0000</bug_when>
    <thetext>Hmm.. good point. Though seems really silly to require event listeners to be added at any particular time for same-origin requests that have never been done cross-origin.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>127126</commentid>
    <comment_count>22</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-08-11 14:01:21 +0000</bug_when>
    <thetext>I just went with what implementations do for now: https://github.com/whatwg/xhr/commit/667d4f3604aaee4e24bde33ed487cf8a98274e70

Basically always require listeners upfront...

I also submitted a correction for Hallvord&apos;s test based on what implementations do today: https://github.com/w3c/web-platform-tests/pull/3451</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>