/*
- * Copyright (C) 2018 Nick Downing <nick@ndcode.org>
+ * Copyright (C) 2018-2021 Nick Downing <nick@ndcode.org>
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
let util = require('util')
let fs_mkdir = util.promisify(fs.mkdir)
-let fs_readFile = util.promisify(fs.readFile)
let fs_stat = util.promisify(fs.stat)
let Site = function(resources, root, options/*, prev_site*/) {
'.jpeg': 'image/jpeg',
'.js': 'application/javascript; charset=utf-8',
'.json': 'application/json; charset=utf-8',
+ '.mp4': 'video/mp4',
+ '.pdf': 'application/pdf',
'.png': 'image/png',
'.svg': 'image/svg+xml',
'.ttf': 'application/octet-stream',
}
Site.prototype.serve_fs = async function(env, pathname) {
- let data
- try {
- data = await fs_readFile(pathname)
- }
- catch (err) {
- if (!(err instanceof Error) || err.code !== 'ENOENT')
- throw err
- return false
- }
- this.serve(env, 200, data, 'fs')
- return true
+ // see serve()
+ console.log(
+ `${env.parsed_url.host} streaming ${env.parsed_url.pathname}`
+ )
+
+ // see serve_internal()
+ env.response.statusCode = 200
+ // since the file may be huge we need to cache it for as long as reasonable
+ if (this.options.caching)
+ env.response.setHeader('Cache-Control', 'max-age=86400')
+ env.response.setHeader('Content-Type', env.mime_type)
+
+ let stream = fs.createReadStream(pathname);
+ return /*await*/ new Promise(
+ (resolve, reject) => {
+ stream.on(
+ 'error',
+ err => {
+ //console.log(`error: ${err.message}`)
+ if (!(err instanceof Error) || err.code !== 'ENOENT')
+ reject(err)
+ resolve(false)
+ }
+ )
+ stream.on(
+ 'data',
+ data => {
+ //console.log(`data: ${data.length} bytes`)
+ env.response.write(data)
+ }
+ )
+ stream.on(
+ 'end',
+ () => {
+ //console.log('end')
+ env.response.end()
+ resolve(true)
+ }
+ )
+ }
+ )
}
Site.prototype.serve_zip = async function(env, zipname, pathname) {
Site.prototype.respond = async function(env) {
env.mime_type = 'application/octet-stream'
- let i = env.parsed_url.pathname.lastIndexOf('.')
+ let pathname = decodeURIComponent(env.parsed_url.pathname)
+ let i = pathname.lastIndexOf('.')
if (i !== -1) {
- let extension = env.parsed_url.pathname.slice(i)
+ let extension = pathname.slice(i)
if (
Object.prototype.hasOwnProperty.call(this.options.mime_types, extension)
)
await this.serve_zip(
env,
this.root + '/_favicon/favicons.zip',
- env.parsed_url.pathname
+ pathname
)
)
return
- let components = env.parsed_url.pathname.split('/')
+ let components = pathname.split('/')
if (components.length) {
assert(components[0].length == 0)
components = components.slice(1)
// deal with ACME challenges for certbot (letsencrypt)
if (components[0] === '.well-known') {
// build path, ensuring that remaining components are safe
- pathname = `${this.options.certbot_webroot}/.well-known`
+ /*let*/ pathname = `${this.options.certbot_webroot}/.well-known`
for (let i = 1; i < components.length; ++i) {
if (components[i].charAt(0) == '.') {
this.die(env, `bad component "${components[i]}" in ${env.parsed_url.pathname}`)