1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-18 06:18:08 +00:00

API for editing files on the controller

Ref https://github.com/GNS3/gns3-gui/issues/1401
This commit is contained in:
Julien Duponchelle 2016-07-20 21:52:12 +02:00
parent bc8a319142
commit e557ccd078
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8
3 changed files with 125 additions and 0 deletions

View File

@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import aiohttp
import asyncio
@ -249,3 +250,85 @@ class ProjectHandler:
yield from response.drain()
yield from response.write_eof()
@Route.get(
r"/projects/{project_id}/files/{path:.+}",
description="Get a file from a project. Beware you have warranty to be able to access only to file global to the project (for example README.txt)",
parameters={
"project_id": "Project UUID",
},
status_codes={
200: "File returned",
403: "Permission denied",
404: "The file doesn't exist"
})
def get_file(request, response):
controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
path = request.match_info["path"]
path = os.path.normpath(path)
# Raise error if user try to escape
if path[0] == ".":
raise aiohttp.web.HTTPForbidden
path = os.path.join(project.path, path)
response.content_type = "application/octet-stream"
response.set_status(200)
response.enable_chunked_encoding()
# Very important: do not send a content length otherwise QT closes the connection (curl can consume the feed)
response.content_length = None
try:
with open(path, "rb") as f:
response.start(request)
while True:
data = f.read(4096)
if not data:
break
yield from response.write(data)
except FileNotFoundError:
raise aiohttp.web.HTTPNotFound()
except PermissionError:
raise aiohttp.web.HTTPForbidden()
@Route.post(
r"/projects/{project_id}/files/{path:.+}",
description="Write a file to a project",
parameters={
"project_id": "Project UUID",
},
raw=True,
status_codes={
200: "File returned",
403: "Permission denied",
404: "The path doesn't exist"
})
def write_file(request, response):
controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"])
path = request.match_info["path"]
path = os.path.normpath(path)
# Raise error if user try to escape
if path[0] == ".":
raise aiohttp.web.HTTPForbidden
path = os.path.join(project.path, path)
response.set_status(200)
try:
with open(path, 'wb+') as f:
while True:
packet = yield from request.content.read(512)
if not packet:
break
f.write(packet)
except FileNotFoundError:
raise aiohttp.web.HTTPNotFound()
except PermissionError:
raise aiohttp.web.HTTPForbidden()

View File

@ -167,6 +167,21 @@ def test_get_file(http_compute, tmpdir):
assert response.status == 403
def test_write_file(http_compute, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"projects_path": str(tmpdir)}):
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
response = http_compute.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True)
assert response.status == 200
with open(os.path.join(project.path, "hello")) as f:
assert f.read() == "world"
response = http_compute.post("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
assert response.status == 403
def test_stream_file(http_compute, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"projects_path": str(tmpdir)}):

View File

@ -175,3 +175,30 @@ def test_export(http_controller, tmpdir, loop, project):
with myzip.open("a") as myfile:
content = myfile.read()
assert content == b"hello"
def test_get_file(http_controller, tmpdir, loop, project):
os.makedirs(project.path, exist_ok=True)
with open(os.path.join(project.path, 'hello'), 'w+') as f:
f.write('world')
response = http_controller.get("/projects/{project_id}/files/hello".format(project_id=project.id), raw=True)
assert response.status == 200
assert response.body == b"world"
response = http_controller.get("/projects/{project_id}/files/false".format(project_id=project.id), raw=True)
assert response.status == 404
response = http_controller.get("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
assert response.status == 403
def test_write_file(http_controller, tmpdir, project):
response = http_controller.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True)
assert response.status == 200
with open(os.path.join(project.path, "hello")) as f:
assert f.read() == "world"
response = http_controller.post("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
assert response.status == 403