title: Unexpected CORS issue for normal images in Chrome and iOS Safari
body: <p>I'm facing a CORS issue that is driving me insane. Allow me to share an example URL:</p>
  
  <p><a href="http://www.jungledragon.com/image/19905/mature_female_eastern_forktail.html/zoom" rel="nofollow">http://www.jungledragon.com/image/19905/mature_female_eastern_forktail.html/zoom</a></p>
  
  <p>As the issue can only be reproduced once per page, here is a list of other images:</p>
  
  <p><a href="http://www.jungledragon.com/all/recent" rel="nofollow">http://www.jungledragon.com/all/recent</a></p>
  
  <p>From that overview, you can open any photo page. Next, from that photo page click the image once more to launch it fullscreen, as that is where the issue lies. </p>
  
  <p>Now allow me to explain the setup, and the problem. The site itself is hosted on a Linux server within my control. The site is at www.jungledragon.com. The images, however, are stored at Amazon S3, where the image bucket has an alias of media.jungledragon.com.</p>
  
  <p>The basic situation is simple:</p>
  
  <pre><code>&lt;div id="slideshow-image-container"&gt;
      &lt;div class="slideshow-image-wrapper"&gt;
      &lt;img src="http://media.jungledragon.com/images/1755/19907_large.jpg?AWSAccessKeyId=05GMT0V3GWVNE7GGM1R2&amp;Expires=1409788810&amp;Signature=QH26XDrVuhyr1Qimd7IOBsnui5s%3D" id="19907" class="img-slideshow img-sec wide" data-constrained="true" data-maxheight="2056" crossorigin="anonymous"&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>As you can see, I'm just using the normal 'html' way of loading an image. The image URL is signed and can time out, but that shouldn't be relevant. It is my understanding that CORS does not apply to this situation, since loading images from an external domain this way has been supported for decades. The image is not loaded using javascript, after all.</p>
  
  <p>Just to be sure though, the crossorigin attribute is set in HTML. Furthermore, as a way of testing, I have set a very liberal CORS policy on the image bucket:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"&gt;
  &lt;CORSRule&gt;
  &lt;AllowedOrigin&gt;*&lt;/AllowedOrigin&gt;
  &lt;AllowedMethod&gt;GET&lt;/AllowedMethod&gt;
  &lt;MaxAgeSeconds&gt;3000&lt;/MaxAgeSeconds&gt;
  &lt;AllowedHeader&gt;Authorization&lt;/AllowedHeader&gt;
  &lt;/CORSRule&gt;
  &lt;CORSRule&gt;
  &lt;AllowedOrigin&gt;*&lt;/AllowedOrigin&gt;
  &lt;AllowedMethod&gt;PUT&lt;/AllowedMethod&gt;
  &lt;MaxAgeSeconds&gt;3000&lt;/MaxAgeSeconds&gt;
  &lt;AllowedHeader&gt;Content-Type&lt;/AllowedHeader&gt;
  &lt;AllowedHeader&gt;x-amz-acl&lt;/AllowedHeader&gt;
  &lt;AllowedHeader&gt;origin&lt;/AllowedHeader&gt;
  &lt;/CORSRule&gt;
  &lt;/CORSConfiguration&gt;
  </code></pre>
  
  <p>Now, the situation gets a bit more complicated. The fullscreen image viewer is supposed to get a background color that is the dominant/average color of the actual image on screen. That color is calculated using canvas, yet it is only calculated once. The first time it is calculated for that image, the result is communicated to the back-end using an ajax call and then stored forever. Subsequent visits to the image will not run the calculation logic again, it will simply set the background color of the body element and all is good.</p>
  
  <p>Here is the logic that does the calculation:</p>
  
  <pre><code>&lt;script&gt;
  $( document ).ready(function() {
  
      &lt;?php if (!$bigimage['dominantcolor']) { ?&gt;
  
          $('#&lt;?= $bigimage['image_id'] ?&gt;').load(function(){
          var rgb = getAverageRGB(document.getElementById('&lt;?= $bigimage['image_id'] ?&gt;'));
          document.body.style.backgroundColor = 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';
  
          if (rgb!==false) {
              $.get(basepath + "image/&lt;?= $bigimage['image_id'] ?&gt;/setcolor/" + rgb.r + "-" + rgb.g + "-" + rgb.b);       
          }
  
          });
  
      &lt;?php } ?&gt;
  
  });
  </code></pre>
  
  <p>Yes, I'm mixing in back-end code with front-end code. The above code says that if we do not yet know the dominant color in the scene, calculate it. The load function is used because at document ready, the actual image from the normal html may not have been loaded completely. Next, if the dominant color is not known yet, and the image is loaded, we trigger the function that calculates the dominant color. Here it is:</p>
  
  <pre><code>function getAverageRGB(imgEl) {
  
      var blockSize = 5, // only visit every 5 pixels
      defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
      canvas = document.createElement('canvas'),
      context = canvas.getContext &amp;&amp; canvas.getContext('2d'),
      data, width, height,
      i = -4,
      length,
      rgb = {r:0,g:0,b:0},
      count = 0;
  
      if (!context) {
          return defaultRGB;
      }
  
      height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
      width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
  
      imgEl.crossOrigin = "anonymous";
  
      context.drawImage(imgEl, 0, 0);
  
      try {
          data = context.getImageData(0, 0, width, height);
      } catch(e) {
          /* security error, img on diff domain */
          return false;
      }
  
      length = data.data.length;
  
      while ( (i += blockSize * 4) &lt; length ) {
          ++count;
          rgb.r += data.data[i];
          rgb.g += data.data[i+1];
          rgb.b += data.data[i+2];
      }
  
      // ~~ used to floor values
      rgb.r = ~~(rgb.r/count);
      rgb.g = ~~(rgb.g/count);
      rgb.b = ~~(rgb.b/count);
  
      return rgb;
  
  }
  </code></pre>
  
  <p>The following line is CORS-relevant:</p>
  
  <pre><code>data = context.getImageData(0, 0, width, height);
  </code></pre>
  
  <p>Although I believe I have set up CORS correctly, I can live with this code failing in some browsers. It seems to work fine in Firefox and IE11, for example. If it fails, I would expect it to fail calculating the dominant color. However, something far worse is happening in highly specific cases: the image is not shown alltogether.</p>
  
  <p>My thinking is that my 'classic' loading of the image via img src tags should have nothing to do with this script working or failing, in all cases at least the image should just load, irrespective of the canvas trick.</p>
  
  <p>Here are the situations I discovered where the image does not load alltogether, which I consider a major issue:</p>
  
  <p>On iOS7 on iPhone 5, the first load works fine. The calculation may fail but the image loads. Refreshing the page often breaks the image. 3rd and 4th tries then continue to succeed, and so on.</p>
  
  <p>Worse, at work in Chrome 36 the image does not load alltogether. I say at work, since at home it is not an issue. Possibly a proxy makes the difference. I can refresh all I want, for images that do not have the calculation ran yet, it keeps failing. </p>
  
  <p>The natural thing to do then is to debug it using Chrome's inspector. Guess what? With the inspector open, it always succeeds. The image will always load and the CORS request headers and responses look perfectly fine. This leaves me with virtually no way to debug this. I can tell though that when opening the inspector when the image does not load does give me the "CORS error" in the console, from the previous request I made. Refreshing with the inspector open will then make that go away.</p>
  
  <p>From reading other questions I've learned that cache may be an influence, yet more likely the issue lies in the origin header not sent by the browser. I believe the issue may be in that direction, yet I fail to understand this:</p>
  
  <ul>
  <li>How it influences my "normal" loading of the image using img tags</li>
  <li>How it is only an issue behind a proxy (supposedly) in Chrome, and only when the inspector windows is closed</li>
  <li>How it works so unreliably and inconsistently in Safari on iOS</li>
  </ul>
  
  <p>As said, I can live with only some browsers succeeding with the canvas part, but I can't live with the image not being normally loaded in any case. That part should just work.</p>
  
  <p>I realize the situation is incredibly hard for you to debug, but I hope my explanation triggers some much-needed help.</p>
  
  <p><strong>Update:</strong> I've discovered that when I remove crossorigin="anonymous" from the img tag, the image will load correctly in the specific scenarios I mentioned. However, the consequence of that move is that the color calculation will no longer work in Chrome, not at home and not at work. It continues to work in Firefox though. I'm investigating what to do next.</p>