Skip to content

Commit a0b73a1

Browse files
committed
fix: reverse SOC/CAC detection order in POST /chunks handler
Try SOC parsing before CAC in the chunk upload handler. CAC parsing accepts any data between 8-4104 bytes, so valid SOC data was always misclassified as CAC and stored at the wrong content-addressed hash instead of the correct SOC address (Hash(Identifier || Owner)).
1 parent e0afe52 commit a0b73a1

2 files changed

Lines changed: 34 additions & 18 deletions

File tree

pkg/api/chunk.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -138,29 +138,33 @@ func (s *Service) chunkUploadHandler(w http.ResponseWriter, r *http.Request) {
138138
return
139139
}
140140

141-
chunk, err := cac.NewWithDataSpan(data)
142-
if err != nil {
143-
// not a valid cac chunk. Check if it's a replica soc chunk.
144-
logger.Debug("chunk upload: create chunk failed", "error", err)
145-
146-
// FromChunk only uses the chunk data to recreate the soc chunk. So the address is irrelevant.
147-
sch, err := soc.FromChunk(swarm.NewChunk(swarm.EmptyAddress, data))
148-
if err != nil {
149-
logger.Debug("chunk upload: create soc chunk from data failed", "error", err)
150-
logger.Error(nil, "chunk upload: create chunk error")
151-
jsonhttp.InternalServerError(ow, "create chunk error")
152-
return
153-
}
141+
// Try SOC first — CAC parsing is too permissive (accepts any 8-4104 byte data),
142+
// so valid SOCs would always be misclassified as CACs if we tried CAC first.
143+
var chunk swarm.Chunk
144+
sch, err := soc.FromChunk(swarm.NewChunk(swarm.EmptyAddress, data))
145+
if err == nil {
154146
chunk, err = sch.Chunk()
155147
if err != nil {
156148
logger.Debug("chunk upload: create chunk from soc failed", "error", err)
157149
logger.Error(nil, "chunk upload: create chunk error")
158150
jsonhttp.InternalServerError(ow, "create chunk error")
159151
return
160152
}
161-
162153
if !soc.Valid(chunk) {
163-
logger.Debug("chunk upload: invalid soc chunk")
154+
// Parsed as SOC structure but invalid — fall through to CAC
155+
chunk, err = cac.NewWithDataSpan(data)
156+
if err != nil {
157+
logger.Debug("chunk upload: create chunk failed", "error", err)
158+
logger.Error(nil, "chunk upload: create chunk error")
159+
jsonhttp.InternalServerError(ow, "create chunk error")
160+
return
161+
}
162+
}
163+
} else {
164+
// Not a SOC — try CAC
165+
chunk, err = cac.NewWithDataSpan(data)
166+
if err != nil {
167+
logger.Debug("chunk upload: create chunk failed", "error", err)
164168
logger.Error(nil, "chunk upload: create chunk error")
165169
jsonhttp.InternalServerError(ow, "create chunk error")
166170
return

pkg/api/chunk_test.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,16 +328,28 @@ func TestChunkUploadSOC(t *testing.T) {
328328
})
329329
)
330330

331-
// drain pusher feed
332-
go func() { <-storerMock.PusherFeed() }()
331+
tag, err := storerMock.NewSession()
332+
if err != nil {
333+
t.Fatal(err)
334+
}
333335

334-
// upload
336+
// upload with tag so chunk is stored in ChunkStore (deferred upload path)
335337
jsonhttptest.Request(t, client, http.MethodPost, chunksEndpoint, http.StatusCreated,
338+
jsonhttptest.WithRequestHeader(api.SwarmTagHeader, fmt.Sprintf("%d", tag.TagID)),
336339
jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr),
337340
jsonhttptest.WithRequestBody(bytes.NewReader(socChunk.Data())),
338341
jsonhttptest.WithExpectedJSONResponse(api.ChunkAddressResponse{Reference: mockSOC.Address()}),
339342
)
340343

344+
// verify chunk exists in store at SOC address
345+
has, err := storerMock.ChunkStore().Has(context.Background(), mockSOC.Address())
346+
if err != nil {
347+
t.Fatal(err)
348+
}
349+
if !has {
350+
t.Fatal("soc chunk not found in store at soc address")
351+
}
352+
341353
// retrieve by SOC address
342354
jsonhttptest.Request(t, client, http.MethodGet, chunksResource(mockSOC.Address()), http.StatusOK,
343355
jsonhttptest.WithExpectedResponse(socChunk.Data()),

0 commit comments

Comments
 (0)