package server import ( "context" "fmt" "net/http" "sort" "strings" handler "git.pyer.club/kingecg/gohttpd/handler" "git.pyer.club/kingecg/gohttpd/model" logger "git.pyer.club/kingecg/gologger" ) type RequestCtxKey string type Route struct { Method string Path string Handler http.Handler matcher *UrlParamMatcher middles *MiddlewareLink wrapped bool } func (route *Route) ServeHTTP(w http.ResponseWriter, r *http.Request) { if route.wrapped == false { route.Handler = route.middles.WrapHandler(route.Handler) route.wrapped = true } route.Handler.ServeHTTP(w, r) } func (route *Route) Match(r *http.Request) bool { l := logger.GetLogger("Route") l.Debug(fmt.Sprintf("match route: %s %s", r.Method, r.URL.Path)) if route.Method != "" && route.Method != r.Method { l.Debug("method not match") return false } if route.matcher != nil && route.matcher.Reg != nil { params, matched := MatchUrlParam(r.URL.Path, route.matcher) if matched { ctx := r.Context() data := ctx.Value(RequestCtxKey("data")).(map[string]interface{}) for _, p := range route.matcher.Params { data[p] = params[p] } return true } l.Debug("Not match matcher reg") return false } if route.Path == "" { return true } return strings.HasPrefix(r.URL.Path, route.Path) } func (route *Route) Add(m Middleware) { route.middles.Add(m) } // NewRoute 返回一个新的Route实例 // 参数: // - method: 请求方法 // - path: 请求路径 // - handleFn: http.Handler处理函数 // 返回值: // - *Route: 一个指向Route的指针 func NewRoute(method string, path string, handleFn http.Handler) *Route { ret := &Route{ Method: method, Path: path, middles: NewMiddlewareLink(), wrapped: false, } p := ParseUrl(path) // 使用handleFn构建handler ret.Handler = handleFn ret.matcher = &p return ret } type Routes []*Route func (rs Routes) Less(i, j int) bool { iPaths := strings.Split(rs[i].Path, "/") jPaths := strings.Split(rs[j].Path, "/") if len(iPaths) > len(jPaths) { return true } if len(iPaths) < len(jPaths) { return false } for k := 0; k < len(iPaths); k++ { if iPaths[k] != jPaths[k] { return iPaths[k] < jPaths[k] } } return false } func (rs Routes) Len() int { return len(rs) } func (rs Routes) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] } // 可以嵌套的Rest http server mux type RestMux struct { Path string routes Routes middlewares *MiddlewareLink wrapperHandler http.Handler } func (mux *RestMux) Use(m Middleware) { mux.middlewares.Add(m) } func (mux *RestMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { if mux.wrapperHandler == nil { mux.wrapperHandler = mux.middlewares.WrapHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { for _, route := range mux.routes { if route.Match(r) { route.ServeHTTP(w, r) return } } http.NotFound(w, r) })) return } mux.wrapperHandler.ServeHTTP(w, r) // c := r.Context() // newRequest := r // if t := c.Value("data"); t == nil { // data := map[string]interface{}{} // cn := context.WithValue(c, RequestCtxKey("data"), data) // newRequest = r.WithContext(cn) // } // if mux.middlewares.Len() > 0 && !mux.middlewares.ServeHTTP(w, newRequest) { // return // } // 根据r 从routes中找到匹配的路由 } func (mux *RestMux) HandleFunc(method string, path string, f func(http.ResponseWriter, *http.Request)) *Route { r := NewRoute(method, path, http.HandlerFunc(f)) mux.routes = append(mux.routes, r) sort.Sort(mux.routes) return r } func (mux *RestMux) Get(path string, f func(http.ResponseWriter, *http.Request)) *Route { return mux.HandleFunc("GET", path, f) } func (mux *RestMux) Post(path string, f func(http.ResponseWriter, *http.Request)) *Route { return mux.HandleFunc("POST", path, f) } func (mux *RestMux) Put(path string, f func(http.ResponseWriter, *http.Request)) *Route { return mux.HandleFunc("PUT", path, f) } func (mux *RestMux) Delete(path string, f func(http.ResponseWriter, *http.Request)) *Route { return mux.HandleFunc("DELETE", path, f) } func (mux *RestMux) Patch(path string, f func(http.ResponseWriter, *http.Request)) *Route { return mux.HandleFunc("PATCH", path, f) } func (mux *RestMux) Head(path string, f func(http.ResponseWriter, *http.Request)) *Route { return mux.HandleFunc("HEAD", path, f) } func (mux *RestMux) Option(path string, f func(http.ResponseWriter, *http.Request)) *Route { return mux.HandleFunc("OPTION", path, f) } func (mux *RestMux) HandleMux(nmux *RestMux) *Route { p := nmux.Path if !strings.HasSuffix(p, "/") { p = p + "/" } r := NewRoute("", p, nmux) mux.routes = append(mux.routes, r) sort.Sort(mux.routes) return r } func NewRestMux(path string) *RestMux { ret := &RestMux{ Path: path, routes: Routes{}, middlewares: NewMiddlewareLink(), } return ret } type ServerMux struct { http.Handler directiveHandlers *MiddlewareLink handlers map[string]http.Handler paths []string wrappedHandler map[string]http.Handler } func (s *ServerMux) Handle(pattern string, handler http.Handler) { if s.handlers == nil { s.handlers = make(map[string]http.Handler) } s.handlers[pattern] = s.directiveHandlers.WrapHandler(handler) s.paths = append(s.paths, pattern) // 自定义比较函数排序s.paths sort.Slice(s.paths, func(i, j int) bool { return len(s.paths[i]) > len(s.paths[j]) || s.paths[i] > s.paths[j] }) } func (s *ServerMux) AddDirective(directiveStr string) { l := logger.GetLogger("ServerMux") strs := strings.Split(directiveStr, " ") directiveName := strs[0] params := strs[1:] directive, ok := DirectiveMap[directiveName] if ok { l.Debug(fmt.Sprintf("add directive: %s", directiveName)) s.directiveHandlers.Add(directive(params...)) } else { l.Error(fmt.Sprintf("directive not found: %s", directiveName)) } } func (s *ServerMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { l := logger.GetLogger("Access") data := map[string]interface{}{} c := r.Context() cn := context.WithValue(c, RequestCtxKey("data"), data) newRequest := r.WithContext(cn) l.Info(fmt.Sprintf("From %s-%s %s", r.RemoteAddr, r.Method, r.URL.Path)) for _, p := range s.paths { if strings.HasPrefix(r.URL.Path, p) { l.Info(fmt.Sprintf("match path: %s", p)) s.handlers[p].ServeHTTP(w, newRequest) // s.directiveHandlers.ServeHTTP(w, newRequest) // ctx := newRequest.Context() // m := ctx.Value(RequestCtxKey("data")).(map[string]interface{}) // _, ok := m["Tg"] // if ok { // wrappedHandler := s.wrappedHandler[p] // if wrappedHandler == nil { // s.wrappedHandler[p] = gzip.DefaultHandler().WrapHandler(s.handlers[p]) // wrappedHandler = s.wrappedHandler[p] // } // wrappedHandler.ServeHTTP(w, newRequest) // } else { // s.handlers[p].ServeHTTP(w, newRequest) // } return } } l.Error(fmt.Sprintf("404: %s", r.URL.Path)) http.NotFound(w, newRequest) } // NewServeMux 根据提供的 HTTP 服务器配置创建并返回一个新的 ServerMux 实例。 // 参数: // - c: 指向 model.HttpServerConfig 结构体的指针,包含服务器的配置信息。 // 返回值: // - *ServerMux: 一个指向 ServerMux 的指针,用于处理 HTTP 请求。 func NewServeMux(c *model.HttpServerConfig) *ServerMux { // 获取名为 "ServerMux" 的日志记录器实例 l := logger.GetLogger("ServerMux") // 记录创建 ServerMux 的调试信息 l.Debug("NewServeMux") // 初始化一个新的 ServerMux 实例 s := &ServerMux{ // 初始化指令处理中间件链 directiveHandlers: NewMiddlewareLink(), // 初始化处理程序映射 handlers: make(map[string]http.Handler), // 初始化路径列表 paths: []string{}, // 初始化包装处理程序映射 wrappedHandler: make(map[string]http.Handler), } s.AddDirective("Record-Access") // 遍历配置中的所有指令 for _, directive := range c.Directives { // 将指令添加到 ServerMux 的指令处理中间件链中 s.AddDirective(string(directive)) } // 遍历配置中的所有 HTTP 路径 for _, httpPath := range c.Paths { // 检查路径配置中是否指定了根目录 if httpPath.Root != "" { // 创建一个新的文件处理程序 fileHandler := handler.NewFileHandler(handler.FileHandler{ // 设置文件处理程序的根目录 Root: httpPath.Root, // 设置文件处理程序的默认文件 Default: httpPath.Default, }) // 将文件处理程序注册到 ServerMux 中 s.Handle(httpPath.Path, fileHandler) // 检查路径配置中是否指定了上游服务器 } else if len(httpPath.Upstreams) != 0 { // 创建一个新的代理处理程序 proxyHandler := handler.NewProxyHandler(&httpPath) // 将代理处理程序注册到 ServerMux 中 s.Handle(httpPath.Path, proxyHandler) // 如果既没有指定根目录也没有指定上游服务器 } else { // 记录不支持的路径类型错误信息 l.Error("Not supportted server path type :", httpPath.Path) } } // 返回初始化好的 ServerMux 实例 return s }