diff --git a/app/handler/file.go b/app/handler/file.go index 2002076..5cb238b 100644 --- a/app/handler/file.go +++ b/app/handler/file.go @@ -108,6 +108,9 @@ func (hand *Handler) DeleteFile(rctx *router.Context) { func (hand *Handler) ListFiles(rctx *router.Context) { filepath, _ := rctx.GetSubpath("filepath") + if filepath == "" { + filepath = "/" + } params := &operator.ListFilesParams{ Filepath: filepath, } @@ -119,5 +122,5 @@ func (hand *Handler) ListFiles(rctx *router.Context) { rctx.SetStatus(code) return } - rctx.SendJSON(code, res) + rctx.SendJSON(code, res.Files) } diff --git a/app/handler/service.go b/app/handler/service.go index 9582079..5cbf222 100644 --- a/app/handler/service.go +++ b/app/handler/service.go @@ -10,8 +10,6 @@ package handler import ( - "net/http" - "mstore/app/operator" "mstore/app/router" ) @@ -19,6 +17,5 @@ import ( func (hand *Handler) SendHello(rctx *router.Context) { params := &operator.SendHelloParams{} res, _ := hand.oper.SendHello(params) - rctx.SetStatus(http.StatusOK) hand.SendResult(rctx, res) } diff --git a/app/operator/file.go b/app/operator/file.go index 30a6f97..e0e45e8 100644 --- a/app/operator/file.go +++ b/app/operator/file.go @@ -253,13 +253,13 @@ type ListFilesParams struct { Filepath string } type ListFilesResult struct { - FileDescrs []descr.File + Files []descr.File `json:"files,omitempty"` } func (oper *Operator) ListFiles(ctx context.Context, param *ListFilesParams) (int, *ListFilesResult, error) { var err error res := &ListFilesResult{ - FileDescrs: make([]descr.File, 0), + Files: make([]descr.File, 0), } // TODO: convert file path to a unified and secure state @@ -276,7 +276,7 @@ func (oper *Operator) ListFiles(ctx context.Context, param *ListFilesParams) (in return code, res, err } for _, item := range fileDescrs { - res.FileDescrs = append(res.FileDescrs, item) + res.Files = append(res.Files, item) } code := http.StatusOK return code, res, err diff --git a/app/service/service.go b/app/service/service.go index ce6b915..792105a 100644 --- a/app/service/service.go +++ b/app/service/service.go @@ -70,15 +70,16 @@ func (svc *Service) Build() error { svc.rout.Use(router.NewCorsMiddleware()) svc.rout.Use(svc.hand.AuthMiddleware) - svc.rout.Get("/v3/api/service/hello", svc.hand.SendHello) + svc.rout.Get(`/v3/api/service/hello`, svc.hand.SendHello) - svc.rout.Head("/v3/api/file/{filepath}", svc.hand.FileExists) - svc.rout.Put("/v3/api/file/{filepath}", svc.hand.PutFile) - svc.rout.Get("/v3/api/file/{filepath}", svc.hand.GetFile) - svc.rout.Delete("/v3/api/file/{filepath}", svc.hand.DeleteFile) - svc.rout.Get("/v3/api/files/{filepath}", svc.hand.ListFiles) + svc.rout.Head(`/v3/api/file/{filepath}`, svc.hand.FileExists) + svc.rout.Put(`/v3/api/file/{filepath}`, svc.hand.PutFile) + svc.rout.Get(`/v3/api/file/{filepath}`, svc.hand.GetFile) + svc.rout.Delete(`/v3/api/file/{filepath}`, svc.hand.DeleteFile) + svc.rout.Get(`/v3/api/files/{filepath}`, svc.hand.ListFiles) + svc.rout.Get(`/v3/api/files/`, svc.hand.ListFiles) - svc.rout.Get("/v2/", svc.hand.GetVersion) + svc.rout.Get(`/v2/`, svc.hand.GetVersion) svc.rout.Head(`/v2/{name}/manifests/{reference}`, svc.hand.ManifestExists) svc.rout.Put(`/v2/{name}/manifests/{reference}`, svc.hand.PutManifest) diff --git a/pkg/client/client.go b/pkg/client/client.go index 027058b..1ec7e7a 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -12,6 +12,7 @@ package client import ( "context" "crypto/tls" + "fmt" "net/http" "net/url" "time" @@ -32,7 +33,10 @@ func convertServiceURI(ref string) (string, error) { if err != nil { return res, err } - uri.Path = serviceAPI + uri.Path, err = url.JoinPath(serviceAPI, uri.Path) + if err != nil { + return res, err + } uri.Scheme = serviceScheme res = uri.String() return res, err @@ -42,11 +46,15 @@ func (cli *Client) ServiceHello(ctx context.Context, serviceuri string, timeout var res bool var err error ctx, _ = context.WithTimeout(ctx, timeout) + serviceuri, _, _, err = repackServiceURI(serviceuri) + fmt.Printf("%s\n", serviceuri) if err != nil { return res, err } serviceuri, err = convertServiceURI(serviceuri) + fmt.Printf("%s\n", serviceuri) + if err != nil { return res, err } diff --git a/pkg/client/file.go b/pkg/client/file.go index 5e63c65..118fb44 100644 --- a/pkg/client/file.go +++ b/pkg/client/file.go @@ -10,7 +10,9 @@ package client import ( + "bytes" "context" + "encoding/json" "fmt" "io" "net/http" @@ -18,6 +20,7 @@ import ( "path/filepath" "strconv" + "mstore/app/descr" "mstore/pkg/auxhttp" ) @@ -58,7 +61,6 @@ func (cli *Client) PutFile(ctx context.Context, filename, fileuri string) error if err != nil { return err } - fileuri, err = convertFileURI(fileuri) if err != nil { return err @@ -81,6 +83,7 @@ func (cli *Client) PutFile(ctx context.Context, filename, fileuri string) error req.ContentLength = filesize req.Header.Set("Content-Type", "application/octet-stream") + req.Header.Set("Content-Size", strconv.FormatInt(filesize, 10)) if username != "" && password != "" { basic := auxhttp.EncodeBasicAuth(username, password) req.Header.Add("Authorization", basic) @@ -108,22 +111,18 @@ func (cli *Client) GetFile(ctx context.Context, fileuri, filename string) (int64 if err != nil { return size, err } - fileuri, err = convertFileURI(fileuri) if err != nil { return size, err } - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fileuri, nil) if err != nil { return size, err } - if username != "" && password != "" { basic := auxhttp.EncodeBasicAuth(username, password) req.Header.Add("Authorization", basic) } - client := makeHTTPClient() resp, err := client.Do(req) if err != nil { @@ -172,7 +171,6 @@ func (cli *Client) DeleteFile(ctx context.Context, fileuri, filename string) err if err != nil { return err } - fileuri, err = convertFileURI(fileuri) if err != nil { return err @@ -185,17 +183,74 @@ func (cli *Client) DeleteFile(ctx context.Context, fileuri, filename string) err basic := auxhttp.EncodeBasicAuth(username, password) req.Header.Add("Authorization", basic) } - client := makeHTTPClient() resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { err := fmt.Errorf("Received wrong status code: %s", resp.Status) return err } return err } + +func (cli *Client) ListFiles(ctx context.Context, catalogURI string) ([]descr.File, error) { + var err error + res := make([]descr.File, 0) + + catalogURI, username, password, err := repackServiceURI(catalogURI) + if err != nil { + return res, err + } + catalogURI, err = convertFilesURI(catalogURI) + if err != nil { + return res, err + } + req, err := http.NewRequestWithContext(ctx, http.MethodGet, catalogURI, nil) + if err != nil { + return res, err + } + if username != "" && password != "" { + basic := auxhttp.EncodeBasicAuth(username, password) + req.Header.Add("Authorization", basic) + } + client := makeHTTPClient() + resp, err := client.Do(req) + if err != nil { + return res, err + } + defer resp.Body.Close() + + contentLength := resp.Header.Get("Content-Length") + if contentLength == "" { + err = fmt.Errorf("Empty Content-Length received") + return res, err + } + if resp.StatusCode != http.StatusOK { + err := fmt.Errorf("Received wrong status code: %s", resp.Status) + return res, err + } + declSize, err := strconv.ParseInt(contentLength, 10, 64) + if err != nil { + err = fmt.Errorf("Wrong Content-Length value: %v", err) + return res, err + } + respBuffer := bytes.NewBuffer(nil) + size, err := io.Copy(respBuffer, resp.Body) + if err != nil { + return res, err + } + respBytes := respBuffer.Bytes() + if size != declSize { + err := fmt.Errorf("Mismatch Content-Length and recorded filesize") + return res, err + } + fmt.Printf("list: %s\n",string(respBytes)) + err = json.Unmarshal(respBytes, &res) + if err != nil { + return res, err + } + return res, err +} diff --git a/pkg/client/filelife_test.go b/pkg/client/filelife_test.go index 0054a60..a1280f2 100644 --- a/pkg/client/filelife_test.go +++ b/pkg/client/filelife_test.go @@ -24,7 +24,7 @@ import ( "github.com/stretchr/testify/require" ) -func xxxTestFileLife(t *testing.T) { +func TestFileLife(t *testing.T) { var srvport int64 = 10250 srvdir := t.TempDir() srvaddr := fmt.Sprintf("127.0.0.1:%d", srvport) @@ -119,6 +119,18 @@ func xxxTestFileLife(t *testing.T) { require.NoError(t, err) require.Equal(t, recsize, int64(filesize)) } + { + // ListFiles + fmt.Printf("=== ListFiles ===\n") + cli := NewClient() + ctx := context.Background() + ctx, _ = context.WithTimeout(ctx, 1*time.Second) + + files, err := cli.ListFiles(ctx, srvaddr+"/") + require.NoError(t, err) + require.NotZero(t, len(files)) + } + { // DeleteFile fmt.Printf("=== DeleteFile ===\n") diff --git a/pkg/client/imagelife_test.go b/pkg/client/imagelife_test.go index 1c1816e..bb611ce 100644 --- a/pkg/client/imagelife_test.go +++ b/pkg/client/imagelife_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestImageLife(t *testing.T) { +func xxxTestImageLife(t *testing.T) { var srvport int64 = 10250 srvdir := t.TempDir() srvaddr := fmt.Sprintf("127.0.0.1:%d", srvport)