Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions src/phoenix/virtualServer/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ if(!self.Config){
*
* `debug`: if present (i.e., `Boolean`), enable workbox debug logging
*/
const url = new URL(location);

/**
* Given a route string, make sure it follows the pattern we expect:
Expand All @@ -47,7 +46,7 @@ if(!self.Config){
* @param {String} route
*/
function getNormalizeRoute() {
let route = url.searchParams.get('route') || 'fs';
let route = (new URL(location)).searchParams.get('route') || 'fs';

// Only a single / at the front of the route
route = route.replace(/^\/*/, '');
Expand All @@ -59,7 +58,7 @@ if(!self.Config){

self.Config = {
route: getNormalizeRoute(),
disableIndexes: url.searchParams.get('disableIndexes') !== null,
disableIndexes: (new URL(location)).searchParams.get('disableIndexes') !== null,
debug: false // this is set via sw messages from phoenix
};
}
62 changes: 32 additions & 30 deletions src/phoenix/virtualServer/content-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,48 @@
*
*/

/* global lookup, importScripts*/
/* global mime, importScripts*/

importScripts('phoenix/virtualServer/mime-types.js');

if(!self.ContentType){
function getMimeType(path) {
return lookup(path) || 'application/octet-stream';
}

// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#Audio_and_video_types
function isMedia(path) {
let mimeType = lookup(path);
if (!mimeType) {
return false;
(function () {
function getMimeType(path) {
return mime.lookup(path) || 'application/octet-stream';
}

mimeType = mimeType.toLowerCase();
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#Audio_and_video_types
function isMedia(path) {
let mimeType = mime.lookup(path);
if (!mimeType) {
return false;
}

// Deal with OGG special case
if (mimeType === 'application/ogg') {
return true;
}
mimeType = mimeType.toLowerCase();

// Anything else with `audio/*` or `video/*` is "media"
return mimeType.startsWith('audio/') || mimeType.startsWith('video/');
}
// Deal with OGG special case
if (mimeType === 'application/ogg') {
return true;
}

// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#Image_types
function isImage(path) {
const mimeType = lookup(path);
if (!mimeType) {
return false;
// Anything else with `audio/*` or `video/*` is "media"
return mimeType.startsWith('audio/') || mimeType.startsWith('video/');
}

return mimeType.toLowerCase().startsWith('image/');
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#Image_types
function isImage(path) {
const mimeType = mime.lookup(path);
if (!mimeType) {
return false;
}

return mimeType.toLowerCase().startsWith('image/');
}

self.ContentType = {
isMedia,
isImage,
getMimeType
};
self.ContentType = {
isMedia,
isImage,
getMimeType
};
}());
}
236 changes: 119 additions & 117 deletions src/phoenix/virtualServer/html-formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,45 @@ importScripts('phoenix/virtualServer/content-type.js');
importScripts('phoenix/virtualServer/icons.js');

if(!self.HtmlFormatter){
// 20-Apr-2004 17:14
const formatDate = d => {
const day = d.getDate();
const month = d.toLocaleString('en-us', {month: 'short'});
const year = d.getFullYear();
const hours = d.getHours();
const mins = d.getMinutes();
return `${day}-${month}-${year} ${hours}:${mins}`;
};

const formatSize = s => {
const units = ['', 'K', 'M'];
if (!s) {
return '-';
}
const i = Math.floor(Math.log(s) / Math.log(1024));
return Math.round(s / Math.pow(1024, i), 2) + units[i];
};

const formatRow = (
icon,
alt = '[ ]',
href,
name,
modified,
size
) => `<tr><td valign='top'><img src='${icon || icons.unknown}' alt='${alt}'></td><td>
(function () {
// 20-Apr-2004 17:14
const formatDate = d => {
const day = d.getDate();
const month = d.toLocaleString('en-us', {month: 'short'});
const year = d.getFullYear();
const hours = d.getHours();
const mins = d.getMinutes();
return `${day}-${month}-${year} ${hours}:${mins}`;
};

const formatSize = s => {
const units = ['', 'K', 'M'];
if (!s) {
return '-';
}
const i = Math.floor(Math.log(s) / Math.log(1024));
return Math.round(s / Math.pow(1024, i), 2) + units[i];
};

const formatRow = (
icon,
alt = '[ ]',
href,
name,
modified,
size
) => `<tr><td valign='top'><img src='${icon || icons.unknown}' alt='${alt}'></td><td>
<a href='${href}'>${name}</a></td>
<td align='right'>${formatDate(new Date(modified))}</td>
<td align='right'>${formatSize(size)}</td><td>&nbsp;</td></tr>`;

const footerClose = '<address>nohost (Web Browser Server)</address></body></html>';
const footerClose = '<address>nohost (Web Browser Server)</address></body></html>';

/**
* Send an Apache-style 404
*/
function format404(url) {
const body = `
/**
* Send an Apache-style 404
*/
function format404(url) {
const body = `
<!DOCTYPE html>
<html><head>
<title>404 Not Found</title>
Expand All @@ -69,21 +70,21 @@ if(!self.HtmlFormatter){
<p>The requested URL ${url} was not found on this server.</p>
<hr>${footerClose}`;

return {
body,
config: {
status: 404,
statusText: 'Not Found',
headers: {'Content-Type': 'text/html'}
}
};
}
return {
body,
config: {
status: 404,
statusText: 'Not Found',
headers: {'Content-Type': 'text/html'}
}
};
}

/**
* Send an Apache-style 500
*/
function format500(path, err) {
const body = `
/**
* Send an Apache-style 500
*/
function format500(path, err) {
const body = `
<!DOCTYPE html>
<html><head>
<title>500 Internal Server Error</title>
Expand All @@ -93,24 +94,24 @@ if(!self.HtmlFormatter){
<p>The error was: ${err.message}.</p>
<hr>${footerClose}`;

return {
body,
config: {
status: 500,
statusText: 'Internal Error',
headers: {'Content-Type': 'text/html'}
}
};
}

/**
* Send an Apache-style directory listing
*/
function formatDir(route, dirPath, entries) {
const parent = self.path.dirname(dirPath) || '/';
// Maintain path sep, but deal with things like spaces in filenames
const url = encodeURI(route + parent);
const header = `
return {
body,
config: {
status: 500,
statusText: 'Internal Error',
headers: {'Content-Type': 'text/html'}
}
};
}

/**
* Send an Apache-style directory listing
*/
function formatDir(route, dirPath, entries) {
const parent = self.path.dirname(dirPath) || '/';
// Maintain path sep, but deal with things like spaces in filenames
const url = encodeURI(route + parent);
const header = `
<!DOCTYPE html>
<html><head><title>Index of ${dirPath}</title></head>
<body><h1>Index of ${dirPath}</h1>
Expand All @@ -121,59 +122,60 @@ if(!self.HtmlFormatter){
<tr><td valign='top'><img src='${icons.back}' alt='[DIR]'></td>
<td><a href='${url}'>Parent Directory</a></td><td>&nbsp;</td>
<td align='right'> - </td><td>&nbsp;</td></tr>`;
const footer = `<tr><th colspan='5'><hr></th></tr></table>${footerClose}`;

const rows = entries.map(entry => {
let entryName = entry.name || entry;
const ext = self.path.extname(entryName);
// Maintain path sep, but deal with things like spaces in filenames
const href = encodeURI(`${route}${self.path.join(dirPath, entryName)}`);
let icon;
let alt;

// TODO: switch this to entry.isDirectory() if possible
if (ContentType.isImage(ext)) {
icon = icons.image2;
alt = '[IMG]';
} else if (ContentType.isMedia(ext)) {
icon = icons.movie;
alt = '[MOV]';
} else if (!ext) {
icon = icons.folder;
alt = '[DIR]';
} else {
icon = icons.text;
alt = '[TXT]';
}
const footer = `<tr><th colspan='5'><hr></th></tr></table>${footerClose}`;

const rows = entries.map(entry => {
let entryName = entry.name || entry;
const ext = self.path.extname(entryName);
// Maintain path sep, but deal with things like spaces in filenames
const href = encodeURI(`${route}${self.path.join(dirPath, entryName)}`);
let icon;
let alt;

// TODO: switch this to entry.isDirectory() if possible
if (ContentType.isImage(ext)) {
icon = icons.image2;
alt = '[IMG]';
} else if (ContentType.isMedia(ext)) {
icon = icons.movie;
alt = '[MOV]';
} else if (!ext) {
icon = icons.folder;
alt = '[DIR]';
} else {
icon = icons.text;
alt = '[TXT]';
}

return formatRow(icon, alt, href, entryName, entry.mtime, entry.size);
}).join('\n');

return {
body: header + rows + footer,
config: {
status: 200,
statusText: 'OK',
headers: {'Content-Type': 'text/html'}
}
};
}

return formatRow(icon, alt, href, entryName, entry.mtime, entry.size);
}).join('\n');
function formatFile(path, content) {
return {
body: content,
config: {
status: 200,
statusText: 'OK',
headers: {'Content-Type': ContentType.getMimeType(path)}
}
};
}

return {
body: header + rows + footer,
config: {
status: 200,
statusText: 'OK',
headers: {'Content-Type': 'text/html'}
}
};
}

function formatFile(path, content) {
return {
body: content,
config: {
status: 200,
statusText: 'OK',
headers: {'Content-Type': ContentType.getMimeType(path)}
}
self.HtmlFormatter = {
format404,
format500,
formatDir,
formatFile
};
}

self.HtmlFormatter = {
format404,
format500,
formatDir,
formatFile
};
}());
}
Loading