ghttp_server.go 14 KB

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