2017-12-29 16:03:30 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
|
|
|
|
|
|
//
|
|
|
|
|
|
// 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://gitee.com/johng/gf.
|
2018-04-13 15:19:31 +08:00
|
|
|
|
// 请求处理.
|
2017-12-31 18:19:58 +08:00
|
|
|
|
|
2017-11-23 10:21:28 +08:00
|
|
|
|
package ghttp
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"os"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"sort"
|
2017-12-30 23:49:55 +08:00
|
|
|
|
"reflect"
|
2017-11-27 12:08:43 +08:00
|
|
|
|
"strings"
|
2017-11-23 10:21:28 +08:00
|
|
|
|
"net/url"
|
2017-11-27 12:08:43 +08:00
|
|
|
|
"net/http"
|
2017-11-27 13:49:23 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/gfile"
|
2018-04-29 23:19:02 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/gtime"
|
2018-05-13 14:23:14 +08:00
|
|
|
|
"gitee.com/johng/gf/g/encoding/ghtml"
|
2017-11-23 10:21:28 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2017-12-08 12:03:21 +08:00
|
|
|
|
// 默认HTTP Server处理入口,http包底层默认使用了gorutine异步处理请求,所以这里不再异步执行
|
2017-11-23 10:21:28 +08:00
|
|
|
|
func (s *Server)defaultHttpHandle(w http.ResponseWriter, r *http.Request) {
|
2017-12-08 12:03:21 +08:00
|
|
|
|
s.handleRequest(w, r)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 执行处理HTTP请求
|
2017-12-18 10:42:59 +08:00
|
|
|
|
// 首先,查找是否有对应域名的处理接口配置;
|
|
|
|
|
|
// 其次,如果没有对应的自定义处理接口配置,那么走默认的域名处理接口配置;
|
|
|
|
|
|
// 最后,如果以上都没有找到处理接口,那么进行文件处理;
|
2017-12-08 12:03:21 +08:00
|
|
|
|
func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
|
2018-04-16 16:23:34 +08:00
|
|
|
|
// 去掉末尾的"/"号
|
|
|
|
|
|
if r.URL.Path != "/" {
|
|
|
|
|
|
r.URL.Path = strings.TrimRight(r.URL.Path, "/")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-14 01:05:46 +08:00
|
|
|
|
// 创建请求处理对象
|
2018-04-11 16:06:45 +08:00
|
|
|
|
request := newRequest(s, r, w)
|
2018-04-19 19:11:10 +08:00
|
|
|
|
|
|
|
|
|
|
defer func() {
|
2018-04-29 23:19:02 +08:00
|
|
|
|
if request.LeaveTime == 0 {
|
|
|
|
|
|
request.LeaveTime = gtime.Microsecond()
|
|
|
|
|
|
}
|
2018-05-31 12:07:31 +08:00
|
|
|
|
// access log
|
|
|
|
|
|
s.handleAccessLog(request)
|
|
|
|
|
|
// error log使用recover进行判断
|
2018-04-19 19:11:10 +08:00
|
|
|
|
if e := recover(); e != nil {
|
|
|
|
|
|
s.handleErrorLog(e, request)
|
|
|
|
|
|
}
|
2018-05-31 12:07:31 +08:00
|
|
|
|
// 将Request对象指针丢到队列中异步关闭
|
|
|
|
|
|
s.closeQueue.PushBack(request)
|
2018-04-19 19:11:10 +08:00
|
|
|
|
}()
|
|
|
|
|
|
|
2018-05-31 12:07:31 +08:00
|
|
|
|
// 路由注册检索
|
|
|
|
|
|
handler := s.getHandler(request)
|
|
|
|
|
|
if handler == nil {
|
|
|
|
|
|
// 如果路由不匹配,那么执行静态文件检索
|
|
|
|
|
|
path := s.paths.Search(r.URL.Path)
|
|
|
|
|
|
if path != "" {
|
|
|
|
|
|
s.serveFile(request, path)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
request.Response.WriteStatus(http.StatusNotFound)
|
|
|
|
|
|
request.Response.OutputBuffer()
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// **********************************************
|
|
|
|
|
|
// 以下操作仅对路由控制有效,包括事件处理,不对静态文件有效
|
|
|
|
|
|
// **********************************************
|
|
|
|
|
|
|
2018-04-14 01:05:46 +08:00
|
|
|
|
// 事件 - BeforeServe
|
|
|
|
|
|
s.callHookHandler(request, "BeforeServe")
|
2018-05-31 12:07:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 执行回调控制器/执行对象/方法
|
|
|
|
|
|
s.callHandler(handler, request)
|
|
|
|
|
|
|
2018-04-14 01:05:46 +08:00
|
|
|
|
// 事件 - AfterServe
|
|
|
|
|
|
s.callHookHandler(request, "AfterServe")
|
2018-05-04 14:35:20 +08:00
|
|
|
|
|
2018-04-29 23:19:02 +08:00
|
|
|
|
// 设置请求完成时间
|
|
|
|
|
|
request.LeaveTime = gtime.Microsecond()
|
2018-05-04 14:35:20 +08:00
|
|
|
|
|
2018-04-14 01:05:46 +08:00
|
|
|
|
// 事件 - BeforeOutput
|
|
|
|
|
|
s.callHookHandler(request, "BeforeOutput")
|
|
|
|
|
|
// 输出Cookie
|
|
|
|
|
|
request.Cookie.Output()
|
|
|
|
|
|
// 输出缓冲区
|
|
|
|
|
|
request.Response.OutputBuffer()
|
|
|
|
|
|
// 事件 - AfterOutput
|
|
|
|
|
|
s.callHookHandler(request, "AfterOutput")
|
2018-04-11 12:05:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-12 17:25:50 +08:00
|
|
|
|
// 初始化控制器
|
2018-01-02 15:52:32 +08:00
|
|
|
|
func (s *Server)callHandler(h *HandlerItem, r *Request) {
|
2017-12-26 10:13:49 +08:00
|
|
|
|
if h.faddr == nil {
|
2017-12-30 23:49:55 +08:00
|
|
|
|
// 新建一个控制器对象处理请求
|
2017-12-26 10:13:49 +08:00
|
|
|
|
c := reflect.New(h.ctype)
|
2018-01-02 15:52:32 +08:00
|
|
|
|
c.MethodByName("Init").Call([]reflect.Value{reflect.ValueOf(r)})
|
2018-04-16 16:50:26 +08:00
|
|
|
|
if !r.IsExited() {
|
2018-04-16 16:50:24 +08:00
|
|
|
|
c.MethodByName(h.fname).Call(nil)
|
|
|
|
|
|
}
|
2018-03-13 17:57:41 +08:00
|
|
|
|
c.MethodByName("Shut").Call([]reflect.Value{reflect.ValueOf(r)})
|
2017-12-26 10:13:49 +08:00
|
|
|
|
} else {
|
2018-04-16 16:50:26 +08:00
|
|
|
|
if !r.IsExited() {
|
2018-04-16 16:50:24 +08:00
|
|
|
|
h.faddr(r)
|
|
|
|
|
|
}
|
2017-12-26 10:13:49 +08:00
|
|
|
|
}
|
2017-12-12 17:25:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-11-23 10:21:28 +08:00
|
|
|
|
// http server静态文件处理
|
2018-05-31 12:07:31 +08:00
|
|
|
|
func (s *Server)serveFile(r *Request, path string) {
|
2017-11-23 10:21:28 +08:00
|
|
|
|
f, err := os.Open(path)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
info, _ := f.Stat()
|
|
|
|
|
|
if info.IsDir() {
|
2018-06-02 23:47:16 +08:00
|
|
|
|
// 处理index files
|
2017-11-23 10:21:28 +08:00
|
|
|
|
if len(s.config.IndexFiles) > 0 {
|
|
|
|
|
|
for _, file := range s.config.IndexFiles {
|
2018-06-02 23:47:16 +08:00
|
|
|
|
// 这里使用s.paths来检索,而不是直接使用path,避免多目录检索情况
|
|
|
|
|
|
// 例如:/tmp目录及源码目录都存在的情况按照优先级会返回/tmp,但是index files只在源码目录中存在
|
|
|
|
|
|
fpath := s.paths.Search(r.URL.Path + gfile.Separator + file)
|
|
|
|
|
|
if fpath != "" {
|
2017-11-23 10:21:28 +08:00
|
|
|
|
f.Close()
|
2018-05-31 12:07:31 +08:00
|
|
|
|
s.serveFile(r, fpath)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-06-02 23:47:16 +08:00
|
|
|
|
// 处理访问目录
|
2017-11-23 10:21:28 +08:00
|
|
|
|
if s.config.IndexFolder {
|
2018-04-14 01:05:46 +08:00
|
|
|
|
s.listDir(r, f)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
} else {
|
2018-04-14 01:05:46 +08:00
|
|
|
|
r.Response.WriteStatus(http.StatusForbidden)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2018-04-20 11:45:47 +08:00
|
|
|
|
// 读取文件内容返回, no buffer
|
2018-04-30 22:14:14 +08:00
|
|
|
|
http.ServeContent(r.Response.Writer, &r.Request, info.Name(), info.ModTime(), f)
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
f.Close()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 目录列表
|
2018-04-14 01:05:46 +08:00
|
|
|
|
func (s *Server)listDir(r *Request, f http.File) {
|
2017-11-23 10:21:28 +08:00
|
|
|
|
dirs, err := f.Readdir(-1)
|
|
|
|
|
|
if err != nil {
|
2018-04-14 01:05:46 +08:00
|
|
|
|
r.Response.WriteStatus(http.StatusInternalServerError, "Error reading directory")
|
2017-11-23 10:21:28 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
|
|
|
|
|
|
|
2018-04-14 01:05:46 +08:00
|
|
|
|
r.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
|
|
|
|
r.Response.Write("<pre>\n")
|
2017-11-23 10:21:28 +08:00
|
|
|
|
for _, d := range dirs {
|
|
|
|
|
|
name := d.Name()
|
|
|
|
|
|
if d.IsDir() {
|
|
|
|
|
|
name += "/"
|
|
|
|
|
|
}
|
2017-12-07 17:34:51 +08:00
|
|
|
|
u := url.URL{Path: name}
|
2018-04-14 01:05:46 +08:00
|
|
|
|
r.Response.Write(fmt.Sprintf("<a href=\"%s\">%s</a>\n", u.String(), ghtml.SpecialChars(name)))
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
2018-04-14 01:05:46 +08:00
|
|
|
|
r.Response.Write("</pre>\n")
|
2017-11-23 10:21:28 +08:00
|
|
|
|
}
|
2018-05-13 14:23:14 +08:00
|
|
|
|
|
|
|
|
|
|
// 开启异步队列处理循环,该异步线程与Server同生命周期
|
|
|
|
|
|
func (s *Server) startCloseQueueLoop() {
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
for {
|
|
|
|
|
|
if v := s.closeQueue.PopFront(); v != nil {
|
|
|
|
|
|
r := v.(*Request)
|
|
|
|
|
|
s.callHookHandler(r, "BeforeClose")
|
|
|
|
|
|
// 关闭当前会话的Cookie
|
|
|
|
|
|
r.Cookie.Close()
|
|
|
|
|
|
// 更新Session会话超时时间
|
|
|
|
|
|
r.Session.UpdateExpire()
|
|
|
|
|
|
s.callHookHandler(r, "AfterClose")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
}
|