新增文档根目录处理逻辑
This commit is contained in:
parent
6693cfe68f
commit
4b346afaec
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
"flag"
|
"flag"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"git.nspix.com/golang/kos"
|
"git.nspix.com/golang/kos"
|
||||||
)
|
)
|
||||||
|
@ -15,7 +16,7 @@ type subServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *subServer) Start(ctx context.Context) (err error) {
|
func (s *subServer) Start(ctx context.Context) (err error) {
|
||||||
kos.Http().Embed("/ui/web", "web", webDir)
|
kos.Http().Root("/web", http.FS(webDir))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<title>Document</title>
|
<title>Document</title>
|
||||||
<link rel="stylesheet" href="css/index.css">
|
<link rel="stylesheet" href="/css/index.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello</h1>
|
<h1>Hello</h1>
|
||||||
|
|
|
@ -3,6 +3,9 @@ package http
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,6 +13,9 @@ type (
|
||||||
FS struct {
|
FS struct {
|
||||||
fs http.FileSystem
|
fs http.FileSystem
|
||||||
modtime time.Time
|
modtime time.Time
|
||||||
|
prefix string
|
||||||
|
indexFile string
|
||||||
|
denyDirectory bool
|
||||||
}
|
}
|
||||||
|
|
||||||
File struct {
|
File struct {
|
||||||
|
@ -74,11 +80,54 @@ func (file *File) Stat() (fs.FileInfo, error) {
|
||||||
return newFileInfo(fi, file.modtime), nil
|
return newFileInfo(fi, file.modtime), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FS) DenyAccessDirectory() {
|
||||||
|
fs.denyDirectory = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FS) SetPrefix(prefix string) {
|
||||||
|
if prefix != "" {
|
||||||
|
if prefix[0] != '/' {
|
||||||
|
prefix = "/" + prefix
|
||||||
|
}
|
||||||
|
prefix = strings.TrimRight(prefix, "/")
|
||||||
|
fs.prefix = prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FS) SetIndexFile(indexFile string) {
|
||||||
|
fs.indexFile = indexFile
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *FS) Open(name string) (http.File, error) {
|
func (fs *FS) Open(name string) (http.File, error) {
|
||||||
|
var (
|
||||||
|
needRetry bool
|
||||||
|
)
|
||||||
|
if name == "" || name == "/" {
|
||||||
|
needRetry = true
|
||||||
|
}
|
||||||
|
if fs.prefix != "" {
|
||||||
|
if !strings.HasPrefix(name, fs.prefix) {
|
||||||
|
name = path.Join(fs.prefix, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
fp, err := fs.fs.Open(name)
|
fp, err := fs.fs.Open(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if fs.denyDirectory {
|
||||||
|
state, err := fp.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if state.IsDir() {
|
||||||
|
if needRetry {
|
||||||
|
if fs.indexFile != "" {
|
||||||
|
return fs.Open(path.Join(name, fs.indexFile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, os.ErrPermission
|
||||||
|
}
|
||||||
|
}
|
||||||
return &File{fp: fp, modtime: fs.modtime}, nil
|
return &File{fp: fp, modtime: fs.modtime}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ type Server struct {
|
||||||
router *router.Router
|
router *router.Router
|
||||||
middleware []Middleware
|
middleware []Middleware
|
||||||
uptime time.Time
|
uptime time.Time
|
||||||
|
enableDocumentRoot bool
|
||||||
|
fileSystem http.FileSystem
|
||||||
anyRequests map[string]http.Handler
|
anyRequests map[string]http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +93,15 @@ func (svr *Server) Group(prefix string, routes []Route, middleware ...Middleware
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svr *Server) Root(prefix string, fs http.FileSystem) {
|
||||||
|
svr.enableDocumentRoot = true
|
||||||
|
s := newFS(svr.uptime, fs)
|
||||||
|
s.SetPrefix(prefix)
|
||||||
|
s.DenyAccessDirectory()
|
||||||
|
s.SetIndexFile("/index.html")
|
||||||
|
svr.fileSystem = s
|
||||||
|
}
|
||||||
|
|
||||||
func (svr *Server) Embed(prefix string, root string, embedFs embed.FS) {
|
func (svr *Server) Embed(prefix string, root string, embedFs embed.FS) {
|
||||||
routePath := prefix
|
routePath := prefix
|
||||||
if !strings.HasSuffix(routePath, "/*filepath") {
|
if !strings.HasSuffix(routePath, "/*filepath") {
|
||||||
|
@ -159,12 +170,24 @@ func (svr *Server) handleRequest(res http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
func (svr *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
file http.File
|
||||||
|
)
|
||||||
for prefix, handle := range svr.anyRequests {
|
for prefix, handle := range svr.anyRequests {
|
||||||
if strings.HasPrefix(request.URL.Path, prefix) {
|
if strings.HasPrefix(request.URL.Path, prefix) {
|
||||||
handle.ServeHTTP(writer, request)
|
handle.ServeHTTP(writer, request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if svr.enableDocumentRoot && request.Method == http.MethodGet {
|
||||||
|
uri := path.Clean(request.URL.Path)
|
||||||
|
if file, err = svr.fileSystem.Open(uri); err == nil {
|
||||||
|
http.ServeContent(writer, request, path.Base(uri), svr.uptime, file)
|
||||||
|
err = file.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
switch request.Method {
|
switch request.Method {
|
||||||
case http.MethodOptions:
|
case http.MethodOptions:
|
||||||
svr.handleOption(writer, request)
|
svr.handleOption(writer, request)
|
||||||
|
|
Loading…
Reference in New Issue