diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 74bb711ef3ded52c2e310fc0fbebc7cd17e52955..eb59e71a030a9a193efd2d83a78bd6b6f27253e9 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -173,7 +173,10 @@ $(document).ready(function () {
 		FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
 			return OC.imagePath('core', 'actions/download');
 		}, function (filename) {
-			window.location = OC.filePath('files', 'ajax', 'download.php') + '?files=' + encodeURIComponent(filename) + '&dir=' + encodeURIComponent($('#dir').val());
+			var url = FileList.getDownloadUrl(filename);
+			if (url) {
+				OC.redirect(url);
+			}
 		});
 	}
 	$('#fileList tr').each(function () {
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 66968ab54c7ee654b39f0fdd1ed2b02a96c0f087..63fd0f4ce0584a5e38e5343af5a16c40d74bfaba 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -780,6 +780,20 @@ var FileList={
 		$('#fileList tr.searchresult').each(function(i,e) {
 			$(e).removeClass("searchresult");
 		});
+	},
+
+	/**
+	 * Returns the download URL of the given file
+	 * @param filename file name of the file
+	 * @param dir optional directory in which the file name is, defaults to the current directory
+	 */
+	getDownloadUrl: function(filename, dir) {
+		var params = {
+			files: filename,
+			dir: dir || FileList.getCurrentDirectory(),
+			download: null
+		};
+		return OC.filePath('files', 'ajax', 'download.php') + '?' + OC.buildQueryString(params);
 	}
 };
 
diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js
new file mode 100644
index 0000000000000000000000000000000000000000..23f7b58dcd9a1ffb8ec724a8fadc61e00abad13d
--- /dev/null
+++ b/apps/files/tests/js/fileactionsSpec.js
@@ -0,0 +1,61 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+describe('FileActions tests', function() {
+	beforeEach(function() {
+		// init horrible parameters
+		var $body = $('body');
+		$body.append('<input type="hidden" id="dir" value="/subdir"></input>');
+		$body.append('<input type="hidden" id="permissions" value="31"></input>');
+		// dummy files table
+		$filesTable = $body.append('<table id="filestable"></table>');
+	});
+	afterEach(function() {
+		$('#dir, #permissions, #filestable').remove();
+	});
+	it('calling display() sets file actions', function() {
+		// note: download_url is actually the link target, not the actual download URL...
+		var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
+
+		// no actions before call
+		expect($tr.find('.action[data-action=Download]').length).toEqual(0);
+		expect($tr.find('.action[data-action=Rename]').length).toEqual(0);
+		expect($tr.find('.action.delete').length).toEqual(0);
+
+		FileActions.display($tr.find('td.filename'), true);
+
+		// actions defined after cal
+		expect($tr.find('.action[data-action=Download]').length).toEqual(1);
+		expect($tr.find('.action[data-action=Rename]').length).toEqual(1);
+		expect($tr.find('.action.delete').length).toEqual(1);
+	});
+	it('redirects to download URL when clicking download', function() {
+		var redirectStub = sinon.stub(OC, 'redirect');
+		// note: download_url is actually the link target, not the actual download URL...
+		var $tr = FileList.addFile('test download File.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
+		FileActions.display($tr.find('td.filename'), true);
+
+		$tr.find('.action[data-action=Download]').click();
+
+		expect(redirectStub.calledOnce).toEqual(true);
+		expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=test%20download%20File.txt&dir=%2Fsubdir&download');
+		redirectStub.restore();
+	});
+});
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index be848e0e0b0833b0f3ad64f6218b99fdae4e5a55..61e026c0725abc697a783b76cf32cd2b0c5f5388 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -32,10 +32,12 @@ describe('FileList tests', function() {
 	});
 	it('generates file element with correct attributes when calling addFile', function() {
 		var lastMod = new Date(10000);
+		// note: download_url is actually the link target, not the actual download URL...
 		var $tr = FileList.addFile('testName.txt', 1234, lastMod, false, false, {download_url: 'test/download/url'});
 
 		expect($tr).toBeDefined();
 		expect($tr[0].tagName.toLowerCase()).toEqual('tr');
+		expect($tr.find('a:first').attr('href')).toEqual('test/download/url');
 		expect($tr.attr('data-type')).toEqual('file');
 		expect($tr.attr('data-file')).toEqual('testName.txt');
 		expect($tr.attr('data-size')).toEqual('1234');
@@ -54,4 +56,8 @@ describe('FileList tests', function() {
 		expect($tr.attr('data-permissions')).toEqual('31');
 		//expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
 	});
+	it('returns correct download URL', function() {
+		expect(FileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=some%20file.txt&dir=%2Fsubdir&download');
+		expect(FileList.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=some%20file.txt&dir=%2Fanotherpath%2Fabc&download');
+	});
 });
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 4c0b0ad9d48a62e95b54600df3b57aa328b34cb9..79c15623c0c9585cd444b0c396463e6a82fa9b8b 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -34,18 +34,16 @@ $(document).ready(function() {
 				window.location = $(tr).find('a.name').attr('href');
 			}
 		});
-		FileActions.register('file', 'Download', OC.PERMISSION_READ, '', function(filename) {
-			var tr = FileList.findFileEl(filename);
-			if (tr.length > 0) {
-				window.location = $(tr).find('a.name').attr('href');
-			}
-		});
-		FileActions.register('dir', 'Download', OC.PERMISSION_READ, '', function(filename) {
+
+		// override since the format is different
+		FileList.getDownloadUrl = function(filename, dir) {
+			// we use this because we need the service and token attributes
 			var tr = FileList.findFileEl(filename);
 			if (tr.length > 0) {
-				window.location = $(tr).find('a.name').attr('href')+'&download';
+				return $(tr).find('a.name').attr('href') + '&download';
 			}
-		});
+			return null;
+		};
 	}
 
 	var file_upload_start = $('#file_upload_start');
diff --git a/core/js/js.js b/core/js/js.js
index 976027dd06b971bcb996fd303e0603017613dbc7..1c7d89ea055adbb0344c596111c67daca0f62102 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -252,6 +252,12 @@ var OC={
 		}
 		return link;
 	},
+	/**
+	 * Redirect to the target URL, can also be used for downloads.
+	 */
+	redirect: function(targetUrl) {
+		window.location = targetUrl;
+	},
 	/**
 	 * get the absolute path to an image file
 	 * @param app the app id to which the image belongs