Description
Since 0.22.2, dulwich tries to negotiate Git protocol v2, however when trying to clone a repo (in my case from Gerrit 3.10.1, almost the last version), the cloning fails.
Here's a traceback with version 0.22.4:
Traceback (most recent call last):
File ".../python3.11/site-packages/dulwich/client.py", line 2435, in _discover_references
[pkt] = list(proto.read_pkt_seq())
^^^^^
ValueError: too many values to unpack (expected 1)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File ".../test.py", line 1, in <module>
from dulwich.porcelain import clone; clone("https://(redacted)")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".../python3.11/site-packages/dulwich/porcelain.py", line 584, in clone
return client.clone(
^^^^^^^^^^^^^
File ".../python3.11/site-packages/dulwich/client.py", line 874, in clone
result = self.fetch(
^^^^^^^^^^^
File ".../python3.11/site-packages/dulwich/client.py", line 984, in fetch
result = self.fetch_pack(
^^^^^^^^^^^^^^^^
File ".../python3.11/site-packages/dulwich/client.py", line 2607, in fetch_pack
refs, server_capabilities, url, symrefs, peeled = self._discover_references(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".../python3.11/site-packages/dulwich/client.py", line 2437, in _discover_references
raise GitProtocolError(
dulwich.errors.GitProtocolError: unexpected number of packets received
Note that the same code works when specifying clone(..., protocol_version=1)
or clone(..., protocol_version=0)
.
The problem occurs in https://github.com/jelmer/dulwich/blob/dulwich-0.22.4/dulwich/client.py#L258-L263:
def negotiate_protocol_version(proto):
pkt = proto.read_pkt_line()
if pkt == b"version 2\n":
return 2
proto.unread_pkt_line(pkt)
return 0
For some reason pkt
is b"version 2"
instead of b"version 2\n"
, so dulwich continues assuming that the server negotiated version 0 and fails as the server sent the version and capabilities instead of the expected single packet # service=...
.
Doing the following would be enough to fix it, however I'm not sure if this is a case where the server is not following the v2 spec or if dulwich is too strict in its handling (though being more lenient is probably a good thing):
pkt = proto.read_pkt_line()
- if pkt == b"version 2\n":
+ if pkt is not None and pkt.strip() == b"version 2":
return 2