this.root = root
}
-Site.prototype.respond = async function(request, response, parsed_url) {
- let path = parsed_url.pathname.split('/')
-
- // path must begin with /
- if (path.length === 0 || path[0].length) {
- server.die(response)
- return
- }
-
- // path elements must be findable in the file system (thus can't be empty)
- let dir_name = ''
- let dir_name_is_pub = false
- for (let i = 1; i < path.length - 1; ++i) {
- dir_name += '/' + path[i]
- if (path[i].length === 0 || path[i].charAt(0) === '.') {
- console.log(parsed_url.host, 'bad path component', dir_name)
- server.die(response)
- return
- }
- let stats
- try {
- stats = await fs_stat(this.root + dir_name)
- }
- catch (err) {
- if (err.code !== 'ENOENT')
- throw err
- if (!dir_name_is_pub) {
- let temp = dir_name + '.pub'
- try {
- stats = await fs_stat(this.root + temp)
- dir_name = temp
- dir_name_is_pub = true
- }
- catch (err2) {
- if (err2.code !== 'ENOENT')
- throw err2
- console.log(parsed_url.host, 'directory not found', dir_name)
- server.die(response)
- return
- }
- }
- if (!stats.isDirectory()) {
- console.log(parsed_url.host, 'not directory', dir_name)
- server.die(response)
- return
- }
- }
- }
-
- file_name = path[path.length - 1]
- if (file_name === '') {
- path[path.length - 1] = 'index.html'
- path = path.join('/')
- console.log(parsed_url.host, 'server.redirecting', parsed_url.pathname, 'to', path)
- server.redirect(response, path + (parsed_url.search || ''))
- return
- }
- let page = path.join('/')
-
- let temp = file_name.lastIndexOf('.')
- let file_type = temp === -1 ? '' : file_name.substring(temp + 1)
- let mime_type =
- Object.prototype.hasOwnProperty.call(config.mime_types, file_type) ?
- config.mime_types[file_type] :
- config.mime_type_default
-
- if (dir_name_is_pub) {
- temp = this.root + dir_name + '/' + file_name
- try {
- let data = await fs_readFile(temp)
- console.log(
- parsed_url.host,
- 'serving',
- temp,
- 'length',
- data.length,
- 'from pub'
- )
- server.serve(response, 200, mime_type, data)
- return
- }
- catch (err) {
- if (err.code !== 'ENOENT')
- throw err
- }
- }
- else {
- // at this point dir_name is guaranteed to be a prefix of page
- // (has no .pub component), though constructed in a roundabout way
- temp = page + '.pub'
- try {
- let data = await fs_readFile(this.root + temp)
- console.log(
- parsed_url.host,
- 'serving',
- temp,
- 'length',
- data.length,
- 'from pub'
- )
- server.serve(response, 200, mime_type, data)
- return
- }
- catch (err) {
- if (err.code !== 'ENOENT')
- throw err
- }
-
- switch (file_type) {
- case 'html':
- temp = page + '.jst'
- let template
- try {
- template = await js_template(this.root, this.root, temp)
- }
- catch (err) {
- if (err.code !== 'ENOENT') // note: err.code might be undefined
- throw err
- template = undefined
- }
- if (template !== undefined) {
- let _out = []
- await template(
- {
- parsed_url: parsed_url,
- response: response,
- request: request,
- site: this
- },
- _out
- )
- let data = Buffer.from(_out.join(''))
- console.log(
- parsed_url.host,
- 'serving',
- temp,
- 'length',
- data.length,
- 'from js'
- )
- server.serve(response, 200, mime_type, data)
- return
- }
- break
-
- case 'css':
- temp = page + '.less'
- try {
- let data = await this.get_less(temp, dir_name)
- console.log(
- parsed_url.host,
- 'serving',
- temp,
- 'length',
- data.length,
- 'from less'
- )
- server.serve(response, 200, mime_type, data)
- return
- }
- catch (err) {
- if (err.code !== 'ENOENT') // note: err.code might be undefined
- throw err
- }
- break
- }
- }
-
- let favicons = await resources.get_zip(this.root + '/favicons.zip')
- if (Object.prototype.hasOwnProperty.call(favicons, page)) {
- let data = favicons[page]
- console.log(
- parsed_url.host,
- 'serving',
- page,
- 'length',
- data.length,
- 'from favicons'
- )
- server.serve(response, 200, mime_type, data)
- return
- }
-
- console.log(parsed_url.host, 'file not found', page)
- server.die(response)
-}
-
Site.prototype.get_email = function(path) {
path = this.root + path
return resources.build_cache_email.get(
path,
- async responseult => {
+ async result => {
console.log('getting', path, 'as email')
- responseult.value = emailjs.server.connect(
+ result.value = emailjs.server.connect(
JSON.parse(await fs_readFile(path))
)
}
path = this.root + path
return resources.build_cache_json.get(
path,
- async responseult => {
+ async result => {
console.log('getting', path, 'as json')
- responseult.value = JSON.parse(await fs_readFile(path))
+ result.value = JSON.parse(await fs_readFile(path))
}
)
}
-Site.prototype.get_less = function(path, dir_name) {
+Site.prototype.get_less = function(dirname, path) {
path = this.root + path
return resources.build_cache_less.get(
path,
- async responseult => {
+ async result => {
console.log('getting', path, 'as less')
let render = await less.render(
await fs_readFile(path, {encoding: 'utf-8'}),
{
//color: true,
- //compresponses: false,
+ //compress: false,
//depends: false,
filename: path,
//globalVars: null,
//lint: false,
//math: 0,
//modifyVars: null,
- paths: [this.root + dir_name],
+ paths: [this.root + dirname],
//plugins: [],
//reUsePluginManager: true,
//rewriteUrls: false,
//urlArgs: ''
}
)
- responseult.deps.concat(render.imports)
- responseult.value = Buffer.from(render.css)
+ result.deps.concat(render.imports)
+ result.value = Buffer.from(render.css)
}
)
}
path = this.root + path
return resources.build_cache_text.get(
path,
- async responseult => {
+ async result => {
console.log('getting', path, 'as text')
- responseult.value = await fs_readFile(path, {encoding: 'utf-8'})
+ result.value = await fs_readFile(path, {encoding: 'utf-8'})
}
)
}
path = this.root + path
return resources.build_cache_zet.get(
path,
- async responseult => {
+ async result => {
console.log('getting', path, 'as zet')
- responseult.deps = [
+ result.deps = [
path + '.map.0',
path + '.param.0',
path + '.v.0',
path + '.vocab.0'
]
- responseult.value = new zetjs.Index(path)
+ result.value = new zetjs.Index(path)
}
)
}
path = this.root + path
return resources.build_cache_zip.get(
path,
- async responseult => {
+ async result => {
console.log('getting', path, 'as zip')
- responseult.value = {}
+ result.value = {}
let zipfile = await yauzl_open(path, {autoClose: false})
let entries = []
await new Promise(
- (responseolve, reject) => {
+ (resolve, reject) => {
zipfile.
on('entry', entry => {entries.push(entry)}).
- on('end', () => responseolve())
+ on('end', () => resolve())
}
)
for (let i = 0; i < entries.length; ++i) {
let read_stream = await new Promise(
- (responseolve, reject) => {
+ (resolve, reject) => {
zipfile.openReadStream(
entries[i],
(err, stream) => {
if (err)
reject(err)
- responseolve(stream)
+ resolve(stream)
}
)
}
)
let write_stream = new stream_buffers.WritableStreamBuffer()
let data = new Promise(
- (responseolve, reject) => {
+ (resolve, reject) => {
write_stream.
- on('finish', () => {responseolve(write_stream.getContents())}).
+ on('finish', () => {resolve(write_stream.getContents())}).
on('error', () => {reject()})
}
)
let path = '/' + entries[i].fileName
data = await data
console.log('entry path', path, 'size', data.length)
- responseult.value[path] = data
+ result.value[path] = data
}
await zipfile.close()
}
return /*await*/ resources.json_cache.flush(this.root + path)
}
+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)
+ }
+}
+
module.exports = Site