Skip to content

Commit 65798a1

Browse files
authored
Merge pull request #57 from Interlisp/fgh_fio
Implement files.interlisp.org server "on top of" online.interlisp.org web portal
2 parents b8ab277 + 36dbe9c commit 65798a1

File tree

9 files changed

+249
-12
lines changed

9 files changed

+249
-12
lines changed

system/oio-dev.service

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ ExecStart=/usr/bin/docker run \
1818
-v /var/run/docker.sock:/var/run/docker.sock \
1919
-v /srv/oio/development:/srv/oio \
2020
-v /srv/oio/static:/srv/static \
21+
-v /srv/oio/files/development:/srv/files \
2122
-v /etc/letsencrypt:/etc/letsencrypt \
2223
-e DEV_OR_PROD \
2324
-e NODE_ENV \

system/oio.service

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ ExecStart=/usr/bin/docker run \
1818
-v /var/run/docker.sock:/var/run/docker.sock \
1919
-v /srv/oio/production:/srv/oio \
2020
-v /srv/oio/static:/srv/static \
21+
-v /srv/oio/files/production:/srv/files \
2122
-v /etc/letsencrypt:/etc/letsencrypt \
2223
-e DEV_OR_PROD \
2324
-e NODE_ENV \

system/oio.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,18 @@ case $1 in
317317
fi
318318
;;
319319

320+
start)
321+
sudo systemctl start "${oio}".service
322+
;;
323+
324+
stop)
325+
sudo systemctl stop "${oio}".service
326+
;;
327+
328+
xstat)
329+
sudo systemctl status "${oio}".service
330+
;;
331+
320332
help)
321333
echo "Usage:"
322334
echo
@@ -354,6 +366,10 @@ case $1 in
354366
echo "${oio} noRm off: turn noDockerRm off"
355367
echo
356368
fi
369+
echo "${oio} start: start ${oio}.service"
370+
echo "${oio} stop: stop ${oio}.service"
371+
echo "${oio} xstat: = systemctl status ${oio}.service"
372+
echo
357373
;;
358374

359375
*)

web-portal/server/js/app.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,15 @@ const session = require("express-session");
2121
const passport = require('passport');
2222
//const favicon = require('serve-favicon')
2323

