diff --git a/app/handler/service.go b/app/handler/service.go index 59354aa..d95bb0d 100644 --- a/app/handler/service.go +++ b/app/handler/service.go @@ -1,6 +1,8 @@ package handler import ( + "net/http" + "mstore/app/operator" "mstore/app/router" ) @@ -10,5 +12,6 @@ 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/router/context.go b/app/router/context.go index 783301e..b17d16d 100644 --- a/app/router/context.go +++ b/app/router/context.go @@ -7,11 +7,11 @@ import ( ) type Context struct { - Ctx context.Context - Request *http.Request - Writer http.ResponseWriter - PathMap map[string]string - StatusCode int + Ctx context.Context + Request *http.Request + Writer http.ResponseWriter + PathMap map[string]string + StatusCode int } func NewContext(writer http.ResponseWriter, request *http.Request) *Context { @@ -30,7 +30,7 @@ func (rctx *Context) SetHeader(key, value string) { } func (rctx *Context) SetStatus(httpStatus int) { - rctx.StatusCode = httpStatus + rctx.StatusCode = httpStatus rctx.Writer.WriteHeader(httpStatus) } diff --git a/app/service/service.go b/app/service/service.go index 832ecf7..e11e3d5 100644 --- a/app/service/service.go +++ b/app/service/service.go @@ -55,6 +55,11 @@ func (svc *Service) Build() error { svc.logg.Infof("Service build ") svc.rout = router.NewRouter() + + svc.rout.Use(router.NewRecoveryMiddleware(svc.logg.Errorf)) + svc.rout.Use(router.NewLoggingMiddleware(svc.logg.Infof)) + svc.rout.Use(router.NewCorsMiddleware()) + svc.rout.Get("/v3/api/service/hello", svc.hand.SendHello) svc.rout.Head("/v3/api/file/{filepath}", svc.hand.FileExists) diff --git a/pkg/client/cliaux.go b/pkg/client/cliaux.go index 979942f..9f16d23 100644 --- a/pkg/client/cliaux.go +++ b/pkg/client/cliaux.go @@ -7,15 +7,18 @@ import ( "strings" ) -const fileAPI = "/v3/api/file/" -const serviceAPI = "/v3/api/service/" +const ( + serviceAPI = "/v3/api/service/" + fileAPI = "/v3/api/file/" + filesAPI = "/v3/api/files/" +) -func createBasicAuthPair(username, password string) string { +func encodeBasicAuth(username, password string) string { auth := username + ":" + password return "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) } -func convertFileLink(ref string) (string, error) { +func convertServiceRefer(ref string) (string, error) { var err error var res string if !strings.Contains(ref, "://") { @@ -25,13 +28,31 @@ func convertFileLink(ref string) (string, error) { if err != nil { return res, err } + url.Path = path.Clean(url.Path) + url.Path = path.Join(serviceAPI, url.Path) + url.User = nil + res = url.String() + return res, err +} + +func convertFileRefer(ref string) (string, error) { + var err error + var res string + if !strings.Contains(ref, "://") { + ref = "https://" + ref + } + url, err := url.Parse(ref) + if err != nil { + return res, err + } + url.Path = path.Clean(url.Path) url.Path = path.Join(fileAPI, url.Path) url.User = nil res = url.String() return res, err } -func convertServiceLink(ref string) (string, error) { +func convertFilesRefer(ref string) (string, error) { var err error var res string if !strings.Contains(ref, "://") { @@ -41,7 +62,8 @@ func convertServiceLink(ref string) (string, error) { if err != nil { return res, err } - url.Path = path.Join(serviceAPI, url.Path) + url.Path = path.Clean(url.Path) + url.Path = path.Join(filesAPI, url.Path) url.User = nil res = url.String() return res, err diff --git a/pkg/client/client.go b/pkg/client/client.go index 715ff96..420bffc 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -11,17 +11,27 @@ import ( "strconv" ) -type Client struct{} +type Client struct { + username string + password string +} func NewClient() *Client { return &Client{} } +func NewClientWithAuth(username, password string) *Client { + return &Client{ + username: username, + password: password, + } +} + func (cli *Client) ServiceHello(ctx context.Context, ref string) (bool, error) { var res bool var err error - ref, err = convertServiceLink(ref) + ref, err = convertServiceRefer(ref) if err != nil { return res, err } @@ -53,7 +63,7 @@ func (cli *Client) FileExists(ctx context.Context, ref string) (bool, error) { var res bool var err error - ref, err = convertFileLink(ref) + ref, err = convertFileRefer(ref) if err != nil { return res, err } @@ -62,6 +72,10 @@ func (cli *Client) FileExists(ctx context.Context, ref string) (bool, error) { return res, err } + if cli.username != "" && cli.password != "" { + req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password)) + } + transport := &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, @@ -81,10 +95,61 @@ func (cli *Client) FileExists(ctx context.Context, ref string) (bool, error) { return res, err } +func (cli *Client) PutFile(ctx context.Context, filename, ref string) error { + var err error + ref, err = convertFileRefer(ref) + if err != nil { + return err + } + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, ref, file) + if err != nil { + return err + } + + if cli.username != "" && cli.password != "" { + req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password)) + } + + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + client := &http.Client{ + Transport: transport, + } + fileinfo, err := os.Stat(filename) + if err != nil { + return err + } + filesize := fileinfo.Size() + + req.ContentLength = filesize + req.Header.Set("Content-Type", "application/octet-stream") + + 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) GetFile(ctx context.Context, ref, filename string) (int64, error) { var err error var size int64 - ref, err = convertFileLink(ref) + ref, err = convertFileRefer(ref) if err != nil { return size, err } @@ -93,6 +158,11 @@ func (cli *Client) GetFile(ctx context.Context, ref, filename string) (int64, er if err != nil { return size, err } + + if cli.username != "" && cli.password != "" { + req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password)) + } + transport := &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, @@ -141,55 +211,9 @@ func (cli *Client) GetFile(ctx context.Context, ref, filename string) (int64, er return size, err } -func (cli *Client) PutFile(ctx context.Context, filename, ref string) error { - var err error - ref, err = convertFileLink(ref) - if err != nil { - return err - } - file, err := os.Open(filename) - if err != nil { - return err - } - defer file.Close() - - req, err := http.NewRequestWithContext(ctx, http.MethodPut, ref, file) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - } - client := &http.Client{ - Transport: transport, - } - fileinfo, err := os.Stat(filename) - if err != nil { - return err - } - filesize := fileinfo.Size() - - req.ContentLength = filesize - req.Header.Set("Content-Type", "application/octet-stream") - - 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) DeleteFile(ctx context.Context, ref, filename string) error { var err error - ref, err = convertFileLink(ref) + ref, err = convertFileRefer(ref) if err != nil { return err } @@ -197,6 +221,11 @@ func (cli *Client) DeleteFile(ctx context.Context, ref, filename string) error { if err != nil { return err } + + if cli.username != "" && cli.password != "" { + req.Header.Add("Authorization", encodeBasicAuth(cli.username, cli.password)) + } + transport := &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index b808702..fadf287 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - //"mstore/pkg/client" "mstore/app/server" "github.com/stretchr/testify/require" @@ -67,12 +66,13 @@ func TestService(t *testing.T) { require.NoError(t, err) require.True(t, helloRes) } + filesize := 32 { // PutFile tmpdir := t.TempDir() tmpfile := filepath.Join(tmpdir, "foo.bin") - filedata := make([]byte, 32) + filedata := make([]byte, filesize) _, err = rand.Read(filedata) require.NoError(t, err) @@ -86,11 +86,21 @@ func TestService(t *testing.T) { err = cli.PutFile(ctx, tmpfile, srvaddr+"/foo.bin") require.NoError(t, err) + } + { + // FileExists + fmt.Printf("=== FileExists ===\n") + cli := NewClient() + ctx := context.Background() + ctx, _ = context.WithTimeout(ctx, 1*time.Second) + exists, err := cli.FileExists(ctx, srvaddr+"/foo.bin") + require.NoError(t, err) + require.True(t, exists) } { // GetFile - fmt.Printf("=== GetFil ===\n") + fmt.Printf("=== GetFile ===\n") cli := NewClient() ctx := context.Background() ctx, _ = context.WithTimeout(ctx, 1*time.Second) @@ -98,9 +108,33 @@ func TestService(t *testing.T) { tmpdir := t.TempDir() tmpfile := filepath.Join(tmpdir, "foo.bin") - _, err = cli.GetFile(ctx, srvaddr+"/foo.bin", tmpfile) + recsize, err := cli.GetFile(ctx, srvaddr+"/foo.bin", tmpfile) require.NoError(t, err) + require.Equal(t, recsize, int64(filesize)) + } + { + // DeleteFile + fmt.Printf("=== DeleteFile ===\n") + cli := NewClient() + ctx := context.Background() + ctx, _ = context.WithTimeout(ctx, 1*time.Second) + tmpdir := t.TempDir() + tmpfile := filepath.Join(tmpdir, "foo.bin") + + err = cli.DeleteFile(ctx, srvaddr+"/foo.bin", tmpfile) + require.NoError(t, err) + } + { + // !FileExists + fmt.Printf("=== FileExists ===\n") + cli := NewClient() + ctx := context.Background() + ctx, _ = context.WithTimeout(ctx, 1*time.Second) + + exists, err := cli.FileExists(ctx, srvaddr+"/foo.bin") + require.NoError(t, err) + require.False(t, exists) } }