UNPKG

@webscale-networks/cloudedge-handlers

Version:

Webscale Networks CloudEDGE Handlers for cloud-agnostic edge function execution

180 lines (170 loc) 6.68 kB
'use strict'; 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; };