Skip to content
New issue

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

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

Already on GitHub? # to your account

V4 signer should encode space in query params with "%20" rather than "+" #243

Open
lostghost opened this issue Oct 6, 2014 · 2 comments

Comments

@lostghost
Copy link
Contributor

Per #242, the v4 signer should encode a space in query params with a "%20" rather than "+" when building the canonicalURI.

http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html

In aws/sign.go#L246 and aws/sign.go#L251 the query string keys and values are encoded with the net/url QueryEscape function. However, that function escapes a space character with a "+" rather than "%20" as required by AWS.

The escaping method for the canonicalQueryString method need to be updated.

One possible solution that continues to use the standard net/url (rather than a custom encoding function) is to use the path escaping functionality in the net/url package as demonstrated here:
http://play.golang.org/p/Po6CFEDcF1

package main

import (
    "fmt"
    "net/url"
)

func main() {

    // Standard QueryEscape call encodes a space with a "+" character.
    // This is because the specs allow either a "+" or "%20" for encoding
    // of a space character in URL Query strings and this function was
    // written for that purpose.

    myFirstString := "Hello world"
    myFirstEncodedString := url.QueryEscape(myFirstString)
    fmt.Println("URL QueryEscape:", myFirstEncodedString)

    // However, the logic for encoding a space using "%20" is build into
    // the net/url package, it is just not readily exposed. We can access
    // it by encoding a url path, where a space must be encoded as "%20"
    // according to spec.

    mySecondString := "Hello world"
    t := &url.URL{Path: mySecondString}
    mySecondEncodedString := t.String()
    fmt.Println("URL Path Encoded:", mySecondEncodedString)
}

I will work on a PR when I get time, but wanted to document the problem and a possible solution here in the meantime.

@alimoeeny
Copy link
Contributor

Thank you @lostghost

@dkolbly
Copy link
Contributor

dkolbly commented Nov 6, 2014

It is also supposed to replace "+" with "%2B", which the url.URL{} trick doesn't seem to accomplish (which I noticed while debugging why I can't s3.Get() objects that have a + in the name)

http://play.golang.org/p/pOfrn-Wsq5

package main

import (
    "fmt"
    "net/url"
)

func main() {

    // Standard QueryEscape call encodes a space with a "+" character.
    // This is because the specs allow either a "+" or "%20" for encoding
    // of a space character in URL Query strings and this function was
    // written for that purpose.

    myFirstString := "Hello world"
    myFirstEncodedString := url.QueryEscape(myFirstString)
    fmt.Println("URL QueryEscape:", myFirstEncodedString)

    // However, the logic for encoding a space using "%20" is build into
    // the net/url package, it is just not readily exposed. We can access
    // it by encoding a url path, where a space must be encoded as "%20"
    // according to spec.

    mySecondString := "Hello world"
    t := &url.URL{Path: mySecondString}
    mySecondEncodedString := t.String()
    fmt.Println("URL Path Encoded:", mySecondEncodedString)

    // Unfortunately, we are also supposed to encode "+" as "%2B", which
    // the url.URL{} trick doesn't do

    myThirdString := "Hello+world"
    t = &url.URL{Path: myThirdString}
    myThirdEncodedString := t.String()
    fmt.Println("URL Path Encoded:", myThirdEncodedString)
}

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants