http_server.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package api
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "os"
  8. "path"
  9. macaron "gopkg.in/macaron.v1"
  10. "github.com/grafana/grafana/pkg/api/live"
  11. httpstatic "github.com/grafana/grafana/pkg/api/static"
  12. "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
  13. "github.com/grafana/grafana/pkg/log"
  14. "github.com/grafana/grafana/pkg/middleware"
  15. "github.com/grafana/grafana/pkg/plugins"
  16. "github.com/grafana/grafana/pkg/setting"
  17. )
  18. type HttpServer struct {
  19. log log.Logger
  20. macaron *macaron.Macaron
  21. context context.Context
  22. streamManager *live.StreamManager
  23. }
  24. func NewHttpServer() *HttpServer {
  25. return &HttpServer{
  26. log: log.New("http.server"),
  27. }
  28. }
  29. func (hs *HttpServer) Start(ctx context.Context) error {
  30. var err error
  31. hs.context = ctx
  32. hs.streamManager = live.NewStreamManager()
  33. hs.macaron = hs.newMacaron()
  34. hs.registerRoutes()
  35. hs.streamManager.Run(ctx)
  36. listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
  37. hs.log.Info("Initializing HTTP Server", "address", listenAddr, "protocol", setting.Protocol, "subUrl", setting.AppSubUrl)
  38. switch setting.Protocol {
  39. case setting.HTTP:
  40. err = http.ListenAndServe(listenAddr, hs.macaron)
  41. case setting.HTTPS:
  42. err = hs.listenAndServeTLS(listenAddr, setting.CertFile, setting.KeyFile)
  43. default:
  44. hs.log.Error("Invalid protocol", "protocol", setting.Protocol)
  45. err = errors.New("Invalid Protocol")
  46. }
  47. return err
  48. }
  49. func (hs *HttpServer) listenAndServeTLS(listenAddr, certfile, keyfile string) error {
  50. if certfile == "" {
  51. return fmt.Errorf("cert_file cannot be empty when using HTTPS")
  52. }
  53. if keyfile == "" {
  54. return fmt.Errorf("cert_key cannot be empty when using HTTPS")
  55. }
  56. if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) {
  57. return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile)
  58. }
  59. if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) {
  60. return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile)
  61. }
  62. return http.ListenAndServeTLS(listenAddr, setting.CertFile, setting.KeyFile, hs.macaron)
  63. }
  64. func (hs *HttpServer) newMacaron() *macaron.Macaron {
  65. macaron.Env = setting.Env
  66. m := macaron.New()
  67. m.Use(middleware.Logger())
  68. m.Use(middleware.Recovery())
  69. if setting.EnableGzip {
  70. m.Use(middleware.Gziper())
  71. }
  72. for _, route := range plugins.StaticRoutes {
  73. pluginRoute := path.Join("/public/plugins/", route.PluginId)
  74. logger.Debug("Plugins: Adding route", "route", pluginRoute, "dir", route.Directory)
  75. hs.mapStatic(m, route.Directory, "", pluginRoute)
  76. }
  77. hs.mapStatic(m, setting.StaticRootPath, "", "public")
  78. hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt")
  79. m.Use(macaron.Renderer(macaron.RenderOptions{
  80. Directory: path.Join(setting.StaticRootPath, "views"),
  81. IndentJSON: macaron.Env != macaron.PROD,
  82. Delims: macaron.Delims{Left: "[[", Right: "]]"},
  83. }))
  84. m.Use(middleware.GetContextHandler())
  85. m.Use(middleware.Sessioner(&setting.SessionOptions))
  86. m.Use(middleware.RequestMetrics())
  87. // needs to be after context handler
  88. if setting.EnforceDomain {
  89. m.Use(middleware.ValidateHostHeader(setting.Domain))
  90. }
  91. return m
  92. }
  93. func (hs *HttpServer) mapStatic(m *macaron.Macaron, rootDir string, dir string, prefix string) {
  94. headers := func(c *macaron.Context) {
  95. c.Resp.Header().Set("Cache-Control", "public, max-age=3600")
  96. }
  97. if setting.Env == setting.DEV {
  98. headers = func(c *macaron.Context) {
  99. c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache")
  100. }
  101. }
  102. m.Use(httpstatic.Static(
  103. path.Join(rootDir, dir),
  104. httpstatic.StaticOptions{
  105. SkipLogging: true,
  106. Prefix: prefix,
  107. AddHeaders: headers,
  108. },
  109. ))
  110. }