Skip to content

Commit d2dd0f7

Browse files
committed
Propagate Content-Length header from incoming PUT call to EOS PuT call
1 parent 9d8ec0d commit d2dd0f7

File tree

10 files changed

+37
-21
lines changed

10 files changed

+37
-21
lines changed

CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @labkode @glpatcern @diocas @jessejeens
1+
* @labkode @glpatcern @diocas @jessegeens

internal/http/services/datagateway/datagateway.go

+1
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ func (s *svc) doPut(w http.ResponseWriter, r *http.Request) {
332332

333333
copyHeader(w.Header(), httpRes.Header)
334334
if httpRes.StatusCode != http.StatusOK {
335+
log.Warn().Int("StatusCode", httpRes.StatusCode).Msg("Non-OK Status Code when sending request to internal data server")
335336
// swallow the body and set content-length to 0 to prevent reverse proxies from trying to read from it
336337
w.Header().Set("Content-Length", "0")
337338
w.WriteHeader(httpRes.StatusCode)

internal/http/services/owncloud/ocdav/put.go

+8
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
278278
httpReq.Header.Set(HeaderLockHolder, lockholder)
279279
}
280280

281+
// We need to pass Content-Length to the storage backend (e.g. EOS).
282+
// However, the Go HTTP Client library may arbitrarily modify or drop
283+
// the Content-Length header, for example when it compresses the data
284+
// See: https://pkg.go.dev/net/http#Request
285+
// Therefore, we use another header to pass it through the internal
286+
// data server
287+
httpReq.Header.Set(HeaderUploadLength, strconv.FormatInt(length, 10))
288+
281289
// Propagate X-Disable-Versioning header
282290
// Used to disable versioning for applications that do not expect this behaviour
283291
// See reva#4855 for more info

pkg/eosclient/eosbinary/eosbinary.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ func (c *Client) Read(ctx context.Context, auth eosclient.Authorization, path st
722722
}
723723

724724
// Write writes a stream to the mgm.
725-
func (c *Client) Write(ctx context.Context, auth eosclient.Authorization, path string, stream io.ReadCloser, app string, disableVersioning bool) error {
725+
func (c *Client) Write(ctx context.Context, auth eosclient.Authorization, path string, stream io.ReadCloser, length int64, app string, disableVersioning bool) error {
726726
fd, err := os.CreateTemp(c.opt.CacheDirectory, "eoswrite-")
727727
if err != nil {
728728
return err

pkg/eosclient/eosclient.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ type EOSClient interface {
5151
Rename(ctx context.Context, auth Authorization, oldPath, newPath string) error
5252
List(ctx context.Context, auth Authorization, path string) ([]*FileInfo, error)
5353
Read(ctx context.Context, auth Authorization, path string) (io.ReadCloser, error)
54-
Write(ctx context.Context, auth Authorization, path string, stream io.ReadCloser, app string, disableVersioning bool) error
54+
Write(ctx context.Context, auth Authorization, path string, stream io.ReadCloser, length int64, app string, disableVersioning bool) error
5555
ListDeletedEntries(ctx context.Context, auth Authorization, maxentries int, from, to time.Time) ([]*DeletedEntry, error)
5656
RestoreDeletedEntry(ctx context.Context, auth Authorization, key string) error
5757
PurgeDeletedEntries(ctx context.Context, auth Authorization) error

pkg/eosclient/eosgrpc/eosgrpc.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -1364,11 +1364,9 @@ func (c *Client) Read(ctx context.Context, auth eosclient.Authorization, path st
13641364

13651365
// Write writes a file to the mgm
13661366
// Somehow the same considerations as Read apply.
1367-
func (c *Client) Write(ctx context.Context, auth eosclient.Authorization, path string, stream io.ReadCloser, app string, disableVersioning bool) error {
1367+
func (c *Client) Write(ctx context.Context, auth eosclient.Authorization, path string, stream io.ReadCloser, length int64, app string, disableVersioning bool) error {
13681368
log := appctx.GetLogger(ctx)
13691369
log.Info().Str("func", "Write").Str("uid,gid", auth.Role.UID+","+auth.Role.GID).Str("path", path).Msg("")
1370-
var length int64
1371-
length = -1
13721370

13731371
u, err := getUser(ctx)
13741372
if err != nil {

pkg/eosclient/eosgrpc/eoshttp.go

+2-13
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,6 @@ func (c *EOSHTTPClient) PUTFile(ctx context.Context, remoteuser string, auth eos
373373
base.RawQuery = queryValues.Encode()
374374
finalurl := base.String()
375375

376-
if err != nil {
377-
log.Error().Str("func", "PUTFile").Str("url", finalurl).Str("err", err.Error()).Msg("can't create request")
378-
return err
379-
}
380376
req, err := http.NewRequestWithContext(ctx, http.MethodPut, finalurl, nil)
381377
if err != nil {
382378
log.Error().Str("func", "PUTFile").Str("url", finalurl).Str("err", err.Error()).Msg("can't create request")
@@ -424,15 +420,8 @@ func (c *EOSHTTPClient) PUTFile(ctx context.Context, remoteuser string, auth eos
424420
}
425421
if length >= 0 {
426422
log.Debug().Str("func", "PUTFile").Int64("Content-Length", length).Msg("setting header")
427-
req.Header.Set("Content-Length", strconv.FormatInt(length, 10))
428-
}
429-
if err != nil {
430-
log.Error().Str("func", "PUTFile").Str("url", loc.String()).Str("err", err.Error()).Msg("can't create redirected request")
431-
return err
432-
}
433-
if length >= 0 {
434-
log.Debug().Str("func", "PUTFile").Int64("Content-Length", length).Msg("setting header")
435-
req.Header.Set("Content-Length", strconv.FormatInt(length, 10))
423+
req.ContentLength = length
424+
req.Header.Set("Content-Length", fmt.Sprintf("%d", length))
436425
}
437426

438427
log.Debug().Str("func", "PUTFile").Str("location", loc.String()).Msg("redirection")

pkg/rhttp/datatx/manager/simple/simple.go

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package simple
2121
import (
2222
"context"
2323
"net/http"
24+
"strconv"
2425

2526
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
2627
"github.com/cs3org/reva/internal/http/services/owncloud/ocdav"
@@ -88,6 +89,14 @@ func (m *manager) Handler(fs storage.FS) (http.Handler, error) {
8889
metadata["disableVersioning"] = disableVersioning
8990
}
9091

92+
contentLength := r.Header.Get(ocdav.HeaderUploadLength)
93+
94+
if _, err := strconv.ParseInt(contentLength, 10, 64); err == nil {
95+
metadata[ocdav.HeaderContentLength] = contentLength
96+
} else {
97+
w.WriteHeader(http.StatusBadRequest)
98+
}
99+
91100
err := fs.Upload(ctx, ref, r.Body, metadata)
92101
switch v := err.(type) {
93102
case nil:

pkg/storage/utils/eosfs/upload.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"strconv"
2727

2828
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
29+
"github.com/cs3org/reva/internal/http/services/owncloud/ocdav"
2930
"github.com/cs3org/reva/pkg/errtypes"
3031
"github.com/cs3org/reva/pkg/storage/utils/chunking"
3132
"github.com/pkg/errors"
@@ -93,7 +94,13 @@ func (fs *eosfs) Upload(ctx context.Context, ref *provider.Reference, r io.ReadC
9394
disableVersioning = false
9495
}
9596

96-
return fs.c.Write(ctx, auth, fn, r, app, disableVersioning)
97+
contentLength := metadata[ocdav.HeaderContentLength]
98+
len, err := strconv.ParseInt(contentLength, 10, 64)
99+
if err != nil {
100+
return errors.New("No content length specified in EOS upload, got: " + contentLength)
101+
}
102+
103+
return fs.c.Write(ctx, auth, fn, r, len, app, disableVersioning)
97104
}
98105

99106
func (fs *eosfs) InitiateUpload(ctx context.Context, ref *provider.Reference, uploadLength int64, metadata map[string]string) (map[string]string, error) {

tests/helpers/helpers.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ import (
2828
"os"
2929
"path/filepath"
3030
"runtime"
31+
"strconv"
3132

3233
"github.com/pkg/errors"
3334

3435
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
3536
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
3637
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
3738
"github.com/cs3org/reva/internal/http/services/datagateway"
39+
"github.com/cs3org/reva/internal/http/services/owncloud/ocdav"
3840
"github.com/cs3org/reva/pkg/httpclient"
3941
"github.com/cs3org/reva/pkg/storage"
4042
"github.com/studio-b12/gowebdav"
@@ -105,7 +107,9 @@ func Upload(ctx context.Context, fs storage.FS, ref *provider.Reference, content
105107
return errors.New("simple upload method not available")
106108
}
107109
uploadRef := &provider.Reference{Path: "/" + uploadID}
108-
err = fs.Upload(ctx, uploadRef, io.NopCloser(bytes.NewReader(content)), map[string]string{})
110+
err = fs.Upload(ctx, uploadRef, io.NopCloser(bytes.NewReader(content)), map[string]string{
111+
ocdav.HeaderUploadLength: strconv.FormatInt(int64(len(content)), 10),
112+
})
109113
return err
110114
}
111115

0 commit comments

Comments
 (0)