24-
// Set up express basics
24+
// Set up main app as well as the filesApp
25+
// And reroute queries with
2526
const app = express();
27+
const filesApp = require('./files');
28+
app.use((req, res, next) => {
29+
if(config.isFIO(req)) filesApp(req, res);
30+
else next();
31+
});
32+
2633
//app.use(favicon(path.join(config.imagesDir, 'favicon.ico')));
2734
app.use(express.json());
2835
app.use(express.urlencoded({ extended: true }));
@@ -37,11 +44,11 @@ logger.token('user', (req, res) => { return (req.user && req.user.username) || "
3744
logger.token('user-agent-short', (req, res) => { return (req.get('User-Agent') && req.get('User-Agent').split(' ', 1)[0]) || "Unknown"; });
3845
app.use(
3946
logger(
40-
':date[iso] :user :method :url :user-agent-short :status :response-time ms - :res[content-length]', {
47+
':date[iso] :user :method :url :user-agent-short :status :response-time ms - :res[content-length]', {
4148
stream: logStream,
4249
skip: (req, res) => {
4350
return !(/^\/interlisp/.test(req.originalUrl) || /^\/client\/go/.test(req.originalUrl) || /^\/main$/.test(req.originalUrl) || /^\/$/.test(req.originalUrl));
44-
}
51+
}
4552
}));
4653

4754
// Set up express session

web-portal/server/js/config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ var isNCO = function(req) {
148148
};
149149
exports.isNCO = isNCO;
150150

151+
var isFIO = function(req) {
152+
return (req.hostname.toLowerCase() == "files.interlisp.org");
153+
}
154+
exports.isFIO = isFIO;
155+
151156
var medleyMemoryArg = "64";
152157
exports.medleyMemoryArg = medleyMemoryArg;
153158

@@ -157,6 +162,9 @@ exports.medleyNetworkHostMode = medleyNetworkHostMode;
157162
var staticHostingPath = "/srv/static";
158163
exports.staticHostingPath = staticHostingPath;
159164

165+
var filesHostingPath = "/srv/files";
166+
exports.filesHostingPath = filesHostingPath;
167+
160168
var idleTimeoutSecs = 7200;
161169
var idleTimeoutSecsGuest = 3600;
162170
exports.idleTimeoutSecs = idleTimeoutSecs;

web-portal/server/js/files.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*******************************************************************************
2+
*
3+
* files.js: Sub-app to handle access to static files through
4+
* files.interlisp.org.
5+
*
6+
* 2024-07-07 Frank Halasz
7+
*
8+
*
9+
* Copyright: 2024 by Interlisp.org
10+
*
11+
*
12+
******************************************************************************/
13+
const mFs = require('fs');
14+
const mPath = require('node:path');
15+
const mExpress = require("express");
16+
17+
const config = require("./config");
18+
const { isText, isBinary, getEncoding } = require('istextorbinary');
19+
20+
const filesApp = mExpress();
21+
22+
// Define function to set content type headers for files with no
23+
// extension. Use isBinary to distinguish octet-stream versus
24+
// text content types.
25+
// Used by mExpress.static
26+
function setContentType(res, path, stat) {
27+
const ext = mPath.extname(path);
28+
if(ext.length == 0) {
29+
const buffer = mFs.readFileSync(path);
30+
const name = mPath.basename(path);
31+
if(isInterlispSource(buffer, name)) {
32+
res.set('Content-Type', 'application/octet-stream');
33+
} else if (isText(null, buffer)) {
34+
res.set('Content-Type', 'text/plain; charset=UTF-8');
35+
res.set('X-Content-Type-Options', 'nosniff');
36+
} else {
37+
res.set('Content-Type', 'application/octet-stream');
38+
}
39+
} else {
40+
switch(ext) {
41+
case '.awk':
42+
case '.cmd':
43+
case '.command':
44+
case '.dribble':
45+
case '.iss':
46+
case '.lisp':
47+
case '.ps1':
48+
case '.sh':
49+
case '.tty':
50+
case '.sh':
51+
case '.yaml':
52+
case '.yml':
53+
res.set('Content-Type', 'text/plain; charset=UTF-8');
54+
break;
55+
}
56+
}
57+
}
58+
59+
// Does buffer contain an Interlisp source file?
60+
function isInterlispSource(buffer, name) {
61+
return (
62+
buffer.includes("(DEFINE-FILE-INFO")
63+
&& buffer.includes(name + "COMS")
64+
);
65+
66+
}
67+
68+
69+
filesApp.use((req, res, next) => {
70+
if(req.protocol === 'https' || !config.supportHttps) next();
71+
else res.redirect(`https://${req.hostname}:${config.httpsRedirectPort}${req.url}`);
72+
});
73+
74+
const staticOptions = {
75+
dotfiles: "allow",
76+
index: "index.html",
77+
setHeaders: setContentType
78+
};
79+
80+
filesApp.use(mExpress.static(config.filesHostingPath, staticOptions));
81+
82+
// can't find file - send error message
83+
filesApp.use((req, res, next) => {
84+
if(req.url == "/favicon.ico") {
85+
res.status(404);
86+
res.end();
87+
} else {
88+
res.status(404);
89+
res.send("<!DOCTYPE html><html><body><h3>ERROR: Cannot find file: " + req.originalUrl + "</h3></body></html>");
90+
}
91+
});
92+
93+
94+
module.exports = filesApp;

web-portal/server/js/server.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
#!/usr/bin/env node
22
/*******************************************************************************
3-
*
4-
* server.js: Start up http(s) server(s) for online.interlisp.org web portal.
3+
*
4+
* server.js: Start up http(s) server(s) for online.interlisp.org web portal.
55
* This is the module that starts up the whole portal by loading
66
* the express app (app.js) and initiating the server listens.
77
* Called by something like "node ./server.js".
8-
*
8+
*
99
* 2021-11-18 Frank Halasz
10-
*
11-
*
12-
* Copyright: 2021-2022 by Interlisp.org
13-
*
10+
*
11+
*
12+
* Copyright: 2021-2024 by Interlisp.org
13+
*
1414
*
1515
******************************************************************************/
1616
var config = require('./config');
@@ -36,9 +36,9 @@ if(config.supportHttps) {
3636
/**
3737
* Create HTTP & HTTPS server.
3838
*/
39-
39+
4040
if(config.supportHttps) {
41-
var sslOpts =
41+
var sslOpts =
4242
{
4343
key: fs.readFileSync(config.tlsKeyPath),
4444
cert: fs.readFileSync(config.tlsCertPath),

0 commit comments

Comments
 (0)