+Site.prototype.serve_jst = async function(env, pathname) {
+ let jst
+ try {
+ jst = await js_template(this.root, this.root, this.root + pathname)
+ }
+ catch (err) {
+ if (err.code !== 'ENOENT')
+ throw err
+ return false
+ }
+ let out = []
+ let mime_type = await jst(env, out)
+ if (mime_type === undefined) {
+ // for directories the mime type must be returned, for files we
+ // can look it up from the pathname starting at current position
+ // (for files we're guaranteed to be on last pathname component)
+ let filetype = env.pathname.slice(env.pathname_pos)
+ assert(
+ Object.prototype.hasOwnProperty.call(config.mime_types, filetype)
+ )
+ mime_type = config.mime_types[filetype]
+ }
+ let data = Buffer.from(out.join(''))
+ console.log(
+ `${env.parsed_url.host} serving ${env.pathname} length ${data.length} from jst`
+ )
+ server.serve(env.response, 200, mime_type, data)
+ return true
+}
+
+Site.prototype.serve_less = async function(env, pathname) {
+ if (env.pathname.slice(env.pathname_pos) !== '.css')
+ return false
+
+ let data
+ try {
+ data = await this.get_less(this.root, pathname)
+ }
+ catch (err) {
+ if (err.code !== 'ENOENT')
+ throw err
+ return false
+ }
+ console.log(
+ `${env.parsed_url.host} serving ${env.pathname} length ${data.length} from less`
+ )
+ server.serve(env.response, 200, config.mime_types['.css'], data)
+ return true
+}
+
+Site.prototype.serve_fs = async function(env, pathname) {
+ let data
+ try {
+ data = await fs_readFile(this.root + pathname)
+ }
+ catch (err) {
+ if (err.code !== 'ENOENT')
+ throw err
+ return false
+ }
+ console.log(
+ `${env.parsed_url.host} serving ${env.pathname} length ${data.length} from fs`
+ )
+ let filetype = env.pathname.slice(env.pathname_pos)
+ server.serve(env.response, 200, config.mime_types[filetype], data)
+ return true
+}
+
+
+Site.prototype.serve_zip = async function(env, pathname) {
+ let zip
+ try {
+ zip = await this.get_zip(pathname)
+ }
+ catch (err) {
+ if (err.code !== 'ENOENT')
+ throw err
+ return false
+ }
+ if (!Object.prototype.hasOwnProperty.call(zip, env.pathname))
+ return false
+ let data = zip[env.pathname]
+ console.log(
+ `${env.parsed_url.host} serving ${env.pathname} length ${data.length} from zip`
+ )
+ let filetype = env.pathname.slice(env.pathname_pos)
+ server.serve(env.response, 200, config.mime_types[filetype], data)
+ return true
+}
+
+Site.prototype.respond = async function(env) {
+ while (true) {
+ if (env.pathname_pos >= env.pathname.length) {
+ let pathname = env.pathname + '/index.html'
+ console.log(
+ `${env.parsed_url.host} redirecting ${env.pathname} to ${pathname}`
+ )
+ server.redirect(
+ env.response,
+ pathname + (env.parsed_url.search || '')
+ )
+ return
+ }
+
+ assert(env.pathname.charAt(env.pathname_pos) === '/')
+ let i = env.pathname_pos + 1
+ let j = env.pathname.indexOf('/', i)
+ if (j === -1)
+ j = env.pathname.length
+ let filename = env.pathname.slice(i, j)
+
+ if (filename.length === 0) {
+ if (j >= env.pathname.length) {
+ let pathname = env.pathname + 'index.html'
+ console.log(
+ `${env.parsed_url.host} redirecting ${env.pathname} to ${pathname}`
+ )
+ server.redirect(
+ env.response,
+ pathname + (env.parsed_url.search || '')
+ )
+ }
+ else {
+ console.log(
+ `${env.parsed_url.host} empty directory name in ${env.pathname}`
+ )
+ server.die(env.response)
+ }
+ return
+ }
+
+ if (
+ filename.charAt(0) === '.' ||
+ filename.charAt(0) === '_'
+ ) {
+ console.log(
+ `${env.parsed_url.host} bad component "${filename}" in ${env.pathname}`
+ )
+ server.die(env.response)
+ return
+ }
+
+ let k = filename.lastIndexOf('.')
+ if (k === -1)
+ k = filename.length
+ let filetype = filename.slice(k)
+
+ if (
+ filetype.length !== 0 &&
+ Object.prototype.hasOwnProperty.call(config.mime_types, filetype)
+ ) {
+ if (j < env.pathname.length) {
+ console.log(
+ `${env.parsed_url.host} non-directory filetype "${filetype}" in ${env.pathname}`
+ )
+ server.die(env.response)
+ return
+ }
+ env.pathname_pos = i + k // advance to "." at start of filetype
+ break
+ }
+
+ env.pathname_pos = j
+ let pathname = env.pathname.slice(0, env.pathname_pos)
+ if (await this.serve_jst(env, pathname + '.dir.jst'))
+ return
+
+ let stats
+ try {
+ stats = await fs_stat(this.root + pathname)
+ }
+ catch (err) {
+ if (err.code !== 'ENOENT')
+ throw err
+ console.log(
+ `${env.parsed_url.host} directory not found: ${pathname}`
+ )
+ server.die(env.response)
+ return
+ }
+ if (!stats.isDirectory()) {
+ console.log(
+ `${env.parsed_url.host} not directory: ${pathname}`
+ )
+ server.die(env.response)
+ return
+ }
+ }
+
+ if (
+ !await this.serve_jst(env, env.pathname + '.jst') &&
+ !await this.serve_less(env, env.pathname + '.less') &&
+ !await this.serve_fs(env, env.pathname) &&
+ !await this.serve_zip(env, '/favicons.zip')
+ ) {
+ console.log(
+ `${env.parsed_url.host} file not found ${env.pathname}`
+ )
+ server.die(env.response)
+ }
+}
+