Skip to content

Commit

Permalink
rfc8114: prefer return minimal
Browse files Browse the repository at this point in the history
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
  • Loading branch information
butonic committed Sep 12, 2022
1 parent da16fd4 commit eef512c
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 95 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/prefer-return-minimal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: support Prefer: return=minimal in PROPFIND

To reduce HTTP body size when listing folders we implemented https://datatracker.ietf.org/doc/html/rfc8144#section-2.1 to omit the 404 propstat part when a `Prefer: return=minimal` header is present.

https://github.com/cs3org/reva/pull/3222
8 changes: 8 additions & 0 deletions internal/http/services/owncloud/ocdav/net/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const (
HeaderLocation = "Location"
HeaderRange = "Range"
HeaderIfMatch = "If-Match"
HeaderPrefer = "Prefer"
HeaderPreferenceApplied = "Preference-Applied"
HeaderVary = "Vary"
)

// webdav headers
Expand Down Expand Up @@ -66,3 +69,8 @@ const (
HeaderLitmus = "X-Litmus"
HeaderTransferAuth = "TransferHeaderAuthorization"
)

// HTTP Prefer header values
const (
HeaderPreferReturn = "return" // eg. return=representation / return=minimal, depth-noroot
)
15 changes: 15 additions & 0 deletions internal/http/services/owncloud/ocdav/net/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,18 @@ func ParseDestination(baseURI, s string) (string, error) {

return urlSplit[1], nil
}

// ParsePrefer parses the prefer header value defined in https://datatracker.ietf.org/doc/html/rfc8144
func ParsePrefer(s string) map[string]string {
parts := strings.Split(s, ",")
m := make(map[string]string, len(parts))
for _, part := range parts {
kv := strings.SplitN(strings.ToLower(strings.Trim(part, " ")), "=", 2)
if len(kv) == 2 {
m[kv[0]] = kv[1]
} else {
m[kv[0]] = "1" // mark it as set
}
}
return m
}
198 changes: 106 additions & 92 deletions internal/http/services/owncloud/ocdav/propfind/propfind.go

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion internal/http/services/owncloud/ocdav/publicfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s

infos := s.getPublicFileInfos(onContainer, depth == net.DepthZero, tokenStatInfo)

propRes, err := propfind.MultistatusResponse(ctx, &pf, infos, s.c.PublicURL, ns, nil)
prefer := net.ParsePrefer(r.Header.Get("prefer"))
returnMinimal := prefer[net.HeaderPreferReturn] == "minimal"

propRes, err := propfind.MultistatusResponse(ctx, &pf, infos, s.c.PublicURL, ns, nil, returnMinimal)
if err != nil {
sublog.Error().Err(err).Msg("error formatting propfind")
w.WriteHeader(http.StatusInternalServerError)
Expand All @@ -120,6 +123,10 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s

w.Header().Set(net.HeaderDav, "1, 3, extended-mkcol")
w.Header().Set(net.HeaderContentType, "application/xml; charset=utf-8")
w.Header().Set(net.HeaderVary, net.HeaderPrefer)
if returnMinimal {
w.Header().Set(net.HeaderPreferenceApplied, "return=minimal")
}
w.WriteHeader(http.StatusMultiStatus)
if _, err := w.Write(propRes); err != nil {
sublog.Err(err).Msg("error writing response")
Expand Down
9 changes: 8 additions & 1 deletion internal/http/services/owncloud/ocdav/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,21 @@ func (s *svc) doFilterFiles(w http.ResponseWriter, r *http.Request, ff *reportFi
infos = append(infos, statRes.Info)
}

responsesXML, err := propfind.MultistatusResponse(ctx, &propfind.XML{Prop: ff.Prop}, infos, s.c.PublicURL, namespace, nil)
prefer := net.ParsePrefer(r.Header.Get("prefer"))
returnMinimal := prefer[net.HeaderPreferReturn] == "minimal"

responsesXML, err := propfind.MultistatusResponse(ctx, &propfind.XML{Prop: ff.Prop}, infos, s.c.PublicURL, namespace, nil, returnMinimal)
if err != nil {
log.Error().Err(err).Msg("error formatting propfind")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set(net.HeaderDav, "1, 3, extended-mkcol")
w.Header().Set(net.HeaderContentType, "application/xml; charset=utf-8")
w.Header().Set(net.HeaderVary, net.HeaderPrefer)
if returnMinimal {
w.Header().Set(net.HeaderPreferenceApplied, "return=minimal")
}
w.WriteHeader(http.StatusMultiStatus)
if _, err := w.Write(responsesXML); err != nil {
log.Err(err).Msg("error writing response")
Expand Down
9 changes: 8 additions & 1 deletion internal/http/services/owncloud/ocdav/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,21 @@ func (h *VersionsHandler) doListVersions(w http.ResponseWriter, r *http.Request,
infos = append(infos, vi)
}

propRes, err := propfind.MultistatusResponse(ctx, &pf, infos, s.c.PublicURL, "", nil)
prefer := net.ParsePrefer(r.Header.Get("prefer"))
returnMinimal := prefer[net.HeaderPreferReturn] == "minimal"

propRes, err := propfind.MultistatusResponse(ctx, &pf, infos, s.c.PublicURL, "", nil, returnMinimal)
if err != nil {
sublog.Error().Err(err).Msg("error formatting propfind")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set(net.HeaderDav, "1, 3, extended-mkcol")
w.Header().Set(net.HeaderContentType, "application/xml; charset=utf-8")
w.Header().Set(net.HeaderVary, net.HeaderPrefer)
if returnMinimal {
w.Header().Set(net.HeaderPreferenceApplied, "return=minimal")
}
w.WriteHeader(http.StatusMultiStatus)
_, err = w.Write(propRes)
if err != nil {
Expand Down

0 comments on commit eef512c

Please sign in to comment.