@@ -477,21 +477,112 @@ func TestBytesHead(t *testing.T) {
477477
478478 resource := "/bytes/" + resp .Reference .String ()
479479
480- jsonhttptest .Request (t , client , http .MethodHead , resource , http .StatusOK ,
481- jsonhttptest .WithExpectedContentLength (len (content )),
482- jsonhttptest .WithExpectedResponseHeader (api .ContentTypeHeader , "application/octet-stream" ),
483- jsonhttptest .WithExpectedResponseHeader (api .AcceptRangesHeader , "bytes" ),
484- )
485- jsonhttptest .Request (t , client , http .MethodGet , resource , http .StatusOK ,
486- jsonhttptest .WithExpectedContentLength (len (content )),
487- jsonhttptest .WithExpectedResponseHeader (api .ContentTypeHeader , "application/octet-stream" ),
488- jsonhttptest .WithExpectedResponseHeader (api .AcceptRangesHeader , "bytes" ),
489- )
480+ for _ , method := range []string {http .MethodHead , http .MethodGet } {
481+ jsonhttptest .Request (t , client , method , resource , http .StatusOK ,
482+ jsonhttptest .WithExpectedContentLength (len (content )),
483+ jsonhttptest .WithExpectedResponseHeader (api .ContentTypeHeader , "application/octet-stream" ),
484+ jsonhttptest .WithExpectedResponseHeader (api .AcceptRangesHeader , "bytes" ),
485+ jsonhttptest .WithExpectedResponseHeader (api .ETagHeader , fmt .Sprintf ("%q" , resp .Reference )),
486+ jsonhttptest .WithNonEmptyResponseHeader ("Last-Modified" ),
487+ )
488+ }
490489 })
491490 }
492491 }
493492}
494493
494+ // TestBytesHeadRangeAndConditional tests that HEAD applies Range and precondition
495+ // headers exactly as GET does, since HEAD differs from GET only in sending no body.
496+ func TestBytesHeadRangeAndConditional (t * testing.T ) {
497+ t .Parallel ()
498+
499+ g := mockbytes .New (0 , mockbytes .MockTypeStandard ).WithModulus (255 )
500+ content , err := g .SequentialBytes (swarm .ChunkSize * 10 )
501+ if err != nil {
502+ t .Fatal (err )
503+ }
504+
505+ client , _ , _ , _ := newTestServer (t , testServerOptions {
506+ Storer : mockstorer .New (),
507+ Post : mockpost .New (mockpost .WithAcceptAll ()),
508+ })
509+
510+ var resp struct {
511+ Reference swarm.Address `json:"reference"`
512+ }
513+ jsonhttptest .Request (t , client , http .MethodPost , "/bytes" , http .StatusCreated ,
514+ jsonhttptest .WithRequestHeader (api .SwarmDeferredUploadHeader , "true" ),
515+ jsonhttptest .WithRequestHeader (api .SwarmPostageBatchIdHeader , batchOkStr ),
516+ jsonhttptest .WithRequestBody (bytes .NewReader (content )),
517+ jsonhttptest .WithUnmarshalJSONResponse (& resp ),
518+ )
519+
520+ resource := "/bytes/" + resp .Reference .String ()
521+ etag := fmt .Sprintf ("%q" , resp .Reference )
522+
523+ tests := []struct {
524+ name string
525+ header [2 ]string
526+ want int
527+ headers []jsonhttptest.Option
528+ }{
529+ {
530+ name : "satisfiable range" ,
531+ header : [2 ]string {api .RangeHeader , "bytes=0-99" },
532+ want : http .StatusPartialContent ,
533+ headers : []jsonhttptest.Option {
534+ jsonhttptest .WithExpectedContentLength (100 ),
535+ jsonhttptest .WithExpectedResponseHeader (api .ContentRangeHeader , fmt .Sprintf ("bytes 0-99/%d" , len (content ))),
536+ },
537+ },
538+ {
539+ name : "unsatisfiable range" ,
540+ header : [2 ]string {api .RangeHeader , "bytes=99999999-" },
541+ want : http .StatusRequestedRangeNotSatisfiable ,
542+ headers : []jsonhttptest.Option {
543+ jsonhttptest .WithExpectedResponseHeader (api .ContentRangeHeader , fmt .Sprintf ("bytes */%d" , len (content ))),
544+ },
545+ },
546+ {
547+ name : "matching if-none-match" ,
548+ header : [2 ]string {"If-None-Match" , etag },
549+ want : http .StatusNotModified ,
550+ headers : []jsonhttptest.Option {
551+ jsonhttptest .WithNoResponseBody (),
552+ },
553+ },
554+ {
555+ name : "non-matching if-none-match" ,
556+ header : [2 ]string {"If-None-Match" , `"0000000000000000000000000000000000000000000000000000000000000001"` },
557+ want : http .StatusOK ,
558+ headers : []jsonhttptest.Option {
559+ jsonhttptest .WithExpectedContentLength (len (content )),
560+ },
561+ },
562+ {
563+ // A body-less response must not inherit the full content length, or the
564+ // server truncates the connection and the client sees an unexpected EOF.
565+ name : "non-matching if-match" ,
566+ header : [2 ]string {"If-Match" , `"0000000000000000000000000000000000000000000000000000000000000001"` },
567+ want : http .StatusPreconditionFailed ,
568+ headers : []jsonhttptest.Option {
569+ jsonhttptest .WithNoResponseBody (),
570+ },
571+ },
572+ }
573+
574+ for _ , tt := range tests {
575+ t .Run (tt .name , func (t * testing.T ) {
576+ for _ , method := range []string {http .MethodHead , http .MethodGet } {
577+ opts := append ([]jsonhttptest.Option {
578+ jsonhttptest .WithRequestHeader (tt .header [0 ], tt .header [1 ]),
579+ }, tt .headers ... )
580+ jsonhttptest .Request (t , client , method , resource , tt .want , opts ... )
581+ }
582+ })
583+ }
584+ }
585+
495586// TestBytesHeadErrorsMatchGet tests that HEAD reports the same status as GET for
496587// references that cannot be served.
497588func TestBytesHeadErrorsMatchGet (t * testing.T ) {
0 commit comments