Friday, July 24, 2015

A HTTP Proxy using Sinatra

I recently found myself wanting to create a HTTP proxy to intercept certain REST requests and translate them into completely different REST requests while at the same time redirecting them to a new location.

You might not want to do EXACTLY what I wanted to do, but there are many similar tasks that either require a proxy or are greatly simplified by a proxy. In my case I essentially wanted to extend an existing application to a new purpose without actually changing any code in that application.  This is the sort of thing proxies are great at.  You have some existing application and you either don't want to change the code (risk breaking existing functionality/incur large testing overhead), or you don't even have any code for it.  As long as you understand the protocol, you can use a proxy to intercept and modify this data thereby adapting an existing application to new purposes without actually touching the old application/code (with the small required exception of pointing it to your proxy).

 If your code/application is communicating via HTTP here are some ideas of things that you might want to do with a proxy:

1 - Insert or remove a specific HTTP Header
2 - Redirect some (but not all) traffic to a different service
3 - Deny access to specific sites/resources
4 - Replace specific resources with custom resources
5 - Log or inspect traffic as it flows across the proxy (debugging)

If you want to do anything like this, you may find this proxy code useful:

A simple HTTP Proxy using Ruby and Sinatra

I have stripped out all of the code specific to my task, and what is left is a simple proxy that intercepts HTTP request and forwards them on to their new location.  It is ready for you to drop in a few lines of code to accomplish your specific task.

For example:

If you wanted to add a specific header to your requests before passing it along you could do this in one line right after the headers are retrieved from the request and before being passed along:

headers = getHeadersFromRequest

I am sure it isn't perfect, so if you do use it and come up with suggestions for improvement let me know in the comments.