From 41721f025d4f562deae67f897efeb12e3926b527 Mon Sep 17 00:00:00 2001
From: Matt Joiner <anacrolix@gmail.com>
Date: Mon, 21 Dec 2020 12:24:24 +1100
Subject: [PATCH] Further fixes to webseed path encoding

---
 webseed/{misc.go => request.go} | 20 ++++++++++++--------
 webseed/request_test.go         | 23 +++++++++++++++++++++++
 2 files changed, 35 insertions(+), 8 deletions(-)
 rename webseed/{misc.go => request.go} (70%)
 create mode 100644 webseed/request_test.go

diff --git a/webseed/misc.go b/webseed/request.go
similarity index 70%
rename from webseed/misc.go
rename to webseed/request.go
index 466c664a..6d62ccb6 100644
--- a/webseed/misc.go
+++ b/webseed/request.go
@@ -10,20 +10,24 @@ import (
 	"github.com/anacrolix/torrent/metainfo"
 )
 
+func trailingPath(infoName string, pathComps []string) string {
+	return path.Join(
+		func() (ret []string) {
+			for _, comp := range append([]string{infoName}, pathComps...) {
+				ret = append(ret, url.QueryEscape(comp))
+			}
+			return
+		}()...,
+	)
+}
+
 // Creates a request per BEP 19.
 func NewRequest(url_ string, fileIndex int, info *metainfo.Info, offset, length int64) (*http.Request, error) {
 	fileInfo := info.UpvertedFiles()[fileIndex]
 	if strings.HasSuffix(url_, "/") {
 		// BEP specifies that we append the file path. We need to escape each component of the path
 		// for things like spaces and '#'.
-		url_ += path.Join(
-			func() (ret []string) {
-				for _, comp := range append([]string{info.Name}, fileInfo.Path...) {
-					ret = append(ret, url.PathEscape(comp))
-				}
-				return
-			}()...,
-		)
+		url_ += trailingPath(info.Name, fileInfo.Path)
 	}
 	req, err := http.NewRequest(http.MethodGet, url_, nil)
 	if err != nil {
diff --git a/webseed/request_test.go b/webseed/request_test.go
new file mode 100644
index 00000000..b82a0057
--- /dev/null
+++ b/webseed/request_test.go
@@ -0,0 +1,23 @@
+package webseed
+
+import (
+	"net/url"
+	"testing"
+
+	qt "github.com/frankban/quicktest"
+)
+
+func TestTrailingPath(t *testing.T) {
+	c := qt.New(t)
+	test := func(parts []string, result string) {
+		unescaped, err := url.QueryUnescape(trailingPath(parts[0], parts[1:]))
+		if !c.Check(err, qt.IsNil) {
+			return
+		}
+		c.Check(unescaped, qt.Equals, result)
+	}
+	test([]string{"a_b-c", "d + e.f"}, "a_b-c/d + e.f")
+	test([]string{"a_1-b_c2", "d 3. (e, f).g"},
+		"a_1-b_c2/d 3. (e, f).g",
+	)
+}
-- 
2.51.0