Skip to content

Commit 45272ce

Browse files
committed
put object with custom meta; enforce size limit
* fix copying multi-value headers * enforce 2KiB total size limit for custom keys Signed-off-by: Alex Aizman <alex.aizman@gmail.com>
1 parent 8c97b2e commit 45272ce

File tree

4 files changed

+70
-30
lines changed

4 files changed

+70
-30
lines changed

ais/tgtobj.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,18 @@ type (
145145
//
146146

147147
// poi.restful entry point
148-
func (poi *putOI) do(resphdr http.Header, r *http.Request, dpq *dpq) (int, error) {
149-
{
150-
poi.oreq = r
151-
poi.r = r.Body
152-
poi.resphdr = resphdr
153-
poi.workFQN = poi.lom.GenFQN(fs.WorkCT, fs.WorkfilePut)
154-
poi.cksumToUse = poi.lom.ObjAttrs().FromHeader(r.Header)
155-
poi.owt = cmn.OwtPut // default
148+
func (poi *putOI) do(resphdr http.Header, r *http.Request, dpq *dpq) (_ int, err error) {
149+
poi.oreq = r
150+
poi.r = r.Body
151+
poi.resphdr = resphdr
152+
poi.workFQN = poi.lom.GenFQN(fs.WorkCT, fs.WorkfilePut)
153+
poi.owt = cmn.OwtPut // default
154+
155+
oah := poi.lom.ObjAttrs()
156+
if poi.cksumToUse, err = oah.FromHeader(r.Header); err != nil {
157+
return 0, err
156158
}
159+
157160
if dpq.sys.owt != "" {
158161
poi.owt.FromS(dpq.sys.owt)
159162
}
@@ -1085,8 +1088,14 @@ func (goi *getOI) getFromNeighbor(lom *core.LOM, tsi *meta.Snode) bool {
10851088
return false
10861089
}
10871090

1088-
cksumToUse := lom.ObjAttrs().FromHeader(resp.Header)
1091+
oah := lom.ObjAttrs()
1092+
cksumToUse, err := oah.FromHeader(resp.Header)
1093+
if err != nil { // unlikely
1094+
debug.AssertNoErr(err)
1095+
nlog.Errorln("invalid obj attrs from neighbor:", err)
1096+
}
10891097
workFQN := lom.GenFQN(fs.WorkCT, fs.WorkfileRemote)
1098+
10901099
poi := allocPOI()
10911100
{
10921101
poi.t = goi.t

api/object.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/NVIDIA/aistore/api/apc"
1919
"github.com/NVIDIA/aistore/cmn"
2020
"github.com/NVIDIA/aistore/cmn/cos"
21+
"github.com/NVIDIA/aistore/cmn/debug"
2122

2223
jsoniter "github.com/json-iterator/go"
2324
)
@@ -176,7 +177,9 @@ func (oah *ObjAttrs) Size() int64 {
176177
}
177178

178179
func (oah *ObjAttrs) Attrs() (out cmn.ObjAttrs) {
179-
out.Cksum = out.FromHeader(oah.wrespHeader)
180+
var err error
181+
out.Cksum, err = out.FromHeader(oah.wrespHeader)
182+
debug.AssertNoErr(err)
180183
return out
181184
}
182185

@@ -451,7 +454,11 @@ func headobj(reqParams *ReqParams, noprops bool) (*cmn.ObjectProps, error) {
451454

452455
// first, cnm.ObjAttrs (compare with `t.objHead`)
453456
op := &cmn.ObjectProps{}
454-
op.Cksum = op.ObjAttrs.FromHeader(hdr)
457+
op.Cksum, err = op.ObjAttrs.FromHeader(hdr)
458+
if err != nil {
459+
debug.AssertNoErr(err)
460+
return nil, err
461+
}
455462

456463
// second, all the rest
457464
err = cmn.IterFields(op, func(tag string, field cmn.IterField) (error, bool) {

cmn/http.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package cmn
88
import (
99
"fmt"
1010
"io"
11+
"maps"
1112
"net/http"
1213
"os"
1314
"path/filepath"
@@ -171,15 +172,9 @@ func WriteErrJSON(w http.ResponseWriter, r *http.Request, out any, err error) er
171172
return err
172173
}
173174

174-
// Copies headers from original request(from client) to
175-
// a new one(inter-cluster call)
176-
func CopyHeaders(dst, src http.Header) {
177-
for k, values := range src {
178-
for _, v := range values {
179-
dst.Set(k, v)
180-
}
181-
}
182-
}
175+
// shallow copy http headers
176+
// inlining but keeping it for now (to maybe add checks if need be)
177+
func CopyHeaders(dst, src http.Header) { maps.Copy(dst, src) }
183178

184179
func ParseReadHeaderTimeout() (_ time.Duration, isSet bool) {
185180
val := os.Getenv(apc.EnvReadHeaderTimeout)

cmn/objattrs.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ const (
4444
OrigFntl = "orig_fntl"
4545
)
4646

47+
const (
48+
maxSizeCustomKVs = 2 * cos.KiB
49+
)
50+
4751
// object properties
48-
// NOTE: embeds system `ObjAttrs` that in turn includes custom user-defined
49-
// NOTE: compare with `apc.LsoMsg`
52+
// embeds system `ObjAttrs` that in turn includes custom user-defined
53+
// (compare with `apc.LsoMsg`)
5054
type ObjectProps struct {
5155
Bck Bck `json:"bucket"`
5256
ObjAttrs
@@ -231,8 +235,9 @@ func ToHeader(oah cos.OAH, hdr http.Header, size int64, cksums ...*cos.Cksum) {
231235
}
232236
}
233237

234-
// NOTE: returning checksum separately for subsequent validation
235-
func (oa *ObjAttrs) FromHeader(hdr http.Header) (cksum *cos.Cksum) {
238+
// return checksum separately for subsequent validation
239+
// parse and set custom metadata, if available
240+
func (oa *ObjAttrs) FromHeader(hdr http.Header) (cksum *cos.Cksum, err error) {
236241
if ty := hdr.Get(apc.HdrObjCksumType); ty != "" {
237242
val := hdr.Get(apc.HdrObjCksumVal)
238243
cksum = cos.NewCksum(ty, val)
@@ -251,13 +256,37 @@ func (oa *ObjAttrs) FromHeader(hdr http.Header) (cksum *cos.Cksum) {
251256
if v := hdr.Get(apc.HdrObjVersion); v != "" {
252257
oa.Ver = &v
253258
}
254-
custom := hdr[http.CanonicalHeaderKey(apc.HdrObjCustomMD)]
255-
for _, v := range custom {
256-
entry := strings.SplitN(v, "=", 2)
257-
debug.Assert(len(entry) == 2)
258-
oa.SetCustomKey(entry[0], entry[1])
259+
260+
// custom metadata: total size limited
261+
if custom, ok := hdr[apc.HdrObjCustomMD]; ok {
262+
var (
263+
size int
264+
keys = make([]string, 0, 10)
265+
)
266+
for _, kvs := range custom {
267+
kv := strings.SplitN(kvs, "=", 2)
268+
if len(kv) != 2 {
269+
oa._undoCustom(keys)
270+
return nil, fmt.Errorf("custom metadata: invalid format %q (expecting key=value)", kvs)
271+
}
272+
size += len(kv[0]) + len(kv[1])
273+
if size > maxSizeCustomKVs {
274+
oa._undoCustom(keys)
275+
return nil, fmt.Errorf("custom metadata: total size exceeds %d bytes", maxSizeCustomKVs)
276+
}
277+
oa.SetCustomKey(kv[0], kv[1])
278+
keys = append(keys, kv[0])
279+
}
280+
}
281+
return cksum, nil
282+
}
283+
284+
// by implication, prior to FromHeader call obj attrs are not supposed to contain any custom keys,
285+
// or at least not those that could've been overwritten
286+
func (oa *ObjAttrs) _undoCustom(keys []string) {
287+
for i := len(keys) - 1; i >= 0; i-- {
288+
oa.DelCustomKey(keys[i])
259289
}
260-
return
261290
}
262291

263292
// local <=> remote equality in the context of cold-GET and download. This function

0 commit comments

Comments
 (0)