Control Public File Response Code in Rails - ruby-on-rails

Let's say that I have a POST endpoint in my Rails app, in which it gets a param called state, which will be an integer of either 200 or 503.
How can I make the Robots.txt file respond with the given state from that POST endpoint, I mean I need a way to control the response code of that only file (Robots.txt) depending on that POST endpoint.
BTW, question is not about how to store that state or something, it's only about how to change the response code of a public file?
Is that possible?
What I have in mind for this and trying now is to have a controller action matching the robots.txt route, but I feel this is so silly to do.

Yes, if you want Rails to be involved in deciding the response for a given URL, then you're going to want to define a controller action to handle those requests.
You can use send_file to actually do the file-sending part.
Depending on your web server's configuration, it's likely you'll need the actual robots.txt file to be stored somewhere other than public/ -- otherwise it might get served without Rails even having a chance to get involved.
You could instead arrange to rewrite your nginx (say) configuration file at runtime, based on what response code you want... but I think that would be silly to do.
A more practical middle-ground would be to have Rails create or delete a marker file, and then use a conditional in the nginx configuration based on whether that file exists. That would be an nginx question though... and would get complicated if you have more than one server.

Related

MVC 5 how to achieve POST that behaves like a redirect to GET with content

My client redirects to a https://domain.com/Controller/GetInfo?Querystring method. Now my query string is getting dangerously close to the 2K limit, so I need to reproduce this behavior but pack my query string into the content of the messages. Since it would be heresy (etc.) to try a GET with content, I'll use a POST. However, I can't redirect to a POST since a Redirect has no content.
So, what I am looking for is the best MVC 5 pattern to resolve this: I need to provide lots of content, but I want the resulting page hosted on my remote server (i.e. as if I had redirected)
Also, since I use load balanced servers in azure, I'd prefer maintaining my clean stateless server if at all possible (else I'll have to introduce session caching).
#AntP is absolutely right in the comments above. If your query string is approaching 2K, then you're abusing it.
If there's a particular object you're referencing, then you can simply include the id or some other identifying piece of it and use that to look it up again from your data store.
If there's no persistent record of the object, then you can use something like Session or TempData to store it between one request and the next.
Regardless, it's not possible to redirect with a request body, with also means it's not possible to redirect using POST. The reason for this that the a redirect is not something the server does, but rather the client. The server merely suggests that the client go to a different URL. It's then up to the client (web browser) to issue a new request for that URL. Since the client is the one issuing the request, it makes the decision about what data is or isn't included in that request, not the server.

Accepting calls from certain URL in Grails

I have a situation that requires me to call a certain controller when a specific request is sent from a certain URL.
Let's say my application is running on: http://www.app.com/listencontroller
When a request is sent to this URL, and the request is sent from http://www.itsme.com, I want to be able to process that request, otherwise I don't want to do anything with it.
How can this be done in a pretty way, i.e. no hard coded URLs in my controller?
Do you mean that the browser must come from the domain itsme.com, or the request must come through a link that's present on a page that resides in itsme.com?
The first would require you to do a reverse dns lookup on request.remoteAddr.
The latter entails looking at the Referer header of the incoming request. This is not bulletproof, as it can be easily spoofed. Also, in some cases it will not be sent at all, so your mileage may vary.
In either case, either a Grails filter or a controller interceptor would probably be the most elegant solution.
In the end this link did the job:
http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/18%20IP%20Address%20Restrictions.html

Security in RESTful Rails controller actions - Should I always use respond_to format block?

