mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
fix: keep node file content byte-faithful in node_file_get
Splitting the file with keepends=False and rejoining with newlines dropped the trailing newline of the last line (and every \r of CRLF files), so returned content was shorter than the file on disk and did not round-trip. Split with keepends=True and join the selected lines verbatim; pagination semantics are unchanged.
This commit is contained in:
parent
57b5baed7f
commit
636abde16c
@ -474,23 +474,26 @@ def get_node_file_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> d
|
||||
raw = raw[:MAX_NODE_FILE_BYTES]
|
||||
truncated = True
|
||||
|
||||
lines = raw.splitlines(keepends=False)
|
||||
# keepends keeps the content byte-faithful: the trailing newline of the
|
||||
# last line and any \r\n endings survive the round trip
|
||||
lines = raw.splitlines(keepends=True)
|
||||
total_lines = len(lines)
|
||||
|
||||
# Apply offset/limit
|
||||
selected = lines[offset: offset + limit] if offset < total_lines else []
|
||||
has_more = (offset + limit) < total_lines or truncated
|
||||
content = "".join(selected)
|
||||
|
||||
return {
|
||||
"file_path": file_path,
|
||||
"content": "\n".join(selected),
|
||||
"content": content,
|
||||
"metadata": {
|
||||
"total_lines": total_lines,
|
||||
"total_bytes": total_bytes,
|
||||
"offset": offset,
|
||||
"limit": limit,
|
||||
"returned_lines": len(selected),
|
||||
"returned_bytes": len("\n".join(selected).encode("utf-8")),
|
||||
"returned_bytes": len(content.encode("utf-8")),
|
||||
"truncated": truncated or has_more,
|
||||
"has_more": has_more,
|
||||
},
|
||||
|
||||
@ -242,6 +242,49 @@ class TestNode:
|
||||
result = get_node_console_info_handler({"project_id": "p1", "node_id": "n1"}, ctx)
|
||||
assert "command" in result
|
||||
|
||||
@staticmethod
|
||||
def _file_conn(text):
|
||||
conn = _mock_conn()
|
||||
conn.http_call.return_value.text = text
|
||||
return conn
|
||||
|
||||
def test_file_get_keeps_trailing_newline(self, ctx):
|
||||
from gns3server.agent.gns3_copilot.gns3_client.api_handlers import get_node_file_handler
|
||||
with patch(f"{AH}._get_connector") as m:
|
||||
m.return_value = self._file_conn("line1\nline2\n")
|
||||
result = get_node_file_handler({"project_id": "p1", "node_id": "n1", "file_path": "startup.cfg"}, ctx)
|
||||
assert result["content"] == "line1\nline2\n"
|
||||
assert result["metadata"]["total_bytes"] == 12
|
||||
assert result["metadata"]["returned_bytes"] == 12
|
||||
assert result["metadata"]["has_more"] is False
|
||||
|
||||
def test_file_get_keeps_crlf_endings(self, ctx):
|
||||
from gns3server.agent.gns3_copilot.gns3_client.api_handlers import get_node_file_handler
|
||||
with patch(f"{AH}._get_connector") as m:
|
||||
m.return_value = self._file_conn("line1\r\nline2\r\n")
|
||||
result = get_node_file_handler({"project_id": "p1", "node_id": "n1", "file_path": "startup.cfg"}, ctx)
|
||||
assert result["content"] == "line1\r\nline2\r\n"
|
||||
assert result["metadata"]["returned_bytes"] == 14
|
||||
|
||||
def test_file_get_without_trailing_newline(self, ctx):
|
||||
from gns3server.agent.gns3_copilot.gns3_client.api_handlers import get_node_file_handler
|
||||
with patch(f"{AH}._get_connector") as m:
|
||||
m.return_value = self._file_conn("line1\nline2")
|
||||
result = get_node_file_handler({"project_id": "p1", "node_id": "n1", "file_path": "startup.cfg"}, ctx)
|
||||
assert result["content"] == "line1\nline2"
|
||||
|
||||
def test_file_get_pagination(self, ctx):
|
||||
from gns3server.agent.gns3_copilot.gns3_client.api_handlers import get_node_file_handler
|
||||
with patch(f"{AH}._get_connector") as m:
|
||||
m.return_value = self._file_conn("line1\nline2\nline3\n")
|
||||
result = get_node_file_handler(
|
||||
{"project_id": "p1", "node_id": "n1", "file_path": "startup.cfg", "offset": 1, "limit": 1}, ctx
|
||||
)
|
||||
assert result["content"] == "line2\n"
|
||||
assert result["metadata"]["total_lines"] == 3
|
||||
assert result["metadata"]["returned_lines"] == 1
|
||||
assert result["metadata"]["has_more"] is True
|
||||
|
||||
|
||||
# ── Link ────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user