diff --git a/lib/browserid/views.js b/lib/browserid/views.js index a11af5abd05cffe8bd4e670304acc047cd99a3fa..c124cea8ee8553b249f891bad322573f02d1e539 100644 --- a/lib/browserid/views.js +++ b/lib/browserid/views.js @@ -5,16 +5,40 @@ const metrics = require('../metrics.js'), url = require('url'), -logger = require('../logging.js').logger; +logger = require('../logging.js').logger, +fs = require('fs'), +connect = require('connect'); // all templated content, redirects, and renames are handled here. // anything that is not an api, and not static - const path = require('path'); + +const VIEW_PATH = path.join(__dirname, "..", "..", "resources", "views"); + +// none of our views include dynamic data. all of them should be served +// with reasonable cache headers. This wrapper around rendering handles +// cache headers maximally leveraging the same logic that connect uses +// issue #910 +function renderCachableView(req, res, template, options) { + fs.stat(path.join(VIEW_PATH, template), function (err, stat) { + res.setHeader('Date', new Date().toUTCString()); + // res.setHeader('Cache-Control', 'public, max-age=' + (maxAge / 1000)); + res.setHeader('Last-Modified', stat.mtime.toUTCString()); + res.setHeader('ETag', connect.utils.etag(stat)); + res.setHeader('Content-Type', 'text/html; charset=utf8'); + if (connect.utils.conditionalGET(req)) { + if (!connect.utils.modified(req, res)) { + return connect.utils.notModified(res); + } + } + res.render(template, options); + }); +} + exports.setup = function(app) { - app.set("views", path.join(__dirname, "..", "..", "resources", "views")); + app.set("views", VIEW_PATH); app.set('view options', { production: config.get('use_minified_resources') @@ -24,7 +48,7 @@ exports.setup = function(app) { // as soon as relative paths are figured out. app.get('/sign_in', function(req, res, next ) { metrics.userEntry(req); - res.render('dialog.ejs', { + renderCachableView(req, res, 'dialog.ejs', { title: 'A Better Way to Sign In', layout: 'dialog_layout.ejs', useJavascript: true, @@ -34,71 +58,73 @@ exports.setup = function(app) { app.get('/communication_iframe', function(req, res, next ) { res.removeHeader('x-frame-options'); - res.render('communication_iframe.ejs', { + renderCachableView(req, res, 'communication_iframe.ejs', { layout: false, production: config.get('use_minified_resources') }); }); app.get("/unsupported_dialog", function(req,res) { - res.render('unsupported_dialog.ejs', {layout: 'dialog_layout.ejs', useJavascript: false}); + renderCachableView(req, res, 'unsupported_dialog.ejs', {layout: 'dialog_layout.ejs', useJavascript: false}); }); // Used for a relay page for communication. - app.get("/relay", function(req,res, next) { + app.get("/relay", function(req, res, next) { // Allow the relay to be run within a frame res.removeHeader('x-frame-options'); - res.render('relay.ejs', { + renderCachableView(req, res, 'relay.ejs', { layout: false, production: config.get('use_minified_resources') }); }); app.get("/authenticate_with_primary", function(req,res, next) { - res.render('authenticate_with_primary.ejs', { layout: false }); + renderCachableView(req, res, 'authenticate_with_primary.ejs', { layout: false }); }); app.get('/', function(req,res) { - res.render('index.ejs', {title: 'A Better Way to Sign In', fullpage: true}); + renderCachableView(req, res, 'index.ejs', {title: 'A Better Way to Sign In', fullpage: true}); }); app.get("/signup", function(req, res) { - res.render('signup.ejs', {title: 'Sign Up', fullpage: false}); + renderCachableView(req, res, 'signup.ejs', {title: 'Sign Up', fullpage: false}); }); app.get("/idp_auth_complete", function(req, res) { - res.render('idp_auth_complete.ejs', { + renderCachableView(req, res, 'idp_auth_complete.ejs', { title: 'Sign In Complete', fullpage: false }); }); app.get("/forgot", function(req, res) { + // !cachable! email embedded in DOM res.render('forgot.ejs', {title: 'Forgot Password', fullpage: false, email: req.query.email}); }); app.get("/signin", function(req, res) { - res.render('signin.ejs', {title: 'Sign In', fullpage: false}); + renderCachableView(req, res, 'signin.ejs', {title: 'Sign In', fullpage: false}); }); app.get("/about", function(req, res) { - res.render('about.ejs', {title: 'About', fullpage: false}); + renderCachableView(req, res, 'about.ejs', {title: 'About', fullpage: false}); }); app.get("/tos", function(req, res) { - res.render('tos.ejs', {title: 'Terms of Service', fullpage: false}); + renderCachableView(req, res, 'tos.ejs', {title: 'Terms of Service', fullpage: false}); }); app.get("/privacy", function(req, res) { - res.render('privacy.ejs', {title: 'Privacy Policy', fullpage: false}); + renderCachableView(req, res, 'privacy.ejs', {title: 'Privacy Policy', fullpage: false}); }); app.get("/verify_email_address", function(req, res) { + // !cachable! token is embedded in DOM res.render('verify_email_address.ejs', {title: 'Complete Registration', fullpage: true, token: req.query.token}); }); app.get("/add_email_address", function(req,res) { - res.render('add_email_address.ejs', {title: 'Verify Email Address', fullpage: false}); + renderCachableView(req, res, 'add_email_address.ejs', {title: 'Verify Email Address', fullpage: false}); }); // REDIRECTS