Skip to content

Commit

Permalink
Merge pull request #1069 from aligent/feature/DO-1484_enable_cache_fo…
Browse files Browse the repository at this point in the history
…r_redirects

Feature/do 1484 enable cache for redirects
  • Loading branch information
crispy101 authored Sep 22, 2023
2 parents b45e284 + c2008a3 commit 3adbbbc
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 15 deletions.
27 changes: 15 additions & 12 deletions packages/prerender-fargate/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# Prerender in Fargate
A construct to host [Prerender](https://github.com/prerender/prerender) in Fargate.

A construct to host [Prerender](https://github.com/prerender/prerender) in Fargate.

## Props
- `prerenderName`: Name of the Prerender service
- `domainName`: Domain name for Prerender
- `vpcId`: VPC to host Prerender in
- `bucketName`: Optional S3 bucket name
- `expirationDays`: Optional days until items expire in bucket (default to 7 days)
- `tokenList`: List of tokens to accept as authentication
- `certificateArn`: Certificate arn to match the domain
- `desiredInstanceCount`: Number of Prerender instances to run (default 1)
- `maxInstanceCount`: Maximum number of Prerender instances to run (default 2)
- `instanceCPU`: CPU to allocate to each instance (default 512)
- `instanceMemory`: Amount of memory to allocate to each instance (default 1024)

- `prerenderName`: Name of the Prerender service
- `domainName`: Domain name for Prerender
- `vpcId`: VPC to host Prerender in
- `bucketName`: Optional S3 bucket name
- `expirationDays`: Optional days until items expire in bucket (default to 7 days)
- `tokenList`: List of tokens to accept as authentication
- `certificateArn`: Certificate arn to match the domain
- `desiredInstanceCount`: Number of Prerender instances to run (default 1)
- `maxInstanceCount`: Maximum number of Prerender instances to run (default 2)
- `instanceCPU`: CPU to allocate to each instance (default 512)
- `instanceMemory`: Amount of memory to allocate to each instance (default 1024)
- `enableRedirectCache`: Cache 301 and 302 responses, too (default false)
2 changes: 2 additions & 0 deletions packages/prerender-fargate/lib/prerender-fargate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface PrerenderOptions {
maxInstanceCount?: number,
instanceCPU?: number,
instanceMemory?: number
enableRedirectCache?: string
}

export class PrerenderFargate extends Construct {
Expand Down Expand Up @@ -80,6 +81,7 @@ export class PrerenderFargate extends Construct {
AWS_ACCESS_KEY_ID: accessKey.accessKeyId,
AWS_SECRET_ACCESS_KEY: accessKey.secretAccessKey.toString(),
AWS_REGION: Stack.of(this).region,
ENABLE_REDIRECT_CACHE: props.enableRedirectCache || "false",
TOKEN_LIST: props.tokenList.toString()
}
},
Expand Down
100 changes: 97 additions & 3 deletions packages/prerender-fargate/lib/prerender/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,102 @@ server.use({
});

server.use(prerender.blacklist());
server.use(prerender.httpHeaders());
server.use(prerender.removeScriptTags());
server.use(s3Cache);

if (process.env.ENABLE_REDIRECT_CACHE.toLowerCase() === 'true'){
var he = require('he');
var s3 = new (require('aws-sdk')).S3({params:{Bucket: process.env.S3_BUCKET_NAME}});
server.use({
// The requestReceived and pageLoaded functions are a modified version of
// httpHeader plugin - https://github.com/prerender/prerender/blob/478fa6d0a5196ea29c88c69e64e72eb5507b6d2c/lib/plugins/httpHeaders.js combined with
// s3cache plugin - https://github.com/prerender/prerender-aws-s3-cache/blob/98707fa0f787de83aa41583682cd2c2d330a9cca/index.js
requestReceived: function(req, res, next) {
if(req.method !== 'GET' && req.method !== 'HEAD') {
return next();
}

var key = req.prerender.url;

if (process.env.S3_PREFIX_KEY) {
key = process.env.S3_PREFIX_KEY + '/' + key;
}

s3.getObject({
Key: key
}, function (err, result) {

if (!err && result) {
console.log("Found cached object: " + key);
if (result.Metadata.location){
res.setHeader('Location', result.Metadata.location);
}
// default 200 for legacy objects that do not have Metadata.httpreturncode defined
return res.send(result.Metadata.httpreturncode || 200, result.Body);
} else {
console.error(err);
}

next();
});
},

pageLoaded: function(req, res, next) {
const statusCodesToCache = ['200', '301', '302'];
var s3Metadata = {}

// Inspect prerender meta tags and update response accordingly
if (req.prerender.content && req.prerender.renderType == 'html') {
const statusMatchRegex = /<meta[^<>]*(?:name=['"]prerender-status-code['"][^<>]*content=['"]([0-9]{3})['"]|content=['"]([0-9]{3})['"][^<>]*name=['"]prerender-status-code['"])[^<>]*>/i;
const headerMatchRegex = /<meta[^<>]*(?:name=['"]prerender-header['"][^<>]*content=['"]([^'"]*?): ?([^'"]*?)['"]|content=['"]([^'"]*?): ?([^'"]*?)['"][^<>]*name=['"]prerender-header['"])[^<>]*>/gi
const head = req.prerender.content.toString().split('</head>', 1).pop()

const statusMatch = statusMatchRegex.exec(head)
if (statusMatch) {
req.prerender.statusCode = statusMatch[1] || statusMatch[2];
req.prerender.content = req.prerender.content.toString().replace(statusMatch[0], '');
}

let headerMatch = headerMatchRegex.exec(head)
while (headerMatch) {
s3Metadata.location = he.decode(headerMatch[2] || headerMatch[4]);
res.setHeader(headerMatch[1] || headerMatch[3], s3Metadata.location);
req.prerender.content = req.prerender.content.toString().replace(headerMatch[0], '');
headerMatch = headerMatchRegex.exec(head)
}

// Skip caching for the http response codes not in the list, such as 404
if ( ! statusCodesToCache.includes(req.prerender.statusCode.toString()) ) {
console.log(`StatusCode ${req.prerender.statusCode} for ${req.prerender.url} is not in the cachable code list. Returning without caching the result.`);
return res.send(req.prerender.statusCode, req.prerender.content);
}
}
s3Metadata.httpreturncode = req.prerender.statusCode.toString()

console.log(`Caching the object ${req.prerender.url} with statusCode ${req.prerender.statusCode}`);
var key = req.prerender.url;

if (process.env.S3_PREFIX_KEY) {
key = process.env.S3_PREFIX_KEY + '/' + key;
}

s3.putObject({
Key: key,
ContentType: 'text/html;charset=UTF-8',
StorageClass: 'REDUCED_REDUNDANCY',
Body: req.prerender.content,
Metadata: s3Metadata
}, function(err, result) {
console.log(result);
if (err) console.error(err);

next();
});
}
});
server.use(prerender.removeScriptTags());
} else {
server.use(prerender.httpHeaders());
server.use(prerender.removeScriptTags());
server.use(s3Cache);
}

server.start();

0 comments on commit 3adbbbc

Please sign in to comment.