1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/querystring.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,121 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +'use strict'; 1.9 + 1.10 +module.metadata = { 1.11 + "stability": "unstable" 1.12 +}; 1.13 + 1.14 +let unescape = decodeURIComponent; 1.15 +exports.unescape = unescape; 1.16 + 1.17 +// encodes a string safely for application/x-www-form-urlencoded 1.18 +// adheres to RFC 3986 1.19 +// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURIComponent 1.20 +function escape(query) { 1.21 + return encodeURIComponent(query). 1.22 + replace(/%20/g, '+'). 1.23 + replace(/!/g, '%21'). 1.24 + replace(/'/g, '%27'). 1.25 + replace(/\(/g, '%28'). 1.26 + replace(/\)/g, '%29'). 1.27 + replace(/\*/g, '%2A'); 1.28 +} 1.29 +exports.escape = escape; 1.30 + 1.31 +// Converts an object of unordered key-vals to a string that can be passed 1.32 +// as part of a request 1.33 +function stringify(options, separator, assigner) { 1.34 + separator = separator || '&'; 1.35 + assigner = assigner || '='; 1.36 + // Explicitly return null if we have null, and empty string, or empty object. 1.37 + if (!options) 1.38 + return ''; 1.39 + 1.40 + // If content is already a string, just return it as is. 1.41 + if (typeof(options) == 'string') 1.42 + return options; 1.43 + 1.44 + // At this point we have a k:v object. Iterate over it and encode each value. 1.45 + // Arrays and nested objects will get encoded as needed. For example... 1.46 + // 1.47 + // { foo: [1, 2, { omg: 'bbq', 'all your base!': 'are belong to us' }], bar: 'baz' } 1.48 + // 1.49 + // will be encoded as 1.50 + // 1.51 + // foo[0]=1&foo[1]=2&foo[2][omg]=bbq&foo[2][all+your+base!]=are+belong+to+us&bar=baz 1.52 + // 1.53 + // Keys (including '[' and ']') and values will be encoded with 1.54 + // `escape` before returning. 1.55 + // 1.56 + // Execution was inspired by jQuery, but some details have changed and numeric 1.57 + // array keys are included (whereas they are not in jQuery). 1.58 + 1.59 + let encodedContent = []; 1.60 + function add(key, val) { 1.61 + encodedContent.push(escape(key) + assigner + escape(val)); 1.62 + } 1.63 + 1.64 + function make(key, value) { 1.65 + if (value && typeof(value) === 'object') 1.66 + Object.keys(value).forEach(function(name) { 1.67 + make(key + '[' + name + ']', value[name]); 1.68 + }); 1.69 + else 1.70 + add(key, value); 1.71 + } 1.72 + 1.73 + Object.keys(options).forEach(function(name) { make(name, options[name]); }); 1.74 + return encodedContent.join(separator); 1.75 + 1.76 + //XXXzpao In theory, we can just use a FormData object on 1.9.3, but I had 1.77 + // trouble getting that working. It would also be nice to stay 1.78 + // backwards-compat as long as possible. Keeping this in for now... 1.79 + // let formData = Cc['@mozilla.org/files/formdata;1']. 1.80 + // createInstance(Ci.nsIDOMFormData); 1.81 + // for ([k, v] in Iterator(content)) { 1.82 + // formData.append(k, v); 1.83 + // } 1.84 + // return formData; 1.85 +} 1.86 +exports.stringify = stringify; 1.87 + 1.88 +// Exporting aliases that nodejs implements just for the sake of 1.89 +// interoperability. 1.90 +exports.encode = stringify; 1.91 +exports.serialize = stringify; 1.92 + 1.93 +// Note: That `stringify` and `parse` aren't bijective as we use `stringify` 1.94 +// as it was implement in request module, but implement `parse` to match nodejs 1.95 +// behavior. 1.96 +// TODO: Make `stringify` implement API as in nodejs and figure out backwards 1.97 +// compatibility. 1.98 +function parse(query, separator, assigner) { 1.99 + separator = separator || '&'; 1.100 + assigner = assigner || '='; 1.101 + let result = {}; 1.102 + 1.103 + if (typeof query !== 'string' || query.length === 0) 1.104 + return result; 1.105 + 1.106 + query.split(separator).forEach(function(chunk) { 1.107 + let pair = chunk.split(assigner); 1.108 + let key = unescape(pair[0]); 1.109 + let value = unescape(pair.slice(1).join(assigner)); 1.110 + 1.111 + if (!(key in result)) 1.112 + result[key] = value; 1.113 + else if (Array.isArray(result[key])) 1.114 + result[key].push(value); 1.115 + else 1.116 + result[key] = [result[key], value]; 1.117 + }); 1.118 + 1.119 + return result; 1.120 +}; 1.121 +exports.parse = parse; 1.122 +// Exporting aliases that nodejs implements just for the sake of 1.123 +// interoperability. 1.124 +exports.decode = parse;