3

I'm using Ruby on Rails. Here is the requirement: the client (a native mobile app developed by me) will send a http post request to my Ruby code, my code will add some extra http headers (based on some business logic), then I need to "forward" or "redirect" this post request to another backend server (which has a REST service) and return its response back to the client.

I have been able to write a rack middleware to intercept the post request and add the extra headers. Originally I thought I could just use http redirect (status code: 307 for post request). But the problem is that the extra headers could NOT be submitted, which is the whole point of my code. So this isn't http redirect or forwarding per se, it's more like transforming a request.

I'm able to make a separate post request from my code using net http. This works. But I have to COPY data from the incoming request to my outgoing request (eg form data, http headers). This copying seems a bit tedious.

I would prefer some kind of simple "repackaging" (which is akin to http redirect or forwarding), that is I copy the whole incoming request to the outgoing request, slap on the extra headers and send it to the destination URL and be done with. I am not sure how to do this, and if doing it this way is even a good idea. For example, HTTP_USER_AGENT shows the OS, browser type of the client, when I'm making a new request, I probably don't need to send this on.

Alternatively, I can copy only the application specific data, because they're all the backend server (the destination of this "redirect") cares about. But I'm averse to hardcoding attributes in my code, causing close-coupling with the client (our native mobile app). Ideally I only copy application-specific data without hardcoding their attribute names. Is this possible? If so, how?

Any advice would be appreciated. Thank you.

Zack Xu
  • 11,505
  • 9
  • 70
  • 78
  • It seems that copying the application-specific HTTP headers and form data isn't as complicated as I thought it would be. All the application-specific application headers start with "HTTP_" (as explained in http://stackoverflow.com/questions/6317705/rackrequest-how-do-i-get-all-headers). The form data can be accessed via request.POST (request being an object of Rack::Request). So I don't need to hardcode any attribute name. – Zack Xu May 16 '16 at 13:52

1 Answers1

3

HTTP does not allow redirects for anything other than GET request.

(This is not technically correct but using HTTP 307 is kind of sketchy - see https://softwareengineering.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect)

If you need too send a POST request to another server for processing then using a proxy as you already seem to be doing is the correct solution.

Recreating the request in the proxy may seem tedious but it actually serves as a guarantee that you are calling the other servers "API" correctly.

While you can simply loop through the request headers:

uri = URI('http://www.example.com/todo.cgi')
req = Net::HTTP::Post.new(uri)

request.headers.each do |key, value|
  req[key] = value
end

And pass the request form data:

req.set_form_data = request.request_parameters

You should ask yourself if it really is prudent to proxy everything.

See http://api.rubyonrails.org/classes/ActionDispatch/Request.html

Community
  • 1
  • 1
max
  • 96,212
  • 14
  • 104
  • 165
  • Note that I DO NOT recommend forwarding like the example above since it has some pretty serious security concerns. Your basically letting the user proxy anything and to the proxied service it appears that the request is a legitimate request coming from your app. I would only use it with a careful whitelist. – max May 16 '16 at 14:15
  • yes, that's a good point. i forgot to mention there's a careful whitelist, so no, not every request is proxied. – Zack Xu May 16 '16 at 14:55
  • "HTTP does not allow redirects for anything other than GET request." That is factually incorrect. But +1 on everything else. – DaSourcerer May 16 '16 at 15:55
  • Actually you are correct there @DaSourcerer. edited. – max May 16 '16 at 16:08