Skip to content

Commit

Permalink
fix(lambda-tiler): serve sprites with correct mime types (#2259)
Browse files Browse the repository at this point in the history
  • Loading branch information
blacha authored Jun 21, 2022
1 parent ee85b1b commit 1014e1c
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 8 deletions.
5 changes: 4 additions & 1 deletion packages/lambda-tiler/src/routes/__tests__/fonts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { mockRequest } from '../../__tests__/xyz.util.js';
import { fontList, getFonts } from '../fonts.js';
import { FsMemory } from './memory.fs.js';

o.spec('listFonts', () => {
o.spec('/v1/fonts', () => {
const memory = new FsMemory();
o.before(() => {
fsa.register('memory://', memory);
Expand Down Expand Up @@ -52,6 +52,8 @@ o.spec('listFonts', () => {
]);
const res = await fontList();
o(res.status).equals(200);
o(res.header('content-type')).equals('application/json');
o(res.header('content-encoding')).equals(undefined);
o(res.body).equals(JSON.stringify(['Roboto Black', 'Roboto Thin']));
});

Expand All @@ -61,6 +63,7 @@ o.spec('listFonts', () => {
const res255 = await handler.router.handle(mockRequest('/v1/fonts/Roboto Thin/0-255.pbf'));
o(res255.status).equals(200);
o(res255.header('content-type')).equals('application/x-protobuf');
o(res255.header('content-encoding')).equals(undefined);

const res404 = await handler.router.handle(mockRequest('/v1/fonts/Roboto Thin/256-512.pbf'));
o(res404.status).equals(404);
Expand Down
64 changes: 64 additions & 0 deletions packages/lambda-tiler/src/routes/__tests__/sprites.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Env } from '@basemaps/shared';
import { fsa } from '@chunkd/fs';
import o from 'ospec';
import { gunzipSync, gzipSync } from 'zlib';
import { handler } from '../../index.js';
import { mockRequest } from '../../__tests__/xyz.util.js';
import { FsMemory } from './memory.fs.js';

o.spec('/v1/sprites', () => {
const memory = new FsMemory();
o.before(() => {
fsa.register('memory://', memory);
});

o.beforeEach(() => {
process.env[Env.AssetLocation] = 'memory://';
});

o.afterEach(() => {
delete process.env[Env.AssetLocation];
memory.files.clear();
});

o('should return 404 if no assets defined', async () => {
delete process.env[Env.AssetLocation];
const res404 = await handler.router.handle(mockRequest('/v1/sprites/topographic.json'));
o(res404.status).equals(404);
});

o('should fetch a json document', async () => {
await Promise.all([
fsa.write('memory://sprites/topographic.json', Buffer.from(JSON.stringify({ test: true }))),
fsa.write('memory://sprites/topographic.png', Buffer.from('')),
]);
const res = await handler.router.handle(mockRequest('/v1/sprites/topographic.json'));
o(res.status).equals(200);
o(res.header('content-type')).equals('application/json');
o(res.header('content-encoding')).equals(undefined);

o(JSON.parse(Buffer.from(res.body, 'base64').toString())).deepEquals({ test: true });
});

o('should fetch a png', async () => {
await Promise.all([
fsa.write('memory://sprites/topographic.json', Buffer.from(JSON.stringify({ test: true }))),
fsa.write('memory://sprites/topographic@2x.png', Buffer.from('')),
]);
const res = await handler.router.handle(mockRequest('/v1/sprites/topographic@2x.png'));
o(res.status).equals(200);
o(res.header('content-type')).equals('image/png');
});

o('should detect gziped files and set content-encoding', async () => {
await Promise.all([
fsa.write('memory://sprites/topographic.json', gzipSync(Buffer.from(JSON.stringify({ test: true })))),
]);
const res = await handler.router.handle(mockRequest('/v1/sprites/topographic.json'));
o(res.status).equals(200);
o(res.header('content-type')).equals('application/json');
o(res.header('content-encoding')).equals('gzip');

o(JSON.parse(gunzipSync(Buffer.from(res.body, 'base64')).toString())).deepEquals({ test: true });
});
});
8 changes: 3 additions & 5 deletions packages/lambda-tiler/src/routes/fonts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ export async function fontGet(req: LambdaHttpRequest<FontGet>): Promise<LambdaHt
try {
const filePath = fsa.join(assetLocation, path.join('fonts', req.params.fontStack, req.params.range)) + '.pbf';
const buf = await fsa.read(filePath);
const res = new LambdaHttpResponse(200, 'ok');
res.buffer(buf, 'application/x-protobuf');
return res;

return LambdaHttpResponse.ok().buffer(buf, 'application/x-protobuf');
} catch (e: any) {
if (e.code === 404) return NotFound;
throw e;
Expand Down Expand Up @@ -47,8 +46,7 @@ export async function fontList(): Promise<LambdaHttpResponse> {
const filePath = fsa.join(assetLocation, '/fonts');
const fonts = await getFonts(filePath);

const res = new LambdaHttpResponse(200, 'ok');
return res.buffer(JSON.stringify(fonts), 'application/json');
return LambdaHttpResponse.ok().buffer(JSON.stringify(fonts), 'application/json');
} catch (e: any) {
if (e.code === 404) return NotFound;
throw e;
Expand Down
17 changes: 15 additions & 2 deletions packages/lambda-tiler/src/routes/sprites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ const Extensions = new Map();
Extensions.set('.png', 'image/png');
Extensions.set('.json', 'application/json');

/**
* Does a buffer look like a gzipped document instead of raw json
*
* Determined by checking the first two bytes are the gzip magic bytes `0x1f 0x8b`
*
* @see https://en.wikipedia.org/wiki/Gzip
*
*/
function isGzip(b: Buffer): boolean {
return b[0] === 0x1f && b[1] === 0x8b;
}

export async function spriteGet(req: LambdaHttpRequest<SpriteGet>): Promise<LambdaHttpResponse> {
const spriteLocation = Env.get(Env.AssetLocation);
if (spriteLocation == null) return NotFound;
Expand All @@ -25,9 +37,10 @@ export async function spriteGet(req: LambdaHttpRequest<SpriteGet>): Promise<Lamb
try {
const filePath = fsa.join(spriteLocation, fsa.join('/sprites', req.params.spriteName));
req.set('target', filePath);

const buf = await fsa.read(filePath);
const res = new LambdaHttpResponse(200, 'ok');
res.buffer(buf, extension);
const res = LambdaHttpResponse.ok().buffer(buf, mimeType);
if (isGzip(buf)) res.header('content-encoding', 'gzip');
return res;
} catch (e: any) {
if (e.code === 404) return NotFound;
Expand Down

0 comments on commit 1014e1c

Please sign in to comment.