mirror of
https://github.com/restic/rest-server.git
synced 2025-10-19 15:43:21 +00:00
refactoring
This commit is contained in:
parent
1ab2939041
commit
465ef4b493
18 changed files with 361 additions and 369 deletions
10
auth.go
Normal file
10
auth.go
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Authorize(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/restic/restic/backend"
|
|
||||||
)
|
|
||||||
|
|
||||||
var root string
|
|
||||||
|
|
||||||
func Init(path string) {
|
|
||||||
root = path
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConfigPath(repository string) string {
|
|
||||||
return filepath.Join(root, repository, string(backend.Config))
|
|
||||||
}
|
|
||||||
|
|
||||||
func DataPath(repository string) string {
|
|
||||||
return filepath.Join(root, repository, string(backend.Data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func SnapshotPath(repository string) string {
|
|
||||||
return filepath.Join(root, repository, string(backend.Snapshot))
|
|
||||||
}
|
|
||||||
|
|
||||||
func IndexPath(repository string) string {
|
|
||||||
return filepath.Join(root, repository, string(backend.Index))
|
|
||||||
}
|
|
||||||
|
|
||||||
func LockPath(repository string) string {
|
|
||||||
return filepath.Join(root, repository, string(backend.Lock))
|
|
||||||
}
|
|
||||||
|
|
||||||
func KeyPath(repository string) string {
|
|
||||||
return filepath.Join(root, repository, string(backend.Key))
|
|
||||||
}
|
|
17
context.go
Normal file
17
context.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
// A Context specifies the root directory where all repositories are stored
|
||||||
|
type Context struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContext(path string) Context {
|
||||||
|
return Context{path}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the file structure of the Context
|
||||||
|
func (c *Context) Init() {
|
||||||
|
|
||||||
|
}
|
40
handlers.go
Normal file
40
handlers.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler func(w http.ResponseWriter, r *http.Request, c *Context)
|
||||||
|
|
||||||
|
func HeadConfig(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "head config")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "get config")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostConfig(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "post config")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListBlob(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "list blob")
|
||||||
|
}
|
||||||
|
|
||||||
|
func HeadBlob(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "head blob")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBlob(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "get blob")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostBlob(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "post blob")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteBlob(w http.ResponseWriter, r *http.Request, c *Context) {
|
||||||
|
fmt.Fprintln(w, "delete blob")
|
||||||
|
}
|
|
@ -1,56 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/bchapuis/restic-server/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HeadConfig(w http.ResponseWriter, r *http.Request) {
|
|
||||||
repo, err := ExtractRepository(r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "403 invalid repository", 403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file := config.ConfigPath(repo)
|
|
||||||
if _, err := os.Stat(file); err != nil {
|
|
||||||
http.Error(w, "404 repository not found", 404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfig(w http.ResponseWriter, r *http.Request) {
|
|
||||||
repo, err := ExtractRepository(r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "403 invalid repository", 403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file := config.ConfigPath(repo)
|
|
||||||
if _, err := os.Stat(file); err == nil {
|
|
||||||
bytes, _ := ioutil.ReadFile(file)
|
|
||||||
w.Write(bytes)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
http.Error(w, "404 repository not found", 404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostConfig(w http.ResponseWriter, r *http.Request) {
|
|
||||||
repo, err := ExtractRepository(r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "403 invalid repository", 403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file := config.ConfigPath(repo)
|
|
||||||
if _, err := os.Stat(file); err == nil {
|
|
||||||
http.Error(w, "409 repository already initialized", 409)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
bytes, _ := ioutil.ReadAll(r.Body)
|
|
||||||
ioutil.WriteFile(file, bytes, 0600)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/bchapuis/restic-server/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HeadData(w http.ResponseWriter, r *http.Request) {
|
|
||||||
repo, err := ExtractRepository(r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "403 invalid repository", 403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
id, err := ExtractID(r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "403 invalid ID", 403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file := filepath.Join(config.DataPath(repo), id.String())
|
|
||||||
if _, err := os.Stat(file); err != nil {
|
|
||||||
http.Error(w, "404 repository not found", 404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetData(w http.ResponseWriter, r *http.Request) {
|
|
||||||
repo, err := ExtractRepository(r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "403 invalid repository", 403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
id, err := ExtractID(r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "403 invalid ID", 403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file := filepath.Join(config.DataPath(repo), id.String())
|
|
||||||
if _, err := os.Stat(file); err != nil {
|
|
||||||
http.Error(w, "404 repository not found", 404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostData(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "data")
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteData(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "data")
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HeadIndex(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "data")
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIndex(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "index")
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostIndex(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "index")
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteIndex(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "index")
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HeadKey(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "data")
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetKey(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "key")
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostKey(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "key")
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteKey(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "key")
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HeadLock(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "data")
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLock(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "lock")
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostLock(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "lock")
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteLock(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "lock")
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RequestLogger(w http.ResponseWriter, r *http.Request) {
|
|
||||||
log.Printf("%v %v", r.Method, r.URL.String())
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HeadSnapshot(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "data")
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSnapshot(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostSnapshot(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteSnapshot(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "snapshot")
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/restic/restic/backend"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExtractUser(r *http.Request) (string, string, error) {
|
|
||||||
return "username", "password", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractRepository(r *http.Request) (string, error) {
|
|
||||||
return "repository", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExtractID(r *http.Request) (backend.ID, error) {
|
|
||||||
path := strings.Split(r.URL.String(), "/")
|
|
||||||
if len(path) != 3 {
|
|
||||||
return backend.ID{}, errors.New("invalid request path")
|
|
||||||
}
|
|
||||||
return backend.ParseID(path[2])
|
|
||||||
}
|
|
13
repository.go
Normal file
13
repository.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
// A Repository is the place where backups are stored
|
||||||
|
type Repository struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the file structure of the Repository
|
||||||
|
func (r *Repository) Init() {
|
||||||
|
|
||||||
|
}
|
BIN
restic-server
Executable file
BIN
restic-server
Executable file
Binary file not shown.
110
router.go
Normal file
110
router.go
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/restic/restic/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Route all the server requests
|
||||||
|
func Router(w http.ResponseWriter, r *http.Request) {
|
||||||
|
m := r.Method
|
||||||
|
u := r.RequestURI
|
||||||
|
|
||||||
|
log.Println("%s %s", m, u)
|
||||||
|
|
||||||
|
if Authorize(r) {
|
||||||
|
if handler := RestAPI(m, u); handler != nil {
|
||||||
|
handler(w, r, nil)
|
||||||
|
} else {
|
||||||
|
http.Error(w, "not found", 404)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http.Error(w, "unauthorized", 403)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the repository name for a given path
|
||||||
|
func RepositoryName(u string) (string, error) {
|
||||||
|
s := strings.Split(u, "/")
|
||||||
|
if len(s) <= 1 {
|
||||||
|
return "", errors.New("path does not contain repository name")
|
||||||
|
}
|
||||||
|
if len(s[1]) < 1 {
|
||||||
|
return "", errors.New("repository name should contain at least 1 character")
|
||||||
|
}
|
||||||
|
match, err := regexp.MatchString("^[a-zA-Z0-9_-]*$", s[1])
|
||||||
|
if !match || err != nil {
|
||||||
|
return "", errors.New("repository name should not contains special characters")
|
||||||
|
}
|
||||||
|
return s[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the backend type for a given path
|
||||||
|
func BackendType(u string) backend.Type {
|
||||||
|
s := strings.Split(u, "/")
|
||||||
|
var bt backend.Type
|
||||||
|
if len(s) > 2 {
|
||||||
|
bt, _ = backend.ParseType(s[2])
|
||||||
|
}
|
||||||
|
return bt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the blob ID for a given path
|
||||||
|
func BlobID(u string) backend.ID {
|
||||||
|
s := strings.Split(u, "/")
|
||||||
|
var id backend.ID
|
||||||
|
if len(s) > 3 {
|
||||||
|
id, _ = backend.ParseID(s[3])
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Rest API returns a Handler when a match occur or nil.
|
||||||
|
func RestAPI(m string, u string) Handler {
|
||||||
|
s := strings.Split(u, "/")
|
||||||
|
|
||||||
|
// Check for valid repository name
|
||||||
|
_, err := RepositoryName(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route config requests
|
||||||
|
bt := BackendType(u)
|
||||||
|
if len(s) == 3 && bt == backend.Config {
|
||||||
|
switch m {
|
||||||
|
case "HEAD":
|
||||||
|
return HeadConfig
|
||||||
|
case "GET":
|
||||||
|
return GetConfig
|
||||||
|
case "POST":
|
||||||
|
return PostConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route blob requests
|
||||||
|
id := BlobID(u)
|
||||||
|
if len(s) == 4 && !bt.IsNull() && bt != backend.Config {
|
||||||
|
if s[3] == "" && m == "GET" {
|
||||||
|
return ListBlob
|
||||||
|
} else if !id.IsNull() {
|
||||||
|
switch m {
|
||||||
|
case "HEAD":
|
||||||
|
return HeadBlob
|
||||||
|
case "GET":
|
||||||
|
return GetBlob
|
||||||
|
case "POST":
|
||||||
|
return PostBlob
|
||||||
|
case "DELETE":
|
||||||
|
return DeleteBlob
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Route struct {
|
|
||||||
method string
|
|
||||||
pattern string
|
|
||||||
handler http.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
type Router struct {
|
|
||||||
filters []http.Handler
|
|
||||||
routes []Route
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRouter() Router {
|
|
||||||
filters := []http.Handler{}
|
|
||||||
routes := []Route{}
|
|
||||||
return Router{filters, routes}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (router *Router) Filter(handler http.Handler) {
|
|
||||||
router.filters = append(router.filters, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (router *Router) FilterFunc(handlerFunc http.HandlerFunc) {
|
|
||||||
router.Filter(handlerFunc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (router *Router) Handle(method string, pattern string, handler http.Handler) {
|
|
||||||
router.routes = append(router.routes, Route{method, pattern, handler})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (router *Router) HandleFunc(method string, pattern string, handlerFunc http.HandlerFunc) {
|
|
||||||
router.Handle(method, pattern, handlerFunc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (router Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
for i := 0; i < len(router.filters); i++ {
|
|
||||||
filter := router.filters[i]
|
|
||||||
filter.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
for i := 0; i < len(router.routes); i++ {
|
|
||||||
route := router.routes[i]
|
|
||||||
if route.method == r.Method && strings.HasPrefix(r.URL.String(), route.pattern) {
|
|
||||||
route.handler.ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
http.NotFound(w, r)
|
|
||||||
}
|
|
168
router_test.go
Normal file
168
router_test.go
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/restic/restic/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRepositoryName(t *testing.T) {
|
||||||
|
var name string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
name, err = RepositoryName("")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("empty string should produce an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err = RepositoryName("/")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("empty repository name should produce an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err = RepositoryName("//")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("empty repository name should produce an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err = RepositoryName("/$test")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("special characters should produce an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err = RepositoryName("/test")
|
||||||
|
if name != "test" {
|
||||||
|
t.Errorf("repository name is %s but should be test", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err = RepositoryName("/test-1234")
|
||||||
|
if name != "test-1234" {
|
||||||
|
t.Errorf("repository name is %s but should be test-1234", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err = RepositoryName("/test_1234")
|
||||||
|
if name != "test_1234" {
|
||||||
|
t.Errorf("repository name is %s but should be test_1234", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBackendType(t *testing.T) {
|
||||||
|
var bt backend.Type
|
||||||
|
|
||||||
|
bt = BackendType("/")
|
||||||
|
if !bt.IsNull() {
|
||||||
|
t.Error("backend type should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
bt = BackendType("/test")
|
||||||
|
if !bt.IsNull() {
|
||||||
|
t.Error("backend type should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
bt = BackendType("/test/config")
|
||||||
|
if bt != backend.Config {
|
||||||
|
t.Error("backend type should be config")
|
||||||
|
}
|
||||||
|
|
||||||
|
bt = BackendType("/test/config/")
|
||||||
|
if bt != backend.Config {
|
||||||
|
t.Error("backend type should be config")
|
||||||
|
}
|
||||||
|
|
||||||
|
bt = BackendType("/test/config/test")
|
||||||
|
if bt != backend.Config {
|
||||||
|
t.Error("backend type should be config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlobID(t *testing.T) {
|
||||||
|
var id backend.ID
|
||||||
|
|
||||||
|
id = BlobID("/")
|
||||||
|
if !id.IsNull() {
|
||||||
|
t.Error("blob id should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
id = BlobID("/test")
|
||||||
|
if !id.IsNull() {
|
||||||
|
t.Error("blob id should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
id = BlobID("/test/data")
|
||||||
|
if !id.IsNull() {
|
||||||
|
t.Error("blob id should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
id = BlobID("/test/data/")
|
||||||
|
if !id.IsNull() {
|
||||||
|
t.Error("blob id should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
id = BlobID("/test/data/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||||
|
if id.IsNull() {
|
||||||
|
t.Error("blob id should not be nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRestAPI(t *testing.T) {
|
||||||
|
type route struct {
|
||||||
|
method string
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
validEndpoints := []route{
|
||||||
|
route{"HEAD", "/repo/config"},
|
||||||
|
route{"GET", "/repo/config"},
|
||||||
|
route{"POST", "/repo/config"},
|
||||||
|
route{"GET", "/repo/data/"},
|
||||||
|
route{"HEAD", "/repo/data/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/data/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"POST", "/repo/data/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"DELETE", "/repo/data/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/snapshot/"},
|
||||||
|
route{"HEAD", "/repo/snapshot/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/snapshot/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"POST", "/repo/snapshot/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"DELETE", "/repo/snapshot/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/index/"},
|
||||||
|
route{"HEAD", "/repo/index/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/index/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"POST", "/repo/index/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"DELETE", "/repo/index/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/snapshot/"},
|
||||||
|
route{"HEAD", "/repo/lock/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/lock/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"POST", "/repo/lock/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"DELETE", "/repo/lock/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/key/"},
|
||||||
|
route{"HEAD", "/repo/key/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/key/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"POST", "/repo/key/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"DELETE", "/repo/key/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, route := range validEndpoints {
|
||||||
|
if RestAPI(route.method, route.path) == nil {
|
||||||
|
t.Errorf("request %s %s should return a handler", route.method, route.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidEndpoints := []route{
|
||||||
|
route{"GET", "/"},
|
||||||
|
route{"GET", "/repo"},
|
||||||
|
route{"GET", "/repo/config/"},
|
||||||
|
route{"GET", "/repo/config/aaaa"},
|
||||||
|
route{"GET", "/repo/data"},
|
||||||
|
route{"GET", "/repo/data/aaaaaaa"},
|
||||||
|
route{"GET", "/repo/keys/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
||||||
|
route{"GET", "/repo/keys/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"},
|
||||||
|
route{"GET", "/repo/keys/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, route := range invalidEndpoints {
|
||||||
|
if RestAPI(route.method, route.path) != nil {
|
||||||
|
t.Errorf("request %s %s should return nil", route.method, route.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
server.go
48
server.go
|
@ -1,52 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import ()
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/bchapuis/restic-server/config"
|
|
||||||
"github.com/bchapuis/restic-server/handlers"
|
|
||||||
"github.com/bchapuis/restic-server/router"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
path, _ := ioutil.TempDir("", "restic-repository-")
|
//path, _ := ioutil.TempDir("", "restic-repository-")
|
||||||
|
|
||||||
config.Init(path)
|
//http.ListenAndServe(":8000", r)
|
||||||
|
|
||||||
r := router.NewRouter()
|
|
||||||
|
|
||||||
r.FilterFunc(handlers.RequestLogger)
|
|
||||||
|
|
||||||
r.HandleFunc("HEAD", "/config", handlers.HeadConfig)
|
|
||||||
r.HandleFunc("GET", "/config", handlers.GetConfig)
|
|
||||||
r.HandleFunc("POST", "/config", handlers.PostConfig)
|
|
||||||
|
|
||||||
r.HandleFunc("HEAD", "/data", handlers.HeadData)
|
|
||||||
r.HandleFunc("GET", "/data", handlers.GetData)
|
|
||||||
r.HandleFunc("POST", "/data", handlers.PostData)
|
|
||||||
r.HandleFunc("DELETE", "/data", handlers.DeleteData)
|
|
||||||
|
|
||||||
r.HandleFunc("HEAD", "/snapshot", handlers.HeadSnapshot)
|
|
||||||
r.HandleFunc("GET", "/snapshot", handlers.GetSnapshot)
|
|
||||||
r.HandleFunc("POST", "/snapshot", handlers.PostSnapshot)
|
|
||||||
r.HandleFunc("DELETE", "/snapshot", handlers.DeleteSnapshot)
|
|
||||||
|
|
||||||
r.HandleFunc("HEAD", "/index", handlers.HeadIndex)
|
|
||||||
r.HandleFunc("GET", "/index", handlers.GetIndex)
|
|
||||||
r.HandleFunc("POST", "/index", handlers.PostIndex)
|
|
||||||
r.HandleFunc("DELETE", "/index", handlers.DeleteIndex)
|
|
||||||
|
|
||||||
r.HandleFunc("HEAD", "/lock", handlers.HeadLock)
|
|
||||||
r.HandleFunc("GET", "/lock", handlers.GetLock)
|
|
||||||
r.HandleFunc("POST", "/lock", handlers.PostLock)
|
|
||||||
r.HandleFunc("DELETE", "/lock", handlers.DeleteLock)
|
|
||||||
|
|
||||||
r.HandleFunc("HEAD", "/key", handlers.HeadKey)
|
|
||||||
r.HandleFunc("GET", "/key", handlers.GetKey)
|
|
||||||
r.HandleFunc("POST", "/key", handlers.PostKey)
|
|
||||||
r.HandleFunc("DELETE", "/key", handlers.DeleteKey)
|
|
||||||
|
|
||||||
http.ListenAndServe(":8000", r)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue