2019-12-13 16:02:48 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
"net/http"
|
2020-02-04 11:02:29 +00:00
|
|
|
"path"
|
2019-12-13 16:02:48 +00:00
|
|
|
"strconv"
|
2020-11-09 13:43:23 +00:00
|
|
|
"strings"
|
|
|
|
"sync"
|
2020-02-14 10:06:43 +00:00
|
|
|
"time"
|
2019-12-13 16:02:48 +00:00
|
|
|
|
2020-11-09 13:43:23 +00:00
|
|
|
sdk "github.com/nspcc-dev/cdn-neofs-sdk"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
2020-04-22 10:34:48 +00:00
|
|
|
"github.com/pkg/errors"
|
2020-02-28 17:03:56 +00:00
|
|
|
"github.com/valyala/fasthttp"
|
2019-12-13 16:02:48 +00:00
|
|
|
"go.uber.org/zap"
|
2020-04-22 10:34:48 +00:00
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
2019-12-13 16:02:48 +00:00
|
|
|
)
|
|
|
|
|
2020-11-09 13:43:23 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-02-28 17:03:56 +00:00
|
|
|
func (a *app) receiveFile(c *fasthttp.RequestCtx) {
|
2019-12-13 16:02:48 +00:00
|
|
|
var (
|
2020-02-28 17:03:56 +00:00
|
|
|
err error
|
2020-11-09 13:43:23 +00:00
|
|
|
disp = "inline"
|
2020-02-28 17:03:56 +00:00
|
|
|
start = time.Now()
|
2020-11-09 13:43:23 +00:00
|
|
|
address = object.NewAddress()
|
2020-02-28 17:03:56 +00:00
|
|
|
sCID, _ = c.UserValue("cid").(string)
|
|
|
|
sOID, _ = c.UserValue("oid").(string)
|
2020-11-09 13:43:23 +00:00
|
|
|
value = strings.Join([]string{sCID, sOID}, "/")
|
|
|
|
|
|
|
|
filename string
|
2019-12-13 16:02:48 +00:00
|
|
|
)
|
|
|
|
|
2020-02-28 17:03:56 +00:00
|
|
|
log := a.log.With(
|
2020-02-25 10:31:20 +00:00
|
|
|
// zap.String("node", con.Target()),
|
2020-02-28 17:03:56 +00:00
|
|
|
zap.String("cid", sCID),
|
|
|
|
zap.String("oid", sOID))
|
2019-12-13 16:02:48 +00:00
|
|
|
|
2020-11-09 13:43:23 +00:00
|
|
|
if err = address.Parse(value); err != nil {
|
|
|
|
log.Error("wrong object address", zap.Error(err))
|
|
|
|
c.Error("wrong object address", fasthttp.StatusBadRequest)
|
2020-02-28 17:03:56 +00:00
|
|
|
return
|
2019-12-13 16:02:48 +00:00
|
|
|
}
|
|
|
|
|
2020-11-09 13:43:23 +00:00
|
|
|
writer := newDetector(c.Response.BodyWriter())
|
|
|
|
obj, err := a.cli.Object().Get(c, address, sdk.WithGetWriter(writer))
|
|
|
|
if err != nil {
|
2020-02-14 10:06:43 +00:00
|
|
|
log.Error("could not receive object",
|
2020-02-25 15:35:46 +00:00
|
|
|
zap.Stringer("elapsed", time.Since(start)),
|
2020-02-14 10:06:43 +00:00
|
|
|
zap.Error(err))
|
2019-12-13 16:02:48 +00:00
|
|
|
|
2020-04-22 10:34:48 +00:00
|
|
|
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()
|
2019-12-13 16:02:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 10:34:48 +00:00
|
|
|
c.Error(msg, code)
|
2020-02-28 17:03:56 +00:00
|
|
|
return
|
2019-12-13 16:02:48 +00:00
|
|
|
}
|
2020-02-28 17:03:56 +00:00
|
|
|
|
2020-11-09 13:43:23 +00:00
|
|
|
if c.Request.URI().QueryArgs().GetBool("download") {
|
|
|
|
disp = "attachment"
|
|
|
|
}
|
2020-02-28 17:03:56 +00:00
|
|
|
|
2020-11-23 09:32:03 +00:00
|
|
|
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:
|
2020-11-09 13:43:23 +00:00
|
|
|
filename = val
|
2020-11-23 09:32:03 +00:00
|
|
|
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))
|
2020-02-28 17:03:56 +00:00
|
|
|
}
|
|
|
|
|
2020-11-09 13:43:23 +00:00
|
|
|
}
|
2020-02-28 17:03:56 +00:00
|
|
|
|
2020-11-09 13:43:23 +00:00
|
|
|
c.SetContentType(writer.contentType)
|
|
|
|
c.Response.Header.Set("Content-Disposition", disp+"; filename="+path.Base(filename))
|
2019-12-13 16:02:48 +00:00
|
|
|
}
|