From 582e3c72ff85fa8700e5a658525012fa966e4327 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Mon, 6 Jun 2016 19:51:35 +0200 Subject: [PATCH] Forward post with large content to compute --- gns3server/controller/compute.py | 17 +++++++++++----- .../api/controller/compute_handler.py | 10 +++++----- tests/controller/test_compute.py | 20 +++++++++---------- tests/handlers/api/controller/test_compute.py | 3 ++- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 61830a40..87a523fb 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -268,15 +268,22 @@ class Compute: def _run_http_query(self, method, path, data=None, timeout=10): with aiohttp.Timeout(timeout): url = self._getUrl(path) - headers = {'content-type': 'application/json'} + headers = {} + headers['content-type'] = 'application/json' + chunked = False if data == {}: data = None elif data is not None: if hasattr(data, '__json__'): - data = data.__json__() - data = json.dumps(data) + data = json.dumps(data.__json__()) + # Stream the request + elif isinstance(data, aiohttp.streams.StreamReader): + chunked = True + headers['content-type'] = 'application/octet-stream' + else: + data = json.dumps(data) - response = yield from self._session.request(method, url, headers=headers, data=data, auth=self._auth) + response = yield from self._session.request(method, url, headers=headers, data=data, auth=self._auth, chunked=chunked) body = yield from response.read() if body: body = body.decode() @@ -301,7 +308,7 @@ class Compute: response.json = json.loads(body) except ValueError: raise aiohttp.web.HTTPConflict(text="The server {} is not a GNS3 server".format(self._id)) - if response.json is None: + else: response.json = {} return response diff --git a/gns3server/handlers/api/controller/compute_handler.py b/gns3server/handlers/api/controller/compute_handler.py index cc1f403e..914c1543 100644 --- a/gns3server/handlers/api/controller/compute_handler.py +++ b/gns3server/handlers/api/controller/compute_handler.py @@ -90,11 +90,11 @@ class ComputeHandler: def get_forward(request, response): controller = Controller.instance() compute = controller.get_compute(request.match_info["compute_id"]) - images = yield from compute.forward("GET", request.match_info["emulator"], request.match_info["action"]) - response.json(images) + res = yield from compute.forward("GET", request.match_info["emulator"], request.match_info["action"]) + response.json(res) @Route.post( - r"/computes/{compute_id}/{emulator}/{action}", + r"/computes/{compute_id}/{emulator}/{action:.+}", parameters={ "compute_id": "Compute UUID" }, @@ -106,8 +106,8 @@ class ComputeHandler: def post_forward(request, response): controller = Controller.instance() compute = controller.get_compute(request.match_info["compute_id"]) - images = yield from compute.forward("POST", request.match_info["emulator"], request.match_info["action"], data=dict(request.json)) - response.json(images) + res = yield from compute.forward("POST", request.match_info["emulator"], request.match_info["action"], data=request.content) + response.json(res) @Route.get( r"/computes/{compute_id}", diff --git a/tests/controller/test_compute.py b/tests/controller/test_compute.py index da055281..5755d9c7 100644 --- a/tests/controller/test_compute.py +++ b/tests/controller/test_compute.py @@ -71,7 +71,7 @@ def test_compute_httpQuery(compute, async_run): response.status = 200 async_run(compute.post("/projects", {"a": "b"})) - mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data='{"a": "b"}', headers={'content-type': 'application/json'}, auth=None) + mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data='{"a": "b"}', headers={'content-type': 'application/json'}, auth=None, chunked=False) assert compute._auth is None @@ -83,7 +83,7 @@ def test_compute_httpQueryAuth(compute, async_run): compute.user = "root" compute.password = "toor" async_run(compute.post("/projects", {"a": "b"})) - mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data='{"a": "b"}', headers={'content-type': 'application/json'}, auth=compute._auth) + mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data='{"a": "b"}', headers={'content-type': 'application/json'}, auth=compute._auth, chunked=False) assert compute._auth.login == "root" assert compute._auth.password == "toor" @@ -96,8 +96,8 @@ def test_compute_httpQueryNotConnected(compute, controller, async_run): response.status = 200 with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: async_run(compute.post("/projects", {"a": "b"})) - mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None) - mock.assert_any_call("POST", "https://example.com:84/v2/compute/projects", data='{"a": "b"}', headers={'content-type': 'application/json'}, auth=None) + mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=False) + mock.assert_any_call("POST", "https://example.com:84/v2/compute/projects", data='{"a": "b"}', headers={'content-type': 'application/json'}, auth=None, chunked=False) assert compute._connected assert compute.version == __version__ controller.notification.emit.assert_called_with("compute.updated", compute.__json__()) @@ -111,7 +111,7 @@ def test_compute_httpQueryNotConnectedInvalidVersion(compute, async_run): with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with pytest.raises(aiohttp.web.HTTPConflict): async_run(compute.post("/projects", {"a": "b"})) - mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None) + mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=False) def test_compute_httpQueryNotConnectedNonGNS3Server(compute, async_run): @@ -122,7 +122,7 @@ def test_compute_httpQueryNotConnectedNonGNS3Server(compute, async_run): with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with pytest.raises(aiohttp.web.HTTPConflict): async_run(compute.post("/projects", {"a": "b"})) - mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None) + mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=False) def test_compute_httpQueryNotConnectedNonGNS3Server2(compute, async_run): @@ -133,7 +133,7 @@ def test_compute_httpQueryNotConnectedNonGNS3Server2(compute, async_run): with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with pytest.raises(aiohttp.web.HTTPConflict): async_run(compute.post("/projects", {"a": "b"})) - mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None) + mock.assert_any_call("GET", "https://example.com:84/v2/compute/version", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=False) def test_compute_httpQueryError(compute, async_run): @@ -152,7 +152,7 @@ def test_compute_httpQuery_project(compute, async_run): project = Project() async_run(compute.post("/projects", project)) - mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data=json.dumps(project.__json__()), headers={'content-type': 'application/json'}, auth=None) + mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data=json.dumps(project.__json__()), headers={'content-type': 'application/json'}, auth=None, chunked=False) def test_connectNotification(compute, async_run): @@ -228,7 +228,7 @@ def test_forward_get(compute, async_run): response.status = 200 with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: async_run(compute.forward("GET", "qemu", "images")) - mock.assert_called_with("GET", "https://example.com:84/v2/compute/qemu/images", auth=None, data=None, headers={'content-type': 'application/json'}) + mock.assert_called_with("GET", "https://example.com:84/v2/compute/qemu/images", auth=None, data=None, headers={'content-type': 'application/json'}, chunked=False) def test_forward_post(compute, async_run): @@ -236,4 +236,4 @@ def test_forward_post(compute, async_run): response.status = 200 with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: async_run(compute.forward("POST", "qemu", "img", data={"id": 42})) - mock.assert_called_with("POST", "https://example.com:84/v2/compute/qemu/img", auth=None, data='{"id": 42}', headers={'content-type': 'application/json'}) + mock.assert_called_with("POST", "https://example.com:84/v2/compute/qemu/img", auth=None, data='{"id": 42}', headers={'content-type': 'application/json'}, chunked=False) diff --git a/tests/handlers/api/controller/test_compute.py b/tests/handlers/api/controller/test_compute.py index 37d9c8f2..1ed0e0e5 100644 --- a/tests/handlers/api/controller/test_compute.py +++ b/tests/handlers/api/controller/test_compute.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import unittest from tests.utils import asyncio_patch @@ -209,4 +210,4 @@ def test_compute_create_img(http_controller, controller): params = {"path": "/test"} with asyncio_patch("gns3server.controller.compute.Compute.forward", return_value=[]) as mock: response = http_controller.post("/computes/my_compute/qemu/img", params) - mock.assert_called_with("POST", "qemu", "img", data={"path": "/test"}) + mock.assert_called_with("POST", "qemu", "img", data=unittest.mock.ANY)