frostfs-http-gw/receive.go
Evgeniy Kulikov a4f7a2f962
Migrate to new release of NeoFS API
- migrate to new release NeoFS API / CDN SDK
- add `Last-Modified` header

Signed-off-by: Evgeniy Kulikov <kim@nspcc.ru>
2020-11-23 12:32:03 +03:00

124 lines
2.7 KiB
Go

package main
import (
"io"
"net/http"
"path"
"strconv"
"strings"
"sync"
"time"
sdk "github.com/nspcc-dev/cdn-neofs-sdk"
"github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/pkg/errors"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type detector struct {
io.Writer
sync.Once
contentType string
}
func newDetector(w io.Writer) *detector {
return &detector{Writer: w}
}
func (d *detector) Write(data []byte) (int, error) {
d.Once.Do(func() {
d.contentType = http.DetectContentType(data)
})
return d.Writer.Write(data)
}
func (a *app) receiveFile(c *fasthttp.RequestCtx) {
var (
err error
disp = "inline"
start = time.Now()
address = object.NewAddress()
sCID, _ = c.UserValue("cid").(string)
sOID, _ = c.UserValue("oid").(string)
value = strings.Join([]string{sCID, sOID}, "/")
filename string
)
log := a.log.With(
// zap.String("node", con.Target()),
zap.String("cid", sCID),
zap.String("oid", sOID))
if err = address.Parse(value); err != nil {
log.Error("wrong object address", zap.Error(err))
c.Error("wrong object address", fasthttp.StatusBadRequest)
return
}
writer := newDetector(c.Response.BodyWriter())
obj, err := a.cli.Object().Get(c, address, sdk.WithGetWriter(writer))
if err != nil {
log.Error("could not receive object",
zap.Stringer("elapsed", time.Since(start)),
zap.Error(err))
var (
msg = errors.Wrap(err, "could not receive object").Error()
code = fasthttp.StatusBadRequest
)
if st, ok := status.FromError(errors.Cause(err)); ok && st != nil {
if st.Code() == codes.NotFound {
code = fasthttp.StatusNotFound
}
msg = st.Message()
}
c.Error(msg, code)
return
}
if c.Request.URI().QueryArgs().GetBool("download") {
disp = "attachment"
}
c.Response.Header.Set("Content-Length", strconv.FormatUint(obj.PayloadSize(), 10))
c.Response.Header.Set("x-object-id", obj.ID().String())
c.Response.Header.Set("x-owner-id", obj.OwnerID().String())
c.Response.Header.Set("x-container-id", obj.ContainerID().String())
for _, attr := range obj.Attributes() {
key := attr.Key()
val := attr.Value()
c.Response.Header.Set("x-"+key, val)
switch key {
case object.AttributeFileName:
filename = val
case object.AttributeTimestamp:
value, err := strconv.ParseInt(val, 10, 64)
if err != nil {
a.log.Info("couldn't parse creation date",
zap.String("key", key),
zap.String("val", val),
zap.Error(err))
continue
}
c.Response.Header.Set("Last-Modified",
time.Unix(value, 0).Format(time.RFC1123))
}
}
c.SetContentType(writer.contentType)
c.Response.Header.Set("Content-Disposition", disp+"; filename="+path.Base(filename))
}