2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-02 19:49:44 +00:00

Fixes for the PR

- Removed external dependencies for test
- Prevent building restic-server w/ Go 1.3

Go versions 1.0, 1.1., and 1.2 are going to fail as well, but they
are "excluded" by README.md already.
This commit is contained in:
Fabian Wickborn 2016-02-21 17:33:45 +01:00
parent d86c093480
commit 51d86370a5
5 changed files with 94 additions and 21 deletions

View File

@ -1,3 +1,5 @@
// +build go1.4
package main package main
import ( import (
@ -10,10 +12,14 @@ import (
"time" "time"
) )
// Context contains repository meta-data.
type Context struct { type Context struct {
path string path string
} }
// AuthHandler wraps h with a http.HandlerFunc that performs basic
// authentication against the user/passwords pairs stored in f and returns the
// http.HandlerFunc.
func AuthHandler(f *HtpasswdFile, h http.Handler) http.HandlerFunc { func AuthHandler(f *HtpasswdFile, h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth() username, password, ok := r.BasicAuth()
@ -29,6 +35,8 @@ func AuthHandler(f *HtpasswdFile, h http.Handler) http.HandlerFunc {
} }
} }
// CheckConfig returns a http.HandlerFunc that checks whether
// a configuration exists.
func CheckConfig(c *Context) http.HandlerFunc { func CheckConfig(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
config := filepath.Join(c.path, "config") config := filepath.Join(c.path, "config")
@ -39,6 +47,8 @@ func CheckConfig(c *Context) http.HandlerFunc {
} }
} }
// GetConfig returns a http.HandlerFunc that allows for a
// config to be retrieved.
func GetConfig(c *Context) http.HandlerFunc { func GetConfig(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
config := filepath.Join(c.path, "config") config := filepath.Join(c.path, "config")
@ -51,6 +61,8 @@ func GetConfig(c *Context) http.HandlerFunc {
} }
} }
// SaveConfig returns a http.HandlerFunc that allows for a
// config to be saved.
func SaveConfig(c *Context) http.HandlerFunc { func SaveConfig(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
config := filepath.Join(c.path, "config") config := filepath.Join(c.path, "config")
@ -68,6 +80,8 @@ func SaveConfig(c *Context) http.HandlerFunc {
} }
} }
// ListBlobs returns a http.HandlerFunc that lists
// all blobs of a given type in an arbitrary order.
func ListBlobs(c *Context) http.HandlerFunc { func ListBlobs(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := strings.Split(r.RequestURI, "/") vars := strings.Split(r.RequestURI, "/")
@ -91,6 +105,8 @@ func ListBlobs(c *Context) http.HandlerFunc {
} }
} }
// CheckBlob reutrns a http.HandlerFunc that tests whether a blob exists
// and returns 200, if it does, or 404 otherwise.
func CheckBlob(c *Context) http.HandlerFunc { func CheckBlob(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := strings.Split(r.RequestURI, "/") vars := strings.Split(r.RequestURI, "/")
@ -105,6 +121,8 @@ func CheckBlob(c *Context) http.HandlerFunc {
} }
} }
// GetBlob returns a http.HandlerFunc that retrieves a blob
// from the repository.
func GetBlob(c *Context) http.HandlerFunc { func GetBlob(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := strings.Split(r.RequestURI, "/") vars := strings.Split(r.RequestURI, "/")
@ -121,6 +139,7 @@ func GetBlob(c *Context) http.HandlerFunc {
} }
} }
// SaveBlob returns a http.HandlerFunc that saves a blob to the repository.
func SaveBlob(c *Context) http.HandlerFunc { func SaveBlob(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := strings.Split(r.RequestURI, "/") vars := strings.Split(r.RequestURI, "/")
@ -141,6 +160,8 @@ func SaveBlob(c *Context) http.HandlerFunc {
} }
} }
// DeleteBlob returns a http.HandlerFunc that deletes a blob from the
// repository.
func DeleteBlob(c *Context) http.HandlerFunc { func DeleteBlob(c *Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := strings.Split(r.RequestURI, "/") vars := strings.Split(r.RequestURI, "/")

View File

@ -1,3 +1,5 @@
// +build go1.4
package main package main
/* /*
@ -36,10 +38,14 @@ import (
// lookup passwords in a htpasswd file // lookup passwords in a htpasswd file
// The entries must have been created with -s for SHA encryption // The entries must have been created with -s for SHA encryption
// HtpasswdFile is a map for usernames to passwords.
type HtpasswdFile struct { type HtpasswdFile struct {
Users map[string]string Users map[string]string
} }
// NewHtpasswdFromFile reads the users and passwords from a htpasswd
// file and returns them. If an error is encountered, it is returned, together
// with a nil-Pointer for the HtpasswdFile.
func NewHtpasswdFromFile(path string) (*HtpasswdFile, error) { func NewHtpasswdFromFile(path string) (*HtpasswdFile, error) {
r, err := os.Open(path) r, err := os.Open(path)
if err != nil { if err != nil {
@ -49,13 +55,16 @@ func NewHtpasswdFromFile(path string) (*HtpasswdFile, error) {
return NewHtpasswd(r) return NewHtpasswd(r)
} }
// NewHtpasswd reads the users and passwords from a htpasswd
// datastream in file and returns them. If an error is encountered,
// it is returned, together with a nil-Pointer for the HtpasswdFile.
func NewHtpasswd(file io.Reader) (*HtpasswdFile, error) { func NewHtpasswd(file io.Reader) (*HtpasswdFile, error) {
csv_reader := csv.NewReader(file) cr := csv.NewReader(file)
csv_reader.Comma = ':' cr.Comma = ':'
csv_reader.Comment = '#' cr.Comment = '#'
csv_reader.TrimLeadingSpace = true cr.TrimLeadingSpace = true
records, err := csv_reader.ReadAll() records, err := cr.ReadAll()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -66,6 +75,9 @@ func NewHtpasswd(file io.Reader) (*HtpasswdFile, error) {
return h, nil return h, nil
} }
// Validate returns true if password matches the stored password
// for user. If no password for user is stored, or the password
// is wrong, false is returned.
func (h *HtpasswdFile) Validate(user string, password string) bool { func (h *HtpasswdFile) Validate(user string, password string) bool {
realPassword, exists := h.Users[user] realPassword, exists := h.Users[user]
if !exists { if !exists {

View File

@ -1,3 +1,5 @@
// +build go1.4
package main package main
import ( import (
@ -6,83 +8,103 @@ import (
"strings" "strings"
) )
// Route is a handler for a path that was already split.
type Route struct { type Route struct {
path []string path []string
handler http.Handler handler http.Handler
} }
// Router maps HTTP methods to a slice of Route handlers.
type Router struct { type Router struct {
routes map[string][]Route routes map[string][]Route
} }
// NewRouter creates a new Router and returns a pointer to it.
func NewRouter() *Router { func NewRouter() *Router {
return &Router{make(map[string][]Route)} return &Router{make(map[string][]Route)}
} }
// Options registers handler for path with method "OPTIONS".
func (router *Router) Options(path string, handler http.Handler) { func (router *Router) Options(path string, handler http.Handler) {
router.Handle("OPTIONS", path, handler) router.Handle("OPTIONS", path, handler)
} }
// OptionsFunc registers handler for path with method "OPTIONS".
func (router *Router) OptionsFunc(path string, handler http.HandlerFunc) { func (router *Router) OptionsFunc(path string, handler http.HandlerFunc) {
router.Handle("OPTIONS", path, handler) router.Handle("OPTIONS", path, handler)
} }
// Get registers handler for path with method "GET".
func (router *Router) Get(path string, handler http.Handler) { func (router *Router) Get(path string, handler http.Handler) {
router.Handle("GET", path, handler) router.Handle("GET", path, handler)
} }
// GetFunc registers handler for path with method "GET".
func (router *Router) GetFunc(path string, handler http.HandlerFunc) { func (router *Router) GetFunc(path string, handler http.HandlerFunc) {
router.Handle("GET", path, handler) router.Handle("GET", path, handler)
} }
// Head registers handler for path with method "HEAD".
func (router *Router) Head(path string, handler http.Handler) { func (router *Router) Head(path string, handler http.Handler) {
router.Handle("HEAD", path, handler) router.Handle("HEAD", path, handler)
} }
// HeadFunc registers handler for path with method "HEAD".
func (router *Router) HeadFunc(path string, handler http.HandlerFunc) { func (router *Router) HeadFunc(path string, handler http.HandlerFunc) {
router.Handle("HEAD", path, handler) router.Handle("HEAD", path, handler)
} }
// Post registers handler for path with method "POST".
func (router *Router) Post(path string, handler http.Handler) { func (router *Router) Post(path string, handler http.Handler) {
router.Handle("POST", path, handler) router.Handle("POST", path, handler)
} }
// PostFunc registers handler for path with method "POST".
func (router *Router) PostFunc(path string, handler http.HandlerFunc) { func (router *Router) PostFunc(path string, handler http.HandlerFunc) {
router.Handle("POST", path, handler) router.Handle("POST", path, handler)
} }
// Put registers handler for path with method "PUT".
func (router *Router) Put(path string, handler http.Handler) { func (router *Router) Put(path string, handler http.Handler) {
router.Handle("PUT", path, handler) router.Handle("PUT", path, handler)
} }
// PutFunc registers handler for path with method "PUT".
func (router *Router) PutFunc(path string, handler http.HandlerFunc) { func (router *Router) PutFunc(path string, handler http.HandlerFunc) {
router.Handle("PUT", path, handler) router.Handle("PUT", path, handler)
} }
// Delete registers handler for path with method "DELETE".
func (router *Router) Delete(path string, handler http.Handler) { func (router *Router) Delete(path string, handler http.Handler) {
router.Handle("DELETE", path, handler) router.Handle("DELETE", path, handler)
} }
// DeleteFunc registers handler for path with method "DELETE".
func (router *Router) DeleteFunc(path string, handler http.HandlerFunc) { func (router *Router) DeleteFunc(path string, handler http.HandlerFunc) {
router.Handle("DELETE", path, handler) router.Handle("DELETE", path, handler)
} }
// Trace registers handler for path with method "TRACE".
func (router *Router) Trace(path string, handler http.Handler) { func (router *Router) Trace(path string, handler http.Handler) {
router.Handle("TRACE", path, handler) router.Handle("TRACE", path, handler)
} }
// TraceFunc registers handler for path with method "TRACE".
func (router *Router) TraceFunc(path string, handler http.HandlerFunc) { func (router *Router) TraceFunc(path string, handler http.HandlerFunc) {
router.Handle("TRACE", path, handler) router.Handle("TRACE", path, handler)
} }
// Connect registers handler for path with method "Connect".
func (router *Router) Connect(path string, handler http.Handler) { func (router *Router) Connect(path string, handler http.Handler) {
router.Handle("Connect", path, handler) router.Handle("Connect", path, handler)
} }
// ConnectFunc registers handler for path with method "Connect".
func (router *Router) ConnectFunc(path string, handler http.HandlerFunc) { func (router *Router) ConnectFunc(path string, handler http.HandlerFunc) {
router.Handle("Connect", path, handler) router.Handle("Connect", path, handler)
} }
// Handle registers a http.Handler for method and uri
func (router *Router) Handle(method string, uri string, handler http.Handler) { func (router *Router) Handle(method string, uri string, handler http.Handler) {
routes := router.routes[method] routes := router.routes[method]
path := strings.Split(uri, "/") path := strings.Split(uri, "/")

View File

@ -1,3 +1,5 @@
// +build go1.4
package main package main
import ( import (
@ -6,8 +8,6 @@ import (
"net/http/httptest" "net/http/httptest"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func TestRouter(t *testing.T) { func TestRouter(t *testing.T) {
@ -38,21 +38,37 @@ func TestRouter(t *testing.T) {
getConfigResp, _ := http.Get(server.URL + "/config") getConfigResp, _ := http.Get(server.URL + "/config")
getConfigBody, _ := ioutil.ReadAll(getConfigResp.Body) getConfigBody, _ := ioutil.ReadAll(getConfigResp.Body)
require.Equal(t, 200, getConfigResp.StatusCode) if getConfigResp.StatusCode != 200 {
require.Equal(t, string(getConfig), string(getConfigBody)) t.Fatalf("Wanted HTTP Status 200, got %d", getConfigResp.StatusCode)
}
if string(getConfig) != string(getConfigBody) {
t.Fatalf("Config wrong:\nWanted '%s'\nGot: '%s'", string(getConfig), string(getConfigBody))
}
postConfigResp, _ := http.Post(server.URL+"/config", "binary/octet-stream", strings.NewReader("post test")) postConfigResp, _ := http.Post(server.URL+"/config", "binary/octet-stream", strings.NewReader("post test"))
postConfigBody, _ := ioutil.ReadAll(postConfigResp.Body) postConfigBody, _ := ioutil.ReadAll(postConfigResp.Body)
require.Equal(t, 200, postConfigResp.StatusCode) if postConfigResp.StatusCode != 200 {
require.Equal(t, string(postConfig), string(postConfigBody)) t.Fatalf("Wanted HTTP Status 200, got %d", postConfigResp.StatusCode)
}
if string(postConfig) != string(postConfigBody) {
t.Fatalf("Config wrong:\nWanted '%s'\nGot: '%s'", string(postConfig), string(postConfigBody))
}
getBlobsResp, _ := http.Get(server.URL + "/blobs/") getBlobsResp, _ := http.Get(server.URL + "/blobs/")
getBlobsBody, _ := ioutil.ReadAll(getBlobsResp.Body) getBlobsBody, _ := ioutil.ReadAll(getBlobsResp.Body)
require.Equal(t, 200, getBlobsResp.StatusCode) if getBlobsResp.StatusCode != 200 {
require.Equal(t, string(getBlobs), string(getBlobsBody)) t.Fatalf("Wanted HTTP Status 200, got %d", getBlobsResp.StatusCode)
}
if string(getBlobs) != string(getBlobsBody) {
t.Fatalf("Config wrong:\nWanted '%s'\nGot: '%s'", string(getBlobs), string(getBlobsBody))
}
getBlobResp, _ := http.Get(server.URL + "/blobs/test") getBlobResp, _ := http.Get(server.URL + "/blobs/test")
getBlobBody, _ := ioutil.ReadAll(getBlobResp.Body) getBlobBody, _ := ioutil.ReadAll(getBlobResp.Body)
require.Equal(t, 200, getBlobResp.StatusCode) if getBlobResp.StatusCode != 200 {
require.Equal(t, string(getBlob), string(getBlobBody)) t.Fatalf("Wanted HTTP Status 200, got %d", getBlobResp.StatusCode)
}
if string(getBlob) != string(getBlobBody) {
t.Fatalf("Config wrong:\nWanted '%s'\nGot: '%s'", string(getBlob), string(getBlobBody))
}
} }

View File

@ -1,3 +1,5 @@
// +build go1.4
package main package main
import ( import (
@ -9,8 +11,8 @@ import (
) )
const ( const (
HTTP = ":8000" defaultHTTPPort = ":8000"
HTTPS = ":8443" defaultHTTPSPort = ":8443"
) )
func main() { func main() {
@ -56,15 +58,15 @@ func main() {
// start the server // start the server
if !*tls { if !*tls {
log.Printf("start server on port %s\n", HTTP) log.Printf("start server on port %s\n", defaultHTTPPort)
http.ListenAndServe(HTTP, handler) http.ListenAndServe(defaultHTTPPort, handler)
} else { } else {
privateKey := filepath.Join(*path, "private_key") privateKey := filepath.Join(*path, "private_key")
publicKey := filepath.Join(*path, "public_key") publicKey := filepath.Join(*path, "public_key")
log.Println("TLS enabled") log.Println("TLS enabled")
log.Printf("private key: %s", privateKey) log.Printf("private key: %s", privateKey)
log.Printf("public key: %s", publicKey) log.Printf("public key: %s", publicKey)
log.Printf("start server on port %s\n", HTTPS) log.Printf("start server on port %s\n", defaultHTTPSPort)
http.ListenAndServeTLS(HTTPS, publicKey, privateKey, handler) http.ListenAndServeTLS(defaultHTTPSPort, publicKey, privateKey, handler)
} }
} }