Motivation

Suppose we want to pass a collection of key/value pairs as a URL parameter, under the following conditions:

For example: url => http://example.com/? str = encode( {foo => “bar/ba.x”, baz => aN+6786kl76sd+123==} )

Using JSON with example above, we would get:

str => {“foo”:“bar/ba.x”,“baz”:“aN+6786kl76sd+123==”}

url => http://example.com/?str= %7B%22foo%22%3A%22bar%2Fba.x%22%2C%22baz%22%3A%22aN%2B6786kl76sd%2B123%3D%3D%22%7D

This works, but because need to URL-encode the values, the quotes and curly-braces in JSON inflate the resulting parameter size, which can be an issue if the parameters are lengthy to begin with.

If we use form-encoding, we can get a reduction in the resulting string size:

str => foo=bar%2Fba.x&baz=aN%2B6786kl76sd%2B123%3D%3D

url => http://example.com?str= foo%3Dbar%252Fba.x%26baz%3DaN%252B6786kl76sd%252B123%253D%253D

But form-encoding increases the complexity of the signature preparation because we need to URL-encode each value prior to form-encoding so any URL-unsafe characters do not conflict with the form-encoding (delimiter collision).

If we can assume that there is at least one character that will not appear in the keys and values of the object, and does not interfere with URL-encoding, then another approach comes to mind: using this safe character as a delimiter between the keys and values of the serialized object.

Using this approach we end up with a shorter string that requires less complexity to produce:

str => foo,bar/ba.x,baz,aN+6786kl76sd+123==

url => http://example.com?str= foo%2Cbar%2Fba.x%2Cbaz%2CaN%2B6786kl76sd%2B123%3D%3D

Steps

Encoding

Decoding

Sample Implementation

JavaScript

[sourcecode lang=“javascript”] function encodeSingleDelimiter (obj, delimeter) { delimeter = delimeter || ‘,’; var pairs = []; for (var i in obj) { var pair = i + delimeter + obj[i]; pairs.push(pair); } return pairs.join(delimeter); }

function decodeSingleDelimiter (str, delimeter) { delimeter = delimeter || ‘,’; var items = str.split(delimeter); var obj = {}; for (var i = 0; i < items.length; i++) { if (0 === i % 2) { var key = items[i]; } else { var val = items[i]; } obj[key] = val } return obj; } [/sourcecode]

References