What Rails module or gem does set default response headers? - ruby-on-rails

With empty Rails app I have Cache-Control set to max-age=0, private, must-revalidate by default.
I want to understand this process better so I am trying to detect code that does this job.
I have checked actionpack, rake middleware, config.action_dispatch.default_headers, initializers and envinronment configs.
I am using Rails 4.2, nginx as web server and Passenger as application server.
Possibly this is some rack middleware or application server itself.

Rack::ETag sets default Cache-Control header.

Related

Rack-cors not showing headers in production env for swagger-ui_rails

I'm currently running a couple of Rails 3.2.x apps. The one using Ruby 1.9.x and is the api endpoint has Rack-cors gem (1.0.1) on it - app Alice; the other runs swagger-ui_rails gem and is the app hosting the api documentation -- app Bob. The swagger docs was created wth swagger-docs gem, which runs format version 1.2. For some reason or another, I cannot get app Alice to give me information for Bob because of this error:
Failed to load https://alice.example.com/api-docs/v1/api-docs.json:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://bob.example.com:3000' is therefore not allowed access.
However! When I look on the network tab, the response is a 200 and I can see the json information. But the response headers definitely do NOT have the required Access-Control-Allow-Origin header.
This happens both thru AWS Elastic Beanstalk (Bob is hosted on EBS) and locally (w/ a bound address).
In my config/environments/production.rb of Alice, I have the following:
config.middleware.insert_before 0, 'Rack::Cors' do
allow do
origins ->(origin, env) do
Rails.logger.warn("CORS origin: #{origin}")
origin =~ /\.example\.com(:\d+)?\z/
end
resource('*', :methods => [:get, :post, :options], :headers => :any)
end
end
When I have this code in config/environments/development.rb in Alice, localhost connects and swagger-ui shows up as expected with no errors in console.
In the network tab of Chrome, this is what I have locally (Bob and Alice in dev/localhost)
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://apitest.bob.com:3000
Access-Control-Expose-Headers:
Access-Control-Max-Age:1728000
Content-Length:1499
Content-Type:application/json
Date:Fri, 22 Sep 2017 21:44:45 GMT
Last-Modified:Mon, 28 Aug 2017 17:37:22 GMT
Server:
Vary:Origin
This is what I get for when Bob is in dev and Alice is in prod:
Accept-Ranges:bytes
Connection:keep-alive
Content-Length:1500
Content-Type:application/json
Date:Fri, 22 Sep 2017 23:10:00 GMT
ETag:"abc-559ce64fb8374"
Last-Modified:Fri, 22 Sep 2017 22:04:35 GMT
Server:
As you can see, prod-Alice does not return any sort of headers the way dev-Alice does, even with the exact same Rack-Cors code block.
rake middleware displays Rack::Cors at the top of the stack, and curl -i https://alice.example.com/api-docs/v1/api-docs.json has never returned the proper access-control headers for me, both locally and on Bob's server.
prod-Bob also has some EBS extensions to add some request headers and methods to nginx. In some other SO post, I saw folks adding in response headers directly via Rails, and so Bob also has the following in application_controller.rb (and in dev, with binding.pry, I can confirm that the response definitely has the specified headers)
after_filter :set_access_control_headers
def set_access_control_headers
headers['Access-Control-Allow-Origin'] = Rails.configuration.hostnames['headers']
headers['Access-Control-Request-Methods'] = 'GET, PUT, POST, OPTIONS'
end
I'm a bit at a loss and any help or thoughts would be appreciated.
The Swagger-docs gem that I'm using puts the .json files that I've created into Rails' /public directory. As such, Rails sees this as static files and not something that should go through Rack middleware. Since our production.rb file had config.serve_static_assets = false, that meant that all these static files were the responsibility of our web server (Apache/Nginx) and not the responsibility of rack-cors gem.
After adding in some CORS headers to Apache, swagger-ui loaded appropriately, but was doubling up the headers - 1st for Apache, 2nd for rack-cors.
I've since removed rack-cors gem and have adjusted the Apache server conf setting on Alice, based on an SO answer related to wildcard subdomains:
/etc/apache2/sites-enabled/mysite.conf
SetEnvIf Origin ^(https?://.+\.example\.com(?::\d{1,5})?)$ CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
Header merge Vary "Origin"
Header set "Access-Control-Allow-Methods" "GET, POST, OPTIONS"

How to configure Phusion Passenger X-frame options?

I'm trying to iframe a site I built (using Rails) and deployed on an ubuntu instance on AWS using Phusion Passenger.
I looked more into it and found that I need to change my X-frame options, a HTTP header from 'SAME ORIGIN' to 'ALLOWALL'. I already added this line into my config/application.rb file and my config/environments/production.rb
config.action_dispatch.default_headers.merge!({'X-Frame-Options' => 'ALLOWALL'})
Even then, when I open my site, I still get these settings in my Network Headers:
Status:200 OK
Transfer-Encoding:chunked
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Powered-By:Phusion Passenger 5.0.11
This leads me to believe that there's a Phusion Passenger config file somewhere that I need to change the X-Frame-Options for. Any clues or help would be great, thanks!
X-Frame-Options header should be set in your vhost (usually Apache or Nginx). For security reasons, if possible, only allow HTTPS whitelisted domains and whitelisted paths.
<virtualHost *:443>
# ... Host and Passenger configuration ...
<Location "/your-iframable-path">
Header always set X-Frame-Options "ALLOW-FROM https://domain-using-iframe"
</Location>
</virtualHost>
I had the same problem. After trying for a long time, I found the solution to it.
Passenger uses a template for it's nginx configuration. When starting passenger, you pass the template to it using the --nginx-config-template parameter.
Now, to configure the X-Frame-Options header for passenger, simply edit the template file. Add the following line under the http { block of the template file:
add_header X-Frame-Options "SAMEORIGIN";
And make sure to run
sudo service passenger restart
To make the changes go live.
:)

net::ERR_CONTENT_DECODING_FAILED when using Rack::Deflater on jruby

net::ERR_CONTENT_DECODING_FAILED
I am receiving this in chrome when Rack::Deflater is enabled, when using on jruby.
After having some reading it looks like this is some jruby issue with gzipping.
Is there any alternative for serving gzipped assets? And also dynamically gzipping responses?
I am hosting the application on heroku. Rails version is 3.2.X
I think this is related with this issue:
https://github.com/jruby/jruby/issues/1371#ref-issue-15218894
This error comes by browser
The response should contain the header telling the client which compression scheme is being used: Content-Encoding: gzip and
The request should contain the correct header: "Accept-Encoding: gzip, deflate"

Sinatra static assets empty

I have a Sinatra app in a Rails app that serves a static asset from a directory. The app is mounted in the Rails routes like this:
mount BeanstalkdView::Server, :at => "/beanstalk"
When I run this locally it works fine, using Thin, but when I run it on my test server (Nginx/Passenger) the static assets behave strange. A request to a static file return 200 OK, but there is no content.
I tell Sinatra where my static files are via set :public_folder, "#{root}/resources" and in the template I load the static files, e.g. a CSS file with #{request.env['SCRIPT_NAME']}/css/file.css. I verified that both paths are correct.
That happens due to ::Rack::Sendfile middleware which is enabled by default in Rails 3.0.x in production (disabled by default in any environment since 3.1.x).
This middleware is really simple but yet powerful. When you pass ::Rack::File or ::Sinatra::StaticFile (or any other object) which respond to :path, this middlware adds X-SendFile (for Apache) or X-SendFile-Redirect (for NGinx) and does not sends actual body. So that Apache or NGinx will handle real file delivery. It's a good and most efficient way to serve static assets in production, however you may disable this middleware (if you don't want to mess with your Nginx/Apache config). Find and comment following config option in your config/environments/production.rb file:
config.action_dispatch.x_sendfile_header
this config option is used to instruct Sendfile middleware which header to set (do not do anything if not specified).
Aleksey V's answer helped me a lot. In the end I fixed this using the proper setting for Nginx in production.rb:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
Make sure you restart your Rails app, Nginx and do a hard refresh in your browser to get the files.
For more info check out: http://jimneath.org/2011/04/05/rails-3-nginx-and-send_file.html.

