Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
Added support for v4 signing to S3. #27
Conversation
|
Most of this PR is switching the S3 requests over to vanilla http.Request structures. This was done because the new AWS signing operates on these. |
dimitern
reviewed
Feb 13, 2015
| + if r.S3BucketEndpoint != "" { | ||
| + return strings.Replace(r.S3BucketEndpoint, "${bucket}", bucketName, -1) | ||
| + } | ||
| + return r.S3Endpoint + "/" + bucketName + "/" |
kat-co
Feb 23, 2015
Member
path.Join scrubs the content and will remove one of the slashes in "http://" in the r.S3Endpoint.
dimitern
reviewed
Feb 13, 2015
| + req.URL.RawQuery = query.Encode() | ||
| + | ||
| + for attempt := attempts.Start(); attempt.Next(); attempt = attempts.Start() { | ||
| + |
dimitern
reviewed
Feb 13, 2015
dimitern
reviewed
Feb 13, 2015
| + query := req.URL.Query() | ||
| + query.Add("upload", "") | ||
| + req.URL.RawQuery = query.Encode() | ||
| + |
dimitern
reviewed
Feb 13, 2015
| - _, err := b.Get("non-existent") | ||
| + s := s3.New(s.s3.Auth, r, aws.SignV2) | ||
| + b, err := s.Bucket("goamz-" + s.Auth.AccessKey) | ||
| + c.Assert(err, IsNil) |
dimitern
Feb 13, 2015
Member
I'd prefer not to use c.Assert in a loop like this, so that a single failure won't stop the test. How about:
if !c.Check(err, IsNil) {
errs <- err
}
_, err = b.Get("non-existent")
dimitern
reviewed
Feb 13, 2015
| - s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL, Sign: aws.SignV2}) | ||
| + s.s3 = s3.New( | ||
| + aws.Auth{"abc", "123"}, | ||
| + aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL, Sign: aws.SignV2}, |
dimitern
Feb 13, 2015
Member
Split aws.Region fields in multiple lines, as it's getting a bit too long.
dimitern
reviewed
Feb 13, 2015
| + return resp, nil | ||
| + } | ||
| + | ||
| + panic("could not complete the request within the specified retry attempts") |
dimitern
Feb 13, 2015
Member
Why not just return an error here? This is production code and I'd rather handle the error outside than to crash the whole process.
kat-co
Feb 23, 2015
Member
This was the pattern established when I began working on the code, but you're correct. I've switched it to an error.
dimitern
reviewed
Feb 13, 2015
| -// URL returns a non-signed URL that allows retriving the |
dimitern
Feb 13, 2015
Member
So we're dropping URL and SignedURL methods entirely? This is not backwards-compatible and will break existing client. Is it possible to leave these two methods in place and somehow simulate what they do with the new logic?
kat-co
Feb 23, 2015
Member
As we discussed:
- This is proposed against v3-unstable, so it will not break anyone.
- SignedURL no longer makes sense as an option since v4 utilizes headers for signing.
I have added the URL function back in.
|
Most of this looks good, however dropping the 2 methods I can't quite get. Also, have you tried running all the s3 tests with -amazon to make sure both the s3test server still works (I'm assuming tests pass, otherwise travis CI would've reported it) and the changes work against live AWS and s3test the same way? |
|
Sorry, I've seen this is actually targeted to v3-unstable, so changes to the interface is fine at this point. However, I still think URL is worth keeping as a method. I'd like to have another look when you're done with the tests. |
dimitern
reviewed
Mar 1, 2015
| + if req.Body != nil { | ||
| + if b, err := ioutil.ReadAll(req.Body); err != nil { | ||
| + return "", err | ||
| + } else { |
dimitern
Mar 1, 2015
Member
I'd pull b, err := ioutil.ReadAll(..) before the if and drop the else clause to reduce the indentation level.
dimitern
reviewed
Mar 1, 2015
| + } else { | ||
| + req.Body = ioutil.NopCloser(bytes.NewBuffer(b)) | ||
| + return hasher(b), nil | ||
| + } | ||
| } else { |
dimitern
reviewed
Mar 1, 2015
| - sort.Strings(sortedHdrVals) | ||
| - hdrVals := strings.Join(sortedHdrVals, ",") | ||
| + | ||
| + var hdrVals string |
dimitern
Mar 1, 2015
Member
How about:
hdrVals := host
if hName != "host" {
canonHdrKey := http.CanonicalHeaderKey(hName)
sortedHdrVals := hdr[canonHdrKey]
sort.Strings(sortedHdrVals)
hdrVals = strings.Join(sortedHdrVals, ",")
}
dimitern
reviewed
Mar 1, 2015
| ) | ||
| var _ = Suite(&SigningSuite{}) | ||
| type SigningSuite struct{} | ||
| +const v4skipReason = `"The signing methodology is a "one size fits all" approach. The hashes we check against don't include headers that are added in as requisite parts for S3. That doesn't mean the tests are invalid, or that signing is broken for these examples, but as long as we're adding heads in, it's impossible to know what the new signature should be. We should revaluate these later.` |
dimitern
Mar 1, 2015
Member
How about:
// TODO(katco-): The signing methodology is a "one size fits all" approach.
// The hashes we check against against don't include headers that are added
// in as requisite parts for S3. That doesn't mean the tests are invalid, or that
// signing is broken for these examples, but as long as we're adding heads in,
// it's impossible to know what the new signature should be. We should reevaluate
// these later. See issue #XYZ.
const v4SkipReason = `Extra headers present - cannot predict generated signature (issue #XYZ)`This will show nicely as we're running tests (i.e. not splitting the output on multiple lines), but also gives the reader of this source enough context to understand the issue. Please, file an issue for this and replace the #XYZ with the issue number.
dimitern
Mar 1, 2015
Member
As for the impossibility of knowing what the hash could be, I guess this is because the hash changes because of the current timestamp (or reqTime). This could be faked for the test servers - setting a fixed time of a request/response. But that's a future improvement. As long as you've actually manually tested the scenarios in the skipped tests I think it's fine.
dimitern
reviewed
Mar 1, 2015
| @@ -25,7 +25,7 @@ var testServer = testutil.NewHTTPServer() | ||
| func (s *S) SetUpSuite(c *C) { | ||
| testServer.Start() | ||
| auth := aws.Auth{"abc", "123"} | ||
| - s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL, Sign: aws.SignV2}) |
dimitern
Mar 1, 2015
Member
It's great you took the time to actually fix the exp/ packages as well. However, they're barely working and are not maintained, so if there are test failures here I don't really care.
dimitern
reviewed
Mar 1, 2015
| multi, err := b.InitMulti("multi", "text/plain", s3.Private) | ||
| c.Assert(err, IsNil) | ||
| parts, err := multi.PutAll(strings.NewReader("part1part2last"), 5) | ||
| - c.Assert(parts, HasLen, 3) |
dimitern
reviewed
Mar 1, 2015
| } | ||
| - panic("unreachable") | ||
| + return resp.Body, nil | ||
| } | ||
| // Put inserts an object into the S3 bucket. |
dimitern
Mar 1, 2015
Member
Or actually, just drop the Put doc comment and body only. rather than PutReader's doc comment as well.
dimitern
reviewed
Mar 1, 2015
| -} | ||
| - | ||
| -// PutReader inserts an object into the S3 bucket by consuming data | ||
| -// from r until EOF. | ||
| func (b *Bucket) PutReader(path string, r io.Reader, length int64, contType string, perm ACL) error { | ||
| return b.PutReaderWithHeader(path, r, length, contType, perm, http.Header{}) | ||
| } | ||
| // PutReader inserts an object into the S3 bucket by consuming data |
dimitern
Mar 1, 2015
Member
Also, restore the two lines below in the doc comment - ... The HTTP PUT request will have...
dimitern
reviewed
Mar 1, 2015
| @@ -96,27 +104,11 @@ func (s *S) TestGet(c *C) { | ||
| c.Assert(string(data), Equals, "content") | ||
| } | ||
| -func (s *S) TestURL(c *C) { |
|
All in all it looks fine, but I'm getting some s3 test failures in both local and live tests. I've sent you a mail with more details. |
|
LGTM with the patch discussed on IRC: http://pastebin.ubuntu.com/10490009/ which makes s3 live tests to pass reliably. However, a side-effect of that is leaving a bunch of buckets after each live test run - please, add an issue for this as well. When we have time, we'll fix it. |
|
Great, I'm merging this. |
kat-co commentedFeb 11, 2015