@@ -2,6 +2,7 @@ package gateway
22
33import (
44 "context"
5+ "encoding/binary"
56 "fmt"
67 "io"
78 "net/http"
@@ -166,20 +167,18 @@ func buildCarParams(r *http.Request, contentTypeParams map[string]string) (CarPa
166167 }
167168
168169 // optional dups from IPIP-412
169- if dups := NewDuplicateBlocksPolicy (contentTypeParams ["dups" ]); dups != DuplicateBlocksUnspecified {
170- switch dups {
171- case DuplicateBlocksExcluded , DuplicateBlocksIncluded :
172- params .Duplicates = dups
173- default :
174- return CarParams {}, fmt .Errorf ("unsupported application/vnd.ipld.car content type dups parameter: %q" , dups )
175- }
176- } else {
170+ dups , err := NewDuplicateBlocksPolicy (contentTypeParams ["dups" ])
171+ if err != nil {
172+ return CarParams {}, err
173+ }
174+ if dups == DuplicateBlocksUnspecified {
177175 // when duplicate block preference is not specified, we set it to
178176 // false, as this has always been the default behavior, we should
179177 // not break legacy clients, and responses to requests made via ?format=car
180178 // should benefit from block deduplication
181- params . Duplicates = DuplicateBlocksExcluded
179+ dups = DuplicateBlocksExcluded
182180 }
181+ params .Duplicates = dups
183182
184183 return params , nil
185184}
@@ -226,31 +225,43 @@ func getCarRootCidAndLastSegment(imPath path.ImmutablePath) (cid.Cid, string, er
226225}
227226
228227func getCarEtag (imPath path.ImmutablePath , params CarParams , rootCid cid.Cid ) string {
229- data := imPath .String ()
228+ h := xxhash .New ()
229+ h .WriteString (imPath .String ())
230+ // be careful with hashes here, we need boundaries and per entry salt, we don't want a request that has:
231+ // - scope = dfs
232+ // and:
233+ // - order = dfs
234+ // to result in the same hash because if we just do hash(scope + order) they would both yield hash("dfs").
230235 if params .Scope != DagScopeAll {
231- data += string (params .Scope )
236+ h .WriteString ("\x00 scope=" )
237+ h .WriteString (string (params .Scope ))
232238 }
233239
234240 // 'order' from IPIP-412 impact Etag only if set to something else
235241 // than DFS (which is the implicit default)
236242 if params .Order != DagOrderDFS {
237- data += string (params .Order )
243+ h .WriteString ("\x00 order=" )
244+ h .WriteString (string (params .Order ))
238245 }
239246
240247 // 'dups' from IPIP-412 impact Etag only if 'y'
241- if dups := params .Duplicates . String () ; dups == "y" {
242- data += dups
248+ if dups := params .Duplicates ; dups == DuplicateBlocksIncluded {
249+ h . WriteString ( " \x00 dups=y" )
243250 }
244251
245252 if params .Range != nil {
246253 if params .Range .From != 0 || params .Range .To != nil {
247- data += strconv .FormatInt (params .Range .From , 10 )
254+ h .WriteString ("\x00 range=" )
255+ var b [8 ]byte
256+ binary .LittleEndian .PutUint64 (b [:], uint64 (params .Range .From ))
257+ h .Write (b [:])
248258 if params .Range .To != nil {
249- data += strconv .FormatInt (* params .Range .To , 10 )
259+ binary .LittleEndian .PutUint64 (b [:], uint64 (* params .Range .To ))
260+ h .Write (b [:])
250261 }
251262 }
252263 }
253264
254- suffix := strconv .FormatUint (xxhash .Sum64 ([] byte ( data ) ), 32 )
265+ suffix := strconv .FormatUint (h .Sum64 (), 32 )
255266 return `W/"` + rootCid .String () + ".car." + suffix + `"`
256267}
0 commit comments