Wednesday, August 15, 2007

Rails - About your application's environment

I set up a rails instance yesterday on my linux box and started it up in the development mode as usual.
From my windows box I accessed the main page (default with rails) of the application. I wanted to verify the environment that rails was loading. So I clicked on the "About your application's environment" link.

I got an error message -
For security purposes, this information is only available to local requests.


Hmm, I knew I had started my server in the development mode and by default this mode considers all requests local.

I doubled checked config/environments/development.rb and found the setting to be right...

# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true


Hmm what is going on?

From development.log I figured the controller for this request to be rails/info with the action name as properties.

%> grep -r "def properties" /usr/local/lib/ruby/gems/1.8/gems /*
/usr/local/lib/ruby/gems/1.8/gems/rails-1.1.6/builtin/rails_info/rails/info_controller.rb: def properties


Ah! So I checked out info_controller.rb

class Rails::InfoController < ActionController::Base
def properties
if local_request?
render :inline => Rails::Info.to_html
else
render :text => '

For security purposes, this information is only available to local requests.

', :status => 500
end
end
end

Tracing local_request? led me to

%> grep -r 'def local_request?' /usr/local/lib/ruby/gems/1.8/gems/*
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/rescue.rb: def local_request? #:doc:
%>


Looking at local_request?

def local_request? #:doc:
[request.remote_addr, request.remote_ip] == ["127.0.0.1"] * 2
end

it is clear that local_request? will return false in this case since I am accessing the page from a different machine.
As I searched for local_request? again, I found this snippet in rescue.rb itself:

def rescue_action(exception)
log_error(exception) if logger
erase_results if performed?

if consider_all_requests_local || local_request?
rescue_action_locally(exception)
else
rescue_action_in_public(exception)
end
end


Ah ha! we need to add consider_all_requests_local to our properties action as well. So I popped open app/controller/application.rb and added the following snippet

class Rails::InfoController < ActionController::Base
def properties
if consider_all_requests_local || local_request?
render :inline => Rails::Info.to_html
else
render :text => '

For security purposes, this information is only available to local requests.

', :status => 500
end
end
end


class ApplicationController < ActionController::Base
# Pick a unique cookie name to distinguish our session data from others'
session :session_key => '_ptracker_session_id'
end

A server restart and I got the output I wanted:

Ruby version1.8.6 (x86_64-linux)
RubyGems version0.9.0
Rails version1.2.3
Active Record version1.15.3
Action Pack version1.13.3
Action Web Service version1.2.3
Action Mailer version1.3.3
Active Support version1.4.2
Application root/home/xxxx/ror
Environmentdevelopment
Database adaptermysql



Hmm maybe I should submit a patch!

2 comments:

Anonymous said...

I am still a bit baffled as to why this has not been fixed yet. It seems your solution should not 'need' to go into the application.rb controller, and mostly because of information handling. I do not feel it is application.rb's responsibility to have information about another class, in this case the InfoController. While I am using this current hack, I am curious if you have come up with anything more subtle, seeing as the problem is still not resolved in rails 2.2.1.

Thanks for your help!!
-Mike

Rupak Ganguly said...

Read this excellent post and you will know... it's the proxy server.