diff --git a/NEWS.md b/NEWS.md index e1fd64fb..c3d841c9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ * Add last_modified field to POST layergroup response (#72) * Deprecate signal handler for USR1, add handler for USR2 (#71) * Fix support for ampersend characters in CartoCSS +* Add support for LZMA compressed GET parameters 1.1.8 ----- diff --git a/lib/cartodb/server_options.js b/lib/cartodb/server_options.js index 24c0b4df..abd60c6f 100644 --- a/lib/cartodb/server_options.js +++ b/lib/cartodb/server_options.js @@ -5,6 +5,7 @@ var _ = require('underscore') , mapnik = require('mapnik') , crypto = require('crypto') , request = require('request') + , LZMA = require('lzma/lzma_worker.js').LZMA ; module.exports = function(){ @@ -255,6 +256,42 @@ module.exports = function(){ */ me.req2params = function(req, callback){ + if ( req.query.lzma ) { + + // TODO: check ? + //console.log("type of req.query.lzma is " + typeof(req.query.lzma)); + //console.log("req.query.lzma is " + req.query.lzma); + + // Decode + var lzma = []; + for (var i=0; i 127 ) num = 127-num; + //console.log(i + " hex: " + hex + " decodes as " + num); + lzma.push( num ); + } + + // Decompress + //console.log("LZMA decompression starts with " + lzma); + LZMA.decompress( + lzma, + function(result) { + //console.log("LZMA decompression completed, payload: "); console.dir(result); + try { + req.query = JSON.parse(result); + me.req2params(req, callback); + } catch (err) { + callback(new Error('Error parsing lzma as JSON: ' + err)); + } + }, + function(percent) { // progress + //console.log("LZMA decompression " + percent + "%"); + } + ); + return; + } + // Whitelist query parameters and attach format var good_query = ['sql', 'geom_type', 'cache_buster', 'cache_policy', 'callback', 'interactivity', 'map_key', 'api_key', 'style', 'style_version', 'style_convert' ]; var bad_query = _.difference(_.keys(req.query), good_query); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 02733829..cb895d39 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -332,6 +332,9 @@ "mapnik": { "version": "0.7.22" }, + "lzma": { + "version": "1.2.2" + }, "semver": { "version": "1.1.3" }, diff --git a/package.json b/package.json index 003cdf79..71c6d619 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "redis": "0.7.2", "hiredis": "~0.1.14", "request": "2.9.202", - "mapnik": "~0.7.14" + "mapnik": "~0.7.14", + "lzma": "~1.2.2" }, "devDependencies": { "mocha": "1.2.1", diff --git a/test/acceptance/server.js b/test/acceptance/server.js index 33f8cc30..cddc1cd4 100644 --- a/test/acceptance/server.js +++ b/test/acceptance/server.js @@ -7,6 +7,7 @@ var semver = require('semver'); var mapnik = require('mapnik'); var Step = require('step'); var http = require('http'); +var LZMA = require('lzma/lzma_worker.js').LZMA; var SQLAPIEmu = require(__dirname + '/../support/SQLAPIEmu.js'); require(__dirname + '/../support/test_helper'); @@ -16,6 +17,27 @@ var serverOptions = require(__dirname + '/../../lib/cartodb/server_options'); var server = new CartodbWindshaft(serverOptions); server.setMaxListeners(0); +// Utility function to compress & encode LZMA +function lzma_compress_to_hex(payload, mode, callback) { + var HEX = [ '0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f' ]; + LZMA.compress(payload, mode, + function(ints) { + for (var i=0; i> 4; + var lo = ints[i] & 0x0f; + ints[i] = HEX[hi] + HEX[lo]; + }; + var hex = ints.join(''); + callback(null, hex); + }, + function(percent) { + //console.log("Compressing: " + percent + "%"); + } + ); +} + suite('server', function() { var redis_client = redis.createClient(global.environment.redis.port); @@ -782,6 +804,41 @@ suite('server', function() { }); }); + test("get'ing a tile with url specified 2.1.0 style (lzma version)", function(done){ + var qo = { + style: test_style_black_210, + style_version: '2.1.0', + cache_buster: 5 + }; + Step ( + function compressQuery () { + //console.log("Compressing starts"); + var next = this; + lzma_compress_to_hex(JSON.stringify(qo), 1, this); + //cosole.log("compress returned " + x ); + }, + function sendRequest(err, lzma) { + //console.log("Compressing ends: " + typeof(lzma) + " - " + lzma); + assert.response(server, { + headers: {host: 'localhost'}, + url: '/tiles/test_table/15/16046/12354.png?lzma=' + lzma, + method: 'GET', + encoding: 'binary' + },{}, this); + }, + function checkResponse(res) { + assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body); + var ct = res.headers['content-type']; + assert.equal(ct, 'image/png'); + assert.imageEqualsFile(res.body, './test/fixtures/test_table_15_16046_12354_styled_black.png', 2, + function(err, similarity) { + if (err) throw err; + done(); + }); + } + ); + }); + // See http://github.com/Vizzuality/Windshaft-cartodb/issues/57 test("GET'ing a tile as anonymous with style set by POST", function(done){ var style = querystring.stringify({style: test_style_black_210, style_version: '2.1.0'});