diff --git a/app/controllers/app.js b/app/controllers/app.js index 013ec6de..51fa900d 100755 --- a/app/controllers/app.js +++ b/app/controllers/app.js @@ -164,13 +164,24 @@ app.set("trust proxy", true); // basic routing app.options('*', function(req,res) { setCrossDomain(res); res.end(); }); -app.all(global.settings.base_url+'/sql', function(req, res) { handleQuery(req, res) } ); -app.all(global.settings.base_url+'/sql.:f', function(req, res) { handleQuery(req, res) } ); -app.get(global.settings.base_url+'/cachestatus', function(req, res) { handleCacheStatus(req, res) } ); -app.get(global.settings.base_url+'/health', function(req, res) { handleHealthCheck(req, res) } ); -app.get(global.settings.base_url+'/version', function(req, res) { - res.send(getVersion()); -}); + +app.all(global.settings.base_url + '/sql', handleQuery); +app.all(global.settings.base_url + '/sql.:f', handleQuery); +app.get(global.settings.base_url + '/cachestatus', handleCacheStatus); +app.get(global.settings.base_url + '/health', handleHealthCheck); +app.get(global.settings.base_url + '/version', handleVersion); + +if (global.settings.user_url) { + var user_url = global.settings.user_url; + if (user_url.indexOf(':user') === -1) { + throw new Error("user_url setting must contain :user") + } + app.all(user_url + global.settings.base_url + '/sql', handleQuery); + app.all(user_url + global.settings.base_url + '/sql.:f', handleQuery); + app.get(user_url + global.settings.base_url + '/cachestatus', handleCacheStatus); + app.get(user_url + global.settings.base_url + '/health', handleHealthCheck); + app.get(user_url + global.settings.base_url + '/version', handleVersion); +} var sqlQueryMayWriteRegex = new RegExp("\\b(alter|insert|update|delete|create|drop|reindex|truncate)\\b", "i"); /** @@ -192,6 +203,10 @@ function sanitize_filename(filename) { } // request handlers +function handleVersion(req, res) { + res.send(getVersion()); +} + function handleQuery(req, res) { // extract input @@ -207,6 +222,8 @@ function handleQuery(req, res) { var requestedFilename = params.filename; var filename = requestedFilename; var requestedSkipfields = params.skipfields; + // if the request contains the user use it, if not guess from the host + var cdbUsername = req.params.user || cdbReq.userByReq(req); var skipfields; var dp = params.dp; // decimal point digits (defaults to 6) var gn = "the_geom"; // TODO: read from configuration file @@ -280,8 +297,7 @@ function handleQuery(req, res) { var formatter; - var cdbUsername = cdbReq.userByReq(req), - authApi = new AuthApi(req, params), + var authApi = new AuthApi(req, params), dbParams; if ( req.profiler ) req.profiler.done('init'); diff --git a/config/environments/development.js.example b/config/environments/development.js.example index 8aa86073..65c2fdfd 100644 --- a/config/environments/development.js.example +++ b/config/environments/development.js.example @@ -1,4 +1,10 @@ module.exports.base_url = '/api/:version'; +// if user_url is defined the api will respond to requests like: +// user_url + base_url +// for example +// /u/:user/api/sql?q=.... +// needs to have :user parameter, if not it will fail on server startup +module.exports.user_url = '/u/:user'; // If useProfiler is true every response will be served with an // X-SQLAPI-Profile header containing elapsed timing for various // steps taken for producing the response. diff --git a/test/acceptance/app.test.js b/test/acceptance/app.test.js index fdf5824d..b6381c0d 100644 --- a/test/acceptance/app.test.js +++ b/test/acceptance/app.test.js @@ -147,6 +147,17 @@ test('GET /api/v1/sql with SQL parameter on SELECT only. no database param, just }); }); +test('GET /u/vizzuality/api/v1/sql with SQL parameter on SELECT only', function(done){ + assert.response(app, { + url: '/u/vizzuality/api/v1/sql?q=SELECT%20*%20FROM%20untitle_table_4', + method: 'GET' + },{ }, function(res) { + assert.equal(res.statusCode, 200, res.body); + done(); + }); +}); + + // See https://github.com/CartoDB/CartoDB-SQL-API/issues/121 test('SELECT from user-specific database', function(done){ var backupDBHost = global.settings.db_host;