Repository: exercism/cli
Pull request #650 (2018-07-17 16:20:15)

Fix the encode problem
Now that the file are download by a get request, if some character do not be encoded will try to get the wrong one. 
Follow the evidence

**https://api.exercism.io/v1/solutions/latest?exercise_id=hello-world&track_id=plsql**
_Response:_
```
{
    "solution": {
        "id": "7f887ffb489c40c8ae1c1481eb2e1165",
        "url": "https://exercism.io/my/solutions/7f887ffb489c40c8ae1c1481eb2e1165",
        "team": null,
        "user": {
            "handle": "williandrade",
            "is_requester": true
        },
        "exercise": {
            "id": "hello-world",
            "instructions_url": "https://exercism.io/my/solutions/7f887ffb489c40c8ae1c1481eb2e1165",
            "auto_approve": true,
            "track": {
                "id": "plsql",
                "language": "PL/SQL"
            }
        },
        "file_download_base_url": "https://api.exercism.io/v1/solutions/7f887ffb489c40c8ae1c1481eb2e1165/files/",
        "files": [
            "README.md",
            "hello_world#.plsql",
            "ut_hello_world#.plsql"
        ],
        "iteration": null
    }
}
```

_Response when do the GET request_
```
========================= BEGIN DumpResponse =========================
HTTP/1.1 404 Not Found
Transfer-Encoding: chunked
Cache-Control: no-cache
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Tue, 17 Jul 2018 14:58:29 GMT
Referrer-Policy: strict-origin-when-cross-origin
Server: nginx/1.10.3 (Ubuntu)
Set-Cookie: site_context=normal; domain=.exercism.io; path=/
Set-Cookie: _exercism_session=MTjAmlcMmkeVLWfioqW5PvGvqFSypvhLk3Kb1zPESLkCbpep5XOD68gVDnUS1wX9DwcSe7nSi%2ByBqhsJBYOGccYUl4LC%2BpCLcDCFHRb%2BGeO22NleSGhHSk9avFom%2BJIGOBtyXv0o9FGmT5fKRtNdV61LDoT65jI0jz%2BqmqmPFhSHusAhy1XPYlxYZliLi6kKhjdPf3wVKkleBHfyI6A5sT7jBQf68BIOzqgeDRxcRjIEYba3CWurtxiTUwpIyV%2FNfw9kS63qvvTo--x0xwl%2BdZYyy1tYlD--KCuaNutWr0d%2Fl%2F9bSp5%2FVQ%3D%3D; domain=.exercism.io; path=/; HttpOnly
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 4783f37e-c921-4203-a92f-e56b2df8fba1
X-Runtime: 0.088371
X-Xss-Protection: 1; mode=block


========================= END DumpResponse =========================
```


nywilken: @williandrade any chance you have time to add a test for this change? I would like to get it in. Let us know if you need help or if you don’t have the time. 

Thanks again for your contributions 
williandrade: Sorry for take to long to answer you guys back, I had some things to do at my job, anyway, I added the change into the test file to embrace the new change. I'm new at this thing of contribute, hope I did it right. =D
nywilken: Thanks for adding the test case. Would you mind rebasing your changes into the latest master https://github.com/exercism/docs/blob/master/contributing/git-basics.md#rebasing

If you need help or run into issues give us a holler and we can help you resolve any git issues. 
williandrade: I did the rebase, however I haven't sure if I did it right :blush:
nywilken: @williandrade it looks like you might've merged and rebased which threw the history out of whack. Please follow the steps below to resolve the rebasing issue. Let me know if you have questions. 

Bring your fork up to date with upstream
```
git checkout master
git pull upstream master
git push origin master
```

Rebase your branch onto latest master
```git checkout development```

Undo last commit to avoid another conflict resolution
```
git reset e1ee85824c40ef0226d53b794954922d73332804
git stash
```
Rebase onto your updated master

```
git rebase master
```

Retrieve last commit which was stashed
```
git stash pop
git commit -a -m "change the test because of the commit 8572e980e811aff3249d980fe04644a51ee5944c"
```

Force push your changes back to your development branch. 
williandrade: omg, I just did what you said and looks that it works kkkkk. Hope that it works properly.

Patch:
diff --git a/cmd/download.go b/cmd/download.go
index 206ee93..0e782d4 100644
--- a/cmd/download.go
+++ b/cmd/download.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	netURL "net/url"
 	"os"
 	"path/filepath"
 	"strings"
@@ -171,7 +172,15 @@ func runDownload(cfg config.Config, flags *pflag.FlagSet, args []string) error {
 	}
 
 	for _, file := range payload.Solution.Files {
-		url := fmt.Sprintf("%s%s", payload.Solution.FileDownloadBaseURL, file)
+		unparsedUrl := fmt.Sprintf("%s%s", payload.Solution.FileDownloadBaseURL, file)
+		parsedUrl, err := netURL.ParseRequestURI(unparsedUrl)
+
+		if err != nil {
+			return err
+		}
+
+		url := parsedUrl.String()
+
 		req, err := client.NewRequest("GET", url, nil)
 		if err != nil {
 			return err


Test patch:
diff --git a/cmd/download_test.go b/cmd/download_test.go
index 2c3200c..140c8d0 100644
--- a/cmd/download_test.go
+++ b/cmd/download_test.go
@@ -166,6 +166,10 @@ func fakeDownloadServer(requestor, teamSlug string) *httptest.Server {
 		fmt.Fprint(w, "this is file 2")
 	})
 
+	mux.HandleFunc("/special-char-filename#.txt", func(w http.ResponseWriter, r *http.Request) {
+		fmt.Fprint(w, "this is a special file")
+	})
+
 	mux.HandleFunc("/file-3.txt", func(w http.ResponseWriter, r *http.Request) {
 		fmt.Fprint(w, "")
 	})
@@ -202,6 +206,11 @@ func assertDownloadedCorrectFiles(t *testing.T, targetDir string) {
 			path:     filepath.Join(targetDir, "bogus-track", "bogus-exercise", "subdir", "file-2.txt"),
 			contents: "this is file 2",
 		},
+		{
+			desc:     "a file that requires URL encoding",
+			path:     filepath.Join(targetDir, "bogus-track", "bogus-exercise", "special-char-filename#.txt"),
+			contents: "this is a special file",
+		},
 	}
 
 	for _, file := range expectedFiles {
@@ -239,6 +248,7 @@ const payloadTemplate = `
 		"files": [
 			"/file-1.txt",
 			"/subdir/file-2.txt",
+			"/special-char-filename#.txt",
 			"/file-3.txt"
 		],
 		"iteration": {