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

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)
}

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

No branches or pull requests

3 participants