Heroku / Cloudfront / Fonts / Firefox - ruby-on-rails

There are quite a few SO questions (1, 2, 3, etc.) that go over the same problem I am having (fonts are not displaying on FireFox due to CORS issue). I have tried all of the proposed solutions in the above questions as well as various blog posts that come up when Googling the issue.
In my specific case I am using Cloudfront on Heroku but I am not using S3 (my assets are pulled to the CDN on first request). I am also using site-wide SSL (and I'm not sure if this is what is causing my issues as all the other examples seem to be for http:// sites). Currently I am trying to use the font_assets gem but when I curl one of my font files (or even a jpg file) I am getting a 301 Moved Permanently instead of a 200.
curl -i https://d2loy3ox2q4ikr.cloudfront.net/assets/fontawesome-webfont-9a3b8f90662fe9149f07a059f1a4c782.woff
HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Date: Wed, 09 Apr 2014 12:27:33 GMT
Location: https://www.transdraft.com/assets/fontawesome-webfont-9a3b8f90662fe9149f07a059f1a4c782.woff
Status: 301 Moved Permanently
X-Cache: Miss from cloudfront
Via: 1.1 1316c66c042cd4b103a533bbf48877a5.cloudfront.net (CloudFront)
X-Amz-Cf-Id: NciaYbAYVS7OpY6ORzjeZMurd_cyBo-B1WfN1QZbSexbM2DoD0vWqg==
curl -i https://d2loy3ox2q4ikr.cloudfront.net/assets/transdraft-hp-2-0fa26dc608ff6a3ea83a093dce8e6338.jpg
HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Date: Wed, 09 Apr 2014 12:28:47 GMT
Location: https://www.transdraft.com/assets/transdraft-hp-2-0fa26dc608ff6a3ea83a093dce8e6338.jpg
Status: 301 Moved Permanently
X-Cache: Miss from cloudfront
Via: 1.1 c8b893f88c46deef2c0f22aefa2d3ecc.cloudfront.net (CloudFront)
X-Amz-Cf-Id: 897u3X7te5f167cZlJiBME1UlBp5NYtGrKm18D4FWOHlTEFMITYTLw==
Any idea what I might be doing wrong?

I fixed this same issue by modifying my application.css.scss to use SCSS imports instead of requires.
From:
//= require font-awesome
To:
#import 'font-awesome';
This may not work for you if you're not using SCSS.

Related

Glyphicon issue / CORS problems still persist, even after using font_assets and custom defining headers

I recently deployed an app -- http://jobs.atlas-china.com
If you go on to http://jobs.atlas-china.com/jobs/2 , you'll notice that the glyphicon for the resume upload does not show up in firefox.
This is because of the Cross Site Header issue. I've tried to fix this by defining a default header, but it's still being wacky.
My application.rb looks like so --
module Atlas
class Application < Rails::Application
config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
config.action_dispatch.default_headers = {
'X-Frame-Options' => 'ALLOWALL',
'X-XSS-Protection' => '1; mode=block',
'X-Content-Type-Options' => 'nosniff',
'Access-Control-Allow-Origin' => ENV['APP_URL']
}
end
end
The font assets are being loaded from cloudfront, so I though this could be a caching issue. However, if I try to make a curl request to the equivalent heroku url, I get --
~$ curl -i http://jobs.atlas-china.com/assets/bootstrap/glyphicons-halflings-regular-fcc658a3dec1be1cb0a9bb81f4c7c6de.woff
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=315360000
Cache-Control: public
Content-Type: font/x-woff
Date: Fri, 30 May 2014 05:13:52 GMT
Expires: Thu, 31 Dec 2037 23:55:55 GMT
Last-Modified: Wed, 16 Apr 2014 06:51:18 GMT
Server: nginx/1.4.7
Content-Length: 23320
Connection: keep-alive
I still don't see anything about an Access-Control-Allow-Origin
What should I be doing here?
update
When I make a curl request to the root url, I do see it though!
curl -i http://jobs.atlas-china.com
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://jobs.atlas-china.com
Cache-Control: max-age=0, private, must-revalidate
Content-Type: text/html; charset=utf-8
Date: Fri, 30 May 2014 05:21:10 GMT
Etag: "a73e238bf8cb6ccb7fdf53ae108e11c6"
Server: nginx/1.4.7 + Phusion Passenger 4.0.41
Set-Cookie: _atlas_session=UkVHc0ZSVko2QmdZMWp3djhuelpvUEtMRXVlU1FJclRSN1dpcTR6QWlDS0gyUU15UmdBY0dZWTMya0FtUnFST2RkVnBiWURUdkRTZVJLNk9JcUxlUnZKWHRWaWoxZnZPdThVVTVMMU5qRlpkQnJxUUVBWHQ3WjUreVZ4VENWeTE1WHF3Sit3ZVFQSzMxYmFRVER0aUpsNUN3OW5IOHJQenIzcU9ZcSt5cndwaWlQRXRheVA3dVZMbTVaek5CRFphLS1SNHo4YjlWQ0JXc0U1MlN5R1NjTVlnPT0%3D--0b975a5008287efb7f8114cbcbedd57b34b7d0f9; path=/; HttpOnly
Status: 200 OK
Strict-Transport-Security: max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: ALLOWALL
X-Powered-By: Phusion Passenger 4.0.41
X-Request-Id: 964dee7f-d49b-4d68-9a35-f8cd0f6371dc
X-Runtime: 0.147926
X-Xss-Protection: 1; mode=block
transfer-encoding: chunked
Connection: keep-alive
Seems to work for me?
CORS
FYI
Seems like you know already, but CORS is basically a way to protect domains / servers from external AJAX requests. The standard setup is the server will deny requests from external domains automatically, regardless of the headers you send
The way to accept / deny any CORS request is to set the policy options on the Rails server, to allow requests from the domains you want. Rails has a gem to help you do this, called Rack-CORS:
#config/application.rb
config.middleware.use Rack::Cors do
allow do
origins 'your_domain.com' #-> has to be exact domain
resource '/your/url', :headers => :any, :methods => [:get, :post, :options]
end
end
I don't know if this will help you or not, but it will certainly give you some ideas as to how to DRY up your CORS headers, as well as giving you the ability to accept requests as you require

HTTP header in Javascript files with puma on development

I have a Rails application, which uses the comfortable mexican sofa CMS. I needed server side events with ActionController::Live, so i use Puma instead of the standard Webrick.
Sometimes some of the javascript assets get served as plain/text and contain the HTTP header like in the following file:
0
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: public, must-revalidate
Last-Modified: Tue, 20 May 2014 09:39:06 GMT
ETag: "9fad3cb6ef7afd353261ec38da25c2e9"
X-Request-Id: 043c6782-4e7c-471a-b6ba-6ea142242fa4
X-Runtime: 0.032228
Content-Length: 820
(function() {
$(function() {
$('form').on('ajax:success', function(e, data, status, xhr) {
...
Any ideas what's the matter and how to fix this?
As it seems this only occurs in Chrome. Firefox and Safari don't have any problems.

enabling rails page caching causes http header charset to disappears

I need charset to be utf-8, which seem to be the case by default. Recently I enabled page caching for a few static pages:
caches_page :about
The caching works fine, and I see the corresponding about.html and contact.html pages generated in my /public folder, except when the page renders, it's no longer in utf-8.
After googling for a bit I tried looking at the http headers with wget, before and after caching:
first time:
$wget --server-response http://localhost:3000/about
HTTP request sent, awaiting response...
1 HTTP/1.1 200 OK
2 X-Ua-Compatible: IE=Edge
3 Etag: "f7b0b4dea015140f3b5ad90c3a392bef"
4 Connection: Keep-Alive
5 Content-Type: text/html; charset=utf-8
6 Date: Sun, 12 Jun 2011 03:44:22 GMT
7 Server: WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12)
8 X-Runtime: 0.235347
9 Content-Length: 5520
10 Cache-Control: max-age=0, private, must-revalidate
cached:
$wget --server-response http://localhost:3000/about
Resolving localhost... 127.0.0.1
Connecting to localhost[127.0.0.1]:3000... connected.
HTTP request sent, awaiting response...
1 HTTP/1.1 200 OK
2 Last-Modified: Sun, 12 Jun 2011 03:34:42 GMT
3 Connection: Keep-Alive
4 Content-Type: text/html
5 Date: Sun, 12 Jun 2011 03:39:53 GMT
6 Server: WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12)
7 Content-Length: 5783
as a result the page displays in ISO-8859-1 and I get a bunch of garbled text. Does anyone know how I can prevent this undesirable result? Thank you.
The solution will depend on the server used.
When you use page cache, the servers reads the server directly, so the rails stack does not provide encoding information to the server. Then the server default apply.
If you're using apache with passenger, add to the configuration:
AddDefaultCharset UTF-8
If you need specific charsets, use a solution like the one in http://www.philsergi.com/2007/06/rails-page-caching-and-mime-types.html
<LocationMatch \/(rss)\/?>
ForceType text/xml;charset=utf-8
</LocationMatch>
<LocationMatch \/(ical)\/?>
ForceType text/calendar;charset=utf-8
</LocationMatch>

Set MIME type for server

i've seen a bunch of topics about setting the MIME types.
But, no one helped me.
He is my problem:
I have a Rails website with bunch of video in .ogv and .mov formats, located in /public folder.
I refer to these files in HTML5 video tag.
There is no problem with .mov files, they are played nice in WebKit browsers.
The problem is with .ogv.
I think, it's because wrong MIME type for .ogv.
Here is what i get for .mov (correct):
$ curl -I http:/mywebsite.com/video.mov
HTTP/1.1 200 OK
Date: Sun, 03 Apr 2011 19:57:41 GMT
ETag: "4d98744c-1bb-87563c0"
Last-Modified: Sun, 03 Apr 2011 13:21:16 GMT
Content-Type: video/quicktime
Content-Length: 443
And here is what i get for .ogv:
$ curl -I http://mywebsite.com/video.ogv
HTTP/1.1 200 OK
Date: Sun, 03 Apr 2011 19:22:20 GMT
ETag: "4d987dcf-379884-81c533dc"
Last-Modified: Sun, 03 Apr 2011 14:01:51 GMT
Content-Type: application/octet-stream
Content-Length: 3643524
Instead of "application/octet-stream" i need "video/ogg".
I have a Mongrel server (no Apache as front-end), as i recently got to know. So, there is no way to use .htaccess.
I need to set MIME-type for regular files, not responses from controller etc.
I've tried several ways, described in my previous question: HTML 5 video (ogv) and MIME types
But i does't works. I still get "application/octet-stream".
My Questions are:
How can i set mime types for regular files, not responses from controller ?
Does Mongrel serves files, located in /public directory, or something else ?
I've figured it out.
All the methods, described in my previous question are setting MIME-types for Rails environment, not Mongrel.
I need additional MIME-types at Mongrel level, not Rails.
So, by starting mongrel via …
/usr/bin/mongrel_rails,
… I need to pass a YAML file to it, that contains additional MIME-types, i want to declare. This YAML file might look like this (mongrel_mime_types.yml):
.ogv: video/ogg
.ogg: application/ogg
.ogx: application/ogg
I keep it in /config/initializers, for convenience.
So, by starting Mongrel, i need to pass this file:
/usr/bin/mongrel_rails -m /path_to_my_project/http/config/initializers/mongrel_mime_types.yml
Now, if i check with curl, I'm getting correct MIME:
$ curl -I http://mywebsite.com/video.ogv
HTTP/1.1 200 OK
Date: Mon, 04 Apr 2011 05:38:01 GMT
ETag: "4d987dcf-379884-81c533dc"
Last-Modified: Sun, 03 Apr 2011 14:01:51 GMT
Content-Type: video/ogg
Content-Length: 3643524

Passenger/Apache: Can't set expire headers for versioned resources (rewrite rule not recognized)

I'm trying to set the expire headers for Rails' auto-versioned resources, like whatever.css?1234567890 . (I don't want to set the expire headers for unversioned resources.) The only method I could find online involved two steps: 1) rewrite all urls that end in 10 digits to load from /public/add_expires_header instead of from /public, where add_expires_header is a symlink that points to /public 2) Add an expiry date to all files from add_expires_header.
Seems like a good idea -- but passenger doesn't seem to recognize the rewrite rule, as indicated by the below curl results.
(Note: a lot of people seemed to think they could accomplish my goal using FilesMatch, but I read elsewhere that FilesMatch can't see the query string.)
#from sites_enabled/sitename in the tags
...
RewriteCond %{QUERY_STRING} ^[0-9]{10}$
RewriteRule ^(.*)$ /add_expires_header%{REQUEST_URI} [QSA]
ExpiresActive On
ExpiresDefault "access plus 1 years"
...
-----
#curl indicates that rewrite rule isn't taking effect
manu#Blade-Server:~$ curl -I -L "http://x.com/stylesheets/style.css?1249092148"
HTTP/1.1 200 OK
Date: Tue, 11 Aug 2009 04:07:49 GMT
Server: Apache/2.2.11 (Ubuntu) Phusion_Passenger/2.2.4 PHP/5.2.6-3ubuntu4.1 with Suhosin-Patch
Last-Modified: Sat, 01 Aug 2009 02:02:28 GMT
ETag: "455b-2fbb-4700aedc5f500"
Accept-Ranges: bytes
Content-Length: 12219
Vary: Accept-Encoding
Content-Type: text/css
manu#Blade-Server:~$ curl -I -L "http://x.com/add_expires_header/stylesheets/style.css?1249092148"
HTTP/1.1 200 OK
Date: Tue, 11 Aug 2009 04:07:55 GMT
Server: Apache/2.2.11 (Ubuntu) Phusion_Passenger/2.2.4 PHP/5.2.6-3ubuntu4.1 with Suhosin-Patch
Last-Modified: Sat, 01 Aug 2009 02:02:28 GMT
ETag: "455b-2fbb-4700aedc5f500"
Accept-Ranges: bytes
Content-Length: 12219
Cache-Control: max-age=31536000
Expires: Wed, 11 Aug 2010 04:07:55 GMT
Vary: Accept-Encoding
Content-Type: text/css
I've also tried including the rewrite stuff in apache2.conf, httpd.conf, and public/.htacess
I prefer to do this by combining it with using an assets host on a separate subdomain to avoid the whole rewrite issue. That way you can set the expire headers for everything on that subdomain. You can activate this in rails in environments/production.rb.
If you don't want to go with a separate subdomain I think the code below should do it, although I have not tested it myself:
ExpiresActive On
<FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
ExpiresDefault "access plus 1 year"
</FilesMatch>

Resources