THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

235 lignes
7.1KB

  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package cmd
  5. import (
  6. "fmt"
  7. "net"
  8. "net/http"
  9. "net/http/fcgi"
  10. _ "net/http/pprof" // Used for debugging if enabled and a web server is running
  11. "os"
  12. "strings"
  13. "code.gitea.io/gitea/modules/graceful"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/setting"
  16. "code.gitea.io/gitea/routers"
  17. "code.gitea.io/gitea/routers/routes"
  18. context2 "github.com/gorilla/context"
  19. "github.com/unknwon/com"
  20. "github.com/urfave/cli"
  21. "golang.org/x/crypto/acme/autocert"
  22. ini "gopkg.in/ini.v1"
  23. )
  24. // CmdWeb represents the available web sub-command.
  25. var CmdWeb = cli.Command{
  26. Name: "web",
  27. Usage: "Start Gitea web server",
  28. Description: `Gitea web server is the only thing you need to run,
  29. and it takes care of all the other things for you`,
  30. Action: runWeb,
  31. Flags: []cli.Flag{
  32. cli.StringFlag{
  33. Name: "port, p",
  34. Value: "3000",
  35. Usage: "Temporary port number to prevent conflict",
  36. },
  37. cli.StringFlag{
  38. Name: "pid, P",
  39. Value: "/var/run/gitea.pid",
  40. Usage: "Custom pid file path",
  41. },
  42. },
  43. }
  44. func runHTTPRedirector() {
  45. source := fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.PortToRedirect)
  46. dest := strings.TrimSuffix(setting.AppURL, "/")
  47. log.Info("Redirecting: %s to %s", source, dest)
  48. handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  49. target := dest + r.URL.Path
  50. if len(r.URL.RawQuery) > 0 {
  51. target += "?" + r.URL.RawQuery
  52. }
  53. http.Redirect(w, r, target, http.StatusTemporaryRedirect)
  54. })
  55. var err = runHTTP(source, context2.ClearHandler(handler))
  56. if err != nil {
  57. log.Fatal("Failed to start port redirection: %v", err)
  58. }
  59. }
  60. func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error {
  61. certManager := autocert.Manager{
  62. Prompt: autocert.AcceptTOS,
  63. HostPolicy: autocert.HostWhitelist(domain),
  64. Cache: autocert.DirCache(directory),
  65. Email: email,
  66. }
  67. go func() {
  68. log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
  69. // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
  70. var err = runHTTP(setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
  71. if err != nil {
  72. log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
  73. }
  74. }()
  75. return runHTTPSWithTLSConfig(listenAddr, certManager.TLSConfig(), context2.ClearHandler(m))
  76. }
  77. func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
  78. if r.Method != "GET" && r.Method != "HEAD" {
  79. http.Error(w, "Use HTTPS", http.StatusBadRequest)
  80. return
  81. }
  82. // Remove the trailing slash at the end of setting.AppURL, the request
  83. // URI always contains a leading slash, which would result in a double
  84. // slash
  85. target := strings.TrimRight(setting.AppURL, "/") + r.URL.RequestURI()
  86. http.Redirect(w, r, target, http.StatusFound)
  87. }
  88. func runWeb(ctx *cli.Context) error {
  89. if os.Getppid() > 1 && len(os.Getenv("LISTEN_FDS")) > 0 {
  90. log.Info("Restarting Gitea on PID: %d from parent PID: %d", os.Getpid(), os.Getppid())
  91. } else {
  92. log.Info("Starting Gitea on PID: %d", os.Getpid())
  93. }
  94. // Set pid file setting
  95. if ctx.IsSet("pid") {
  96. setting.CustomPID = ctx.String("pid")
  97. }
  98. // Perform global initialization
  99. routers.GlobalInit()
  100. // Set up Macaron
  101. m := routes.NewMacaron()
  102. routes.RegisterRoutes(m)
  103. // Flag for port number in case first time run conflict.
  104. if ctx.IsSet("port") {
  105. setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, ctx.String("port"), 1)
  106. setting.HTTPPort = ctx.String("port")
  107. switch setting.Protocol {
  108. case setting.UnixSocket:
  109. case setting.FCGI:
  110. default:
  111. // Save LOCAL_ROOT_URL if port changed
  112. cfg := ini.Empty()
  113. if com.IsFile(setting.CustomConf) {
  114. // Keeps custom settings if there is already something.
  115. if err := cfg.Append(setting.CustomConf); err != nil {
  116. return fmt.Errorf("Failed to load custom conf '%s': %v", setting.CustomConf, err)
  117. }
  118. }
  119. defaultLocalURL := string(setting.Protocol) + "://"
  120. if setting.HTTPAddr == "0.0.0.0" {
  121. defaultLocalURL += "localhost"
  122. } else {
  123. defaultLocalURL += setting.HTTPAddr
  124. }
  125. defaultLocalURL += ":" + setting.HTTPPort + "/"
  126. cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
  127. if err := cfg.SaveTo(setting.CustomConf); err != nil {
  128. return fmt.Errorf("Error saving generated JWT Secret to custom config: %v", err)
  129. }
  130. }
  131. }
  132. listenAddr := setting.HTTPAddr
  133. if setting.Protocol != setting.UnixSocket {
  134. listenAddr += ":" + setting.HTTPPort
  135. }
  136. log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
  137. if setting.LFS.StartServer {
  138. log.Info("LFS server enabled")
  139. }
  140. if setting.EnablePprof {
  141. go func() {
  142. log.Info("Starting pprof server on localhost:6060")
  143. log.Info("%v", http.ListenAndServe("localhost:6060", nil))
  144. }()
  145. }
  146. var err error
  147. switch setting.Protocol {
  148. case setting.HTTP:
  149. NoHTTPRedirector()
  150. err = runHTTP(listenAddr, context2.ClearHandler(m))
  151. case setting.HTTPS:
  152. if setting.EnableLetsEncrypt {
  153. err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
  154. break
  155. }
  156. if setting.RedirectOtherPort {
  157. go runHTTPRedirector()
  158. } else {
  159. NoHTTPRedirector()
  160. }
  161. err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
  162. case setting.FCGI:
  163. NoHTTPRedirector()
  164. // FCGI listeners are provided as stdin - this is orthogonal to the LISTEN_FDS approach
  165. // in graceful and systemD
  166. NoMainListener()
  167. var listener net.Listener
  168. listener, err = net.Listen("tcp", listenAddr)
  169. if err != nil {
  170. log.Fatal("Failed to bind %s: %v", listenAddr, err)
  171. }
  172. defer func() {
  173. if err := listener.Close(); err != nil {
  174. log.Fatal("Failed to stop server: %v", err)
  175. }
  176. }()
  177. err = fcgi.Serve(listener, context2.ClearHandler(m))
  178. case setting.UnixSocket:
  179. // This could potentially be inherited using LISTEN_FDS but currently
  180. // these cannot be inherited
  181. NoHTTPRedirector()
  182. NoMainListener()
  183. if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) {
  184. log.Fatal("Failed to remove unix socket directory %s: %v", listenAddr, err)
  185. }
  186. var listener *net.UnixListener
  187. listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: listenAddr, Net: "unix"})
  188. if err != nil {
  189. break // Handle error after switch
  190. }
  191. // FIXME: add proper implementation of signal capture on all protocols
  192. // execute this on SIGTERM or SIGINT: listener.Close()
  193. if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
  194. log.Fatal("Failed to set permission of unix socket: %v", err)
  195. }
  196. err = http.Serve(listener, context2.ClearHandler(m))
  197. default:
  198. log.Fatal("Invalid protocol: %s", setting.Protocol)
  199. }
  200. if err != nil {
  201. log.Critical("Failed to start server: %v", err)
  202. }
  203. log.Info("HTTP Listener: %s Closed", listenAddr)
  204. graceful.Manager.WaitForServers()
  205. graceful.Manager.WaitForTerminate()
  206. log.Close()
  207. return nil
  208. }