Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to delete Object in empty dir with s3.DeleteObject #1853

Closed
svenwltr opened this issue Mar 21, 2018 · 3 comments
Closed

Unable to delete Object in empty dir with s3.DeleteObject #1853

svenwltr opened this issue Mar 21, 2018 · 3 comments
Labels
documentation This is a problem with documentation. guidance Question that needs advice or information.

Comments

@svenwltr
Copy link

svenwltr commented Mar 21, 2018

Solution

Set the aws.Config.DisableRestProtocolURICleaning member to true, to use adjacent slashes, trailing slashes, or dot slash(./) in key names.

svc := s3.New(sess, &aws.Config{
   	DisableRestProtocolURICleaning: aws.Bool(true),
})
out, err := svc.GetObject(&s3.GetObjectInput {
   	Bucket: aws.String("bucketname"),
    	Key: aws.String("//foo//bar//moo"),
})

Version of AWS SDK for Go?

v1.13.17

Version of Go (go version)?

go version go1.9.2 linux/amd64

What issue did you see?

It is not possible to delete an Object in an "empty dir" with s3.DeleteObject, since the SDK converts // to / in the request path.

Steps to reproduce

  1. Create Object: aws s3 cp holidays s3://aws-empty-object-test/foo//bar/holidays
upload: ./holidays to s3://aws-empty-object-test/foo//bar/holidays
  1. Verify object is there: aws s3 ls s3://aws-empty-object-test/foo//bar/.
2018-03-21 09:25:17        142 holidays
  1. Delete Object: ./bug-test foo//bar/holidays (see example below).
{
  Bucket: "aws-empty-object-test",
  Key: "foo//bar/holidays"
}
sending AWS request:
    > DELETE /aws-empty-object-test/foo/bar/holidays HTTP/1.1
    > Host: aws-empty-object-test.s3.eu-west-1.amazonaws.com
    > Authorization: <hidden>
    > User-Agent: aws-sdk-go/1.13.17 (go1.9.2; linux; amd64)
    > X-Amz-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    > X-Amz-Date: 20180321T084011Z

Note that the path is /aws-empty-object-test/foo/bar/holidays instead of /aws-empty-object-test/foo//bar/holidays.

  1. Verify object is still there: aws s3 ls s3://aws-empty-object-test/foo//bar/.
2018-03-21 09:25:17        142 holidays

Verification of the example code

  1. Create Object: aws s3 cp holidays s3://aws-empty-object-test/blub/holidays
upload: ./holidays to s3://aws-empty-object-test/foo//bar/holidays
  1. Verify object is there: aws s3 ls s3://aws-empty-object-test/blub/.
2018-03-21 09:40:42        142 holidays
  1. Delete Object: ./bug-test blub/holidays (see example below).
{
  Bucket: "aws-empty-object-test",
  Key: "blub/holidays"
}
sending AWS request:
    > DELETE /aws-empty-object-test/blub/holidays HTTP/1.1
    > Host: aws-empty-object-test.s3.eu-west-1.amazonaws.com
    > Authorization: <hidden>
    > User-Agent: aws-sdk-go/1.13.17 (go1.9.2; linux; amd64)
    > X-Amz-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    > X-Amz-Date: 20180321T084432Z
  1. Verify object is still there: aws s3 ls s3://aws-empty-object-test/blub/.

Example Code

package main

import (
	"fmt"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

func main() {
	sess, err := session.NewSessionWithOptions(session.Options{
		Config: aws.Config{
			Region: aws.String("eu-west-1"),
		},
		SharedConfigState: session.SharedConfigEnable,
		Profile:           "default",
	})
	if err != nil {
		panic(err)
	}

	sess.Handlers.Send.PushFront(func(r *request.Request) {
		fmt.Printf("sending AWS request:\n%s\n", DumpRequest(r.HTTPRequest))
	})

	svc := s3.New(sess)
	params := &s3.DeleteObjectInput{
		Bucket: aws.String("aws-empty-object-test"),
		Key:    aws.String(os.Args[1]),
	}
	fmt.Println(params)
	_, err = svc.DeleteObject(params)
	if err != nil {
		panic(err)
	}
}
package main

import (
	"bytes"
	"net/http"
	"net/http/httputil"
	"regexp"

	"github.com/rebuy-de/aws-nuke/pkg/util"
)

var (
	RESecretHeader = regexp.MustCompile(`(?m:^([^:]*(Auth|Security)[^:]*):.*$)`)
)

func HideSecureHeaders(dump []byte) []byte {
	return RESecretHeader.ReplaceAll(dump, []byte("$1: <hidden>"))
}

func DumpRequest(r *http.Request) string {
	dump, err := httputil.DumpRequest(r, true)
	if err != nil {
		panic(err)
	}

	dump = bytes.TrimSpace(dump)
	dump = HideSecureHeaders(dump)
	dump = util.IndentBytes(dump, []byte("    > "))
	return string(dump)
}
@xibz
Copy link
Contributor

xibz commented Mar 21, 2018

Hello @svenwltr, thank you for reaching out to us. Try setting DisableRestProtocolURICleaning in the aws.Config. That should preserve the extra /. Please let us know if that resolves your issue.

@xibz xibz added the guidance Question that needs advice or information. label Mar 21, 2018
@svenwltr
Copy link
Author

Thank you @xibz, this indeed works. I hope changing this does not cause any other side effects.

I guess it is hard to fix it in general for DeleteObjectInput, but it might be helpful to add a note to the docs, since "empty directories" are possible in S3.

@diehlaws diehlaws added the documentation This is a problem with documentation. label Aug 2, 2019
@diehlaws
Copy link
Contributor

diehlaws commented Aug 2, 2019

Thanks for the feedback @svenwltr and I'm glad to hear this config option works as expected for you. Since this use case applies to other API calls in addition to DeleteObject we'll be adding a note about this config option at the top of the documentation page for the S3 package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation This is a problem with documentation. guidance Question that needs advice or information.
Projects
None yet
Development

No branches or pull requests

3 participants