| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | package restserver | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2023-03-23 19:19:18 +01:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | 	"log" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/gorilla/handlers" | 
					
						
							| 
									
										
											  
											
												Add Prometheus metrics
Exposes a few metrics for Prometheus under /metrics if started with --prometheus.
Example:
    # HELP rest_server_blob_read_bytes_total Total number of bytes read from blobs
    # TYPE rest_server_blob_read_bytes_total counter
    rest_server_blob_read_bytes_total{repo="test",type="data"} 2.13557024e+09
    rest_server_blob_read_bytes_total{repo="test",type="index"} 1.198653e+06
    rest_server_blob_read_bytes_total{repo="test",type="keys"} 5388
    rest_server_blob_read_bytes_total{repo="test",type="locks"} 1975
    rest_server_blob_read_bytes_total{repo="test",type="snapshots"} 10018
    # HELP rest_server_blob_read_total Total number of blobs read
    # TYPE rest_server_blob_read_total counter
    rest_server_blob_read_total{repo="test",type="data"} 3985
    rest_server_blob_read_total{repo="test",type="index"} 21
    rest_server_blob_read_total{repo="test",type="keys"} 12
    rest_server_blob_read_total{repo="test",type="locks"} 12
    rest_server_blob_read_total{repo="test",type="snapshots"} 32
    # HELP rest_server_blob_write_bytes_total Total number of bytes written to blobs
    # TYPE rest_server_blob_write_bytes_total counter
    rest_server_blob_write_bytes_total{repo="test",type="data"} 1.063726179e+09
    rest_server_blob_write_bytes_total{repo="test",type="index"} 395586
    rest_server_blob_write_bytes_total{repo="test",type="locks"} 1975
    rest_server_blob_write_bytes_total{repo="test",type="snapshots"} 1933
    # HELP rest_server_blob_write_total Total number of blobs written
    # TYPE rest_server_blob_write_total counter
    rest_server_blob_write_total{repo="test",type="data"} 226
    rest_server_blob_write_total{repo="test",type="index"} 6
    rest_server_blob_write_total{repo="test",type="locks"} 12
    rest_server_blob_write_total{repo="test",type="snapshots"} 6
											
										 
											2017-10-24 23:03:50 +08:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus/promhttp" | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	"github.com/restic/rest-server/quota" | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-14 15:53:29 -06:00
										 |  |  | func (s *Server) debugHandler(next http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | 	return http.HandlerFunc( | 
					
						
							|  |  |  | 		func(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 			log.Printf("%s %s", r.Method, r.URL) | 
					
						
							|  |  |  | 			next.ServeHTTP(w, r) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-14 15:53:29 -06:00
										 |  |  | func (s *Server) logHandler(next http.Handler) http.Handler { | 
					
						
							| 
									
										
										
										
											2023-03-23 19:19:18 +01:00
										 |  |  | 	var accessLog io.Writer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if s.Log == "-" { | 
					
						
							|  |  |  | 		accessLog = os.Stdout | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		accessLog, err = os.OpenFile(s.Log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			log.Fatalf("error: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return handlers.CombinedLoggingHandler(accessLog, next) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | func (s *Server) checkAuth(r *http.Request) (username string, ok bool) { | 
					
						
							|  |  |  | 	if s.NoAuth { | 
					
						
							|  |  |  | 		return username, true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-01 02:31:43 +01:00
										 |  |  | 	if s.ProxyAuthUsername != "" { | 
					
						
							|  |  |  | 		username = r.Header.Get(s.ProxyAuthUsername) | 
					
						
							|  |  |  | 		if username == "" { | 
					
						
							|  |  |  | 			return "", false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var password string | 
					
						
							|  |  |  | 		username, password, ok = r.BasicAuth() | 
					
						
							|  |  |  | 		if !ok || !s.htpasswdFile.Validate(username, password) { | 
					
						
							|  |  |  | 			return "", false | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return username, true | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 14:36:33 +08:00
										 |  |  | func (s *Server) wrapMetricsAuth(f http.HandlerFunc) http.HandlerFunc { | 
					
						
							| 
									
										
										
										
											2021-01-04 20:23:26 +08:00
										 |  |  | 	return func(w http.ResponseWriter, r *http.Request) { | 
					
						
							| 
									
										
										
										
											2021-01-07 14:36:33 +08:00
										 |  |  | 		username, ok := s.checkAuth(r) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			httpDefaultError(w, http.StatusUnauthorized) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if s.PrivateRepos && username != "metrics" { | 
					
						
							| 
									
										
										
										
											2021-01-04 20:23:26 +08:00
										 |  |  | 			httpDefaultError(w, http.StatusUnauthorized) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		f(w, r) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | // NewHandler returns the master HTTP multiplexer/router. | 
					
						
							|  |  |  | func NewHandler(server *Server) (http.Handler, error) { | 
					
						
							| 
									
										
										
										
											2024-11-01 02:31:43 +01:00
										 |  |  | 	if !server.NoAuth && server.ProxyAuthUsername == "" { | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 		var err error | 
					
						
							| 
									
										
										
										
											2022-03-25 15:39:20 -04:00
										 |  |  | 		if server.HtpasswdPath == "" { | 
					
						
							|  |  |  | 			server.HtpasswdPath = filepath.Join(server.Path, ".htpasswd") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		server.htpasswdFile, err = NewHtpasswdFromFile(server.HtpasswdPath) | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2022-03-25 15:39:20 -04:00
										 |  |  | 			return nil, fmt.Errorf("cannot load %s (use --no-auth to disable): %v", server.HtpasswdPath, err) | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-03-25 22:25:16 -04:00
										 |  |  | 		log.Printf("Loaded htpasswd file %s", server.HtpasswdPath) | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 10:43:33 +02:00
										 |  |  | 	const GiB = 1024 * 1024 * 1024 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	if server.MaxRepoSize > 0 { | 
					
						
							|  |  |  | 		log.Printf("Initializing quota (can take a while)...") | 
					
						
							|  |  |  | 		qm, err := quota.New(server.Path, server.MaxRepoSize) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		server.quotaManager = qm | 
					
						
							| 
									
										
										
										
											2021-01-04 15:29:18 +08:00
										 |  |  | 		log.Printf("Quota initialized, currently using %.2f GiB", float64(qm.SpaceUsed())/GiB) | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	mux := http.NewServeMux() | 
					
						
							| 
									
										
										
										
											2018-04-15 08:31:50 -06:00
										 |  |  | 	if server.Prometheus { | 
					
						
							| 
									
										
										
										
											2021-01-04 20:23:26 +08:00
										 |  |  | 		if server.PrometheusNoAuth { | 
					
						
							|  |  |  | 			mux.Handle("/metrics", promhttp.Handler()) | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2021-01-07 14:36:33 +08:00
										 |  |  | 			mux.HandleFunc("/metrics", server.wrapMetricsAuth(promhttp.Handler().ServeHTTP)) | 
					
						
							| 
									
										
										
										
											2021-01-04 20:23:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
											  
											
												Add Prometheus metrics
Exposes a few metrics for Prometheus under /metrics if started with --prometheus.
Example:
    # HELP rest_server_blob_read_bytes_total Total number of bytes read from blobs
    # TYPE rest_server_blob_read_bytes_total counter
    rest_server_blob_read_bytes_total{repo="test",type="data"} 2.13557024e+09
    rest_server_blob_read_bytes_total{repo="test",type="index"} 1.198653e+06
    rest_server_blob_read_bytes_total{repo="test",type="keys"} 5388
    rest_server_blob_read_bytes_total{repo="test",type="locks"} 1975
    rest_server_blob_read_bytes_total{repo="test",type="snapshots"} 10018
    # HELP rest_server_blob_read_total Total number of blobs read
    # TYPE rest_server_blob_read_total counter
    rest_server_blob_read_total{repo="test",type="data"} 3985
    rest_server_blob_read_total{repo="test",type="index"} 21
    rest_server_blob_read_total{repo="test",type="keys"} 12
    rest_server_blob_read_total{repo="test",type="locks"} 12
    rest_server_blob_read_total{repo="test",type="snapshots"} 32
    # HELP rest_server_blob_write_bytes_total Total number of bytes written to blobs
    # TYPE rest_server_blob_write_bytes_total counter
    rest_server_blob_write_bytes_total{repo="test",type="data"} 1.063726179e+09
    rest_server_blob_write_bytes_total{repo="test",type="index"} 395586
    rest_server_blob_write_bytes_total{repo="test",type="locks"} 1975
    rest_server_blob_write_bytes_total{repo="test",type="snapshots"} 1933
    # HELP rest_server_blob_write_total Total number of blobs written
    # TYPE rest_server_blob_write_total counter
    rest_server_blob_write_total{repo="test",type="data"} 226
    rest_server_blob_write_total{repo="test",type="index"} 6
    rest_server_blob_write_total{repo="test",type="locks"} 12
    rest_server_blob_write_total{repo="test",type="snapshots"} 6
											
										 
											2017-10-24 23:03:50 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	mux.Handle("/", server) | 
					
						
							| 
									
										
											  
											
												Add Prometheus metrics
Exposes a few metrics for Prometheus under /metrics if started with --prometheus.
Example:
    # HELP rest_server_blob_read_bytes_total Total number of bytes read from blobs
    # TYPE rest_server_blob_read_bytes_total counter
    rest_server_blob_read_bytes_total{repo="test",type="data"} 2.13557024e+09
    rest_server_blob_read_bytes_total{repo="test",type="index"} 1.198653e+06
    rest_server_blob_read_bytes_total{repo="test",type="keys"} 5388
    rest_server_blob_read_bytes_total{repo="test",type="locks"} 1975
    rest_server_blob_read_bytes_total{repo="test",type="snapshots"} 10018
    # HELP rest_server_blob_read_total Total number of blobs read
    # TYPE rest_server_blob_read_total counter
    rest_server_blob_read_total{repo="test",type="data"} 3985
    rest_server_blob_read_total{repo="test",type="index"} 21
    rest_server_blob_read_total{repo="test",type="keys"} 12
    rest_server_blob_read_total{repo="test",type="locks"} 12
    rest_server_blob_read_total{repo="test",type="snapshots"} 32
    # HELP rest_server_blob_write_bytes_total Total number of bytes written to blobs
    # TYPE rest_server_blob_write_bytes_total counter
    rest_server_blob_write_bytes_total{repo="test",type="data"} 1.063726179e+09
    rest_server_blob_write_bytes_total{repo="test",type="index"} 395586
    rest_server_blob_write_bytes_total{repo="test",type="locks"} 1975
    rest_server_blob_write_bytes_total{repo="test",type="snapshots"} 1933
    # HELP rest_server_blob_write_total Total number of blobs written
    # TYPE rest_server_blob_write_total counter
    rest_server_blob_write_total{repo="test",type="data"} 226
    rest_server_blob_write_total{repo="test",type="index"} 6
    rest_server_blob_write_total{repo="test",type="locks"} 12
    rest_server_blob_write_total{repo="test",type="snapshots"} 6
											
										 
											2017-10-24 23:03:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 01:28:13 +08:00
										 |  |  | 	var handler http.Handler = mux | 
					
						
							|  |  |  | 	if server.Debug { | 
					
						
							|  |  |  | 		handler = server.debugHandler(handler) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if server.Log != "" { | 
					
						
							|  |  |  | 		handler = server.logHandler(handler) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return handler, nil | 
					
						
							| 
									
										
										
										
											2017-06-21 15:23:33 -06:00
										 |  |  | } |