Skip to content

Commit 43b4908

Browse files
committed
Escape question marks in filenames
1 parent 6c065e5 commit 43b4908

File tree

2 files changed

+27
-13
lines changed

2 files changed

+27
-13
lines changed

lib/client.js

+13-12
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function removeLeadingSlash(filename) {
6464
function encodeSpecialCharacters(filename) {
6565
// Note: these characters are valid in URIs, but S3 does not like them for
6666
// some reason.
67-
return encodeURI(filename).replace(/[!'()#*+ ]/g, function (char) {
67+
return encodeURI(filename).replace(/[!'()#*+? ]/g, function (char) {
6868
return '%' + char.charCodeAt(0).toString(16);
6969
});
7070
}
@@ -255,7 +255,7 @@ Client.prototype.request = function(method, filename, headers){
255255
var options = { hostname: this.host, agent: this.agent, port: this.port }
256256
, date = new Date
257257
, headers = headers || {}
258-
, fixedFilename = encodeSpecialCharacters(ensureLeadingSlash(filename));
258+
, fixedFilename = ensureLeadingSlash(filename);
259259

260260
// Default headers
261261
headers.Date = date.toUTCString()
@@ -323,7 +323,7 @@ Client.prototype.request = function(method, filename, headers){
323323

324324
Client.prototype.put = function(filename, headers){
325325
headers = utils.merge({}, headers || {});
326-
return this.request('PUT', filename, headers);
326+
return this.request('PUT', encodeSpecialCharacters(filename), headers);
327327
};
328328

329329
/**
@@ -548,7 +548,7 @@ Client.prototype.copyFileTo = function(sourceFilename, destBucket, destFilename,
548548
*/
549549

550550
Client.prototype.get = function(filename, headers){
551-
return this.request('GET', filename, headers);
551+
return this.request('GET', encodeSpecialCharacters(filename), headers);
552552
};
553553

554554
/**
@@ -583,7 +583,7 @@ Client.prototype.getFile = function(filename, headers, fn){
583583
*/
584584

585585
Client.prototype.head = function(filename, headers){
586-
return this.request('HEAD', filename, headers);
586+
return this.request('HEAD', encodeSpecialCharacters(filename), headers);
587587
};
588588

589589
/**
@@ -618,7 +618,7 @@ Client.prototype.headFile = function(filename, headers, fn){
618618
*/
619619

620620
Client.prototype.del = function(filename, headers){
621-
return this.request('DELETE', filename, headers);
621+
return this.request('DELETE', encodeSpecialCharacters(filename), headers);
622622
};
623623

624624
/**
@@ -781,11 +781,9 @@ Client.prototype.list = function(params, headers, fn){
781781
params = null;
782782
}
783783

784-
// Stringify the list params but don't encode them yet, since ::request
785-
// already encodes the value, leading to double-encoding issues
786-
var url = params ? '?' + decodeURIComponent(qs.stringify(params)) : '';
787-
788-
return this.getFile(url, headers, function(err, res){
784+
var url = params ? '?' + qs.stringify(params) : '';
785+
var req = this.request('GET', url, headers);
786+
registerReqListeners(req, function(err, res){
789787
if (err) return fn(err);
790788

791789
var xmlStr = '';
@@ -809,8 +807,11 @@ Client.prototype.list = function(params, headers, fn){
809807

810808
fn(null, data);
811809
});
812-
}).on('error', fn);
810+
});
813811
});
812+
req.on('error', fn);
813+
req.end();
814+
return req;
814815
};
815816

816817
/**

test/knox.test.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,17 @@ function runTestsForStyle(style, userFriendlyName) {
317317
done();
318318
});
319319
});
320+
321+
specify('with ? in the file name', function (done) {
322+
var buffer = new Buffer('a string of stuff');
323+
var headers = { 'Content-Type': 'text/plain' };
324+
325+
client.putBuffer(buffer, '/buffer?with?questions.txt', headers, function (err, res) {
326+
assert.ifError(err);
327+
assert.equal(res.statusCode, 200);
328+
done();
329+
});
330+
});
320331
});
321332

322333
describe('copy()', function () {
@@ -593,7 +604,8 @@ function runTestsForStyle(style, userFriendlyName) {
593604
it('should remove the files as seen in list()', function (done) {
594605
// Intentionally mix no leading slashes or leading slashes: see #121.
595606
var files = ['/test/user3.json', 'test/string.txt', '/test/apos\'trophe.txt', '/buffer.txt', '/buffer2.txt',
596-
'google', 'buffer with spaces.txt', 'buffer+with+pluses.txt', '/ø', 'ø/ø', '/test/versioned.txt#1'];
607+
'google', 'buffer with spaces.txt', 'buffer+with+pluses.txt', 'buffer?with?questions.txt',
608+
'/ø', 'ø/ø', '/test/versioned.txt#1'];
597609
client.deleteMultiple(files, function (err, res) {
598610
assert.ifError(err);
599611
assert.equal(res.statusCode, 200);
@@ -610,6 +622,7 @@ function runTestsForStyle(style, userFriendlyName) {
610622
assert(keys.indexOf('google') === -1);
611623
assert(keys.indexOf('buffer with spaces.txt') === -1);
612624
assert(keys.indexOf('buffer+with+pluses.txt') === -1);
625+
assert(keys.indexOf('buffer?with?questions.txt') === -1);
613626
assert(keys.indexOf('ø') === -1);
614627
assert(keys.indexOf('ø/ø') === -1);
615628
assert(keys.indexOf('/test/versioned.txt#1') === -1);

0 commit comments

Comments
 (0)