Separate server and site functionality (site is after host has been identified)
authorNick Downing <downing.nick@gmail.com>
Mon, 8 Oct 2018 06:59:48 +0000 (17:59 +1100)
committerNick Downing <downing.nick@gmail.com>
Mon, 8 Oct 2018 07:23:07 +0000 (18:23 +1100)
ndserver.js
server.js [new file with mode: 0644]
site.js

index 82eb733..2dbd737 100755 (executable)
@@ -4,7 +4,7 @@ let commander = require('commander')
 let fs = require('fs')
 let http = require('http')
 let https = require('https')
-let site = require('./site')
+let server = require('./server')
 
 commander.version('1.0.0').option(
   '-c, --enable-caching',
@@ -27,9 +27,10 @@ commander.version('1.0.0').option(
   8443
 ).parse(process.argv)
 
+server.set_caching(commander.enableCaching)
 if (commander.httpPort !== -1) {
   http.createServer(
-    (req, res) => site.tryApp(req, res, 'http') // ignore returned promise
+    (req, res) => server.app(req, res, 'http') // ignore returned promise
   ).listen(commander.httpPort)
   console.log('HTTP server listening on port', commander.httpPort)
 }
@@ -39,7 +40,7 @@ if (commander.httpsPort !== -1) {
       'cert': fs.readFileSync(commander.sslCert),
       'key': fs.readFileSync(commander.sslKey)
     },
-    (req, res) => site.tryApp(req, res, 'https') // ignore returned promise
+    (req, res) => server.app(req, res, 'https') // ignore returned promise
   ).listen(commander.httpsPort)
   console.log('HTTPS server listening on port', commander.httpsPort)
 }
diff --git a/server.js b/server.js
new file mode 100644 (file)
index 0000000..14d30ef
--- /dev/null
+++ b/server.js
@@ -0,0 +1,74 @@
+let assert = require('assert')
+let config = require('./config')
+let site = require('./site')
+
+let caching = false
+let set_caching = value => {
+  caching = value
+}
+
+let serve = (res, status, mime_type, data) => {
+  res.statusCode = status
+  // html files will be direct recipient of links/bookmarks so can't have
+  // a long lifetime, other files like css or images are often large files
+  // and won't change frequently (but we'll need cache busting eventually)
+  if (caching && mime_type !== config.mime_types_html)
+    res.setHeader('Cache-Control', 'max-age=3600')
+  res.setHeader('Content-Type', mime_type)
+  res.setHeader('Content-Length', data.length)
+  res.end(data)
+}
+
+let die = res => {
+  let body = '<html><body>Page not found</body></html>'
+  serve(res, 404, config.mime_type_html, new Buffer(body, 'utf8'))
+}
+
+let redirect = (res, location) => {
+  res.statusCode = 301
+  res.setHeader('Location', location)
+  res.end('Redirecting to ' + location)
+}
+
+let app = async (req, res, protocol) => {
+  await config.refresh()
+  try {
+    let domain_name = req.headers.host || 'localhost'
+    let temp = domain_name.indexOf(':')
+    let port_suffix = temp === -1 ? '' : domain_name.substring(temp)
+    domain_name = domain_name.substring(
+      0,
+      domain_name.length - port_suffix.length
+    )
+    if (!config.sites.hasOwnProperty(domain_name)) {
+      console.log('nonexistent site', domain_name)
+      die(res)
+      return
+    }
+    temp = config.sites[domain_name]
+    switch (temp.type) {
+    case 'redirect':
+      let new_domain = temp.domain
+      console.log('redirecting', domain_name, 'to', new_domain)
+      redirect(res, protocol + '://' + new_domain + port_suffix + req.url)
+      break
+    case 'site':
+      await site.app(domain_name, temp.root, req, res, protocol)
+      break
+    default:
+      assert(false)
+    }
+  }
+  catch (err) {
+    let message = (err.stack || err.message).toString()
+    console.error(message)
+    let body = '<html><body><pre>' + message + '</pre></body></html>'
+    serve(res, 500, config.mime_type_html, new Buffer(body, 'utf8'))
+  }
+}
+
+exports.set_caching = set_caching
+exports.serve = serve
+exports.die = die
+exports.redirect = redirect
+exports.app = app
diff --git a/site.js b/site.js
index 8db0246..a16e46b 100644 (file)
--- a/site.js
+++ b/site.js
@@ -5,6 +5,7 @@ let crypto = require('crypto')
 let fs = require('fs')
 let config = require('./config')
 let resources = require('./resources')
+let server = require('./server')
 let util = require('util')
 let url = require('url')
 let XDate = require('xdate')
@@ -12,63 +13,17 @@ let XDate = require('xdate')
 let fs_readFile = util.promisify(fs.readFile)
 let fs_stat = util.promisify(fs.stat)
 
