Categories
How It Works

CORS – Not Beer

Making remote files accessible isn’t always as simple as a link.

I’ve been struggling with the idea of remote loading SVGs. There are a lot of problems with this, mostly due to the DOM structure of how your browser loads an SVG file.

What’s an SVG and the DOM? What’s an SVG and the DOM?

Scalable Vector Graphics, or SVG, is a special XML file. It’s generally used like an image, like JPG or PNG, and contains vector graphics. This makes it smaller than PNGs and scalable without resolution loss. Pretty nifty for icons. In fact, better than my beloved Fonts.

This is a part of the Document Object Model, or DOM. In the file, you tell it how you want the content to render. It’s why an SVG can be so powerful, having all the code you need inside a small file. It’s also why it’s so dangerous. Specifically if can contain Javascript code, which can be embedded and hidden in an image. And that can do a lot of damage. If you’re not paying attention, you can upload an SVG with javascript that runs code on the user’s browser. Bad times all around.

Making this worse, if you use <img> tags to embed the SVG, many browsers will execute the code. Even today. Yeah… Not really a good thing.

Top ↑

Embedding SVGs externally has a cost Embedding SVGs externally has a cost

If you want to include an SVG file in your web page, you can use that dangerous <img> tag, but you can also use <svg> code right in the document. The problem there is that requires the SVG to essentially be pasted into the code. For PHP, you can use code like file_get_contents() (which doesn’t always work remotely) or if you’re WordPressy, wp_remote_get()

The catch there? They’re slow if you list, oh, 69 images on a page. You can, of course, use <img> tags and that loads the SVG remotely, perfectly happily. If you’re sure about your SVGs, this is okay. You’re just going to lose one big, super big feature about SVGs.

You can’t use CSS to edit them (color, resizing, etc) anymore.

And that, my friends, is a big problem.

Top ↑

Javascript End Run Javascript End Run

I wasn’t willing to compromise speed or flexibility. I’m particular like that. So I looked up how you can use javascript to hack the DOM. I quickly found SVGInjector, a fast, caching, dynamic inline SVG DOM injection library. Installing and configuring was easy buuuuut…

You saw that but coming, right?

Right.

It didn’t work. Because of CORS.

Top ↑

What the heck is CORS? What the heck is CORS?

Cross Origin Resource Sharing, CORS, is that magical thing that says “Hey you can’t run this resource remotely, yo!” Generally it’s related to Fonts (if you’ve ever tried to embed your own fonts from your own servers, you’d have run into this). I happened to hit it on SVGs, and basically the server where I host the icons wasn’t allowing my servers (local or otherwise) to load the icons.

Thankfully! I use DreamObjects, and you can totally set up CORS on DreamObjects. You can do it on Amazon S3, and I think all the various CEPH-esque services let you.

The catch here (hah you saw that coming, right?) is that not all clients let you do it. Lucky for me, I have s3cmd on my laptop (you should too if you’re going to work with S3 type services – it’ll make your life easier). Installing is easy, and you just have to make a .s3cfg file (DreamHost has some instructions).

Once that’s set up, you can make your rules file like this:

<CORSConfiguration>
<CORSRule>
    <ID>Allow My Icons</ID>
    <AllowedOrigin>https://www.example.com</AllowedOrigin>
    <AllowedOrigin>http://www.example.com</AllowedOrigin>
    <AllowedOrigin>https://example.com</AllowedOrigin>
    <AllowedOrigin>http://example.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedHeader>Content-*</AllowedHeader>
    <AllowedHeader>Host</AllowedHeader>
    <ExposeHeader>ETag</ExposeHeader>
    <MaxAgeSeconds>86400</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>

and then you can set (and check) your CORS:

ipstenu@Uhura:~$ s3cmd setcors Development/example.com/cors-rules.xml s3://my-icons
ipstenu@Uhura:~$ s3cmd info s3://my-icons
s3://my-icons/ (bucket):
   Location:  us-west-1
   Payer:     BucketOwner
   Expiration Rule: none
   Policy:    none
   CORS:      <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule><ID>Allow My Icons</ID><AllowedMethod>GET</AllowedMethod><AllowedMethod>HEAD</AllowedMethod><AllowedOrigin>http://example.com</AllowedOrigin><AllowedOrigin>http://example.com </AllowedOrigin><AllowedOrigin>https://www.example.com </AllowedOrigin><AllowedOrigin>https://www.example.com </AllowedOrigin><AllowedHeader>Content-*</AllowedHeader><AllowedHeader>Host</AllowedHeader><MaxAgeSeconds>86400</MaxAgeSeconds><ExposeHeader>ETag</ExposeHeader></CORSRule></CORSConfiguration>
   ACL:       lezpress: FULL_CONTROL

And now you can embed your SVGs remotely.