From f13307387fcd0322b304b2372aefbe45137f07d6 Mon Sep 17 00:00:00 2001
From: Kirill Smelkov <kirr@nexedi.com>
Date: Thu, 18 May 2023 19:50:10 +0300
Subject: [PATCH] client: Don't allow master_nodes and name to be present in
 options
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Because list of masters and cluster name must be already present in
netloc and path. Previously e.g.

	neo://db@伪,尾,纬?master_nodes=a,b,c"

would mean to use master nodes {a,b,c} not {伪,尾,纬}. Now it is treated as
invalid URI to remove ambiguity. Same for cluster name.

/cc @levin.zimmermann
/reviewed-by @jm
/reviewed-on https://lab.nexedi.com/nexedi/neoppod/merge_requests/21

(cherry-picked from commit 22ccebd6338fca3a18ca74ba07a4d4d8e7793300)
---
 neo/client/zodburi.py           | 8 ++++++--
 neo/tests/client/testZODBURI.py | 4 ++++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/neo/client/zodburi.py b/neo/client/zodburi.py
index a0a430e5..a950be6f 100644
--- a/neo/client/zodburi.py
+++ b/neo/client/zodburi.py
@@ -66,6 +66,10 @@ def _resolve_uri(uri):
     neokw = OrderedDict()
     neokw['master_nodes'] = ' '.join(master_list)
     neokw['name'] = name
+    def setopt(k, v):
+        if k in ('master_nodes', 'name'):
+            raise ValueError("invalid uri: %s : invalid option %s" % (uri, k))
+        neokw[k] = v
 
     # get options from query: only those that are defined by NEO schema go to
     # storage - rest are returned as database options
@@ -73,14 +77,14 @@ def _resolve_uri(uri):
     neo_options = neo_zconf_options()
     for k, v in OrderedDict(parse_qsl(query)).items():
         if k in neo_options:
-            neokw[k] = v
+            setopt(k, v)
         else:
             # it might be option for storage, but not in canonical form e.g.
             # read_only -> read-only  (zodburi world settled on using "_" and
             # ZConfig world on "-" as separators)
             k2 = canonical_opt_name(k)
             if k2 in neo_options:
-                neokw[k2] = v
+                setopt(k2, v)
 
             # else keep this kv as db option
             else:
diff --git a/neo/tests/client/testZODBURI.py b/neo/tests/client/testZODBURI.py
index 46cc88fe..3c32c4c1 100644
--- a/neo/tests/client/testZODBURI.py
+++ b/neo/tests/client/testZODBURI.py
@@ -72,6 +72,10 @@ class ZODBURITests(unittest.TestCase):
         # db @ master not fully specified
         self.assertRaises(ValueError, _resolve_uri, "neo://master")
 
+        # master_nodes and name provided in options (they come in netloc)
+        self.assertRaises(ValueError, _resolve_uri, "neo://db@master?master_nodes=a,b,c")
+        self.assertRaises(ValueError, _resolve_uri, "neo://db@master?name=zzz")
+
         # verify zodburi resolver produces expected zconfig
         for uri, zconf_ok, dbkw_ok in testv:
             zconf_ok = "%import neo.client\n<NEOStorage>\n" + zconf_ok + \
-- 
2.30.9