diff --git a/tests/trustless_gateway_raw_test.go b/tests/trustless_gateway_raw_test.go index 8f5962885..8094f92d5 100644 --- a/tests/trustless_gateway_raw_test.go +++ b/tests/trustless_gateway_raw_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/ipfs/gateway-conformance/tooling/car" + . "github.com/ipfs/gateway-conformance/tooling/check" "github.com/ipfs/gateway-conformance/tooling/specs" . "github.com/ipfs/gateway-conformance/tooling/test" ) @@ -125,3 +126,131 @@ func TestTrustlessRaw(t *testing.T) { RunWithSpecs(t, tests, specs.TrustlessGatewayRaw) } + +func TestTrustlessRawRanges(t *testing.T) { + // Multi-range requests MUST conform to the HTTP semantics. The server does not + // need to be able to support returning multiple ranges. However, it must respond + // correctly. + fixture := car.MustOpenUnixfsCar("gateway-raw-block.car") + + var ( + contentType string + contentRange string + ) + + RunWithSpecs(t, SugarTests{ + { + Name: "GETaa with application/vnd.ipld.raw with single range request includes correct bytes", + Request: Request(). + Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")). + Headers( + Header("Accept", "application/vnd.ipld.raw"), + Header("Range", "bytes=6-16"), + ), + Response: Expect(). + Status(206). + Headers( + Header("Content-Type").Contains("application/vnd.ipld.raw"), + Header("Content-Range").Equals("bytes 6-16/31"), + ). + Body(fixture.MustGetRawData("dir", "ascii.txt")[6:17]), + }, + { + Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes", + Request: Request(). + Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")). + Headers( + Header("Accept", "application/vnd.ipld.raw"), + Header("Range", "bytes=6-16,0-4"), + ), + Response: Expect(). + Status(206). + Headers( + Header("Content-Type"). + Checks(func(v string) bool { + contentType = v + return v != "" + }), + Header("Content-Range"). + ChecksAll(func(v []string) bool { + if len(v) == 1 { + contentRange = v[0] + } + return true + }), + ), + }, + }, specs.PathGatewayRaw) + + tests := SugarTests{} + + if strings.Contains(contentType, "application/vnd.ipld.raw") { + // The server is not able to respond to a multi-range request. Therefore, + // there might be only one range or... just the whole file, depending on the headers. + + if contentRange == "" { + // Server does not support range requests and must send back the complete file. + tests = append(tests, SugarTest{ + Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes", + Request: Request(). + Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")). + Headers( + Header("Accept", "application/vnd.ipld.raw"), + Header("Range", "bytes=6-16,0-4"), + ), + Response: Expect(). + Status(206). + Headers( + Header("Content-Type").Contains("application/vnd.ipld.raw"), + Header("Content-Range").IsEmpty(), + ). + Body(fixture.MustGetRawData("dir", "ascii.txt")), + }) + } else { + // Server supports range requests but only the first range. + tests = append(tests, SugarTest{ + Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes", + Request: Request(). + Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")). + Headers( + Header("Accept", "application/vnd.ipld.raw"), + Header("Range", "bytes=6-16,0-4"), + ), + Response: Expect(). + Status(206). + Headers( + Header("Content-Type").Contains("application/vnd.ipld.raw"), + Header("Content-Range", "bytes 6-16/31"), + ). + Body(fixture.MustGetRawData("dir", "ascii.txt")[6:17]), + }) + } + } else if strings.Contains(contentType, "multipart/byteranges") { + // The server supports responding with multi-range requests. + tests = append(tests, SugarTest{ + Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes", + Request: Request(). + Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")). + Headers( + Header("Accept", "application/vnd.ipld.raw"), + Header("Range", "bytes=6-16,0-4"), + ), + Response: Expect(). + Status(206). + Headers( + Header("Content-Type").Contains("multipart/byteranges"), + ). + Body(And( + Contains("Content-Range: bytes 6-16/31"), + Contains("Content-Type: application/vnd.ipld.raw"), + Contains(string(fixture.MustGetRawData("dir", "ascii.txt")[6:17])), + Contains("Content-Range: bytes 0-4/31"), + Contains(string(fixture.MustGetRawData("dir", "ascii.txt")[0:5])), + )), + }) + } else { + t.Error("Content-Type header did not match any of the accepted options") + } + + RunWithSpecs(t, tests, specs.TrustlessGatewayRaw) +}