Skip to content

Commit

Permalink
🏗✨ Use localhost:8000 template for all directory listings (#18718)
Browse files Browse the repository at this point in the history
  • Loading branch information
alanorozco committed Oct 15, 2018
1 parent 9a98709 commit 493ea5f
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 71 deletions.
92 changes: 81 additions & 11 deletions build-system/app-index/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,96 @@

const BBPromise = require('bluebird');
const fs = BBPromise.promisifyAll(require('fs'));
const {join, normalize, sep} = require('path');


// TODO(alanorozco): Use JSX once we're ready.
const templateFile = 'build-system/app-index/template.html';
const templateFile = join(__dirname, '/template.html');
const proxyFormFile = join(__dirname, '/proxy-form.html');
const listingHeaderFile = join(__dirname, '/listing-header.html');


function renderFileLink(base, location) {
return `<li><a href="${base}/${location}">${location}</a></li>`;
return `<li>
<a href="${base.replace(/\/$/, '')}/${location}">${location}</a>
</li>`;
}


function renderIndex(req, res) {
Promise.all([fs.readdirAsync('./examples/'), fs.readFileAsync(templateFile)])
.then(result => {
const files = result[0];
const template = result[1].toString();
function renderListing(basepath) {
// currently sitting on build-system/app-index, so we go back two dirs for the
// repo root.
const rootPath = join(__dirname, '../../');

res.end(template.replace('<!-- examples -->',
files.map(file => renderFileLink('/examples', file)).join('')));
});
// join / normalize from root dir
const path = normalize(join(rootPath, basepath));

// null byte(s), bad request
if (~path.indexOf('\0')) {
return Promise.resolve(null);
}

// malicious path
if ((path + sep).substr(0, rootPath.length) !== rootPath) {
return Promise.resolve(null);
}

return fs.statAsync(path).then(stat => {
if (!stat.isDirectory()) {
return null;
}

return Promise.all([
fs.readdirAsync(path),
fs.readFileAsync(templateFile),
]).then(result => {
const files = result[0];
const template = result[1].toString();
return template
.replace('<!-- basepath -->', basepath)
.replace('<!-- listing -->',
files.map(file => renderFileLink(basepath, file)).join(''));
});
}).catch(() => /* empty catch for fallbacks */ null);
}


function serveListingWithReplacements(
req, res, next, path, replacements = {}) {

Promise.all(
[renderListing(path)].concat(
Object.values(replacements).map(p =>
fs.readFileAsync(p)))).then(result => {
let output = result[0];

if (!output) {
next();
return;
}

let i = 1;
Object.keys(replacements).forEach(key => {
output = output.replace(key, result[i++]);
});

res.end(output);
});
}


function serveIndex(req, res, next) {
serveListingWithReplacements(req, res, next, '/examples', {
'<!-- bottom_of_header -->': proxyFormFile,
});
}

module.exports = renderIndex;

function serveListing(req, res, next) {
serveListingWithReplacements(req, res, next, req.url.replace(/^\/~/, '/'), {
'<!-- bottom_of_header -->': listingHeaderFile,
});
}


module.exports = {serveIndex, serveListing};
3 changes: 3 additions & 0 deletions build-system/app-index/listing-header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="block">
<a href="/">← Back to main</a>
</div>
47 changes: 47 additions & 0 deletions build-system/app-index/proxy-form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div class="block proxy-form-container">
<form id="proxy-form">
<label for="proxy-input">
<span>Load URL by Proxy</span>
<input type="url" class="text-input" id="proxy-input"
placeholder="https://">
</label>
<div class="form-info">
<a href="https://github.com/ampproject/amphtml/blob/master/contributing/TESTING.md#document-proxy">
What's this?
</a>
</div>
</form>
</div>
<script>
// TODO(alanorozco): Write this in ES2015 to be transpiled.
function getLocation(href) {
var l = document.createElement("a");
l.href = href;
return l;
}

function attachProxyFormListeners() {
var form = document.getElementById('proxy-form');
var input = document.getElementById('proxy-input');

form.addEventListener('submit', function (e) {
var location = getLocation(input.value);
var suffix =
location.host +
location.pathname +
location.search +
location.hash;
var redirectUrl = '/proxy/s/' + suffix;

e.preventDefault();

window.location = redirectUrl;
});
}

function attachListeners() {
attachProxyFormListeners();
}

attachListeners();
</script>
59 changes: 6 additions & 53 deletions build-system/app-index/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
display: block;
flex: 1;
}
.examples-bottom {
.file-list-container {
background: #f8f8f8;
}
h3 {
Expand Down Expand Up @@ -204,67 +204,20 @@ <h1 class="amp-logo">AMP</h1>
<li><a href="https://percy.io/ampproject/amphtml/">Percy</a></li>
</ul>
</header>
<div class="block proxy-form-contianer">
<form id="proxy-form">
<label for="proxy-input">
<span>Load URL by Proxy</span>
<input type="url" class="text-input" id="proxy-input"
placeholder="https://">
</label>
<div class="form-info">
<a href="https://github.com/ampproject/amphtml/blob/master/contributing/TESTING.md#document-proxy">
What's this?
</a>
</div>
</form>
</div>
<!-- bottom_of_header -->
</wrap>
<div class="examples-bottom">
<div class="file-list-container">
<wrap>
<h3 class="code">/examples/</h3>
<h3 class="code"><!-- basepath --></h3>
<div class="push-right-after-heading">
<!-- TODO(alanorozco): Enable once we figure out the issue with /~ -->
<!--a href="/~" class="underlined">List root directory</a-->
<a href="/~" class="underlined">List root directory</a>
</div>
<ul class="file-list"><!-- examples --></ul>
<ul class="file-list"><!-- listing --></ul>
</wrap>
</div>
<div class="center">
Built with 💙 by
<a href="https://ampproject.org" class="underlined">the AMP Project</a>.
</div>
<script>
// TODO(alanorozco): Write this in ES2015 to be transpiled.
function getLocation(href) {
var l = document.createElement("a");
l.href = href;
return l;
}

function attachProxyFormListeners() {
var form = document.getElementById('proxy-form');
var input = document.getElementById('proxy-input');

form.addEventListener('submit', function(e) {
var location = getLocation(input.value);
var suffix =
location.host +
location.pathname +
location.search +
location.hash;
var redirectUrl = '/proxy/s/' + suffix;

e.preventDefault();

window.location = redirectUrl;
});
}

function attachListeners() {
attachProxyFormListeners();
}

attachListeners();
</script>
</body>
</html>
13 changes: 6 additions & 7 deletions build-system/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const fs = BBPromise.promisifyAll(require('fs'));
const jsdom = require('jsdom');
const multer = require('multer');
const path = require('path');
const renderIndex = require('./app-index/index');
const request = require('request');
const {serveIndex, serveListing} = require('./app-index/index');
const pc = process;
const countries = require('../examples/countries.json');
const runVideoTestBench = require('./app-video-testbench');
Expand Down Expand Up @@ -62,12 +62,11 @@ app.get('/serve_mode=:mode', (req, res) => {
});

if (!global.AMP_TESTING) {
app.get('/', renderIndex);

// TODO(alanorozco): This doesn't quite work. Listing dirs is fine, but file
// links go to a /~ base path, which obviously 404's.
//
// app.use('/~', express.static('/'), serveIndex(`${__dirname}/../`));
app.get('/', serveIndex);
app.get([
'/~',
'/*',
], serveListing);
}


Expand Down

0 comments on commit 493ea5f

Please sign in to comment.