-let serve = (res, status, mime_type, data) => {
-  res.statusCode = status
-  // html files will be direct recipient of links/bookmarks so can't have
-  // a long lifetime, other files like css or images are often large files
-  // and won't change frequently (but we'll need cache busting eventually)
-  if (
-    false && //commander.enableCaching &&
-    mime_type !== config.mime_types_html
-  )
-    res.setHeader('Cache-Control', 'max-age=3600')
-  res.setHeader('Content-Type', mime_type)
-  res.setHeader('Content-Length', data.length)
-  res.end(data)
-}
-
-let die = res => {
-  let body = '<html><body>Page not found</body></html>'
-  serve(res, 404, config.mime_type_html, new Buffer(body, 'utf8'))
-}
-
-let redirect = (res, location) => {
-  res.statusCode = 301
-  res.setHeader('Location', location)
-  res.end('Redirecting to ' + location)
-}
-
-let app = async (req, res, protocol) => {
-  let site = req.headers.host || 'localhost'
-  let temp = site.indexOf(':')
-  let port_suffix = temp === -1 ? '' : site.substring(temp)
-  site = site.substring(0, site.length - port_suffix.length)
-  if (!config.sites.hasOwnProperty(site)) {
-    console.log('nonexistent site', site)
-    die(res)
-    return
-  }
-  temp = config.sites[site]
-  let site_root
-  if (temp.type === 'redirect') {
-    let site_domain = temp.domain
-    console.log('redirecting', site, 'to', site_domain)
-    redirect(res, protocol + '://' + site_domain + port_suffix + req.url)
-    return
-  }
-  else if (temp.type === 'site')
-    site_root = temp.root
-  else
-    assert(false)
-
+let app = async (site, site_root, req, res, protocol) => {
   // parse the pathname portion of url
   // this is actually cheating since it's not a complete url
   let parsed_url = url.parse(req.url, true)
   let path = parsed_url.pathname.split('/')
 
   // path must begin with /
-  if (path.length === 0 || path[0].length)
-    return die(res)
+  if (path.length === 0 || path[0].length) {
+    server.die(res)
+    return
+  }
 
   // path elements must be findable in the file system (thus can't be empty)
   let dir_name = ''
@@ -77,7 +32,8 @@ let app = async (req, res, protocol) => {
     dir_name += '/' + path[i]
     if (path[i].length === 0 || path[i].charAt(0) === '.') {
       console.log(site, 'bad path component', dir_name)
-      return die(res)
+      server.die(res)
+      return
     }
     let stats
     try {
@@ -97,12 +53,14 @@ let app = async (req, res, protocol) => {
           if (err2.code !== 'ENOENT')
             throw err2
           console.log(site, 'directory not found', dir_name)
-          return die(res)
+          server.die(res)
+          return
         }
       }
       if (!stats.isDirectory()) {
         console.log(site, 'not directory', dir_name)
-        return die(res)
+        server.die(res)
+        return
       }
     }
   }
@@ -111,8 +69,8 @@ let app = async (req, res, protocol) => {
   if (file_name === '') {
     path[path.length - 1] = 'index.html'
     path = path.join('/')
-    console.log(site, 'redirecting', parsed_url.pathname, 'to', path)
-    redirect(res, path + (parsed_url.search || ''))
+    console.log(site, 'server.redirecting', parsed_url.pathname, 'to', path)
+    server.redirect(res, path + (parsed_url.search || ''))
     return
   }
   let page = path.slice(1).join('/')
@@ -181,7 +139,7 @@ let app = async (req, res, protocol) => {
         data.length,
         'from pub'
       )
-      serve(res, 200, mime_type, data)
+      server.serve(res, 200, mime_type, data)
       return
     }
     catch (err) {
@@ -201,7 +159,7 @@ let app = async (req, res, protocol) => {
         data.length,
         'from pub'
       )
-      serve(res, 200, mime_type, data)
+      server.serve(res, 200, mime_type, data)
       return
     }
     catch (err) {
@@ -259,7 +217,7 @@ let app = async (req, res, protocol) => {
           data.length,
           'from js'
         )
-        serve(res, 200, mime_type, data)
+        server.serve(res, 200, mime_type, data)
         return
       }
       catch (err) {
@@ -280,7 +238,7 @@ let app = async (req, res, protocol) => {
           data.length,
           'from less'
         )
-        serve(res, 200, mime_type, data)
+        server.serve(res, 200, mime_type, data)
         return
       }
       catch (err) {
@@ -303,29 +261,12 @@ let app = async (req, res, protocol) => {
       data.length,
       'from favicons'
     )
-    serve(res, 200, mime_type, data)
+    server.serve(res, 200, mime_type, data)
     return
   }
 
   console.log(site, 'file not found', page)
-  return die(res)
-}
-
-let tryApp = async (req, res, protocol) => {
-  await config.refresh()
-  try {
-    await app(req, res, protocol)
-  }
-  catch (err) {
-    let message = (err.stack || err.message).toString()
-    console.error(message)
-    let body = '<html><body><pre>' + message + '</pre></body></html>'
-    serve(res, 500, config.mime_type_html, new Buffer(body, 'utf8'))
-  }
+  server.die(res)
 }
 
-exports.serve = serve
-exports.die = die
-exports.redirect = redirect
 exports.app = app
-exports.tryApp = tryApp