Skip to content

Commit

Permalink
Merge pull request #9240 from davidschuette/streamable-file-update
Browse files Browse the repository at this point in the history
feat(common): extend streamable-file header support
  • Loading branch information
kamilmysliwiec authored Mar 1, 2022
2 parents 74789fd + 9ca2a9a commit c653ed5
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 10 deletions.
6 changes: 4 additions & 2 deletions integration/send-files/e2e/express.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { join } from 'path';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';

const readmeString = readFileSync(join(process.cwd(), 'Readme.md')).toString();
const readme = readFileSync(join(process.cwd(), 'Readme.md'));
const readmeString = readme.toString();

describe('Express FileSend', () => {
let app: NestExpressApplication;
Expand Down Expand Up @@ -53,12 +54,13 @@ describe('Express FileSend', () => {
expect(res.body.toString()).to.be.eq(readmeString);
});
});
it('should return a file with correct content type and disposition', async () => {
it('should return a file with correct headers', async () => {
return request(app.getHttpServer())
.get('/file/with/headers')
.expect(200)
.expect('Content-Type', 'text/markdown')
.expect('Content-Disposition', 'attachment; filename="Readme.md"')
.expect('Content-Length', readme.byteLength.toString())
.expect(res => {
expect(res.text).to.be.eq(readmeString);
});
Expand Down
16 changes: 15 additions & 1 deletion integration/send-files/e2e/fastify.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { readFileSync } from 'fs';
import { join } from 'path';
import { AppModule } from '../src/app.module';

const readmeString = readFileSync(join(process.cwd(), 'Readme.md')).toString();
const readme = readFileSync(join(process.cwd(), 'Readme.md'));
const readmeString = readme.toString();

describe('Fastify FileSend', () => {
let app: NestFastifyApplication;
Expand Down Expand Up @@ -67,4 +68,17 @@ describe('Fastify FileSend', () => {
expect(payload.toString()).to.be.eq(readmeString);
});
});
it('should return a file with correct headers', async () => {
return app
.inject({ url: '/file/with/headers', method: 'get' })
.then(({ statusCode, headers, payload }) => {
expect(statusCode).to.equal(200);
expect(headers['content-type']).to.equal('text/markdown');
expect(headers['content-disposition']).to.equal(
'attachment; filename="Readme.md"',
);
expect(headers['content-length']).to.equal(readme.byteLength);
expect(payload).to.equal(readmeString);
});
});
});
2 changes: 2 additions & 0 deletions integration/send-files/src/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ export class AppService {
}

getFileWithHeaders(): StreamableFile {
const file = readFileSync(join(process.cwd(), 'Readme.md'));
return new StreamableFile(
createReadStream(join(process.cwd(), 'Readme.md')),
{
type: 'text/markdown',
disposition: 'attachment; filename="Readme.md"',
length: file.byteLength,
},
);
}
Expand Down
13 changes: 10 additions & 3 deletions packages/common/file-stream/streamable-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@ export class StreamableFile {
}

getHeaders() {
const { type = 'application/octet-stream', disposition = null } =
this.options;
return { type, disposition };
const {
type = 'application/octet-stream',
disposition = undefined,
length = undefined,
} = this.options;
return {
type,
disposition,
length,
};
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface StreamableFileOptions {
type?: string;
disposition?: string;
length?: number;
}
26 changes: 26 additions & 0 deletions packages/common/test/file-stream/streamable-file.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,32 @@ describe('StreamableFile', () => {
expect(streamableFile.getStream()).to.equal(stream);
});
});
describe('when options is empty', () => {
it('should return application/octet-stream for type and undefined for others', () => {
const stream = new Readable();
const streamableFile = new StreamableFile(stream);
expect(streamableFile.getHeaders()).to.deep.equal({
type: 'application/octet-stream',
disposition: undefined,
length: undefined,
});
});
});
describe('when options is defined', () => {
it('should pass provided headers', () => {
const stream = new Readable();
const streamableFile = new StreamableFile(stream, {
type: 'application/pdf',
disposition: 'inline',
length: 100,
});
expect(streamableFile.getHeaders()).to.deep.equal({
type: 'application/pdf',
disposition: 'inline',
length: 100,
});
});
});
describe('otherwise', () => {
describe('when input is a Buffer instance', () => {
it('should create a readable stream and push the input buffer', () => {
Expand Down
16 changes: 14 additions & 2 deletions packages/platform-express/adapters/express-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,24 @@ export class ExpressAdapter extends AbstractHttpAdapter {
}
if (body instanceof StreamableFile) {
const streamHeaders = body.getHeaders();
if (response.getHeader('Content-Type') === undefined) {
if (
response.getHeader('Content-Type') === undefined &&
streamHeaders.type !== undefined
) {
response.setHeader('Content-Type', streamHeaders.type);
}
if (response.getHeader('Content-Disposition') === undefined) {
if (
response.getHeader('Content-Disposition') === undefined &&
streamHeaders.disposition !== undefined
) {
response.setHeader('Content-Disposition', streamHeaders.disposition);
}
if (
response.getHeader('Content-Length') === undefined &&
streamHeaders.length !== undefined
) {
response.setHeader('Content-Length', streamHeaders.length);
}
return body.getStream().pipe(response);
}
return isObject(body) ? response.json(body) : response.send(String(body));
Expand Down
16 changes: 14 additions & 2 deletions packages/platform-fastify/adapters/fastify-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,24 @@ export class FastifyAdapter<
}
if (body instanceof StreamableFile) {
const streamHeaders = body.getHeaders();
if (fastifyReply.getHeader('Content-Type') === undefined) {
if (
fastifyReply.getHeader('Content-Type') === undefined &&
streamHeaders.type !== undefined
) {
fastifyReply.header('Content-Type', streamHeaders.type);
}
if (fastifyReply.getHeader('Content-Disposition') === undefined) {
if (
fastifyReply.getHeader('Content-Disposition') === undefined &&
streamHeaders.disposition !== undefined
) {
fastifyReply.header('Content-Disposition', streamHeaders.disposition);
}
if (
fastifyReply.getHeader('Content-Length') === undefined &&
streamHeaders.length !== undefined
) {
fastifyReply.header('Content-Length', streamHeaders.length);
}
body = body.getStream();
}
return fastifyReply.send(body);
Expand Down

0 comments on commit c653ed5

Please sign in to comment.