Wondering if I should ALWAYS use the respond_to/format.xxx block in ALL of my actions in ALL of my controllers. This came up because I realized that, for apps using only HTML response format (no respond_to block), I could send some other type of request (say XML) and get a valid response. Is this considered insecure? Feels to me like it is, and it seems that the solution would be to ALWAYS add the respond_to/format.xxx block to EVERY action on EVERY controller even if you are just using HTML only. That way, any non-html requests will get rejected (as they should).
So, is there ever a situation where it would be OK to leave out the respond_to/format.xxx bits for any given action? Even if you were just doing a simple, standard, HTML-only app? It seems like different versions of rails code generators have generated different things regarding this over time. Just wondering what is considered best practice, and when you can get away without using it.
And if the answer is "Yes, you should use it all the time in every action to be secure", then would it not be considered boilerplate at that point? And shouldn't it be pushed down into rails somehow so we don't have to write it out over and over again every single time?
I don't think this has any impact on the security of your application. Presuming that the inbound HTTP request is well-formed and the client is authenticated to make the request, you as the server don't really care what the client receives. In fact, the client could be passing in all sorts of headers and parameters that you totally ignore and it's up to the client to handle unexpected formats or errors. This is integral to the underlying architecture of HTTP.
In any case, you can set the routes up to not accept the .format parameter, in which case a request for .xml will result in a 404 or other type of error.
If you only use one format, don't the respond_to block, it clutters code with unnecessary artifacts.

In Rails, can an internal request be generated that behaves identically to an HTTP request?

Within my Rails application, I'd like to generate requests that behave identically to "genuine" HTTP requests.
For a somewhat contrived example, suppose I were creating a system that could batch incoming HTTP requests for later processing. The interface for it would be something like:
Create a new batch resource via the usual CRUD methodology (POST, receive a location to the newly created resource).
Update the batch resource by sending it URLs, HTTP methods, and data to be added to the collection of requests it's supposed to later perform in bulk.
"Process" the batch resource, wherein it would iterate over its collection of requests (each of which might be represented by a URL, HTTP method, and a set of data), and somehow tell Rails to process those requests in the same way as it would were they coming in as normal, "non-batched" requests.
It seems to me that there are two important pieces of work that need to happen to make this functional:
First, the incoming requests need to be somehow saved for later. This could be simply a case of saving various aspects of the incoming request, such as the path, method, data, headers, etc. that are already exposed as part of the incoming request object within a controller. It would be nice if there was a more "automatic" way of handling this--perhaps something more like object marshaling or serialization--but the brute force approach of recording individual parameters should work as well.
Second, the saved requests need to be able to be re-injected into the rails application at a later time, and go through the same process that a normal HTTP request goes through: routing, controllers, views, etc. I'd like to be able to capture the response in a string, much as the HTTP client would have seen it, and I'd also like to do this using Rails' internal machinery rather than simply using an HTTP library to have the application literally make a new request to itself.
Thoughts?
a straight forward way of storing the arguments should be serializing the request object in your controller - this should contain all important data
to call the requests later on, i would consider using the Dispatcher.dispatch class method, that takes 3 arguments: the cgi request, the session options (CgiRequest::DEFAULT_SESSION_OPTIONS should be ok) and the stream which the output is written to
Rack Middleware
After doing a lot of investigation after I'd initially asked this question, I eventually experimented with and successfully implemented a solution using Rack Middleware.
A Basic Methodology
In the `call' method of the middleware:
Check to see if we're making a request as a nested resource of a
transaction object, or if it's an otherwise ordinary request. If it's
ordinary, proceed as normal through the middleware by making a call to
app.call(env), and return the status, headers, and response.
Unless this is a transaction commit, record the "interesting" parts of the
request's env hash, and save them to the database as an "operation" associated
with this transaction object.
If this is a transaction commit, retrieve all of the relevant operations
for this transaction. Either create a new request environment, or clone the
existing one and populate it with the values saved for the operation. Also
make a copy of the original request environment for later restoration, if
control is meant to pass through the application normally post-commit.
Feed the constructed environment into a call to app.call(env). Repeat for
each operation.
If the original request environment was preserved, restore it and make one
final call to app.call(env), returning from the invocation of `call' in the
middleware the status, headers, and response from this final call to
app.call(env).
A Sample Application
I've implemented an example implementation of the methodology I describe here, which I've made available on GitHub. It also contains an in-depth example describing how the implementation might look from an API perspective. Be warned: it's quite rough, totally undocumented (with the exception of the README), and quite possibly in violation of Rails good coding practices. It can be obtained here:
http://github.com/mcwehner/transact-example
A Plugin/Gem
I'm also beginning work on a plugin or gem that will provide this sort of interface to any Rails application. It's in its formative stages (in fact it's completely devoid of code at the moment), and work on it will likely proceed slowly. Explore it as it develops here:
http://github.com/mcwehner/transact
See also
Railscasts - Rack Middleware
Rails Guides - Rails on Rack

How do you see the client-side URL in ColdFusion?

Let's say, on a ColdFusion site, that the user has navigated to
http://www.example.com/sub1/
The server-side code typically used to tell you what URL the user is at, looks like:
http://#cgi.server_name##cgi.script_name#?#cgi.query_string#
however, "cgi.script_name" automatically includes the default cfm file for that folder- eg, that code, when parsed and expanded, is going to show us "http://www.example.com/sub1/index.cfm"
So, whether the user is visiting sub1/index.cfm or sub1/, the "cgi.script_name" var is going to include that "index.cfm".
The question is, how does one figure out which URL the user actually visited? This question is mostly for SEO-purposes- It's often preferable to 301 redirect "/index.cfm" to "/" to make sure there's only one URL for any piece of content- Since this is mostly for the benefit of spiders, javascript isn't an appropriate solution in this case. Also, assume one does not have access to isapi_rewrite or mod_rewrite- The question is how to achieve this within ColdFusion, specifically.
I suppose this won't be possible.
If the client requests "GET /", it will be translated by the web server to "GET /{whatever-default-file-exists-fist}" before ColdFusion even gets invoked. (This is necessary for the web server to know that ColdFusion has to be invoked in the first place!)
From ColdFusion's (or any application server's) perspective, the client requested "GET /index.cfm", and that's what you see in #CGI#.
As you've pointed out yourself, it would be possible to make a distinction by using a URL-rewriting tool. Since you specifically excluded that path, I can only say that you're out of luck here.
Not sure that it is possible using CF only, but you can make the trick using webserver's URL rewriting -- if you're using them, of course.
For Apache it can look this way. Say, we're using following mod_rewrite rule:
RewriteRule ^page/([0-9]+)/?$
index.cfm?page=$1&noindex=yes [L]
Now when we're trying to access URL http://website.com/page/10/ CGI shows:
QUERY_STRING page=10&noindex=yes
See the idea? Think same thing is possible when using IIS.
Hope this helps.
I do not think this is possible in CF. From my understanding, the webserver (Apache, IIS, etc) determines what default page to show, and requests it from CF. Therefore, CF does not know what the actual called page is.
Sergii is right that you could use URL rewrting to do this. If that is not available to you, you could use the fact that a specific page is given precedence in the list of default pages.
Let's assume that default.htm is the first page in the list of default pages. Write a generic default.htm that automatically forwards to index.cfm (or whatever). If you can adjust the list of defaults, you can have CF do a 301 redirect. If not, you can do a meta-refresh, or JS redirect, or somesuch in an HTML file.
I think this is possible.
Using GetHttpRequestData you will have access to all the HTTP headers.
Then the GET header in that should tell you what file the browser is requesting.
Try
<cfdump var="#GetHttpRequestData()#">
to see exactly what you have available to use.
Note - I don't have Coldfusion to hand to verify this.
Edit: Having done some more research it appears that GetHttpRequestData doesn't include the GET header. So this method probably won't work.
I am sure there is a way however - try dumping the CGI scope and see what you have.
If you are able to install ISAPI_rewrite (Assuming you're on IIS) - http://www.helicontech.com/isapi_rewrite/
It will insert a variable x-rewrite-url into the GetHttpRequestData() result structure which will either have / or /index.cfm depending on which URL was visited.
Martin

Resources