feat: response.attachment append a parameter: options from contentDisposition (#1240)
This commit is contained in:
parent
d32623baa7
commit
9146024e10
3 changed files with 139 additions and 4 deletions
|
@ -271,11 +271,11 @@ ctx.redirect('/cart');
|
||||||
ctx.body = 'Redirecting to shopping cart';
|
ctx.body = 'Redirecting to shopping cart';
|
||||||
```
|
```
|
||||||
|
|
||||||
### response.attachment([filename])
|
### response.attachment([filename], [options])
|
||||||
|
|
||||||
Set `Content-Disposition` to "attachment" to signal the client
|
Set `Content-Disposition` to "attachment" to signal the client
|
||||||
to prompt for download. Optionally specify the `filename` of the
|
to prompt for download. Optionally specify the `filename` of the
|
||||||
download.
|
download and some [options](https://github.com/jshttp/content-disposition#options).
|
||||||
|
|
||||||
### response.headerSent
|
### response.headerSent
|
||||||
|
|
||||||
|
|
|
@ -285,9 +285,9 @@ module.exports = {
|
||||||
* @api public
|
* @api public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
attachment(filename) {
|
attachment(filename, options) {
|
||||||
if (filename) this.type = extname(filename);
|
if (filename) this.type = extname(filename);
|
||||||
this.set('Content-Disposition', contentDisposition(filename));
|
this.set('Content-Disposition', contentDisposition(filename, options));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -48,3 +48,138 @@ describe('ctx.attachment([filename])', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// reference test case of content-disposition module
|
||||||
|
describe('contentDisposition(filename, options)', () => {
|
||||||
|
describe('with "fallback" option', () => {
|
||||||
|
it('should require a string or Boolean', () => {
|
||||||
|
const ctx = context();
|
||||||
|
assert.throws(() => { ctx.attachment('plans.pdf', { fallback: 42 }); },
|
||||||
|
/fallback.*string/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should default to true', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('€ rates.pdf');
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="? rates.pdf"; filename*=UTF-8\'\'%E2%82%AC%20rates.pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when "false"', () => {
|
||||||
|
it('should not generate ISO-8859-1 fallback', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('£ and € rates.pdf', { fallback: false });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should keep ISO-8859-1 filename', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('£ rates.pdf', { fallback: false });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="£ rates.pdf"');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when "true"', () => {
|
||||||
|
it('should generate ISO-8859-1 fallback', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('£ and € rates.pdf', { fallback: true });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="£ and ? rates.pdf"; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass through ISO-8859-1 filename', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('£ rates.pdf', { fallback: true });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="£ rates.pdf"');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when a string', () => {
|
||||||
|
it('should require an ISO-8859-1 string', () => {
|
||||||
|
const ctx = context();
|
||||||
|
assert.throws(() => { ctx.attachment('€ rates.pdf', { fallback: '€ rates.pdf' }); },
|
||||||
|
/fallback.*iso-8859-1/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use as ISO-8859-1 fallback', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('£ and € rates.pdf', { fallback: '£ and EURO rates.pdf' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="£ and EURO rates.pdf"; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use as fallback even when filename is ISO-8859-1', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('"£ rates".pdf', { fallback: '£ rates.pdf' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="£ rates.pdf"; filename*=UTF-8\'\'%22%C2%A3%20rates%22.pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing if equal to filename', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('plans.pdf', { fallback: 'plans.pdf' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="plans.pdf"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use the basename of the string', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('€ rates.pdf', { fallback: '/path/to/EURO rates.pdf' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment; filename="EURO rates.pdf"; filename*=UTF-8\'\'%E2%82%AC%20rates.pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing without filename option', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment(undefined, { fallback: 'plans.pdf' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with "type" option', () => {
|
||||||
|
it('should default to attachment', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment();
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'attachment');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require a string', () => {
|
||||||
|
const ctx = context();
|
||||||
|
assert.throws(() => { ctx.attachment(undefined, { type: 42 }); },
|
||||||
|
/invalid type/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require a valid type', () => {
|
||||||
|
const ctx = context();
|
||||||
|
assert.throws(() => { ctx.attachment(undefined, { type: 'invlaid;type' }); },
|
||||||
|
/invalid type/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a header with inline type', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment(undefined, { type: 'inline' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'inline');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a header with inline type & filename', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment('plans.pdf', { type: 'inline' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'inline; filename="plans.pdf"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should normalize type', () => {
|
||||||
|
const ctx = context();
|
||||||
|
ctx.attachment(undefined, { type: 'INLINE' });
|
||||||
|
assert.equal(ctx.response.header['content-disposition'],
|
||||||
|
'inline');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue