diff --git a/internal/http/services/dataprovider/dataprovider.go b/internal/http/services/dataprovider/dataprovider.go index ff72e11fa0..af2926a0c1 100644 --- a/internal/http/services/dataprovider/dataprovider.go +++ b/internal/http/services/dataprovider/dataprovider.go @@ -21,7 +21,11 @@ package dataprovider import ( "fmt" "net/http" + "strings" + "time" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/cs3org/reva/internal/http/utils" "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/rhttp/global" "github.com/cs3org/reva/pkg/storage" @@ -48,6 +52,28 @@ type svc struct { storage storage.FS } +type WrappedResponseWriter struct { + http.ResponseWriter + statusCode int +} + +func (w *WrappedResponseWriter) WriteHeader(statusCode int) { + w.statusCode = statusCode + // delay this +} + +func (w *WrappedResponseWriter) SendResponse() { + w.ResponseWriter.WriteHeader(w.statusCode) +} + +func (w *WrappedResponseWriter) Header() http.Header { + return w.ResponseWriter.Header() +} + +func (w *WrappedResponseWriter) Write(bytes []byte) (int, error) { + return w.ResponseWriter.Write(bytes) +} + // New returns a new datasvc func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) { conf := &config{} @@ -107,6 +133,37 @@ type Composable interface { UseIn(composer *tusd.StoreComposer) } +func (s *svc) writeFileInfoHeaders(w http.ResponseWriter, r *http.Request, dest string) error { + ctx := r.Context() + log := appctx.GetLogger(ctx) + log.Debug().Msg("dataprovider: writeFileInfoHeaders()") + fn := dest + + // FIXME: seems trim prefix doesn't trim anything + fsfn := strings.TrimPrefix(fn, s.conf.Prefix) + log.Debug().Str("dest", dest).Str("fsfn", fsfn).Msg("writeFileInfoHeaders") + //ref := &provider.Reference{Spec: &provider.Reference_Path{Path: fsfn}} + // TODO: try reading info data + ref := &provider.Reference{Spec: &provider.Reference_Path{Path: fsfn}} + sRes, err := s.storage.GetMD(ctx, ref) + if err != nil { + log.Error().Err(err).Msg("error sending grpc GetMD request after upload") + return err + } + + log.Debug().Interface("fileid", sRes.GetId()).Msg("Got fileid") + w.Header().Add("Content-Type", sRes.GetMimeType()) + w.Header().Set("ETag", sRes.GetEtag()) + // FIXME: implement wrap on this layer + //w.Header().Set("OC-FileId", wrapResourceID(sRes.GetId())) + w.Header().Set("OC-ETag", sRes.GetEtag()) + t := utils.TSToTime(sRes.GetMtime()) + lastModifiedString := t.Format(time.RFC1123) + w.Header().Set("Last-Modified", lastModifiedString) + w.Header().Set("X-OC-MTime", "accepted") + return nil +} + func (s *svc) setHandler() (err error) { composable, ok := s.storage.(Composable) if ok && !s.conf.DisableTus { @@ -120,8 +177,9 @@ func (s *svc) setHandler() (err error) { composable.UseIn(composer) config := tusd.Config{ - BasePath: s.conf.Prefix, - StoreComposer: composer, + BasePath: s.conf.Prefix, + StoreComposer: composer, + NotifyCompleteUploads: true, //Logger: logger, // TODO use logger } @@ -158,7 +216,36 @@ func (s *svc) setHandler() (err error) { case "HEAD": handler.HeadFile(w, r) case "PATCH": - handler.PatchFile(w, r) + // HACK: make it possible to send headers after the TUS handler has already sent the response + wrappedWriter := &WrappedResponseWriter{ResponseWriter: w} + + var uploadStorage map[string]string + + // HACK: need to get access to the upload info, which is only accessible + // through the events + quit := make(chan struct{}) + go func() { + for { + select { + case info := <-handler.CompleteUploads: + if info.HTTPRequest.URI == r.RequestURI { + uploadStorage = info.Upload.Storage + } + case <-quit: + return + } + } + }() + + handler.PatchFile(wrappedWriter, r) + close(quit) + + if uploadStorage != nil { + log.Debug().Interface("uploadStorage", uploadStorage).Msg("Upload complete") + s.writeFileInfoHeaders(w, r, uploadStorage["InternalDestination"]) + } + + wrappedWriter.SendResponse() // PUT provides a wrapper around the POST call, to save the caller from // the trouble of configuring the tus client. case "PUT": diff --git a/internal/http/services/dataprovider/put.go b/internal/http/services/dataprovider/put.go index 6471b475d5..8783cb982b 100644 --- a/internal/http/services/dataprovider/put.go +++ b/internal/http/services/dataprovider/put.go @@ -36,6 +36,7 @@ import ( func (s *svc) doPut(w http.ResponseWriter, r *http.Request) { ctx := r.Context() log := appctx.GetLogger(ctx) + log.Debug().Msg("dataprovider: doPut()") fn := r.URL.Path fsfn := strings.TrimPrefix(fn, s.conf.Prefix) @@ -49,6 +50,7 @@ func (s *svc) doPut(w http.ResponseWriter, r *http.Request) { } r.Body.Close() + w.WriteHeader(http.StatusOK) }