server.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. package xweb
  2. import (
  3. "crypto/tls"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "net/http/pprof"
  8. "os"
  9. "runtime"
  10. runtimePprof "runtime/pprof"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "github.com/go-xweb/httpsession"
  15. "github.com/go-xweb/log"
  16. )
  17. // ServerConfig is configuration for server objects.
  18. type ServerConfig struct {
  19. Addr string
  20. Port int
  21. RecoverPanic bool
  22. Profiler bool
  23. EnableGzip bool
  24. StaticExtensionsToGzip []string
  25. Url string
  26. UrlPrefix string
  27. UrlSuffix string
  28. StaticHtmlDir string
  29. SessionTimeout time.Duration
  30. }
  31. var ServerNumber uint = 0
  32. // Server represents a xweb server.
  33. type Server struct {
  34. Config *ServerConfig
  35. Apps map[string]*App
  36. AppsNamePath map[string]string
  37. Name string
  38. SessionManager *httpsession.Manager
  39. RootApp *App
  40. Logger *log.Logger
  41. Env map[string]interface{}
  42. //save the listener so it can be closed
  43. l net.Listener
  44. }
  45. func NewServer(args ...string) *Server {
  46. name := ""
  47. if len(args) == 1 {
  48. name = args[0]
  49. } else {
  50. name = fmt.Sprintf("Server%d", ServerNumber)
  51. ServerNumber++
  52. }
  53. s := &Server{
  54. Config: Config,
  55. Env: map[string]interface{}{},
  56. Apps: map[string]*App{},
  57. AppsNamePath: map[string]string{},
  58. Name: name,
  59. }
  60. Servers[s.Name] = s
  61. s.SetLogger(log.New(os.Stdout, "", log.Ldefault()))
  62. app := NewApp("/", "root")
  63. s.AddApp(app)
  64. return s
  65. }
  66. func (s *Server) AddApp(a *App) {
  67. a.BasePath = strings.TrimRight(a.BasePath, "/") + "/"
  68. s.Apps[a.BasePath] = a
  69. if a.Name != "" {
  70. s.AppsNamePath[a.Name] = a.BasePath
  71. }
  72. a.Server = s
  73. a.Logger = s.Logger
  74. if a.BasePath == "/" {
  75. s.RootApp = a
  76. }
  77. }
  78. func (s *Server) AddAction(cs ...interface{}) {
  79. s.RootApp.AddAction(cs...)
  80. }
  81. func (s *Server) AutoAction(c ...interface{}) {
  82. s.RootApp.AutoAction(c...)
  83. }
  84. func (s *Server) AddRouter(url string, c interface{}) {
  85. s.RootApp.AddRouter(url, c)
  86. }
  87. func (s *Server) AddTmplVar(name string, varOrFun interface{}) {
  88. s.RootApp.AddTmplVar(name, varOrFun)
  89. }
  90. func (s *Server) AddTmplVars(t *T) {
  91. s.RootApp.AddTmplVars(t)
  92. }
  93. func (s *Server) AddFilter(filter Filter) {
  94. s.RootApp.AddFilter(filter)
  95. }
  96. func (s *Server) AddConfig(name string, value interface{}) {
  97. s.RootApp.SetConfig(name, value)
  98. }
  99. func (s *Server) SetConfig(name string, value interface{}) {
  100. s.RootApp.SetConfig(name, value)
  101. }
  102. func (s *Server) GetConfig(name string) interface{} {
  103. return s.RootApp.GetConfig(name)
  104. }
  105. func (s *Server) error(w http.ResponseWriter, status int, content string) error {
  106. return s.RootApp.error(w, status, content)
  107. }
  108. func (s *Server) initServer() {
  109. if s.Config == nil {
  110. s.Config = &ServerConfig{}
  111. s.Config.Profiler = true
  112. }
  113. for _, app := range s.Apps {
  114. app.initApp()
  115. }
  116. }
  117. // ServeHTTP is the interface method for Go's http server package
  118. func (s *Server) ServeHTTP(c http.ResponseWriter, req *http.Request) {
  119. s.Process(c, req)
  120. }
  121. // Process invokes the routing system for server s
  122. // non-root app's route will override root app's if there is same path
  123. func (s *Server) Process(w http.ResponseWriter, req *http.Request) {
  124. var result bool = true
  125. _, _ = XHook.Call("BeforeProcess", &result, s, w, req)
  126. if !result {
  127. return
  128. }
  129. if s.Config.UrlSuffix != "" && strings.HasSuffix(req.URL.Path, s.Config.UrlSuffix) {
  130. req.URL.Path = strings.TrimSuffix(req.URL.Path, s.Config.UrlSuffix)
  131. }
  132. if s.Config.UrlPrefix != "" && strings.HasPrefix(req.URL.Path, "/"+s.Config.UrlPrefix) {
  133. req.URL.Path = strings.TrimPrefix(req.URL.Path, "/"+s.Config.UrlPrefix)
  134. }
  135. if req.URL.Path[0] != '/' {
  136. req.URL.Path = "/" + req.URL.Path
  137. }
  138. for _, app := range s.Apps {
  139. if app != s.RootApp && strings.HasPrefix(req.URL.Path, app.BasePath) {
  140. app.routeHandler(req, w)
  141. return
  142. }
  143. }
  144. s.RootApp.routeHandler(req, w)
  145. _, _ = XHook.Call("AfterProcess", &result, s, w, req)
  146. }
  147. // Run starts the web application and serves HTTP requests for s
  148. func (s *Server) RunBase(addr string, mux *http.ServeMux) {
  149. addrs := strings.Split(addr, ":")
  150. s.Config.Addr = addrs[0]
  151. s.Config.Port, _ = strconv.Atoi(addrs[1])
  152. s.initServer()
  153. //mux := http.NewServeMux()
  154. if s.Config.Profiler {
  155. mux.Handle("/debug/pprof", http.HandlerFunc(pprof.Index))
  156. mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
  157. mux.Handle("/debug/pprof/block", pprof.Handler("block"))
  158. mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
  159. mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
  160. mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
  161. mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
  162. mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
  163. mux.Handle("/debug/pprof/startcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  164. StartCPUProfile()
  165. }))
  166. mux.Handle("/debug/pprof/stopcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  167. StopCPUProfile()
  168. }))
  169. mux.Handle("/debug/pprof/memprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  170. runtime.GC()
  171. runtimePprof.WriteHeapProfile(rw)
  172. }))
  173. mux.Handle("/debug/pprof/gc", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  174. PrintGCSummary(rw)
  175. }))
  176. }
  177. if c, err := XHook.Call("MuxHandle", mux); err == nil {
  178. if ret := XHook.Value(c, 0); ret != nil {
  179. mux = ret.(*http.ServeMux)
  180. }
  181. }
  182. mux.Handle("/", s)
  183. s.Logger.Infof("http server is listening %s", addr)
  184. l, err := net.Listen("tcp", addr)
  185. if err != nil {
  186. s.Logger.Error("ListenAndServe:", err)
  187. }
  188. s.l = l
  189. err = http.Serve(s.l, mux)
  190. s.l.Close()
  191. }
  192. func (s *Server) Run(addr string) {
  193. addrs := strings.Split(addr, ":")
  194. s.Config.Addr = addrs[0]
  195. s.Config.Port, _ = strconv.Atoi(addrs[1])
  196. s.initServer()
  197. mux := http.NewServeMux()
  198. if s.Config.Profiler {
  199. mux.Handle("/debug/pprof", http.HandlerFunc(pprof.Index))
  200. mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
  201. mux.Handle("/debug/pprof/block", pprof.Handler("block"))
  202. mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
  203. mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
  204. mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
  205. mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
  206. mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
  207. mux.Handle("/debug/pprof/startcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  208. StartCPUProfile()
  209. }))
  210. mux.Handle("/debug/pprof/stopcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  211. StopCPUProfile()
  212. }))
  213. mux.Handle("/debug/pprof/memprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  214. runtime.GC()
  215. runtimePprof.WriteHeapProfile(rw)
  216. }))
  217. mux.Handle("/debug/pprof/gc", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  218. PrintGCSummary(rw)
  219. }))
  220. }
  221. if c, err := XHook.Call("MuxHandle", mux); err == nil {
  222. if ret := XHook.Value(c, 0); ret != nil {
  223. mux = ret.(*http.ServeMux)
  224. }
  225. }
  226. mux.Handle("/", s)
  227. s.Logger.Infof("http server is listening %s", addr)
  228. l, err := net.Listen("tcp", addr)
  229. if err != nil {
  230. s.Logger.Error("ListenAndServe:", err)
  231. }
  232. s.l = l
  233. err = http.Serve(s.l, mux)
  234. s.l.Close()
  235. }
  236. // RunFcgi starts the web application and serves FastCGI requests for s.
  237. func (s *Server) RunFcgi(addr string) {
  238. s.initServer()
  239. s.Logger.Infof("fcgi server is listening %s", addr)
  240. s.listenAndServeFcgi(addr)
  241. }
  242. // RunScgi starts the web application and serves SCGI requests for s.
  243. func (s *Server) RunScgi(addr string) {
  244. s.initServer()
  245. s.Logger.Infof("scgi server is listening %s", addr)
  246. s.listenAndServeScgi(addr)
  247. }
  248. // RunTLS starts the web application and serves HTTPS requests for s.
  249. func (s *Server) RunTLS(addr string, config *tls.Config) error {
  250. s.initServer()
  251. mux := http.NewServeMux()
  252. mux.Handle("/", s)
  253. l, err := tls.Listen("tcp", addr, config)
  254. if err != nil {
  255. s.Logger.Errorf("Listen: %v", err)
  256. return err
  257. }
  258. s.l = l
  259. s.Logger.Infof("https server is listening %s", addr)
  260. return http.Serve(s.l, mux)
  261. }
  262. // Close stops server s.
  263. func (s *Server) Close() {
  264. if s.l != nil {
  265. s.l.Close()
  266. }
  267. }
  268. // SetLogger sets the logger for server s
  269. func (s *Server) SetLogger(logger *log.Logger) {
  270. s.Logger = logger
  271. s.Logger.SetPrefix("[" + s.Name + "] ")
  272. if s.RootApp != nil {
  273. s.RootApp.Logger = s.Logger
  274. }
  275. }
  276. func (s *Server) InitSession() {
  277. if s.SessionManager == nil {
  278. s.SessionManager = httpsession.Default()
  279. }
  280. if s.Config.SessionTimeout > time.Second {
  281. s.SessionManager.SetMaxAge(s.Config.SessionTimeout)
  282. }
  283. s.SessionManager.Run()
  284. if s.RootApp != nil {
  285. s.RootApp.SessionManager = s.SessionManager
  286. }
  287. }
  288. func (s *Server) SetTemplateDir(path string) {
  289. s.RootApp.SetTemplateDir(path)
  290. }
  291. func (s *Server) SetStaticDir(path string) {
  292. s.RootApp.SetStaticDir(path)
  293. }
  294. func (s *Server) App(name string) *App {
  295. path, ok := s.AppsNamePath[name]
  296. if ok {
  297. return s.Apps[path]
  298. }
  299. return nil
  300. }