@@ -477,7 +477,7 @@ func TestGatewaySymlink(t *testing.T) {
477
477
func TestGatewayUnixFSFileRanges(t *testing.T) {
478
478
tooling.LogTestGroup(t, GroupUnixFS)
479
479
480
-
// Multi-range requests MUST conform to the HTTP semantics. The server does not
480
+
// Range requests MUST conform to the HTTP semantics. The server does not
481
481
// need to be able to support returning multiple ranges. However, it must respond
482
482
// correctly.
483
483
fixture := car.MustOpenUnixfsCar("path_gateway_unixfs/dir-with-files.car")
@@ -488,8 +488,22 @@ func TestGatewayUnixFSFileRanges(t *testing.T) {
488
488
)
489
489
490
490
RunWithSpecs(t, SugarTests{
491
+
{
492
+
Name: "GET for /ipfs/ file includes Accept-Ranges header",
493
+
Hint: "Gateway returns explicit hint that range requests are supported. This is important for interop with HTTP reverse proxies, CDNs, caches.",
494
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#accept-ranges-response-header",
495
+
Request: Request().
496
+
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()),
497
+
Response: Expect().
498
+
Status(200).
499
+
Headers(
500
+
Header("Accept-Ranges").Equals("bytes"),
501
+
).
502
+
Body(fixture.MustGetRawData("ascii.txt")),
503
+
},
491
504
{
492
505
Name: "GET for /ipfs/ file with single range request includes correct bytes",
506
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header",
493
507
Request: Request().
494
508
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
495
509
Headers(
@@ -498,13 +512,30 @@ func TestGatewayUnixFSFileRanges(t *testing.T) {
498
512
Response: Expect().
499
513
Status(206).
500
514
Headers(
501
-
Header("Content-Type").Contains("text/plain"),
502
515
Header("Content-Range").Equals("bytes 6-16/31"),
503
516
).
504
517
Body(fixture.MustGetRawData("ascii.txt")[6:17]),
505
518
},
506
519
{
507
-
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
520
+
Name: "GET for /ipfs/ file with suffix range request includes correct bytes from the end of file",
521
+
Hint: "Ensures it is possible to read the tail of a file",
522
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header",
523
+
Request: Request().
524
+
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
525
+
Headers(
526
+
Header("Range", "bytes=-3"),
527
+
),
528
+
Response: Expect().
529
+
Status(206).
530
+
Headers(
531
+
Header("Content-Range").Equals("bytes 28-30/31"),
532
+
).
533
+
Body(fixture.MustGetRawData("ascii.txt")[28:31]),
534
+
},
535
+
{
536
+
Name: "GET for /ipfs/ file with multiple range request returned HTTP 206",
537
+
Hint: "This test reads Content-Type and Content-Range of response, which enable later tests to check if response was acceptable (either single range, or multiple ones)",
538
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header",
508
539
Request: Request().
509
540
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
510
541
Headers(
@@ -515,13 +546,16 @@ func TestGatewayUnixFSFileRanges(t *testing.T) {
515
546
Headers(
516
547
Header("Content-Type").
517
548
Checks(func(v string) bool {
549
+
// Not really a test, just inspect value
518
550
contentType = v
519
-
return v != ""
551
+
return true
520
552
}),
521
553
Header("Content-Range").
522
554
ChecksAll(func(v []string) bool {
555
+
// Not really a test, just inspect value
523
556
if len(v) == 1 {
524
557
contentRange = v[0]
558
+
525
559
}
526
560
return true
527
561
}),
@@ -531,49 +565,31 @@ func TestGatewayUnixFSFileRanges(t *testing.T) {
531
565
532
566
tests := SugarTests{}
533
567
534
-
if strings.Contains(contentType, "text/plain") {
535
-
// The server is not able to respond to a multi-range request. Therefore,
536
-
// there might be only one range or... just the whole file, depending on the headers.
568
+
multipleRangeSupported := strings.Contains(contentType, "multipart/byteranges")
569
+
onlySingleRangeSupported := !multipleRangeSupported && contentRange != ""
537
570
538
-
if contentRange == "" {
539
-
// Server does not support range requests and must send back the complete file.
540
-
tests = append(tests, SugarTest{
541
-
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
542
-
Request: Request().
543
-
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
544
-
Headers(
545
-
Header("Range", "bytes=6-16,0-4"),
546
-
),
547
-
Response: Expect().
548
-
Status(206).
549
-
Headers(
550
-
Header("Content-Type").Contains("text/plain"),
551
-
Header("Content-Range").IsEmpty(),
552
-
).
553
-
Body(fixture.MustGetRawData("ascii.txt")),
554
-
})
555
-
} else {
556
-
// Server supports range requests but only the first range.
557
-
tests = append(tests, SugarTest{
558
-
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
559
-
Request: Request().
560
-
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
561
-
Headers(
562
-
Header("Range", "bytes=6-16,0-4"),
563
-
),
564
-
Response: Expect().
565
-
Status(206).
566
-
Headers(
567
-
Header("Content-Type").Contains("text/plain"),
568
-
Header("Content-Range", "bytes 6-16/31"),
569
-
).
570
-
Body(fixture.MustGetRawData("ascii.txt")[6:17]),
571
-
})
572
-
}
573
-
} else if strings.Contains(contentType, "multipart/byteranges") {
571
+
if onlySingleRangeSupported {
572
+
// Server supports range requests but only the first range.
573
+
tests = append(tests, SugarTest{
574
+
Name: "GET for /ipfs/ file with multiple range request returns correct bytes for the first range",
575
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header",
576
+
Request: Request().
577
+
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
578
+
Headers(
579
+
Header("Range", "bytes=6-16,0-4"),
580
+
),
581
+
Response: Expect().
582
+
Status(206).
583
+
Headers(
584
+
Header("Content-Range", "bytes 6-16/31"),
585
+
).
586
+
Body(fixture.MustGetRawData("ascii.txt")[6:17]),
587
+
})
588
+
} else if multipleRangeSupported {
574
589
// The server supports responding with multi-range requests.
575
590
tests = append(tests, SugarTest{
576
591
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
592
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header",
577
593
Request: Request().
578
594
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
579
595
Headers(
@@ -586,16 +602,48 @@ func TestGatewayUnixFSFileRanges(t *testing.T) {
586
602
).
587
603
Body(And(
588
604
Contains("Content-Range: bytes 6-16/31"),
589
-
Contains("Content-Type: text/plain"),
590
605
Contains(string(fixture.MustGetRawData("ascii.txt")[6:17])),
591
606
Contains("Content-Range: bytes 0-4/31"),
592
607
Contains(string(fixture.MustGetRawData("ascii.txt")[0:5])),
593
608
)),
594
609
})
595
610
} else {
596
-
t.Error("Content-Type header did not match any of the accepted options")
611
+
t.Error("Content-Range and Content-Type header did not match any of the accepted options for a Range request (neither single or multiple ranges are supported)")
597
612
}
598
613
614
+
// Range request should work when unrelated parts of DAG not available.
615
+
missingBlockFixture := car.MustOpenUnixfsCar("trustless_gateway_car/file-3k-and-3-blocks-missing-block.car")
616
+
tests = append(tests, SugarTest{
617
+
Name: "GET Range of file succeeds even if the gateway is missing a block AFTER the requested range",
618
+
Hint: "This MUST succeed despite the fact that bytes beyond the end of range are not retrievable",
619
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header",
620
+
Request: Request().
621
+
Path("/ipfs/{{cid}}", missingBlockFixture.MustGetCidWithCodec(0x70)).
622
+
Headers(
623
+
Header("Range", "bytes=997-1000"),
624
+
),
625
+
Response: Expect().
626
+
Status(206).
627
+
Headers(
628
+
Header("Content-Range").Equals("bytes 997-1000/3072"),
629
+
),
630
+
}, SugarTest{
631
+
Name: "GET Range of file succeeds even if the gateway is missing a block BEFORE the requested range",
632
+
Hint: "This MUST succeed despite the fact that bytes beyond the end of range are not retrievable",
633
+
Spec: "https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header",
634
+
Request: Request().
635
+
Path("/ipfs/{{cid}}", missingBlockFixture.MustGetCidWithCodec(0x70)).
636
+
Headers(
637
+
Header("Range", "bytes=2200-2201"),
638
+
),
639
+
Response: Expect().
640
+
Status(206).
641
+
Headers(
642
+
Header("Content-Range").Equals("bytes 2200-2201/3072"),
643
+
),
644
+
},
645
+
)
646
+
599
647
RunWithSpecs(t, tests, specs.PathGatewayUnixFS)
600
648
}
601
649
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4