Skip to content

Instantly share code, notes, and snippets.

@rgould
Forked from acaporrini/compress_urls.md
Last active February 4, 2019 13:15
Show Gist options
  • Save rgould/aa1da965bd8f616443724b1bf9e3eb5c to your computer and use it in GitHub Desktop.
Save rgould/aa1da965bd8f616443724b1bf9e3eb5c to your computer and use it in GitHub Desktop.

How to compress url parameters (and any other string) in Rails

Introduction

Working with web applications and microservices we often have the problem of passing long lists of values through http requests. While the canonical way of doing this would be to use a POST request or another HTML method and pass the values in the body of the request, this is not always a solution for us.

In fact there are cases where we want to generate action urls that can be passed to other users as link and reused by them to trigger the action in the target Rails application.

The only way to achieve this is for us to be able to pass these values as url parameters in a GET request.

Unfortunately the url maximum lenght might be limited both by the browsers and web servers so we needed to find a workaround for this by compressing the values string with the zlib library.

Example

Our client application generate a request to another app appending a list of values as an array parameter, normally the request url would look like:

http://serverapp.com?myvalues[]=value_1&myvalues[]=value_2&myvalues[]=value_3... # A very long list that exced the maximum allowed number

In order to be able to use this urls we take the values inside the my_values array and we create a string of comma separated values:

comma_separated_values = my_values.join(",")
=> "value_1,value_2,value_3"

Then we compress the values using Zlib:

compressed_values = Zlib::Deflate.deflate(comma_separated_values)
=> "x\x9C+K\xCC)M\x8D7\xD4)\x03\xD3FP\xDA\x18\x00g$\bc"

We then encode base64 the compressed values:

encoded_values = Base64.strict_encode64(compressed_values)
 => "eJwrS8wpTY031CkD00ZQ2hgAZyQIYw=="

Finally we encode the string to be safelly passed as a string parameter:

url_safe_values = CGI.escape(encoded_values)
=>  "eJwrS8wpTY031CkD00ZQ2hgAZyQIYw%3D%3D"

Now we can append the compressed string to our url as a parameter:

request_url =  "http://serverapp.com?myvalues=#{url_safe_values}"
=> "http://serverapp.com?myvalues=eJwrS8wpTY031CkD00ZQ2hgAZyQIYw%3D%3D"

Now we can use this url to issue requests to our server, in orded to be able to process this, the server must implement the decompression logic, which will basically do the reverse process of what we have done in the client:

Unescape the values:

unescaped_values = CGI.unescape(params[:my_values])
=> "eJwrS8wpTY031CkD00ZQ2hgAZyQIYw=="

Decode them:

encoded_values = Base64.strict_decode64(unescaped_values)
=> "x\x9C+K\xCC)M\x8D7\xD4)\x03\xD3FP\xDA\x18\x00g$\bc"

Decompress them:

comma_separated_values = Zlib::Inflate.inflate(encoded_values)
=> "value_1,value_2,value_3"

And finally expand the comma separated values in the original array:

array_of_values = comma_separated_values.split(",")
=> ["value_1", "value_2", "value_3"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment