{"action":"created","issue":{"url":"https://api.github.com/repos/mrjones/oauth/issues/34","labels_url":"https://api.github.com/repos/mrjones/oauth/issues/34/labels{/name}","comments_url":"https://api.github.com/repos/mrjones/oauth/issues/34/comments","events_url":"https://api.github.com/repos/mrjones/oauth/issues/34/events","html_url":"https://github.com/mrjones/oauth/issues/34","id":99989185,"number":34,"title":"broken request if parameter contains \";\"","user":{"login":"mnovozhylov","id":197380,"avatar_url":"https://avatars.githubusercontent.com/u/197380?v=3","gravatar_id":"","url":"https://api.github.com/users/mnovozhylov","html_url":"https://github.com/mnovozhylov","followers_url":"https://api.github.com/users/mnovozhylov/followers","following_url":"https://api.github.com/users/mnovozhylov/following{/other_user}","gists_url":"https://api.github.com/users/mnovozhylov/gists{/gist_id}","starred_url":"https://api.github.com/users/mnovozhylov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mnovozhylov/subscriptions","organizations_url":"https://api.github.com/users/mnovozhylov/orgs","repos_url":"https://api.github.com/users/mnovozhylov/repos","events_url":"https://api.github.com/users/mnovozhylov/events{/privacy}","received_events_url":"https://api.github.com/users/mnovozhylov/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-08-10T06:55:20Z","updated_at":"2015-09-07T02:53:22Z","closed_at":null,"body":"hey @mrjones ,\r\n\r\nfirst of all, thanks for the nice library!\r\ni'm trying to re-use it in upwork/golang-upwork project, and i've found an interesting issue:\r\n```\r\nparams := make(map[string]string)\r\nparams[\"q\"] = \"golang\"\r\nparams[\"paging\"] = \"1;10\"\r\n\r\nline 675: t := userRequest.URL.Query()\r\nline 676: log.Fatal(userRequest)\r\n2015/08/10 07:59:26 &{GET https://www.upwork.com/api/profiles/v2/search/jobs.json?paging=1;10&q=golang HTTP/1.1 1 1 map[] <nil> 0 [] false www.upwork.com map[] map[] <nil> map[]   <nil>}\r\n\r\nseems to be OK, but:\r\nline 677: log.Fatal(t)\r\n2015/08/10 08:02:40 map[10:[] q:[golang] paging:[1]]\r\nHOW?!\r\n\r\nlet's change params[q] to params[\"q\"] = \"golang;test\"\r\nuserRequest looks correct:\r\n2015/08/10 08:11:25 &{GET https://www.upwork.com/api/profiles/v2/search/jobs.json?q=golang;test&paging=1;10 HTTP/1.1 1 1 map[] <nil> 0 [] false www.upwork.com map[] map[] <nil> map[]   <nil>}\r\nbut suddenly userRequest.URL.Query() returns:\r\n2015/08/10 08:12:51 map[paging:[1] 10:[] q:[golang] test:[]]\r\n```\r\n\r\njfyi, URL.Query() recognizes \";\" and \"&\" as delimeters (http://stackoverflow.com/questions/3481664/semicolon-as-url-query-separator)\r\n\r\nquick fix can look like:\r\n```\r\ndiff --git a/oauth.go b/oauth.go\r\nindex 3d195ce..d1b9b61 100644\r\n--- a/oauth.go\r\n+++ b/oauth.go\r\n@@ -669,6 +669,7 @@ func (rt *RoundTripper) RoundTrip(userRequest *http.Request) (*http.Response, er\r\n        if userRequest.Header.Get(\"Content-Type\") !=\r\n                \"application/x-www-form-urlencoded\" {\r\n                // Most of the time we get parameters from the query string:\r\n+               userRequest.URL.RawQuery = strings.Replace(userRequest.URL.RawQuery, \";\", \"%3B\", -1)\r\n                for k, vs := range(userRequest.URL.Query()) {\r\n                        if len(vs) != 1 {\r\n                                return nil, fmt.Errorf(\"Must have exactly one value per param\")\r\n```\r\nin that case library works as expected\r\n\r\nor the library could encode \";\" before creating a request (and might decode it before signing a request to have a valid signature created), or smth similar"},"comment":{"url":"https://api.github.com/repos/mrjones/oauth/issues/comments/138165919","html_url":"https://github.com/mrjones/oauth/issues/34#issuecomment-138165919","issue_url":"https://api.github.com/repos/mrjones/oauth/issues/34","id":138165919,"user":{"login":"mrjones","id":75486,"avatar_url":"https://avatars.githubusercontent.com/u/75486?v=3","gravatar_id":"","url":"https://api.github.com/users/mrjones","html_url":"https://github.com/mrjones","followers_url":"https://api.github.com/users/mrjones/followers","following_url":"https://api.github.com/users/mrjones/following{/other_user}","gists_url":"https://api.github.com/users/mrjones/gists{/gist_id}","starred_url":"https://api.github.com/users/mrjones/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrjones/subscriptions","organizations_url":"https://api.github.com/users/mrjones/orgs","repos_url":"https://api.github.com/users/mrjones/repos","events_url":"https://api.github.com/users/mrjones/events{/privacy}","received_events_url":"https://api.github.com/users/mrjones/received_events","type":"User","site_admin":false},"created_at":"2015-09-07T02:53:21Z","updated_at":"2015-09-07T02:53:21Z","body":"Ah, I *think* I understand better now.  However, I could still be mis-understanding something, if so please let me know.\r\n\r\nI just committed change c4fac5ef43dacbdd6dfe0b159fb24b0e33ea5bbb which I hope will help you.\r\n\r\nTo communicate fully what's happening here, I must point out that as of recently, there are two different ways to make HTTP requests.  This all started with 5faa557585ac2fde321eada0a28eb6f1b4176319, when I introduced a second way.\r\n- The old way works by calling Get()/Post()/etc directly on the Consumer object.\r\n- The new way works by using an http.Client from the MakeHttpClient method on the Consumer.\r\n\r\nI think the second way is more flexible, and generally \"better\", but I'd like to keep both ways working.  So, there is a function (makeAuthorizedRequestReader) which translates from the old interface to the new one internally. \r\n\r\nCorrect me if I'm wrong, but I assume that you are using the \"old\" way (calling Get directly)?    People who use the new interface should be able to access to RawQuery directly on the http.Request object, and therefore shouldn't need any special support inside the library.\r\n\r\nAssuming I understand correctly: We only need to fix the old interface.  Therefore, I applied the exact fix that you recommended (replacing \";\" with \"%3B\" in the RawQuery) in the old-to-new translation method (makeAuthorizedRequestReader).\r\n\r\nI hope this will fix your code as it stands. I also believe you could switch to the new http.Client interface, which would enable you to control the escaping yourself by editing RawQuery.  You might like other aspects of the new interface as well.\r\n\r\nI committed two tests as part of c4fac5ef43dacbdd6dfe0b159fb24b0e33ea5bbb, to demonstrate what I think *should* happen.\r\n\r\nPlease do let me know if this fixes your issue!"}}