| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-02-15 21:29:20 +08:00
										 |  |  | 	"crypto/tls" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-04-27 14:54:21 +08:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/live" | 
					
						
							| 
									
										
										
										
											2019-01-16 21:53:59 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/routing" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	httpstatic "github.com/grafana/grafana/pkg/api/static" | 
					
						
							| 
									
										
										
										
											2017-04-25 23:17:45 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/bus" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/components/simplejson" | 
					
						
							| 
									
										
										
										
											2019-06-13 16:55:38 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/localcache" | 
					
						
							| 
									
										
										
										
											2019-05-13 14:45:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2019-04-08 19:31:46 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/remotecache" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/middleware" | 
					
						
							| 
									
										
										
										
											2017-04-25 23:17:45 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							| 
									
										
										
										
											2018-05-01 21:51:15 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/registry" | 
					
						
							| 
									
										
										
										
											2018-10-26 16:40:33 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/datasources" | 
					
						
							| 
									
										
										
										
											2018-10-12 17:26:42 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/hooks" | 
					
						
							| 
									
										
										
										
											2019-06-13 22:47:52 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/login" | 
					
						
							| 
									
										
										
										
											2019-02-12 04:12:01 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/quota" | 
					
						
							| 
									
										
										
										
											2018-05-24 21:26:27 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/rendering" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2019-11-18 16:49:08 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util/errutil" | 
					
						
							| 
									
										
										
										
											2019-01-16 21:53:59 +08:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | 	"github.com/prometheus/client_golang/prometheus/promhttp" | 
					
						
							| 
									
										
										
										
											2019-05-27 23:47:29 +08:00
										 |  |  | 	macaron "gopkg.in/macaron.v1" | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 21:51:15 +08:00
										 |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2018-07-01 22:01:43 +08:00
										 |  |  | 	registry.Register(®istry.Descriptor{ | 
					
						
							|  |  |  | 		Name:         "HTTPServer", | 
					
						
							|  |  |  | 		Instance:     &HTTPServer{}, | 
					
						
							|  |  |  | 		InitPriority: registry.High, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2018-05-01 21:51:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-30 19:32:18 +08:00
										 |  |  | type ProvisioningService interface { | 
					
						
							|  |  |  | 	ProvisionDatasources() error | 
					
						
							|  |  |  | 	ProvisionNotifications() error | 
					
						
							|  |  |  | 	ProvisionDashboards() error | 
					
						
							|  |  |  | 	GetDashboardProvisionerResolvedPath(name string) string | 
					
						
							| 
									
										
										
										
											2019-10-31 21:27:31 +08:00
										 |  |  | 	GetAllowUiUpdatesFromConfig(name string) bool | 
					
						
							| 
									
										
										
										
											2019-04-30 19:32:18 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 05:13:46 +08:00
										 |  |  | type HTTPServer struct { | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	log           log.Logger | 
					
						
							|  |  |  | 	macaron       *macaron.Macaron | 
					
						
							|  |  |  | 	context       context.Context | 
					
						
							|  |  |  | 	streamManager *live.StreamManager | 
					
						
							| 
									
										
										
										
											2018-04-30 22:21:04 +08:00
										 |  |  | 	httpSrv       *http.Server | 
					
						
							| 
									
										
										
										
											2017-02-06 16:40:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:15:50 +08:00
										 |  |  | 	RouteRegister        routing.RouteRegister    `inject:""` | 
					
						
							|  |  |  | 	Bus                  bus.Bus                  `inject:""` | 
					
						
							|  |  |  | 	RenderService        rendering.Service        `inject:""` | 
					
						
							|  |  |  | 	Cfg                  *setting.Cfg             `inject:""` | 
					
						
							|  |  |  | 	HooksService         *hooks.HooksService      `inject:""` | 
					
						
							|  |  |  | 	CacheService         *localcache.CacheService `inject:""` | 
					
						
							|  |  |  | 	DatasourceCache      datasources.CacheService `inject:""` | 
					
						
							|  |  |  | 	AuthTokenService     models.UserTokenService  `inject:""` | 
					
						
							|  |  |  | 	QuotaService         *quota.QuotaService      `inject:""` | 
					
						
							|  |  |  | 	RemoteCacheService   *remotecache.RemoteCache `inject:""` | 
					
						
							|  |  |  | 	ProvisioningService  ProvisioningService      `inject:""` | 
					
						
							|  |  |  | 	Login                *login.LoginService      `inject:""` | 
					
						
							|  |  |  | 	License              models.Licensing         `inject:""` | 
					
						
							|  |  |  | 	BackendPluginManager backendplugin.Manager    `inject:""` | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 21:51:15 +08:00
										 |  |  | func (hs *HTTPServer) Init() error { | 
					
						
							| 
									
										
										
										
											2018-04-27 19:41:58 +08:00
										 |  |  | 	hs.log = log.New("http.server") | 
					
						
							| 
									
										
										
										
											2018-05-01 21:51:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-01 22:01:43 +08:00
										 |  |  | 	hs.streamManager = live.NewStreamManager() | 
					
						
							|  |  |  | 	hs.macaron = hs.newMacaron() | 
					
						
							|  |  |  | 	hs.registerRoutes() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 21:51:15 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-01 21:51:15 +08:00
										 |  |  | func (hs *HTTPServer) Run(ctx context.Context) error { | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	hs.context = ctx | 
					
						
							| 
									
										
										
										
											2018-07-02 14:35:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-01 22:01:43 +08:00
										 |  |  | 	hs.applyRoutes() | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	hs.streamManager.Run(ctx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	hs.httpSrv = &http.Server{ | 
					
						
							|  |  |  | 		Addr:    fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort), | 
					
						
							|  |  |  | 		Handler: hs.macaron, | 
					
						
							| 
									
										
										
										
											2019-10-22 19:07:43 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	switch setting.Protocol { | 
					
						
							| 
									
										
										
										
											2019-08-16 23:06:54 +08:00
										 |  |  | 	case setting.HTTP2: | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 		if err := hs.configureHttp2(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2019-08-16 23:06:54 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	case setting.HTTPS: | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 		if err := hs.configureHttps(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var listener net.Listener | 
					
						
							|  |  |  | 	switch setting.Protocol { | 
					
						
							|  |  |  | 	case setting.HTTP, setting.HTTPS, setting.HTTP2: | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		listener, err = net.Listen("tcp", hs.httpSrv.Addr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return errutil.Wrapf(err, "failed to open listener on address %s", hs.httpSrv.Addr) | 
					
						
							| 
									
										
										
										
											2017-02-06 16:40:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-27 14:54:21 +08:00
										 |  |  | 	case setting.SOCKET: | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 		var err error | 
					
						
							|  |  |  | 		listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: setting.SocketPath, Net: "unix"}) | 
					
						
							| 
									
										
										
										
											2017-04-27 14:54:21 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 			return errutil.Wrapf(err, "failed to open listener for socket %s", setting.SocketPath) | 
					
						
							| 
									
										
										
										
											2017-04-27 14:54:21 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-22 21:14:44 +08:00
										 |  |  | 		// Make socket writable by group
 | 
					
						
							| 
									
										
										
										
											2019-10-09 00:57:53 +08:00
										 |  |  | 		if err := os.Chmod(setting.SocketPath, 0660); err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 			return errutil.Wrapf(err, "failed to change socket permissions") | 
					
						
							| 
									
										
										
										
											2019-10-09 00:57:53 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		hs.log.Error("Invalid protocol", "protocol", setting.Protocol) | 
					
						
							|  |  |  | 		return fmt.Errorf("invalid protocol %q", setting.Protocol) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-22 21:14:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	hs.log.Info("HTTP Server Listen", "address", listener.Addr().String(), "protocol", | 
					
						
							|  |  |  | 		setting.Protocol, "subUrl", setting.AppSubUrl, "socket", setting.SocketPath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var wg sync.WaitGroup | 
					
						
							|  |  |  | 	wg.Add(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// handle http shutdown on server context done
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2019-11-27 20:42:15 +08:00
										 |  |  | 		defer wg.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 		<-ctx.Done() | 
					
						
							|  |  |  | 		if err := hs.httpSrv.Shutdown(context.Background()); err != nil { | 
					
						
							|  |  |  | 			hs.log.Error("Failed to shutdown server", "error", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch setting.Protocol { | 
					
						
							|  |  |  | 	case setting.HTTP, setting.SOCKET: | 
					
						
							|  |  |  | 		if err := hs.httpSrv.Serve(listener); err != nil { | 
					
						
							|  |  |  | 			if err == http.ErrServerClosed { | 
					
						
							|  |  |  | 				hs.log.Debug("server was shutdown gracefully") | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case setting.HTTP2, setting.HTTPS: | 
					
						
							|  |  |  | 		if err := hs.httpSrv.ServeTLS(listener, setting.CertFile, setting.KeyFile); err != nil { | 
					
						
							|  |  |  | 			if err == http.ErrServerClosed { | 
					
						
							|  |  |  | 				hs.log.Debug("server was shutdown gracefully") | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2017-04-27 14:54:21 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 		panic(fmt.Sprintf("Unhandled protocol %q", setting.Protocol)) | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	wg.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | func (hs *HTTPServer) configureHttps() error { | 
					
						
							|  |  |  | 	if setting.CertFile == "" { | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 		return fmt.Errorf("cert_file cannot be empty when using HTTPS") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	if setting.KeyFile == "" { | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 		return fmt.Errorf("cert_key cannot be empty when using HTTPS") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) { | 
					
						
							|  |  |  | 		return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) { | 
					
						
							|  |  |  | 		return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 21:29:20 +08:00
										 |  |  | 	tlsCfg := &tls.Config{ | 
					
						
							|  |  |  | 		MinVersion:               tls.VersionTLS12, | 
					
						
							|  |  |  | 		PreferServerCipherSuites: true, | 
					
						
							|  |  |  | 		CipherSuites: []uint16{ | 
					
						
							| 
									
										
										
										
											2020-02-19 01:58:36 +08:00
										 |  |  | 			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | 
					
						
							|  |  |  | 			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | 
					
						
							|  |  |  | 			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | 
					
						
							|  |  |  | 			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | 
					
						
							| 
									
										
										
										
											2017-02-15 21:29:20 +08:00
										 |  |  | 			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, | 
					
						
							|  |  |  | 			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, | 
					
						
							| 
									
										
										
										
											2020-02-19 01:58:36 +08:00
										 |  |  | 			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, | 
					
						
							| 
									
										
										
										
											2017-02-15 21:29:20 +08:00
										 |  |  | 			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, | 
					
						
							| 
									
										
										
										
											2020-02-19 01:58:36 +08:00
										 |  |  | 			tls.TLS_RSA_WITH_AES_128_GCM_SHA256, | 
					
						
							|  |  |  | 			tls.TLS_RSA_WITH_AES_256_GCM_SHA384, | 
					
						
							|  |  |  | 			tls.TLS_RSA_WITH_AES_128_CBC_SHA, | 
					
						
							|  |  |  | 			tls.TLS_RSA_WITH_AES_256_CBC_SHA, | 
					
						
							| 
									
										
										
										
											2017-02-15 21:29:20 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-18 05:10:12 +08:00
										 |  |  | 	hs.httpSrv.TLSConfig = tlsCfg | 
					
						
							| 
									
										
										
										
											2018-04-17 02:22:12 +08:00
										 |  |  | 	hs.httpSrv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) | 
					
						
							| 
									
										
										
										
											2017-06-18 05:10:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | func (hs *HTTPServer) configureHttp2() error { | 
					
						
							|  |  |  | 	if setting.CertFile == "" { | 
					
						
							| 
									
										
										
										
											2019-08-16 23:06:54 +08:00
										 |  |  | 		return fmt.Errorf("cert_file cannot be empty when using HTTP2") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	if setting.KeyFile == "" { | 
					
						
							| 
									
										
										
										
											2019-08-16 23:06:54 +08:00
										 |  |  | 		return fmt.Errorf("cert_key cannot be empty when using HTTP2") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) { | 
					
						
							|  |  |  | 		return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) { | 
					
						
							|  |  |  | 		return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tlsCfg := &tls.Config{ | 
					
						
							|  |  |  | 		MinVersion:               tls.VersionTLS12, | 
					
						
							|  |  |  | 		PreferServerCipherSuites: false, | 
					
						
							|  |  |  | 		CipherSuites: []uint16{ | 
					
						
							|  |  |  | 			tls.TLS_CHACHA20_POLY1305_SHA256, | 
					
						
							|  |  |  | 			tls.TLS_AES_128_GCM_SHA256, | 
					
						
							|  |  |  | 			tls.TLS_AES_256_GCM_SHA384, | 
					
						
							|  |  |  | 			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | 
					
						
							|  |  |  | 			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | 
					
						
							| 
									
										
										
										
											2020-02-19 01:58:36 +08:00
										 |  |  | 			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | 
					
						
							| 
									
										
										
										
											2019-08-16 23:06:54 +08:00
										 |  |  | 			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | 
					
						
							| 
									
										
										
										
											2020-02-19 01:58:36 +08:00
										 |  |  | 			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, | 
					
						
							|  |  |  | 			tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, | 
					
						
							| 
									
										
										
										
											2019-08-16 23:06:54 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		NextProtos: []string{"h2", "http/1.1"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hs.httpSrv.TLSConfig = tlsCfg | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 19:07:21 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2019-08-16 23:06:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 05:13:46 +08:00
										 |  |  | func (hs *HTTPServer) newMacaron() *macaron.Macaron { | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	macaron.Env = setting.Env | 
					
						
							|  |  |  | 	m := macaron.New() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-02 14:35:50 +08:00
										 |  |  | 	// automatically set HEAD for every GET
 | 
					
						
							|  |  |  | 	m.SetAutoHead(true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return m | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (hs *HTTPServer) applyRoutes() { | 
					
						
							|  |  |  | 	// start with middlewares & static routes
 | 
					
						
							|  |  |  | 	hs.addMiddlewaresAndStaticRoutes() | 
					
						
							|  |  |  | 	// then add view routes & api routes
 | 
					
						
							|  |  |  | 	hs.RouteRegister.Register(hs.macaron) | 
					
						
							|  |  |  | 	// then custom app proxy routes
 | 
					
						
							|  |  |  | 	hs.initAppPluginRoutes(hs.macaron) | 
					
						
							|  |  |  | 	// lastly not found route
 | 
					
						
							| 
									
										
										
										
											2018-10-12 17:26:42 +08:00
										 |  |  | 	hs.macaron.NotFound(hs.NotFoundHandler) | 
					
						
							| 
									
										
										
										
											2018-07-02 14:35:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { | 
					
						
							|  |  |  | 	m := hs.macaron | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	m.Use(middleware.Logger()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if setting.EnableGzip { | 
					
						
							|  |  |  | 		m.Use(middleware.Gziper()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-15 20:51:15 +08:00
										 |  |  | 	m.Use(middleware.Recovery()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	for _, route := range plugins.StaticRoutes { | 
					
						
							|  |  |  | 		pluginRoute := path.Join("/public/plugins/", route.PluginId) | 
					
						
							| 
									
										
										
										
											2017-10-12 21:29:01 +08:00
										 |  |  | 		hs.log.Debug("Plugins: Adding route", "route", pluginRoute, "dir", route.Directory) | 
					
						
							| 
									
										
										
										
											2019-11-29 23:34:20 +08:00
										 |  |  | 		hs.mapStatic(m, route.Directory, "", pluginRoute) | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 19:54:00 +08:00
										 |  |  | 	hs.mapStatic(m, setting.StaticRootPath, "build", "public/build") | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	hs.mapStatic(m, setting.StaticRootPath, "", "public") | 
					
						
							|  |  |  | 	hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-31 06:01:51 +08:00
										 |  |  | 	if setting.ImageUploadProvider == "local" { | 
					
						
							| 
									
										
										
										
											2018-05-24 21:26:27 +08:00
										 |  |  | 		hs.mapStatic(m, hs.Cfg.ImagesDir, "", "/public/img/attachments") | 
					
						
							| 
									
										
										
										
											2017-12-31 06:01:51 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-06 15:22:59 +08:00
										 |  |  | 	m.Use(middleware.AddDefaultResponseHeaders()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-27 23:47:29 +08:00
										 |  |  | 	if setting.ServeFromSubPath && setting.AppSubUrl != "" { | 
					
						
							|  |  |  | 		m.SetURLPrefix(setting.AppSubUrl) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	m.Use(macaron.Renderer(macaron.RenderOptions{ | 
					
						
							|  |  |  | 		Directory:  path.Join(setting.StaticRootPath, "views"), | 
					
						
							|  |  |  | 		IndentJSON: macaron.Env != macaron.PROD, | 
					
						
							|  |  |  | 		Delims:     macaron.Delims{Left: "[[", Right: "]]"}, | 
					
						
							|  |  |  | 	})) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-25 23:17:45 +08:00
										 |  |  | 	m.Use(hs.healthHandler) | 
					
						
							| 
									
										
										
										
											2017-09-07 04:24:10 +08:00
										 |  |  | 	m.Use(hs.metricsEndpoint) | 
					
						
							| 
									
										
										
										
											2019-04-08 19:31:46 +08:00
										 |  |  | 	m.Use(middleware.GetContextHandler( | 
					
						
							|  |  |  | 		hs.AuthTokenService, | 
					
						
							|  |  |  | 		hs.RemoteCacheService, | 
					
						
							|  |  |  | 	)) | 
					
						
							| 
									
										
										
										
											2017-02-17 22:02:14 +08:00
										 |  |  | 	m.Use(middleware.OrgRedirect()) | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// needs to be after context handler
 | 
					
						
							|  |  |  | 	if setting.EnforceDomain { | 
					
						
							|  |  |  | 		m.Use(middleware.ValidateHostHeader(setting.Domain)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 16:40:33 +08:00
										 |  |  | 	m.Use(middleware.HandleNoCacheHeader()) | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 05:13:46 +08:00
										 |  |  | func (hs *HTTPServer) metricsEndpoint(ctx *macaron.Context) { | 
					
						
							| 
									
										
										
										
											2018-09-13 20:36:16 +08:00
										 |  |  | 	if !hs.Cfg.MetricsEndpointEnabled { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-12 13:27:47 +08:00
										 |  |  | 	if ctx.Req.Method != http.MethodGet || ctx.Req.URL.Path != "/metrics" { | 
					
						
							| 
									
										
										
										
											2017-09-07 04:24:10 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-20 02:15:18 +08:00
										 |  |  | 	if hs.metricsEndpointBasicAuthEnabled() && !BasicAuthenticatedRequest(ctx.Req, hs.Cfg.MetricsEndpointBasicAuthUsername, hs.Cfg.MetricsEndpointBasicAuthPassword) { | 
					
						
							| 
									
										
										
										
											2018-11-15 06:37:32 +08:00
										 |  |  | 		ctx.Resp.WriteHeader(http.StatusUnauthorized) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2018-11-15 04:42:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-15 13:33:48 +08:00
										 |  |  | 	promhttp. | 
					
						
							|  |  |  | 		HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{}). | 
					
						
							| 
									
										
										
										
											2017-10-23 15:35:46 +08:00
										 |  |  | 		ServeHTTP(ctx.Resp, ctx.Req.Request) | 
					
						
							| 
									
										
										
										
											2017-09-07 04:24:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 05:13:46 +08:00
										 |  |  | func (hs *HTTPServer) healthHandler(ctx *macaron.Context) { | 
					
						
							| 
									
										
										
										
											2017-11-21 22:01:59 +08:00
										 |  |  | 	notHeadOrGet := ctx.Req.Method != http.MethodGet && ctx.Req.Method != http.MethodHead | 
					
						
							|  |  |  | 	if notHeadOrGet || ctx.Req.URL.Path != "/api/health" { | 
					
						
							| 
									
										
										
										
											2017-04-25 23:17:45 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data := simplejson.New() | 
					
						
							| 
									
										
										
										
											2017-04-25 23:23:38 +08:00
										 |  |  | 	data.Set("database", "ok") | 
					
						
							| 
									
										
										
										
											2017-04-25 23:17:45 +08:00
										 |  |  | 	data.Set("version", setting.BuildVersion) | 
					
						
							|  |  |  | 	data.Set("commit", setting.BuildCommit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := bus.Dispatch(&models.GetDBHealthQuery{}); err != nil { | 
					
						
							| 
									
										
										
										
											2017-04-25 23:24:36 +08:00
										 |  |  | 		data.Set("database", "failing") | 
					
						
							| 
									
										
										
										
											2017-05-10 21:23:59 +08:00
										 |  |  | 		ctx.Resp.Header().Set("Content-Type", "application/json; charset=UTF-8") | 
					
						
							|  |  |  | 		ctx.Resp.WriteHeader(503) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ctx.Resp.Header().Set("Content-Type", "application/json; charset=UTF-8") | 
					
						
							|  |  |  | 		ctx.Resp.WriteHeader(200) | 
					
						
							| 
									
										
										
										
											2017-04-25 23:17:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dataBytes, _ := data.EncodePretty() | 
					
						
							| 
									
										
										
										
											2019-10-09 00:57:53 +08:00
										 |  |  | 	if _, err := ctx.Resp.Write(dataBytes); err != nil { | 
					
						
							|  |  |  | 		hs.log.Error("Failed to write to response", "err", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-25 23:17:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 05:13:46 +08:00
										 |  |  | func (hs *HTTPServer) mapStatic(m *macaron.Macaron, rootDir string, dir string, prefix string) { | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	headers := func(c *macaron.Context) { | 
					
						
							|  |  |  | 		c.Resp.Header().Set("Cache-Control", "public, max-age=3600") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 19:54:00 +08:00
										 |  |  | 	if prefix == "public/build" { | 
					
						
							|  |  |  | 		headers = func(c *macaron.Context) { | 
					
						
							|  |  |  | 			c.Resp.Header().Set("Cache-Control", "public, max-age=31536000") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 21:36:32 +08:00
										 |  |  | 	if setting.Env == setting.DEV { | 
					
						
							|  |  |  | 		headers = func(c *macaron.Context) { | 
					
						
							|  |  |  | 			c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m.Use(httpstatic.Static( | 
					
						
							|  |  |  | 		path.Join(rootDir, dir), | 
					
						
							|  |  |  | 		httpstatic.StaticOptions{ | 
					
						
							|  |  |  | 			SkipLogging: true, | 
					
						
							|  |  |  | 			Prefix:      prefix, | 
					
						
							|  |  |  | 			AddHeaders:  headers, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	)) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-11-20 02:15:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (hs *HTTPServer) metricsEndpointBasicAuthEnabled() bool { | 
					
						
							|  |  |  | 	return hs.Cfg.MetricsEndpointBasicAuthUsername != "" && hs.Cfg.MetricsEndpointBasicAuthPassword != "" | 
					
						
							|  |  |  | } |