Files
gf/net/ghttp/ghttp_server_handler.go

228 lines
6.5 KiB
Go
Raw Normal View History

// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
2017-12-29 16:03:30 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2017-12-31 18:19:58 +08:00
2017-11-23 10:21:28 +08:00
package ghttp
import (
2019-06-19 09:06:52 +08:00
"net/http"
"os"
"sort"
"strings"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/encoding/ghtml"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/os/gspath"
"github.com/gogf/gf/os/gtime"
2017-11-23 10:21:28 +08:00
)
2017-12-08 12:03:21 +08:00
// 默认HTTP Server处理入口http包底层默认使用了gorutine异步处理请求所以这里不再异步执行
2019-06-19 09:06:52 +08:00
func (s *Server) defaultHttpHandle(w http.ResponseWriter, r *http.Request) {
s.handleRequest(w, r)
2017-12-08 12:03:21 +08:00
}
// 执行处理HTTP请求
// 首先,查找是否有对应域名的处理接口配置;
// 其次,如果没有对应的自定义处理接口配置,那么走默认的域名处理接口配置;
// 最后,如果以上都没有找到处理接口,那么进行文件处理;
2019-06-19 09:06:52 +08:00
func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
// 重写规则判断
if len(s.config.Rewrites) > 0 {
if rewrite, ok := s.config.Rewrites[r.URL.Path]; ok {
r.URL.Path = rewrite
}
}
2019-06-19 09:06:52 +08:00
// URI默认值
if r.URL.Path == "" {
r.URL.Path = "/"
}
2019-06-19 09:06:52 +08:00
// 去掉末尾的"/"号
if r.URL.Path != "/" {
for r.URL.Path[len(r.URL.Path)-1] == '/' {
r.URL.Path = r.URL.Path[:len(r.URL.Path)-1]
}
}
2018-04-16 16:23:34 +08:00
2019-06-19 09:06:52 +08:00
// 创建请求处理对象
request := newRequest(s, r, w)
2019-06-19 09:06:52 +08:00
defer func() {
// 设置请求完成时间
request.LeaveTime = gtime.Microsecond()
// 事件 - BeforeOutput
if !request.IsExited() {
s.callHookHandler(HOOK_BEFORE_OUTPUT, request)
}
// 如果没有产生异常状态那么设置返回状态为200
if request.Response.Status == 0 {
request.Response.Status = http.StatusOK
}
// error log
if e := recover(); e != nil {
request.Response.WriteStatus(http.StatusInternalServerError)
s.handleErrorLog(e, request)
}
// access log
s.handleAccessLog(request)
// 输出Cookie
request.Cookie.Output()
// 输出缓冲区
request.Response.Output()
// 事件 - AfterOutput
if !request.IsExited() {
s.callHookHandler(HOOK_AFTER_OUTPUT, request)
}
// 更新Session会话超时时间
request.Session.UpdateExpire()
}()
2019-06-19 09:06:52 +08:00
// ============================================================
// 优先级控制:
// 静态文件 > 动态服务 > 静态目录
// ============================================================
2019-06-19 09:06:52 +08:00
staticFile := ""
isStaticDir := false
// 优先执行静态文件检索(检测是否存在对应的静态文件包括index files处理)
if s.config.FileServerEnabled {
staticFile, isStaticDir = s.searchStaticFile(r.URL.Path)
if staticFile != "" {
request.isFileRequest = true
}
}
2019-06-19 09:06:52 +08:00
// 动态服务检索
if !request.isFileRequest || isStaticDir {
request.handlers, request.hasHookHandler = s.getHandlersWithCache(request)
2019-06-19 09:06:52 +08:00
}
2019-06-19 09:06:52 +08:00
// 判断最终对该请求提供的服务方式
if isStaticDir && request.handlers != nil {
2019-06-19 09:06:52 +08:00
request.isFileRequest = false
}
2018-11-23 09:20:45 +08:00
2019-06-19 09:06:52 +08:00
// 事件 - BeforeServe
s.callHookHandler(HOOK_BEFORE_SERVE, request)
2018-08-16 18:17:47 +08:00
2019-06-19 09:06:52 +08:00
// 执行静态文件服务/回调控制器/执行对象/方法
if !request.IsExited() {
if request.isFileRequest {
// 静态服务
2019-06-19 09:06:52 +08:00
s.serveFile(request, staticFile)
} else {
if len(request.handlers) > 0 {
2019-06-19 09:06:52 +08:00
// 动态服务
request.Middleware.Next()
2019-06-19 09:06:52 +08:00
} else {
if isStaticDir {
// 静态目录
s.serveFile(request, staticFile)
} else {
if len(request.Response.Header()) == 0 &&
request.Response.Status == 0 &&
request.Response.BufferLength() == 0 {
request.Response.WriteStatus(http.StatusNotFound)
}
}
}
}
}
2019-06-19 09:06:52 +08:00
// 事件 - AfterServe
if !request.IsExited() {
s.callHookHandler(HOOK_AFTER_SERVE, request)
}
2018-04-11 12:05:25 +08:00
}
// 查找静态文件的绝对路径
func (s *Server) searchStaticFile(uri string) (filePath string, isDir bool) {
2019-06-19 09:06:52 +08:00
// 优先查找URI映射
if len(s.config.StaticPaths) > 0 {
for _, item := range s.config.StaticPaths {
if len(uri) >= len(item.prefix) && strings.EqualFold(item.prefix, uri[0:len(item.prefix)]) {
// 防止类似 /static/style 映射到 /static/style.css 的情况
if len(uri) > len(item.prefix) && uri[len(item.prefix)] != '/' {
continue
}
return gspath.Search(item.path, uri[len(item.prefix):], s.config.IndexFiles...)
}
}
}
// 其次查找root和search path
if len(s.config.SearchPaths) > 0 {
for _, path := range s.config.SearchPaths {
if filePath, isDir = gspath.Search(path, uri, s.config.IndexFiles...); filePath != "" {
return filePath, isDir
}
}
}
return "", false
}
// http server静态文件处理path可以为相对路径也可以为绝对路径
2019-07-24 22:48:43 +08:00
func (s *Server) serveFile(r *Request, path string, allowIndex ...bool) {
2019-06-19 09:06:52 +08:00
f, err := os.Open(path)
if err != nil {
r.Response.WriteStatus(http.StatusForbidden)
return
}
defer f.Close()
info, _ := f.Stat()
if info.IsDir() {
2019-07-24 22:48:43 +08:00
if s.config.IndexFolder || (len(allowIndex) > 0 && allowIndex[0]) {
2019-06-19 09:06:52 +08:00
s.listDir(r, f)
} else {
r.Response.WriteStatus(http.StatusForbidden)
}
} else {
// 读取文件内容返回, no buffer
http.ServeContent(r.Response.Writer, r.Request, info.Name(), info.ModTime(), f)
}
2017-11-23 10:21:28 +08:00
}
2018-11-17 11:17:02 +08:00
// 显示目录列表
2019-06-19 09:06:52 +08:00
func (s *Server) listDir(r *Request, f http.File) {
files, err := f.Readdir(-1)
if err != nil {
r.Response.WriteStatus(http.StatusInternalServerError, "Error reading directory")
return
}
sort.Slice(files, func(i, j int) bool { return files[i].Name() < files[j].Name() })
2019-07-24 22:48:43 +08:00
if r.Response.Header().Get("Content-Type") == "" {
r.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
}
r.Response.Write(`<html>`)
r.Response.Write(`<head></head>`)
r.Response.Write(`<body>`)
r.Response.Writef(`<h1>Index of %s</h1>`, r.URL.Path)
2019-07-24 22:48:43 +08:00
r.Response.Writef(`<hr />`)
r.Response.Write(`<table>`)
2019-06-19 09:06:52 +08:00
if r.URL.Path != "/" {
r.Response.Write(`<tr>`)
r.Response.Writef(`<td><a href="%s">..</a></td>`, gfile.Dir(r.URL.Path))
r.Response.Write(`</tr>`)
2019-06-19 09:06:52 +08:00
}
2019-07-24 22:48:43 +08:00
name := ""
size := ""
2019-06-19 09:06:52 +08:00
for _, file := range files {
2019-07-24 22:48:43 +08:00
name = file.Name()
size = gfile.FormatSize(file.Size())
2019-06-19 09:06:52 +08:00
if file.IsDir() {
name += "/"
2019-07-24 22:48:43 +08:00
size = "-"
2019-06-19 09:06:52 +08:00
}
2019-07-24 22:48:43 +08:00
r.Response.Write(`<tr>`)
r.Response.Writef(`<td><a href="%s/%s">%s</a></td>`, r.URL.Path, name, ghtml.SpecialChars(name))
2019-07-24 22:48:43 +08:00
r.Response.Writef(`<td style="width:80px;text-align:center;">%s</td>`, size)
r.Response.Writef(`<td>%s</td>`, gtime.New(file.ModTime()).ISO8601())
2019-07-24 22:48:43 +08:00
r.Response.Write(`</tr>`)
2019-06-19 09:06:52 +08:00
}
2019-07-24 22:48:43 +08:00
r.Response.Write(`</table>`)
r.Response.Write(`</body>`)
r.Response.Write(`</html>`)
2017-11-23 10:21:28 +08:00
}