forked from thanos-io/objstore
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Sync with upstream Thanos (thanos-io#13)
Sync with upstream Thanos Signed-off-by: Kemal Akkoyun <[email protected]>
- Loading branch information
1 parent
024223b
commit c3c9e6b
Showing
20 changed files
with
420 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright (c) The Thanos Authors. | ||
// Licensed under the Apache License 2.0. | ||
|
||
package clientutil | ||
|
||
import ( | ||
"net/http" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
// ParseContentLength returns the content length (in bytes) parsed from the Content-Length | ||
// HTTP header in input. | ||
func ParseContentLength(m http.Header) (int64, error) { | ||
const name = "Content-Length" | ||
|
||
v, ok := m[name] | ||
if !ok { | ||
return 0, errors.Errorf("%s header not found", name) | ||
} | ||
|
||
if len(v) == 0 { | ||
return 0, errors.Errorf("%s header has no values", name) | ||
} | ||
|
||
ret, err := strconv.ParseInt(v[0], 10, 64) | ||
if err != nil { | ||
return 0, errors.Wrapf(err, "convert %s", name) | ||
} | ||
|
||
return ret, nil | ||
} | ||
|
||
// ParseLastModified returns the timestamp parsed from the Last-Modified | ||
// HTTP header in input. | ||
// Passing an second parameter, named f, to specify the time format. | ||
// If f is empty then RFC3339 will be used as default format. | ||
func ParseLastModified(m http.Header, f string) (time.Time, error) { | ||
const ( | ||
name = "Last-Modified" | ||
defaultFormat = time.RFC3339 | ||
) | ||
|
||
v, ok := m[name] | ||
if !ok { | ||
return time.Time{}, errors.Errorf("%s header not found", name) | ||
} | ||
|
||
if len(v) == 0 { | ||
return time.Time{}, errors.Errorf("%s header has no values", name) | ||
} | ||
|
||
if f == "" { | ||
f = defaultFormat | ||
} | ||
|
||
mod, err := time.Parse(f, v[0]) | ||
if err != nil { | ||
return time.Time{}, errors.Wrapf(err, "parse %s", name) | ||
} | ||
|
||
return mod, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Copyright (c) The Thanos Authors. | ||
// Licensed under the Apache License 2.0. | ||
|
||
package clientutil | ||
|
||
import ( | ||
"net/http" | ||
"testing" | ||
"time" | ||
|
||
alioss "github.com/aliyun/aliyun-oss-go-sdk/oss" | ||
"github.com/efficientgo/tools/core/pkg/testutil" | ||
) | ||
|
||
func TestParseLastModified(t *testing.T) { | ||
location, _ := time.LoadLocation("GMT") | ||
tests := map[string]struct { | ||
headerValue string | ||
expectedVal time.Time | ||
expectedErr string | ||
format string | ||
}{ | ||
"no header": { | ||
expectedErr: "Last-Modified header not found", | ||
}, | ||
"empty format string to default RFC3339 format": { | ||
headerValue: "2015-11-06T10:07:11.000Z", | ||
expectedVal: time.Date(2015, time.November, 6, 10, 7, 11, 0, time.UTC), | ||
format: "", | ||
}, | ||
"valid RFC3339 header value": { | ||
headerValue: "2015-11-06T10:07:11.000Z", | ||
expectedVal: time.Date(2015, time.November, 6, 10, 7, 11, 0, time.UTC), | ||
format: time.RFC3339, | ||
}, | ||
"invalid RFC3339 header value": { | ||
headerValue: "invalid", | ||
expectedErr: `parse Last-Modified: parsing time "invalid" as "2006-01-02T15:04:05Z07:00": cannot parse "invalid" as "2006"`, | ||
format: time.RFC3339, | ||
}, | ||
"valid RFC1123 header value": { | ||
headerValue: "Fri, 24 Feb 2012 06:07:48 GMT", | ||
expectedVal: time.Date(2012, time.February, 24, 6, 7, 48, 0, location), | ||
format: time.RFC1123, | ||
}, | ||
"invalid RFC1123 header value": { | ||
headerValue: "invalid", | ||
expectedErr: `parse Last-Modified: parsing time "invalid" as "Mon, 02 Jan 2006 15:04:05 MST": cannot parse "invalid" as "Mon"`, | ||
format: time.RFC1123, | ||
}, | ||
} | ||
|
||
for testName, testData := range tests { | ||
t.Run(testName, func(t *testing.T) { | ||
meta := http.Header{} | ||
if testData.headerValue != "" { | ||
meta.Add(alioss.HTTPHeaderLastModified, testData.headerValue) | ||
} | ||
|
||
actual, err := ParseLastModified(meta, testData.format) | ||
|
||
if testData.expectedErr != "" { | ||
testutil.NotOk(t, err) | ||
testutil.Equals(t, testData.expectedErr, err.Error()) | ||
} else { | ||
testutil.Ok(t, err) | ||
testutil.Assert(t, testData.expectedVal.Equal(actual)) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestParseContentLength(t *testing.T) { | ||
tests := map[string]struct { | ||
headerValue string | ||
expectedVal int64 | ||
expectedErr string | ||
}{ | ||
"no header": { | ||
expectedErr: "Content-Length header not found", | ||
}, | ||
"invalid header value": { | ||
headerValue: "invalid", | ||
expectedErr: `convert Content-Length: strconv.ParseInt: parsing "invalid": invalid syntax`, | ||
}, | ||
"valid header value": { | ||
headerValue: "12345", | ||
expectedVal: 12345, | ||
}, | ||
} | ||
|
||
for testName, testData := range tests { | ||
t.Run(testName, func(t *testing.T) { | ||
meta := http.Header{} | ||
if testData.headerValue != "" { | ||
meta.Add(alioss.HTTPHeaderContentLength, testData.headerValue) | ||
} | ||
|
||
actual, err := ParseContentLength(meta) | ||
|
||
if testData.expectedErr != "" { | ||
testutil.NotOk(t, err) | ||
testutil.Equals(t, testData.expectedErr, err.Error()) | ||
} else { | ||
testutil.Ok(t, err) | ||
testutil.Equals(t, testData.expectedVal, actual) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.