[lxc-devel] [lxd/master] Fix file push/pull with names containing spaces

albertodonato on Github lxc-bot at linuxcontainers.org
Mon Jul 3 09:31:55 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 313 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170703/f85ba481/attachment.bin>
-------------- next part --------------
From 015e52323cb794cd6bc389d6617207c2f0da82bf Mon Sep 17 00:00:00 2001
From: Alberto Donato <alberto.donato at canonical.com>
Date: Mon, 3 Jul 2017 11:10:52 +0200
Subject: [PATCH] Fix file push/pull with names containing spaces.

Signed-off-by: Alberto Donato <alberto.donato at canonical.com>
---
 client/lxd_containers.go | 12 ++++++++----
 shared/util.go           | 11 +++++++++++
 shared/util_test.go      | 11 +++++++++++
 test/suites/filemanip.sh | 11 +++++++++++
 4 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/client/lxd_containers.go b/client/lxd_containers.go
index 24a7f2d11..a077afc93 100644
--- a/client/lxd_containers.go
+++ b/client/lxd_containers.go
@@ -471,8 +471,10 @@ func (r *ProtocolLXD) ExecContainer(containerName string, exec api.ContainerExec
 // GetContainerFile retrieves the provided path from the container
 func (r *ProtocolLXD) GetContainerFile(containerName string, path string) (io.ReadCloser, *ContainerFileResponse, error) {
 	// Prepare the HTTP request
-	url := fmt.Sprintf("%s/1.0/containers/%s/files?path=%s", r.httpHost, containerName, path)
-	req, err := http.NewRequest("GET", url, nil)
+	requestUrl := shared.URLEncode(
+		fmt.Sprintf("%s/1.0/containers/%s/files", r.httpHost, containerName),
+		map[string]string{"path": path})
+	req, err := http.NewRequest("GET", requestUrl, nil)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -551,8 +553,10 @@ func (r *ProtocolLXD) CreateContainerFile(containerName string, path string, arg
 	}
 
 	// Prepare the HTTP request
-	url := fmt.Sprintf("%s/1.0/containers/%s/files?path=%s", r.httpHost, containerName, path)
-	req, err := http.NewRequest("POST", url, args.Content)
+	requestUrl := shared.URLEncode(
+		fmt.Sprintf("%s/1.0/containers/%s/files", r.httpHost, containerName),
+		map[string]string{"path": path})
+	req, err := http.NewRequest("POST", requestUrl, args.Content)
 	if err != nil {
 		return err
 	}
diff --git a/shared/util.go b/shared/util.go
index 43cba2579..a2c4cece0 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -12,6 +12,7 @@ import (
 	"io/ioutil"
 	"math"
 	"net/http"
+	"net/url"
 	"os"
 	"os/exec"
 	"path"
@@ -28,6 +29,16 @@ import (
 const SnapshotDelimiter = "/"
 const DefaultPort = "8443"
 
+// URLEncode encodes a path and query parameters to a URL.
+func URLEncode(path string, query map[string]string) string {
+	params := url.Values{}
+	for key, value := range query {
+		params.Add(key, value)
+	}
+	u := &url.URL{Path: path, RawQuery: params.Encode()}
+	return u.String()
+}
+
 // AddSlash adds a slash to the end of paths if they don't already have one.
 // This can be useful for rsyncing things, since rsync has behavior present on
 // the presence or absence of a trailing slash.
diff --git a/shared/util_test.go b/shared/util_test.go
index 458c8fca9..ea4024683 100644
--- a/shared/util_test.go
+++ b/shared/util_test.go
@@ -9,6 +9,17 @@ import (
 	"testing"
 )
 
+
+func TestURLEncode(t *testing.T) {
+	url := URLEncode(
+		"/path/with spaces",
+		map[string]string{"param": "with spaces", "other": "without"})
+	expected := "/path/with%20spaces?other=without&param=with+spaces"
+	if url != expected {
+		t.Error(fmt.Errorf("'%s' != '%s'", url, expected))
+	}
+}
+
 func TestFileCopy(t *testing.T) {
 	helloWorld := []byte("hello world\n")
 	source, err := ioutil.TempFile("", "")
diff --git a/test/suites/filemanip.sh b/test/suites/filemanip.sh
index d1e8e58c2..2368c9143 100644
--- a/test/suites/filemanip.sh
+++ b/test/suites/filemanip.sh
@@ -36,6 +36,17 @@ test_filemanip() {
 
   lxc exec filemanip -- rm -rf /tmp/ptest/source
 
+  # Test pushing/pulling a file with spaces
+  echo "foo" > "${TEST_DIR}/source/file with spaces"
+
+  lxc file push -p -r "${TEST_DIR}"/source filemanip/tmp/ptest
+  lxc exec filemanip -- find /tmp/ptest/source | grep -q "file with spaces"
+  rm -rf "${TEST_DIR}/source/file with spaces"
+
+  lxc file pull -p -r filemanip/tmp/ptest "${TEST_DIR}/dest"
+  find "${TEST_DIR}/dest/" | grep "file with spaces"
+  rm -rf "${TEST_DIR}/dest"
+
   # Check that file permissions are not applied to intermediate directories
 
   lxc file push -p --mode=400 "${TEST_DIR}"/source/foo \


More information about the lxc-devel mailing list