mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-06 20:17:38 +01:00
filer: hide write controls in the UI on the read-only port (#12429)
* filer: hide write controls in the UI on the read-only port The read-only port accepts only GET and HEAD, but its directory page offered New Folder, Upload, drag-and-drop, rename and delete, each of which failed with 405. Requests that come through the read-only handler now render the page without those controls or the upload script. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * filer: test the directory page controls on each port Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * filer: match the rendered row buttons in the port test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e44c16802d
commit
878979af70
4 files changed
+84
-1
No files matched your search
@@ -194,7 +194,7 @@ func (fs *FilerServer) readonlyFilerHandler(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet, http.MethodHead:
|
||||
fs.GetOrHeadHandler(w, r)
|
||||
fs.GetOrHeadHandler(w, r.WithContext(context.WithValue(r.Context(), readOnlyListingKey{}, true)))
|
||||
default:
|
||||
requestMethod = "INVALID"
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
|
||||
@@ -13,6 +13,10 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/version"
|
||||
)
|
||||
|
||||
// readOnlyListingKey marks a request served on the read-only port, whose
|
||||
// listing page must not offer write operations.
|
||||
type readOnlyListingKey struct{}
|
||||
|
||||
// listDirectoryHandler lists directories and folders under a directory
|
||||
// files are sorted by name and paginated via "lastFileName" and "limit".
|
||||
// sub directories are listed on the first page, when "lastFileName"
|
||||
@@ -91,6 +95,7 @@ func (fs *FilerServer) listDirectoryHandler(w http.ResponseWriter, r *http.Reque
|
||||
ShouldDisplayLoadMore bool
|
||||
EmptyFolder bool
|
||||
ShowDirectoryDelete bool
|
||||
ReadOnly bool
|
||||
}{
|
||||
version.Version(),
|
||||
path,
|
||||
@@ -101,6 +106,7 @@ func (fs *FilerServer) listDirectoryHandler(w http.ResponseWriter, r *http.Reque
|
||||
shouldDisplayLoadMore,
|
||||
emptyFolder,
|
||||
fs.option.ShowUIDirectoryDelete,
|
||||
ctx.Value(readOnlyListingKey{}) != nil,
|
||||
})
|
||||
if err != nil {
|
||||
glog.V(0).InfofCtx(ctx, "Template Execute Error: %v", err)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package weed_server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/filer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/security"
|
||||
)
|
||||
|
||||
func TestListDirectoryWriteControlsFollowPort(t *testing.T) {
|
||||
mtime := time.Unix(1700000000, 0)
|
||||
store := newRenameTestStore()
|
||||
store.entries["/docs"] = &filer.Entry{FullPath: "/docs", Attr: filer.Attr{Mtime: mtime, Mode: os.ModeDir | 0755}}
|
||||
store.entries["/docs/sub"] = &filer.Entry{FullPath: "/docs/sub", Attr: filer.Attr{Mtime: mtime, Mode: os.ModeDir | 0755}}
|
||||
store.entries["/docs/a.txt"] = &filer.Entry{FullPath: "/docs/a.txt", Attr: filer.Attr{Mtime: mtime, Mode: 0644}}
|
||||
store.entries["/empty"] = &filer.Entry{FullPath: "/empty", Attr: filer.Attr{Mtime: mtime, Mode: os.ModeDir | 0755}}
|
||||
fs := &FilerServer{
|
||||
filer: newRenameTestFiler(t, store),
|
||||
option: &FilerOption{ExposeDirectoryData: true, DirListingLimit: 100, ShowUIDirectoryDelete: true},
|
||||
filerGuard: security.NewGuard(nil, "", 0, "", 0),
|
||||
}
|
||||
|
||||
writeControls := []string{
|
||||
`onclick="handleCreateDir()"`,
|
||||
`for="fileElem"`,
|
||||
`for="dirElem"`,
|
||||
`onclick="handleRename(`,
|
||||
`onclick="handleDelete(`,
|
||||
`class="row add-files"`,
|
||||
"function uploadFile(",
|
||||
}
|
||||
|
||||
render := func(t *testing.T, handler http.HandlerFunc, path string) string {
|
||||
t.Helper()
|
||||
rec := httptest.NewRecorder()
|
||||
handler(rec, httptest.NewRequest(http.MethodGet, path, nil))
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("GET %s: status %d, body %s", path, rec.Code, rec.Body.String())
|
||||
}
|
||||
return rec.Body.String()
|
||||
}
|
||||
|
||||
for _, path := range []string{"/docs/", "/empty/"} {
|
||||
readOnly := render(t, fs.readonlyFilerHandler, path)
|
||||
if !strings.Contains(readOnly, "<ol class=\"breadcrumb\">") {
|
||||
t.Fatalf("read-only listing of %s is not the directory page:\n%s", path, readOnly)
|
||||
}
|
||||
for _, control := range writeControls {
|
||||
if strings.Contains(readOnly, control) {
|
||||
t.Errorf("read-only listing of %s offers %q", path, control)
|
||||
}
|
||||
}
|
||||
}
|
||||
if readOnly := render(t, fs.readonlyFilerHandler, "/docs/"); !strings.Contains(readOnly, "a.txt") || !strings.Contains(readOnly, "sub") {
|
||||
t.Errorf("read-only listing lost its entries:\n%s", readOnly)
|
||||
}
|
||||
|
||||
writable := render(t, fs.GetOrHeadHandler, "/docs/") + render(t, fs.GetOrHeadHandler, "/empty/")
|
||||
for _, control := range writeControls {
|
||||
if !strings.Contains(writable, control) {
|
||||
t.Errorf("listing on the main port is missing %q", control)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div>
|
||||
{{ if not .ReadOnly }}
|
||||
<div class="btn-group btn-group-sm pull-right" role="group" style="margin-top:3px;">
|
||||
<label class="btn btn-default" onclick="handleCreateDir()">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> New Folder
|
||||
@@ -98,6 +99,7 @@
|
||||
<span class="glyphicon glyphicon-folder-close" aria-hidden="true"></span> Upload Folder
|
||||
</label>
|
||||
</div>
|
||||
{{ end }}
|
||||
<ol class="breadcrumb">
|
||||
{{ range $entry := .Breadcrumbs }}
|
||||
<li><a href="{{ printpath $entry.Link }}">
|
||||
@@ -114,9 +116,11 @@
|
||||
<input type="file" id="dirElem" webkitdirectory multiple onchange="handleFiles(this.files)">
|
||||
|
||||
{{ if .EmptyFolder }}
|
||||
{{ if not .ReadOnly }}
|
||||
<div class="row add-files">
|
||||
+
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<table width="100%" class="table table-hover">
|
||||
{{ $path := .Path }}
|
||||
@@ -148,6 +152,7 @@
|
||||
<td align="right" nowrap>
|
||||
{{ $entry.Timestamp.Format "2006-01-02 15:04" }}
|
||||
</td>
|
||||
{{ if not $.ReadOnly }}
|
||||
<td style="width:75px">
|
||||
<div class="btn-group btn-group-xs pull-right operations" role="group">
|
||||
<label class="btn" onclick="handleRename('{{ $entry.Name }}', '{{ printpath $path "/" }}')">
|
||||
@@ -165,6 +170,7 @@
|
||||
{{ end }}
|
||||
</div>
|
||||
</td>
|
||||
{{ end }}
|
||||
</tr>
|
||||
{{ end }}
|
||||
</table>
|
||||
@@ -186,6 +192,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
{{ if not .ReadOnly }}
|
||||
<script type="text/javascript">
|
||||
// ************************ Drag and drop ***************** //
|
||||
let dropArea = document.getElementById("drop-area");
|
||||
@@ -442,4 +449,5 @@
|
||||
reloadPage();
|
||||
}
|
||||
</script>
|
||||
{{ end }}
|
||||
</html>
|
||||
Reference in new issue
Block a user