[now dev] Add etag response header for Lambda invocations (#2502)

This matches the behavior in production.
This commit is contained in:
Nathan Rajlich
2019-07-07 06:19:54 -07:00
committed by Leo Lamprecht
parent 2414767026
commit f80f1f79a6
6 changed files with 14 additions and 8 deletions

View File

@@ -1,7 +1,6 @@
import chalk from 'chalk'; import chalk from 'chalk';
import execa from 'execa'; import execa from 'execa';
import npa from 'npm-package-arg'; import npa from 'npm-package-arg';
import { createHash } from 'crypto';
import { join, resolve } from 'path'; import { join, resolve } from 'path';
import { funCacheDir } from '@zeit/fun'; import { funCacheDir } from '@zeit/fun';
import cacheDirectory from 'cache-or-tmp-directory'; import cacheDirectory from 'cache-or-tmp-directory';
@@ -12,6 +11,7 @@ import {
BuilderCacheCleanError BuilderCacheCleanError
} from '../errors-ts'; } from '../errors-ts';
import wait from '../output/wait'; import wait from '../output/wait';
import { getSha } from '../sha';
import { Output } from '../output'; import { Output } from '../output';
import * as staticBuilder from './static-builder'; import * as staticBuilder from './static-builder';
@@ -215,9 +215,3 @@ function getPackageName(
} }
return null; return null;
} }
function getSha(buffer: Buffer): string {
const hash = createHash('sha256');
hash.update(buffer);
return hash.digest('hex');
}

View File

@@ -11,6 +11,7 @@ import chalk from 'chalk';
import which from 'which'; import which from 'which';
import ora, { Ora } from 'ora'; import ora, { Ora } from 'ora';
import { getSha } from '../sha';
import { Output } from '../output'; import { Output } from '../output';
import { relative } from '../path-helpers'; import { relative } from '../path-helpers';
import { LambdaSizeExceededError } from '../errors-ts'; import { LambdaSizeExceededError } from '../errors-ts';
@@ -354,6 +355,7 @@ export async function executeBuild(
} }
} }
}); });
asset.sha = getSha(asset.zipBuffer, 'sha1');
} }
match.buildTimestamp = Date.now(); match.buildTimestamp = Date.now();

View File

@@ -839,7 +839,7 @@ export default class DevServer {
return; return;
case 'Lambda': case 'Lambda':
if (!asset.fn) { if (!asset.fn || !asset.sha) {
// This is mostly to appease TypeScript since `fn` is an optional prop, // This is mostly to appease TypeScript since `fn` is an optional prop,
// but this shouldn't really ever happen since we run the builds before // but this shouldn't really ever happen since we run the builds before
// responding to HTTP requests. // responding to HTTP requests.
@@ -894,6 +894,7 @@ export default class DevServer {
res.statusCode = result.statusCode; res.statusCode = result.statusCode;
this.setResponseHeaders(res, nowRequestId, result.headers); this.setResponseHeaders(res, nowRequestId, result.headers);
res.setHeader('etag', `W/"${asset.sha}"`);
let resBody: Buffer | string | undefined; let resBody: Buffer | string | undefined;
if (result.encoding === 'base64' && typeof result.body === 'string') { if (result.encoding === 'base64' && typeof result.body === 'string') {

View File

@@ -59,6 +59,7 @@ export interface BuilderInputs {
export type BuiltLambda = Lambda & { export type BuiltLambda = Lambda & {
fn?: FunLambda; fn?: FunLambda;
sha?: string;
}; };
export type BuilderOutput = BuiltLambda | FileFsRef | FileBlob; export type BuilderOutput = BuiltLambda | FileFsRef | FileBlob;

7
src/util/sha.ts Normal file
View File

@@ -0,0 +1,7 @@
import { createHash } from 'crypto';
export function getSha(buffer: Buffer, cypher: string = 'sha256'): string {
const hash = createHash(cypher);
hash.update(buffer);
return hash.digest('hex');
}

View File

@@ -44,6 +44,7 @@ function testFixture(name, fn) {
function validateResponseHeaders(t, res) { function validateResponseHeaders(t, res) {
t.is(res.headers.get('cache-control'), 'public, max-age=0, must-revalidate'); t.is(res.headers.get('cache-control'), 'public, max-age=0, must-revalidate');
t.is(res.headers.get('x-now-trace'), 'dev1'); t.is(res.headers.get('x-now-trace'), 'dev1');
t.truthy(/^W\/"[0-9a-f]{40}"$/.test(res.headers.get('etag')));
t.truthy( t.truthy(
/^dev1:[0-9a-z]{5}-[1-9][0-9]+-[a-f0-9]{12}$/.test( /^dev1:[0-9a-z]{5}-[1-9][0-9]+-[a-f0-9]{12}$/.test(
res.headers.get('x-now-id') res.headers.get('x-now-id')