@webscale-networks/cloudedge-handlers
Version:
Webscale Networks CloudEDGE Handlers for cloud-agnostic edge function execution
180 lines (170 loc) • 6.68 kB
JavaScript
;
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
const http = require('../../utils/src/headers.js');
// Parses the Lambda@Edge event and returns the event type, which will be
// 'origin-request' or 'origin-response'. If an event type cannot be found, null
// is returned.
exports.eventType = (awsEvent) => {
return _.get(awsEvent, 'Records[0].cf.config.eventType') || null;
};
// Generates an HTTP response with Webscale's default error page. Responses
// generated within a origin request function must not change the Content-Length
// header. Likewise, Transfer-Encoding and Via headers cannot be changed within
// a origin response function.
exports.defaultErrorResponse = (headers) => {
const content = fs.readFileSync(
path.resolve(
__dirname,
'../../error.html',
),
'utf8',
);
let response = {
body: content,
bodyEncoding: 'text',
status: '502',
};
let preservedHeaders = {};
// Transfer-Encoding and Via headers are not preserved by AWS, even if they
// generated response does not touch them.
if (_.get(headers,'transfer-encoding')) {
preservedHeaders['transfer-encoding'] = headers['transfer-encoding'];
}
if (_.get(headers, 'via')) {
preservedHeaders['via'] = headers['via'];
}
// Content-Length is generated by AWS.
preservedHeaders['content-type'] = [{
key: 'Content-Type',
value: 'text/html',
}];
response.headers = preservedHeaders;
return response;
};
// Generates an HTTP response with Webscale's default error page.
exports.defaultServerlessErrorResponse = () => {
const content = fs.readFileSync(
path.resolve(
__dirname,
'../../error.html',
),
'utf8',
);
const response = {
body: Buffer.from(content).toString('base64'),
bodyEncoding: 'base64',
status: '502',
headers: {
'content-type': ['text/html']
}
};
return response;
};
// Converts a Lambda@Edge configuration and request object into a Webscale
// request object.
exports.originToWebscaleRequest = (config, request) => {
const customHeaders = _.get(request, 'origin.custom.customHeaders');
const result = {
headers: new http.Headers(request.headers || {}),
method: request.method,
peerAddress: request.clientIp,
query: request.querystring,
path: request.uri,
originRequest: {
headers: new http.Headers(customHeaders || {}),
host: _.get(request, 'origin.custom.domainName'),
path: _.get(request, 'origin.custom.path'),
keepaliveTimeout: _.get(request, 'origin.custom.keepaliveTimeout'),
port: _.get(request, 'origin.custom.port'),
protocol: _.get(request, 'origin.custom.protocol'),
readTimeout: _.get(request, 'origin.custom.readTimeout'),
sslProtocols: _.get(request, 'origin.custom.sslProtocols'),
},
providerSpecific: {
authMethod: _.get(request, 'origin.custom.authMethod'),
distributionDomainName: config.distributionDomainName,
distributionId: config.distributionId,
region: _.get(request, 'origin.custom.region'),
requestId: config.requestId,
},
};
if (request.body) {
const body = {};
body['truncated'] = request.body.inputTruncated;
body['modified'] = false;
body['encoding'] = 'text';
// Request body is always base64-encoded.
body['data'] = Buffer.from(request.body.data, 'base64').toString();
result['body'] = body;
}
return result;
};
// Converts a Lambda@Edge response to a Webscale response. The origin-response
// event does not include the response body.
// For further reference, see:
// https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-generating-http-responses-in-requests.html#lambda-generating-http-responses-errors
// https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#response-event-fields
exports.originToWebscaleResponse = (config, response) => {
return {
body: {},
headers: new http.Headers(response.headers || {}),
statusCode: response.status,
providerSpecific: {
distributionDomainName: config.distributionDomainName,
distributionId: config.distributionId,
requestId: config.requestId,
},
};
};
// Converts a Webscale request to a Lambda@Edge request. Only attributes that
// are permitted to be updated are converted.
exports.webscaleToOriginRequest = (wRequest) => {
const request = {
headers: wRequest.headers ? wRequest.headers.toCloudProvider() : {},
querystring: wRequest.query,
clientIp: wRequest.peerAddress,
method: wRequest.method,
uri: wRequest.path,
body: {
action: wRequest.body.modified ? 'replace' : 'read-only',
encoding: wRequest.body.encoding,
data: wRequest.body.data,
inputTruncated: wRequest.body.truncated,
},
origin: {
custom: {
customHeaders: wRequest.originRequest.headers ?
wRequest.originRequest.headers.toCloudProvider() : {},
domainName: wRequest.originRequest.host,
path: wRequest.originRequest.path,
keepaliveTimeout: wRequest.originRequest.keepaliveTimeout,
port: wRequest.originRequest.port,
protocol: wRequest.originRequest.protocol,
readTimeout: wRequest.originRequest.readTimeout,
sslProtocols: wRequest.originRequest.sslProtocols,
}
}
};
if (wRequest.providerSpecific && wRequest.providerSpecific.authMethod) {
request.origin.custom.authMethod = wRequest.providerSpecific.authMethod;
}
if (wRequest.providerSpecific && wRequest.providerSpecific.region) {
request.origin.custom.region = wRequest.providerSpecific.region;
}
return request;
};
// Converts a Webscale response into a Lambda@Edge response that can be
// returned.
exports.webscaleToOriginResponse = (wResponse) => {
let response = {
status: wResponse.statusCode,
headers: wResponse.headers ? wResponse.headers.toCloudProvider() : {},
};
if (wResponse.body.data) {
response['body'] = wResponse.body.data;
response['bodyEncoding'] = wResponse.body.encoding;
}
return response;
};