0

Introduction

I'm writing a script that will alter the way a person views 4chan, when inside a thread, as well as adding some functionality.

In a 4chan thread, when you upload an image, the server will generate a thumbnail with the same name as the original file and also save that image for people to view, but with the name being the unix timestamp. When you click the thumbnail, its src is changed to its parent's href, meaning the name of the image is merely the timestamp, and not a useful name at all.

There are two problems with this

  1. When the thread has 404'd, there is a chance that you can't open the image anymore, since it has been removed from the server.
  2. The name of the image you download doesn't match the displayed name.

In this SO answer, you can see that the only lossless method that is also able to handle all types of files (I should be able to load jpg, png, gif and webm) is doing a query to the server, asking for the file, reading it and converting it to a data URI. When the image is cached inside the src attribute, I can (according to this SO answer) simply add a download attribute with the original filename, and my two points will be resolved.

The problem

I'm injecting the following script into 4chan with Styler, a Chrome extension.

$(function(){
  if ($('body').hasClass('is_thread')) {
    $.getScript("http://my.url/updater.js").done(function() {
      $('html').addClass('done')
    }).fail(function() {
      $('html').addClass('done failed')
    })
  }
})

The script at my url is then loaded into the document itself, and does its own thing from there on (I plan on sharing the code with some people, that's why I've (temporarily) put the script on a server).

Inside the script there is a part that loops over all new posts and tries to request the file again.

var $media = $post.find('img, video')
if ($media.length) {
  $.ajax({
    url: $media.parent().attr('href'),
    method: 'GET',
    success: function (data) {
      console.log(data)
    },
    error: function () {
      console.log('error')
    }
  })
}

The AJAX call is being made, but the following error occurs:

XMLHttpRequest cannot load http://i.4cdn.org/b/123456789.jpg. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://boards.4chan.org' is therefore not allowed access.

When Adding the following to the call

headers: {
  'Access-Control-Allow-Origin': 'http://boards.4chan.org'
}

I get the following error:

XMLHttpRequest cannot load http://i.4cdn.org/b/123456789.jpg. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://boards.4chan.org' is therefore not allowed access. The response had HTTP status code 405.

I am testing this on the http server and have also tried setting it to *, https... and http(s)..., but no luck.

From the 4chan API:

CORS is supported with an origin of http(s)://boards.4chan.org

Does anybody know how I can fix this? I know there is a way to convert img srces to data URI with canvas, but that can be lossy and is limited to jpg, png and webp (in Chrome). I've settled on this method, since the API specifically states that CORS should be enabled for http://boards.4chan.org.

If you want to do the same thing I'm doing, you will have to install Styler, copy the code and upload a file to a server. Here is a minimal updater.js file.

var jq
;(function () {
  var script = document.createElement('script')
  script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'
  script.type = 'text/javascript'
  script.onload = function () {
    jq = window.jQuery.noConflict()
    jq('.postContainer.replyContainer').each(function () {
      var $post = jq(this)
      var $media = $post.find('img, video')
      if ($media.length) {
        jq.ajax({
          url: $media.parent().attr('href'),
          method: 'GET',
          headers: {
            'Access-Control-Allow-Origin': 'http://boards.4chan.org'
          },
          success: function (data) {
            console.log(data)
          },
          error: function () {
            console.log('error')
          }
        })
      }
    })
  }
  document.getElementsByTagName('head')[0].appendChild(script)
})()
Community
  • 1
  • 1
Gust van de Wal
  • 5,211
  • 1
  • 24
  • 48

1 Answers1

5

Not sure what the problem could be other than just the statement CORS is supported with an origin of http(s)://boards.4chan.org maybe not actually being true.

Anyway if you can’t make it work otherwise, a fallback it to use a CORS proxy. The way that works is, instead of sending your request to http://i.4cdn.org/b/123456789.jpg directly, send it here:

https://cors-anywhere.herokuapp.com/http://i.4cdn.org/b/123456789.jpg

That’ll cause the request to be sent to https://cors-anywhere.herokuapp.com, a proxy which will then send it to http://i.4cdn.org/b/123456789.jpg. And when that proxy gets the response, it’ll take it and add the Access-Control-Allow-Origin response header to it and then pass that back to your requesting frontend code as the response.

That response with the Access-Control-Allow-Origin response header is what the browser running your frontend code sees, so the error message the browser is showing you now goes away, and the browser allows your frontend JavaScript code to access the response.

Or you can use the code from https://github.com/Rob--W/cors-anywhere/ to set up your own proxy.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • This totally worked! Although it's a bit of a hack, I guess there's no other option than to use this or my own proxy until I've heard back from 4chan about the issue – Gust van de Wal May 04 '17 at 01:24