ghttp_server.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package ghttp
  7. import (
  8. "bytes"
  9. "context"
  10. "github.com/gogf/gf/debug/gdebug"
  11. "github.com/gogf/gf/errors/gcode"
  12. "github.com/gogf/gf/errors/gerror"
  13. "github.com/gogf/gf/internal/intlog"
  14. "net/http"
  15. "os"
  16. "runtime"
  17. "strings"
  18. "time"
  19. "github.com/gogf/gf/os/gsession"
  20. "github.com/gogf/gf/container/garray"
  21. "github.com/gogf/gf/container/gtype"
  22. "github.com/gogf/gf/os/gcache"
  23. "github.com/gogf/gf/os/genv"
  24. "github.com/gogf/gf/os/gfile"
  25. "github.com/gogf/gf/os/glog"
  26. "github.com/gogf/gf/os/gproc"
  27. "github.com/gogf/gf/os/gtimer"
  28. "github.com/gogf/gf/text/gregex"
  29. "github.com/gogf/gf/util/gconv"
  30. "github.com/olekukonko/tablewriter"
  31. )
  32. func init() {
  33. // Initialize the methods map.
  34. for _, v := range strings.Split(supportedHttpMethods, ",") {
  35. methodsMap[v] = struct{}{}
  36. }
  37. }
  38. // SetGraceful enables/disables the graceful reload feature for server,
  39. // which is false in default.
  40. //
  41. // Note that this feature switch is not for single server instance but for whole process.
  42. // Deprecated, use configuration of ghttp.Server for controlling this feature.
  43. func SetGraceful(enabled bool) {
  44. gracefulEnabled = enabled
  45. }
  46. // serverProcessInit initializes some process configurations, which can only be done once.
  47. func serverProcessInit() {
  48. if !serverProcessInitialized.Cas(false, true) {
  49. return
  50. }
  51. // This means it is a restart server, it should kill its parent before starting its listening,
  52. // to avoid duplicated port listening in two processes.
  53. if genv.Get(adminActionRestartEnvKey) != "" {
  54. if p, e := os.FindProcess(gproc.PPid()); e == nil {
  55. p.Kill()
  56. p.Wait()
  57. } else {
  58. glog.Error(e)
  59. }
  60. }
  61. // Signal handler.
  62. go handleProcessSignal()
  63. // Process message handler.
  64. // It's enabled only graceful feature is enabled.
  65. if gracefulEnabled {
  66. intlog.Printf(context.TODO(), "%d: graceful reload feature is enabled", gproc.Pid())
  67. go handleProcessMessage()
  68. } else {
  69. intlog.Printf(context.TODO(), "%d: graceful reload feature is disabled", gproc.Pid())
  70. }
  71. // It's an ugly calling for better initializing the main package path
  72. // in source development environment. It is useful only be used in main goroutine.
  73. // It fails retrieving the main package path in asynchronous goroutines.
  74. gfile.MainPkgPath()
  75. }
  76. // GetServer creates and returns a server instance using given name and default configurations.
  77. // Note that the parameter <name> should be unique for different servers. It returns an existing
  78. // server instance if given <name> is already existing in the server mapping.
  79. func GetServer(name ...interface{}) *Server {
  80. serverName := defaultServerName
  81. if len(name) > 0 && name[0] != "" {
  82. serverName = gconv.String(name[0])
  83. }
  84. if s := serverMapping.Get(serverName); s != nil {
  85. return s.(*Server)
  86. }
  87. s := &Server{
  88. name: serverName,
  89. plugins: make([]Plugin, 0),
  90. servers: make([]*gracefulServer, 0),
  91. closeChan: make(chan struct{}, 10000),
  92. serverCount: gtype.NewInt(),
  93. statusHandlerMap: make(map[string][]HandlerFunc),
  94. serveTree: make(map[string]interface{}),
  95. serveCache: gcache.New(),
  96. routesMap: make(map[string][]registeredRouteItem),
  97. }
  98. // Initialize the server using default configurations.
  99. if err := s.SetConfig(NewConfig()); err != nil {
  100. panic(gerror.WrapCode(gcode.CodeInvalidConfiguration, err, ""))
  101. }
  102. // Record the server to internal server mapping by name.
  103. serverMapping.Set(serverName, s)
  104. return s
  105. }
  106. // Start starts listening on configured port.
  107. // This function does not block the process, you can use function Wait blocking the process.
  108. func (s *Server) Start() error {
  109. // Register group routes.
  110. s.handlePreBindItems()
  111. // Server process initialization, which can only be initialized once.
  112. serverProcessInit()
  113. // Server can only be run once.
  114. if s.Status() == ServerStatusRunning {
  115. return gerror.NewCode(gcode.CodeInvalidOperation, "server is already running")
  116. }
  117. // Logging path setting check.
  118. if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
  119. if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
  120. return err
  121. }
  122. }
  123. // Default session storage.
  124. if s.config.SessionStorage == nil {
  125. path := ""
  126. if s.config.SessionPath != "" {
  127. path = gfile.Join(s.config.SessionPath, s.name)
  128. if !gfile.Exists(path) {
  129. if err := gfile.Mkdir(path); err != nil {
  130. return gerror.WrapCodef(gcode.CodeInternalError, err, `mkdir failed for "%s"`, path)
  131. }
  132. }
  133. }
  134. s.config.SessionStorage = gsession.NewStorageFile(path)
  135. }
  136. // Initialize session manager when start running.
  137. s.sessionManager = gsession.New(
  138. s.config.SessionMaxAge,
  139. s.config.SessionStorage,
  140. )
  141. // PProf feature.
  142. if s.config.PProfEnabled {
  143. s.EnablePProf(s.config.PProfPattern)
  144. }
  145. // Default HTTP handler.
  146. if s.config.Handler == nil {
  147. s.config.Handler = s
  148. }
  149. // Install external plugins.
  150. for _, p := range s.plugins {
  151. if err := p.Install(s); err != nil {
  152. s.Logger().Fatal(err)
  153. }
  154. }
  155. // Check the group routes again.
  156. s.handlePreBindItems()
  157. // If there's no route registered and no static service enabled,
  158. // it then returns an error of invalid usage of server.
  159. if len(s.routesMap) == 0 && !s.config.FileServerEnabled {
  160. return gerror.NewCode(
  161. gcode.CodeInvalidOperation,
  162. `there's no route set or static feature enabled, did you forget import the router?`,
  163. )
  164. }
  165. // Start the HTTP server.
  166. reloaded := false
  167. fdMapStr := genv.Get(adminActionReloadEnvKey)
  168. if len(fdMapStr) > 0 {
  169. sfm := bufferToServerFdMap([]byte(fdMapStr))
  170. if v, ok := sfm[s.name]; ok {
  171. s.startServer(v)
  172. reloaded = true
  173. }
  174. }
  175. if !reloaded {
  176. s.startServer(nil)
  177. }
  178. // If this is a child process, it then notifies its parent exit.
  179. if gproc.IsChild() {
  180. gtimer.SetTimeout(time.Duration(s.config.GracefulTimeout)*time.Second, func() {
  181. if err := gproc.Send(gproc.PPid(), []byte("exit"), adminGProcCommGroup); err != nil {
  182. intlog.Error(context.TODO(), "server error in process communication:", err)
  183. }
  184. })
  185. }
  186. s.dumpRouterMap()
  187. return nil
  188. }
  189. // DumpRouterMap dumps the router map to the log.
  190. func (s *Server) dumpRouterMap() {
  191. if s.config.DumpRouterMap && len(s.routesMap) > 0 {
  192. buffer := bytes.NewBuffer(nil)
  193. table := tablewriter.NewWriter(buffer)
  194. table.SetHeader([]string{"SERVER", "DOMAIN", "ADDRESS", "METHOD", "ROUTE", "HANDLER", "MIDDLEWARE"})
  195. table.SetRowLine(true)
  196. table.SetBorder(false)
  197. table.SetCenterSeparator("|")
  198. for _, item := range s.GetRouterArray() {
  199. data := make([]string, 7)
  200. data[0] = item.Server
  201. data[1] = item.Domain
  202. data[2] = item.Address
  203. data[3] = item.Method
  204. data[4] = item.Route
  205. data[5] = item.handler.Name
  206. data[6] = item.Middleware
  207. table.Append(data)
  208. }
  209. table.Render()
  210. s.config.Logger.Header(false).Printf("\n%s", buffer.String())
  211. }
  212. }
  213. // GetRouterArray retrieves and returns the router array.
  214. // The key of the returned map is the domain of the server.
  215. func (s *Server) GetRouterArray() []RouterItem {
  216. m := make(map[string]*garray.SortedArray)
  217. address := s.config.Address
  218. if s.config.HTTPSAddr != "" {
  219. if len(address) > 0 {
  220. address += ","
  221. }
  222. address += "tls" + s.config.HTTPSAddr
  223. }
  224. for k, registeredItems := range s.routesMap {
  225. array, _ := gregex.MatchString(`(.*?)%([A-Z]+):(.+)@(.+)`, k)
  226. for index, registeredItem := range registeredItems {
  227. item := RouterItem{
  228. Server: s.name,
  229. Address: address,
  230. Domain: array[4],
  231. Type: registeredItem.Handler.Type,
  232. Middleware: array[1],
  233. Method: array[2],
  234. Route: array[3],
  235. Priority: len(registeredItems) - index - 1,
  236. handler: registeredItem.Handler,
  237. }
  238. switch item.handler.Type {
  239. case handlerTypeController, handlerTypeObject, handlerTypeHandler:
  240. item.IsServiceHandler = true
  241. case handlerTypeMiddleware:
  242. item.Middleware = "GLOBAL MIDDLEWARE"
  243. }
  244. if len(item.handler.Middleware) > 0 {
  245. for _, v := range item.handler.Middleware {
  246. if item.Middleware != "" {
  247. item.Middleware += ","
  248. }
  249. item.Middleware += gdebug.FuncName(v)
  250. }
  251. }
  252. // If the domain does not exist in the dump map, it creates the map.
  253. // The value of the map is a custom sorted array.
  254. if _, ok := m[item.Domain]; !ok {
  255. // Sort in ASC order.
  256. m[item.Domain] = garray.NewSortedArray(func(v1, v2 interface{}) int {
  257. item1 := v1.(RouterItem)
  258. item2 := v2.(RouterItem)
  259. r := 0
  260. if r = strings.Compare(item1.Domain, item2.Domain); r == 0 {
  261. if r = strings.Compare(item1.Route, item2.Route); r == 0 {
  262. if r = strings.Compare(item1.Method, item2.Method); r == 0 {
  263. if item1.handler.Type == handlerTypeMiddleware && item2.handler.Type != handlerTypeMiddleware {
  264. return -1
  265. } else if item1.handler.Type == handlerTypeMiddleware && item2.handler.Type == handlerTypeMiddleware {
  266. return 1
  267. } else if r = strings.Compare(item1.Middleware, item2.Middleware); r == 0 {
  268. r = item2.Priority - item1.Priority
  269. }
  270. }
  271. }
  272. }
  273. return r
  274. })
  275. }
  276. m[item.Domain].Add(item)
  277. }
  278. }
  279. routerArray := make([]RouterItem, 0, 128)
  280. for _, array := range m {
  281. for _, v := range array.Slice() {
  282. routerArray = append(routerArray, v.(RouterItem))
  283. }
  284. }
  285. return routerArray
  286. }
  287. // Run starts server listening in blocking way.
  288. // It's commonly used for single server situation.
  289. func (s *Server) Run() {
  290. if err := s.Start(); err != nil {
  291. s.Logger().Fatal(err)
  292. }
  293. // Blocking using channel.
  294. <-s.closeChan
  295. // Remove plugins.
  296. if len(s.plugins) > 0 {
  297. for _, p := range s.plugins {
  298. intlog.Printf(context.TODO(), `remove plugin: %s`, p.Name())
  299. if err := p.Remove(); err != nil {
  300. intlog.Errorf(context.TODO(), "%+v", err)
  301. }
  302. }
  303. }
  304. s.Logger().Printf("%d: all servers shutdown", gproc.Pid())
  305. }
  306. // Wait blocks to wait for all servers done.
  307. // It's commonly used in multiple servers situation.
  308. func Wait() {
  309. <-allDoneChan
  310. // Remove plugins.
  311. serverMapping.Iterator(func(k string, v interface{}) bool {
  312. s := v.(*Server)
  313. if len(s.plugins) > 0 {
  314. for _, p := range s.plugins {
  315. intlog.Printf(context.TODO(), `remove plugin: %s`, p.Name())
  316. p.Remove()
  317. }
  318. }
  319. return true
  320. })
  321. glog.Printf("%d: all servers shutdown", gproc.Pid())
  322. }
  323. // startServer starts the underlying server listening.
  324. func (s *Server) startServer(fdMap listenerFdMap) {
  325. var httpsEnabled bool
  326. // HTTPS
  327. if s.config.TLSConfig != nil || (s.config.HTTPSCertPath != "" && s.config.HTTPSKeyPath != "") {
  328. if len(s.config.HTTPSAddr) == 0 {
  329. if len(s.config.Address) > 0 {
  330. s.config.HTTPSAddr = s.config.Address
  331. s.config.Address = ""
  332. } else {
  333. s.config.HTTPSAddr = defaultHttpsAddr
  334. }
  335. }
  336. httpsEnabled = len(s.config.HTTPSAddr) > 0
  337. var array []string
  338. if v, ok := fdMap["https"]; ok && len(v) > 0 {
  339. array = strings.Split(v, ",")
  340. } else {
  341. array = strings.Split(s.config.HTTPSAddr, ",")
  342. }
  343. for _, v := range array {
  344. if len(v) == 0 {
  345. continue
  346. }
  347. fd := 0
  348. itemFunc := v
  349. array := strings.Split(v, "#")
  350. if len(array) > 1 {
  351. itemFunc = array[0]
  352. // The windows OS does not support socket file descriptor passing
  353. // from parent process.
  354. if runtime.GOOS != "windows" {
  355. fd = gconv.Int(array[1])
  356. }
  357. }
  358. if fd > 0 {
  359. s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
  360. } else {
  361. s.servers = append(s.servers, s.newGracefulServer(itemFunc))
  362. }
  363. s.servers[len(s.servers)-1].isHttps = true
  364. }
  365. }
  366. // HTTP
  367. if !httpsEnabled && len(s.config.Address) == 0 {
  368. s.config.Address = defaultHttpAddr
  369. }
  370. var array []string
  371. if v, ok := fdMap["http"]; ok && len(v) > 0 {
  372. array = strings.Split(v, ",")
  373. } else {
  374. array = strings.Split(s.config.Address, ",")
  375. }
  376. for _, v := range array {
  377. if len(v) == 0 {
  378. continue
  379. }
  380. fd := 0
  381. itemFunc := v
  382. array := strings.Split(v, "#")
  383. if len(array) > 1 {
  384. itemFunc = array[0]
  385. // The windows OS does not support socket file descriptor passing
  386. // from parent process.
  387. if runtime.GOOS != "windows" {
  388. fd = gconv.Int(array[1])
  389. }
  390. }
  391. if fd > 0 {
  392. s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
  393. } else {
  394. s.servers = append(s.servers, s.newGracefulServer(itemFunc))
  395. }
  396. }
  397. // Start listening asynchronously.
  398. serverRunning.Add(1)
  399. for _, v := range s.servers {
  400. go func(server *gracefulServer) {
  401. s.serverCount.Add(1)
  402. err := (error)(nil)
  403. if server.isHttps {
  404. err = server.ListenAndServeTLS(s.config.HTTPSCertPath, s.config.HTTPSKeyPath, s.config.TLSConfig)
  405. } else {
  406. err = server.ListenAndServe()
  407. }
  408. // The process exits if the server is closed with none closing error.
  409. if err != nil && !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) {
  410. s.Logger().Fatal(err)
  411. }
  412. // If all the underlying servers shutdown, the process exits.
  413. if s.serverCount.Add(-1) < 1 {
  414. s.closeChan <- struct{}{}
  415. if serverRunning.Add(-1) < 1 {
  416. serverMapping.Remove(s.name)
  417. allDoneChan <- struct{}{}
  418. }
  419. }
  420. }(v)
  421. }
  422. }
  423. // Status retrieves and returns the server status.
  424. func (s *Server) Status() int {
  425. if serverRunning.Val() == 0 {
  426. return ServerStatusStopped
  427. }
  428. // If any underlying server is running, the server status is running.
  429. for _, v := range s.servers {
  430. if v.status == ServerStatusRunning {
  431. return ServerStatusRunning
  432. }
  433. }
  434. return ServerStatusStopped
  435. }
  436. // getListenerFdMap retrieves and returns the socket file descriptors.
  437. // The key of the returned map is "http" and "https".
  438. func (s *Server) getListenerFdMap() map[string]string {
  439. m := map[string]string{
  440. "https": "",
  441. "http": "",
  442. }
  443. for _, v := range s.servers {
  444. str := v.address + "#" + gconv.String(v.Fd()) + ","
  445. if v.isHttps {
  446. if len(m["https"]) > 0 {
  447. m["https"] += ","
  448. }
  449. m["https"] += str
  450. } else {
  451. if len(m["http"]) > 0 {
  452. m["http"] += ","
  453. }
  454. m["http"] += str
  455. }
  456. }
  457. return m
  458. }
  459. // IsExitError checks if given error is an exit error of server.
  460. // This is used in old version of server for custom error handler.
  461. // Deprecated.
  462. func IsExitError(err interface{}) bool {
  463. errStr := gconv.String(err)
  464. if strings.EqualFold(errStr, exceptionExit) ||
  465. strings.EqualFold(errStr, exceptionExitAll) ||
  466. strings.EqualFold(errStr, exceptionExitHook) {
  467. return true
  468. }
  469. return false
  470. }