[#240] Fix native index page
All checks were successful
/ DCO (pull_request) Successful in 27s
/ Vulncheck (pull_request) Successful in 55s
/ Builds (pull_request) Successful in 1m36s
/ OCI image (pull_request) Successful in 2m22s
/ Lint (pull_request) Successful in 2m12s
/ Tests (pull_request) Successful in 57s
/ Integration tests (pull_request) Successful in 6m59s

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2025-05-06 11:37:28 +03:00
parent 39cf4e508e
commit 52481375b0
3 changed files with 76 additions and 30 deletions

View file

@ -76,13 +76,13 @@ func newListObjectsResponseNative(attrs map[string]string) ResponseObject {
} }
} }
func getNextDir(filepath, prefix string) string { func getNextDir(filepath, prefix string) *string {
restPath := strings.Replace(filepath, prefix, "", 1) restPath := strings.Replace(filepath, prefix, "", 1)
index := strings.Index(restPath, "/") index := strings.Index(restPath, "/")
if index == -1 { if index == -1 {
return "" return nil
} }
return restPath[:index] return ptr(restPath[:index])
} }
func lastPathElement(path string) string { func lastPathElement(path string) string {
@ -143,7 +143,7 @@ func getParent(encPrefix string) string {
if slashIndex == -1 { if slashIndex == -1 {
return "" return ""
} }
return prefix[:slashIndex] return prefix[:slashIndex+1]
} }
func urlencode(path string) string { func urlencode(path string) string {
@ -259,7 +259,7 @@ func (h *Handler) getDirObjectsNative(ctx context.Context, bucketInfo *data.Buck
if _, ok := dirs[objExt.Object.FileName]; ok { if _, ok := dirs[objExt.Object.FileName]; ok {
continue continue
} }
objExt.Object.GetURL = "/get/" + bucketInfo.CID.EncodeToString() + urlencode(objExt.Object.FilePath) objExt.Object.GetURL = "/get/" + bucketInfo.CID.EncodeToString() + "/" + urlencode(objExt.Object.FilePath)
dirs[objExt.Object.FileName] = struct{}{} dirs[objExt.Object.FileName] = struct{}{}
} else { } else {
objExt.Object.GetURL = "/get/" + bucketInfo.CID.EncodeToString() + "/" + objExt.Object.OID objExt.Object.GetURL = "/get/" + bucketInfo.CID.EncodeToString() + "/" + objExt.Object.OID
@ -331,13 +331,13 @@ func (h *Handler) headDirObject(ctx context.Context, cnrID cid.ID, objID oid.ID,
} }
dirname := getNextDir(attrs[object.AttributeFilePath], basePath) dirname := getNextDir(attrs[object.AttributeFilePath], basePath)
if dirname == "" { if dirname == nil {
return newListObjectsResponseNative(attrs), nil return newListObjectsResponseNative(attrs), nil
} }
return ResponseObject{ return ResponseObject{
FileName: dirname, FileName: *dirname,
FilePath: basePath + dirname, FilePath: basePath + *dirname,
IsDir: true, IsDir: true,
}, nil }, nil
} }

View file

@ -520,15 +520,23 @@ func TestIndex(t *testing.T) {
obj1.SetAttributes(prepareObjectAttributes(object.AttributeFilePath, "prefix/obj1")) obj1.SetAttributes(prepareObjectAttributes(object.AttributeFilePath, "prefix/obj1"))
hc.frostfs.objects[cnrID.String()+"/"+obj1ID.String()] = obj1 hc.frostfs.objects[cnrID.String()+"/"+obj1ID.String()] = obj1
obj2ID := oidtest.ID()
obj2 := object.New()
obj2.SetID(obj2ID)
obj2.SetPayload([]byte("obj2"))
obj2.SetAttributes(prepareObjectAttributes(object.AttributeFilePath, "/dir/.."))
hc.frostfs.objects[cnrID.String()+"/"+obj2ID.String()] = obj2
hc.tree.containers[cnrID.String()] = containerInfo{ hc.tree.containers[cnrID.String()] = containerInfo{
trees: map[string]map[string]nodeResponse{ trees: map[string]map[string]nodeResponse{
"system": {"bucket-settings": nodeResponse{nodeID: 1}}, "system": {"bucket-settings": nodeResponse{nodeID: 1}},
"version": { "version": {
"": nodeResponse{}, //root "<root>": nodeResponse{}, //root
"prefix": nodeResponse{ "prefix": nodeResponse{
nodeID: 1, nodeID: 1,
meta: []nodeMeta{{key: tree.FileNameKey, value: []byte("prefix")}}}, meta: []nodeMeta{{key: tree.FileNameKey, value: []byte("prefix")}},
"obj1": nodeResponse{ },
"prefix/obj1": nodeResponse{
parentID: 1, parentID: 1,
nodeID: 2, nodeID: 2,
meta: []nodeMeta{ meta: []nodeMeta{
@ -536,6 +544,23 @@ func TestIndex(t *testing.T) {
{key: "OID", value: []byte(obj1ID.String())}, {key: "OID", value: []byte(obj1ID.String())},
}, },
}, },
"": nodeResponse{
nodeID: 3,
meta: []nodeMeta{{key: tree.FileNameKey, value: []byte("")}},
},
"/dir": nodeResponse{
parentID: 3,
nodeID: 4,
meta: []nodeMeta{{key: tree.FileNameKey, value: []byte("dir")}},
},
"/dir/..": nodeResponse{
parentID: 4,
nodeID: 5,
meta: []nodeMeta{
{key: tree.FileNameKey, value: []byte("..")},
{key: "OID", value: []byte(obj2ID.String())},
},
},
}, },
}, },
} }
@ -563,6 +588,21 @@ func TestIndex(t *testing.T) {
r = prepareGetRequest(ctx, "bucket", "dummy") r = prepareGetRequest(ctx, "bucket", "dummy")
hc.Handler().DownloadByAddressOrBucketName(r) hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), "Index of s3://bucket/dummy") require.Contains(t, string(r.Response.Body()), "Index of s3://bucket/dummy")
r = prepareGetRequest(ctx, "bucket", "")
hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), `<a href="/get/bucket/">..</a>`)
require.Contains(t, string(r.Response.Body()), `<a href="/get/bucket//">/</a>`)
r = prepareGetRequest(ctx, "bucket", "/")
hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), `<a href="/get/bucket/">..</a>`)
require.Contains(t, string(r.Response.Body()), `<a href="/get/bucket//dir/">dir/</a>`)
r = prepareGetRequest(ctx, "bucket", "/dir/")
hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), `<a href="/get/bucket//">..</a>`)
require.Contains(t, string(r.Response.Body()), `<a href="/get/bucket//dir%2F..">..</a>`)
}) })
t.Run("native", func(t *testing.T) { t.Run("native", func(t *testing.T) {
@ -575,6 +615,13 @@ func TestIndex(t *testing.T) {
obj1.SetAttributes(prepareObjectAttributes(object.AttributeFilePath, "prefix/obj1")) obj1.SetAttributes(prepareObjectAttributes(object.AttributeFilePath, "prefix/obj1"))
hc.frostfs.objects[cnrID.String()+"/"+obj1ID.String()] = obj1 hc.frostfs.objects[cnrID.String()+"/"+obj1ID.String()] = obj1
obj2ID := oidtest.ID()
obj2 := object.New()
obj2.SetID(obj2ID)
obj2.SetPayload([]byte("obj2"))
obj2.SetAttributes(prepareObjectAttributes(object.AttributeFilePath, "/dir/.."))
hc.frostfs.objects[cnrID.String()+"/"+obj2ID.String()] = obj2
r := prepareGetRequest(ctx, cnrID.EncodeToString(), "prefix/") r := prepareGetRequest(ctx, cnrID.EncodeToString(), "prefix/")
hc.Handler().DownloadByAddressOrBucketName(r) hc.Handler().DownloadByAddressOrBucketName(r)
require.Equal(t, fasthttp.StatusNotFound, r.Response.StatusCode()) require.Equal(t, fasthttp.StatusNotFound, r.Response.StatusCode())
@ -598,6 +645,21 @@ func TestIndex(t *testing.T) {
r = prepareGetRequest(ctx, cnrID.EncodeToString(), "dummy") r = prepareGetRequest(ctx, cnrID.EncodeToString(), "dummy")
hc.Handler().DownloadByAddressOrBucketName(r) hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), "Index of frostfs://"+cnrID.String()+"/dummy") require.Contains(t, string(r.Response.Body()), "Index of frostfs://"+cnrID.String()+"/dummy")
r = prepareGetRequest(ctx, cnrID.EncodeToString(), "")
hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), `<a href="/get/`+cnrID.String()+`/">..</a>`)
require.Contains(t, string(r.Response.Body()), `<a href="/get/`+cnrID.String()+`//">/</a>`)
r = prepareGetRequest(ctx, cnrID.EncodeToString(), "/")
hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), `<a href="/get/`+cnrID.String()+`/">..</a>`)
require.Contains(t, string(r.Response.Body()), `<a href="/get/`+cnrID.String()+`//dir/">dir/</a>`)
r = prepareGetRequest(ctx, cnrID.EncodeToString(), "/dir/")
hc.Handler().DownloadByAddressOrBucketName(r)
require.Contains(t, string(r.Response.Body()), `<a href="/get/`+cnrID.String()+`//">..</a>`)
require.Contains(t, string(r.Response.Body()), `<a href="/get/`+cnrID.String()+`/`+obj2ID.String()+`">..</a>`)
}) })
} }

View file

@ -56,40 +56,24 @@
</thead> </thead>
<tbody> <tbody>
{{ $parentPrefix := getParent .Prefix }} {{ $parentPrefix := getParent .Prefix }}
{{if $parentPrefix }}
<tr> <tr>
<td> <td>
⮐<a href="/get/{{$container}}{{ urlencode $parentPrefix }}/">..</a> ⮐<a href="/get/{{$container}}/{{ urlencode $parentPrefix }}">..</a>
</td> </td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
{{else}}
<tr>
<td>
⮐<a href="/get/{{$container}}/">..</a>
</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
{{end}}
{{range .Objects}} {{range .Objects}}
<tr> <tr>
<td> <td>
{{if .IsDir}} {{if .IsDir}}
🗀 🗀
<a href="{{.GetURL}}/"> <a href="{{.GetURL}}/">{{.FileName}}/</a>
{{.FileName}}/
</a>
{{else}} {{else}}
🗎 🗎
<a href="{{ .GetURL }}"> <a href="{{ .GetURL }}">{{.FileName}}</a>
{{.FileName}}
</a>
{{end}} {{end}}
</td> </td>
<td>{{.OID}}</td> <td>{{.OID}}</td>