Skip to content

Commit b4dac5c

Browse files
committed
fix: handle tags like debian/2%2.6-21 as identifiers
Git refnames are relatively free-form and can contain all sort for special characters, not just `/` and `#`, see http://git-scm.com/docs/git-check-ref-format In particular, Debian's DEP-14 standard for storing packaging in git repositories mandates the use of the `%` character in tags in some cases like `debian/2%2.6-21`. Unfortunately python-gitlab currently only escapes `/` to `%2F` and in some cases `#` to `%23`. This means that when using the commit API to retrieve information about the `debian/2%2.6-21` tag only the slash is escaped before being inserted in the URL path and the `%` is left untouched, resulting in something like `/api/v4/projects/123/repository/commits/debian%2F2%2.6-21`. When urllib3 seees that it detects the invalid `%` escape and then urlencodes the whole string, resulting in `/api/v4/projects/123/repository/commits/debian%252F2%252.6-21`, where the original `/` got escaped twice and produced `%252F`. To avoid the issue, fully urlencode identifiers and parameters to avoid the urllib3 auto-escaping in all cases. Signed-off-by: Emanuele Aina <emanuele.aina@collabora.com>
1 parent aa13214 commit b4dac5c

File tree

2 files changed

+11
-3
lines changed

2 files changed

+11
-3
lines changed

gitlab/tests/test_utils.py

+8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ def test_clean_str_id():
2727
dest = "foo%23bar%2Fbaz%2F"
2828
assert dest == utils.clean_str_id(src)
2929

30+
src = "foo%bar/baz/"
31+
dest = "foo%25bar%2Fbaz%2F"
32+
assert dest == utils.clean_str_id(src)
33+
3034

3135
def test_sanitized_url():
3236
src = "http://localhost/foo/bar"
@@ -48,6 +52,10 @@ def test_sanitize_parameters_slash():
4852
assert "foo%2Fbar" == utils.sanitize_parameters("foo/bar")
4953

5054

55+
def test_sanitize_parameters_slash_and_percent():
56+
assert "foo%2Fbar%25quuz" == utils.sanitize_parameters("foo/bar%quuz")
57+
58+
5159
def test_sanitize_parameters_dict():
5260
source = {"url": "foo/bar", "id": 1}
5361
expected = {"url": "foo%2Fbar", "id": 1}

gitlab/utils.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

1818
from typing import Any, Callable, Dict, Optional
19-
from urllib.parse import urlparse
19+
from urllib.parse import quote, urlparse
2020

2121
import requests
2222

@@ -57,14 +57,14 @@ def copy_dict(dest: Dict[str, Any], src: Dict[str, Any]) -> None:
5757

5858

5959
def clean_str_id(id: str) -> str:
60-
return id.replace("/", "%2F").replace("#", "%23")
60+
return quote(id, safe="")
6161

6262

6363
def sanitize_parameters(value):
6464
if isinstance(value, dict):
6565
return dict((k, sanitize_parameters(v)) for k, v in value.items())
6666
if isinstance(value, str):
67-
return value.replace("/", "%2F")
67+
return quote(value, safe="")
6868
return value
6969

7070

0 commit comments

Comments
 (0)