support for OPTIONS method

Massimo Melina committed Dec 23, 2021 at 16:32 UTC 7f9c84bc1dd7ca698f2af03d03bb8c729b126cac
4 files changed +24 -5
src/const.ts
+3
@@ -10,3 +10,6 @@ export const FRONTEND_URI = SPECIAL_URI + 'front/'
10 export const API_URI = SPECIAL_URI + 'api/'
11
12 export const argv = minimist(process.argv.slice(2))
13 +
14 +export const METHOD_NOT_ALLOWED = 405
15 +export const NO_CONTENT = 204
src/index.ts
+2 -2
@@ -37,7 +37,7 @@ srv.use(mount(API_URI, new Koa()
37 const serveFrontendPrefixed = mount(FRONTEND_URI.slice(0,-1), serveFrontend)
38 srv.use(async (ctx, next) => {
39 const { path } = ctx
40 - if (ctx.method !== 'GET' || ctx.body)
40 + if (ctx.body)
41 return await next()
42 if (path.startsWith(FRONTEND_URI))
43 return await serveFrontendPrefixed(ctx,next)
@@ -48,7 +48,7 @@ srv.use(async (ctx, next) => {
48 if (!source || await isDirectory(source)) { // this folder was requested without the trailing /
49 ctx.set({ server:'HFS '+BUILD_TIMESTAMP })
50 return path.endsWith('/') ? await serveFrontend(ctx, next)
51 - : ctx.redirect(ctx.path + '/')
51 + : ctx.redirect(path + '/')
52 }
53 if (source)
54 return source.includes('//') ? mount(path,proxy(source,{}))(ctx,next)
src/serveFile.ts
+9 -1
@@ -1,11 +1,19 @@
1 import Koa from 'koa'
2 import { createReadStream } from 'fs'
3 import fs from 'fs/promises'
4 +import { METHOD_NOT_ALLOWED, NO_CONTENT } from './const'
5
6 export function serveFile(source: string) : Koa.Middleware {
7 return async (ctx) => {
8 const { range } = ctx.request.header
9 ctx.set('Accept-Ranges', 'bytes')
10 + if (ctx.method === 'OPTIONS') {
11 + ctx.status = NO_CONTENT
12 + ctx.set({ Allow: 'OPTIONS, GET' })
13 + return
14 + }
15 + if (ctx.method !== 'GET')
16 + return ctx.status = METHOD_NOT_ALLOWED
17 if (!range)
18 return ctx.body = createReadStream(source)
19 const ranges = range.split('=')[1]
@@ -28,4 +36,4 @@ export function serveFile(source: string) : Koa.Middleware {
36 ctx.set('Content-Range', `bytes ${start}-${end}/${stat.size}`)
37 ctx.body = createReadStream(source, { start, end })
38 }
31 -}
\ No newline at end of file
39 +}
src/serveFrontend.ts
+10 -2
@@ -2,13 +2,14 @@ import proxy from 'koa-better-http-proxy'
2 import Koa from 'koa'
3 import mime from 'mime-types'
4 import { createReadStream, readFile } from 'fs'
5 -import { DEV, FRONTEND_URI } from './const'
5 +import { DEV, FRONTEND_URI, METHOD_NOT_ALLOWED, NO_CONTENT } from './const'
6
7 export const serveFrontend = DEV ? serveProxyFrontend() : serveStaticFrontend()
8
9 function serveProxyFrontend() {
10 console.debug('fronted: proxied')
11 return proxy('localhost:3000', {
12 + filter: ctx => ctx.method === 'GET' || (ctx.status = METHOD_NOT_ALLOWED) && false,
13 proxyReqPathResolver: (ctx) => ctx.path.endsWith('/') ? '/' : ctx.path,
14 userResDecorator: (res, data, req) => {
15 return req.url.endsWith('/') ? replaceFrontEndRes(data.toString('utf8'))
@@ -20,7 +21,14 @@ function serveProxyFrontend() {
21 function serveStaticFrontend() : Koa.Middleware {
22 const BASE = __dirname + (DEV ? '/../dist' : '') + '/frontend/'
23 return async (ctx, next) => {
23 - let { path } = ctx
24 + let { path, method } = ctx
25 + if (method === 'OPTIONS') {
26 + ctx.status = NO_CONTENT
27 + ctx.set({ Allow: 'OPTIONS, GET' })
28 + return
29 + }
30 + if (method !== 'GET')
31 + return ctx.status = METHOD_NOT_ALLOWED
32 if (path.endsWith('/')) {
33 const res = await filePromise(BASE + 'index.html')
34 ctx.body = replaceFrontEndRes(res.toString('utf8'))