Skip to content

Commit bb13217

Browse files
committed
Blob checksum header parsing in HeadObjectResponse
1 parent 04872c1 commit bb13217

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed

ds3/ds3Client_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1911,3 +1911,31 @@ func TestVerifyPhysicalPlacementForObjectsWithFullDetailsSpectraS3(t *testing.T)
19111911
}
19121912
ds3Testing.AssertBool(t, "WriteProtected", false, tape.WriteProtected)
19131913
}
1914+
1915+
func TestHeadObject(t *testing.T) {
1916+
bucketName := "bucket1"
1917+
objectName := "obj1"
1918+
1919+
responseHeaders := &http.Header{}
1920+
responseHeaders.Add("x-amz-meta-key", "value")
1921+
responseHeaders.Add("ds3-blob-checksum-type", "MD5")
1922+
responseHeaders.Add("ds3-blob-checksum-offset-0", "4nQGNX4nyz0pi8Hvap79PQ==")
1923+
responseHeaders.Add("ds3-blob-checksum-offset-10485760", "965Aa0/n8DlO1IwXYFh4bg==")
1924+
responseHeaders.Add("ds3-blob-checksum-offset-20971520", "iV2OqJaXJ/jmqgRSb1HmFA==")
1925+
1926+
response, err := mockedClient(t).
1927+
Expecting(HTTP_VERB_HEAD, "/" + bucketName + "/" + objectName, &url.Values{}, &http.Header{}, nil).
1928+
Returning(200, "", responseHeaders).
1929+
HeadObject(models.NewHeadObjectRequest(bucketName, objectName))
1930+
1931+
ds3Testing.AssertNilError(t, err)
1932+
1933+
if response.BlobChecksumType != models.CHECKSUM_TYPE_MD5 {
1934+
t.Fatalf("Expected checksum type to be 'MD5' but was '%s'.", response.BlobChecksumType.String())
1935+
}
1936+
1937+
ds3Testing.AssertInt(t, "# of blob checksums", 3, len(response.BlobChecksums))
1938+
ds3Testing.AssertString(t, "checksum at offset '0'", "4nQGNX4nyz0pi8Hvap79PQ==", response.BlobChecksums[0])
1939+
ds3Testing.AssertString(t, "checksum at offset '10485760'", "965Aa0/n8DlO1IwXYFh4bg==", response.BlobChecksums[10485760])
1940+
ds3Testing.AssertString(t, "checksum at offset '20971520'", "iV2OqJaXJ/jmqgRSb1HmFA==", response.BlobChecksums[20971520])
1941+
}

ds3/models/headObjectResponse.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import (
1818
)
1919

2020
type HeadObjectResponse struct {
21-
21+
BlobChecksumType ChecksumType
22+
BlobChecksums map[int64]string
2223
Headers *http.Header
2324
}
2425

@@ -29,7 +30,15 @@ func NewHeadObjectResponse(webResponse WebResponse) (*HeadObjectResponse, error)
2930

3031
switch code := webResponse.StatusCode(); code {
3132
case 200:
32-
return &HeadObjectResponse{Headers: webResponse.Header()}, nil
33+
checksumType, err := getBlobChecksumType(webResponse.Header())
34+
if err != nil {
35+
return nil, err
36+
}
37+
checksumMap, err := getBlobChecksumMap(webResponse.Header())
38+
if err != nil {
39+
return nil, err
40+
}
41+
return &HeadObjectResponse{BlobChecksumType: checksumType, BlobChecksums: checksumMap, Headers: webResponse.Header()}, nil
3342
default:
3443
return nil, buildBadStatusCodeError(webResponse, expectedStatusCodes)
3544
}

ds3/models/responseParsingUtil.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,53 @@ package models
1414
import (
1515
"strconv"
1616
"log"
17+
"strings"
18+
"net/http"
1719
)
1820

1921
// Contains utils used by model parsers to parse response payloads.
2022

23+
const BLOB_CHECKSUM_TYPE_HEADER string = "ds3-blob-checksum-type"
24+
const BLOB_CHECKSUM_HEADER string = "ds3-blob-checksum-offset-"
25+
26+
// Parses blob checksum header if exists. This is used by HeadObjectResponse.
27+
func getBlobChecksumType(headers *http.Header) (ChecksumType, error) {
28+
checksumStr := headers.Get(BLOB_CHECKSUM_TYPE_HEADER)
29+
if len(checksumStr) == 0 {
30+
return NONE, nil
31+
}
32+
var checksumEnum ChecksumType
33+
err := checksumEnum.UnmarshalText([]byte(checksumStr))
34+
if err != nil {
35+
return UNDEFINED, err
36+
}
37+
return checksumEnum, nil
38+
}
39+
40+
// Parses response headers and creates a map of blob offset to blob checksum
41+
// for all occurrences of headers with prefix defined in BLOB_CHECKSUM_HEADER.
42+
// This is used by HeadObjectResponse.
43+
func getBlobChecksumMap(headers *http.Header) (map[int64]string, error) {
44+
blobChecksumMap := make(map[int64]string)
45+
46+
if headers == nil || len(*headers) == 0 {
47+
return blobChecksumMap, nil
48+
}
49+
50+
for key := range *headers {
51+
if strings.HasPrefix(strings.ToLower(key), strings.ToLower(BLOB_CHECKSUM_HEADER)) {
52+
offsetStr := strings.TrimPrefix(strings.ToLower(key), strings.ToLower(BLOB_CHECKSUM_HEADER))
53+
offset, err := strconv.ParseInt(offsetStr, 10, 64)
54+
if err != nil {
55+
return blobChecksumMap, err
56+
}
57+
blobChecksumMap[offset] = headers.Get(key)
58+
}
59+
}
60+
61+
return blobChecksumMap, nil
62+
}
63+
2164
// Interface defined for spectra defined enums.
2265
// Used for generic parsing of enums.
2366
type Ds3Enum interface {

0 commit comments

Comments
 (0)