Rails 3 Asset Pipeline + Apache + Phusion Passenger

I am using Rails 3.1 w/asset pipeline, phusion 3.0.x and apache 2.2.17.
In the configuration documentation at http://guides.rubyonrails.org/asset_pipeline.html, in section 4.1.1 it states that I need to add a section to my apache config:
<LocationMatch "^/assets/.*$">
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
Header unset Last-Modified
Header unset ETag
FileETag None
# RFC says only cache for 1 year
ExpiresActive On
ExpiresDefault "access plus 1 year"
</LocationMatch>
I have been assuming that Phusion Passenger has just been "handling" this... or have I been negligent in not RTFM? If I want to take advantage of the fingerprinting, do I need to add this to the apache config?
If you want the full benefits of the asset pipeline, you do, indeed, need to add this to your Apache configs. Without that section, your Apache configuration is likely specifically telling browsers not to cache assets - resulting in an unnecessary number of round trips between the browser and your server.
In order to get this to work, you may need to enable a few more Apache modules. To do this:
sudo a2enmod
# Choose headers
sudo a2enmod
# Choose expires
sudo service apache2 restart
To debug your set-up, I recommend using the Live Headers Firefox plugin. Using that, specifically request an asset URL (e.g. http://mysite.com/assets/application-8a0ae0b2d708f797674b7123c37501ba.css)and look at the cache headers before and after you make this change. Find an example asset URL by doing a View Source on any page.
After the change, you should see that the cache expiration is set to one year in the future.

Resources