From 9d63e073498d5381a0a406837b7287c9a88f94fd Mon Sep 17 00:00:00 2001 From: David Marteau Date: Tue, 25 Oct 2022 18:36:05 +0200 Subject: [PATCH] Fix complexdata decoding as invalid base64 Fix https://github.com/3liz/py-qgis-wps/issues/31 --- CHANGELOG.md | 3 ++ pyqgiswps/app/request.py | 8 --- pyqgiswps/app/service.py | 17 +------ pyqgiswps/executors/io/geometryio.py | 2 + pyqgiswps/ogc/ows/request.py | 25 ++++++---- tests/unittests/processing/test_owsexecute.py | 50 +++++++++++++++++++ tests/unittests/test_execute.py | 2 +- 7 files changed, 73 insertions(+), 34 deletions(-) create mode 100644 tests/unittests/processing/test_owsexecute.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d870171..d9c8fac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # Changes + ## Unreleased +* Fix invalid decoding of complex data as base64 + - Fix https://github.com/3liz/py-qgis-wps/issues/31 * Fix mandatory SERVICE parameters for POST WPS requests * Deprecate `host_proxy` in favor of `proxy_url` option * Define explicit `HTTP\_PROXY` option diff --git a/pyqgiswps/app/request.py b/pyqgiswps/app/request.py index 2456038..09b7d43 100644 --- a/pyqgiswps/app/request.py +++ b/pyqgiswps/app/request.py @@ -105,14 +105,6 @@ def __repr__(self) -> str: def dumps( self ): return json.dumps(self.json, allow_nan=False) - # - # Execute - # - async def execute(self, service: Service, uuid: UUID, - map_uri: Optional[str]=None) -> bytes: - - return await service.execute(self.identifier, self, uuid, map_uri) - class WPSResponse: diff --git a/pyqgiswps/app/service.py b/pyqgiswps/app/service.py index d528708..d619dcb 100644 --- a/pyqgiswps/app/service.py +++ b/pyqgiswps/app/service.py @@ -19,8 +19,6 @@ from pyqgiswps.exceptions import ( MissingParameterValue, NoApplicableCode, - InvalidParameterValue, - UnknownProcessError ) from pyqgiswps.inout.inputs import ComplexInput, LiteralInput, BoundingBoxInput from pyqgiswps.executors.processingexecutor import ProcessingExecutor @@ -62,10 +60,7 @@ def get_process(self, ident: str, map_uri: Optional[str]=None) -> WPSProcess: return self.get_processes((ident,), map_uri=map_uri)[0] def get_processes(self, idents: Iterable[str], map_uri: Optional[str]=None) -> Iterable[WPSProcess]: - try: - return self.executor.get_processes(idents, map_uri=map_uri) - except UnknownProcessError as exc: - raise InvalidParameterValue(f"Invalid process '{exc}'") + return self.executor.get_processes(idents, map_uri=map_uri) def get_results(self, uuid: str) -> Any: doc = self.executor.get_results(uuid) @@ -89,16 +84,6 @@ def kill_job(self, uuid: str, pid: Optional[int] = None) -> bool: """ return self.executor.kill_job(uuid, pid) - async def execute(self, identifier: str, wps_request: WPSRequest, uuid: str, - map_uri: Optional[str]=None) -> bytes: - """Parse and perform Execute WPS request call - - :param identifier: process identifier string - :param wps_request: pyqgiswps.WPSRequest structure with parsed inputs, still in memory - :param uuid: string identifier of the request - """ - process = self.get_process(identifier, map_uri=map_uri) - return await self.execute_process(process, wps_request, uuid) async def execute_process(self, process: WPSProcess, wps_request: WPSRequest, uuid: str) -> bytes: """Parse and perform Execute WPS request call diff --git a/pyqgiswps/executors/io/geometryio.py b/pyqgiswps/executors/io/geometryio.py index 68bd858..4d8d85b 100644 --- a/pyqgiswps/executors/io/geometryio.py +++ b/pyqgiswps/executors/io/geometryio.py @@ -138,6 +138,8 @@ def json_to_geometry( data: str ) -> Geometry: data = data['geometry'] geom = ogr.CreateGeometryFromJson(json.dumps(data)) if geom: + # XXX There is no method for direct import + # from json geom = QgsGeometry.fromWkt(geom.ExportToWkt()) if crs and crs.isValid(): geom = QgsReferencedGeometry(geom,crs) diff --git a/pyqgiswps/ogc/ows/request.py b/pyqgiswps/ogc/ows/request.py index 87bc268..9786ef1 100644 --- a/pyqgiswps/ogc/ows/request.py +++ b/pyqgiswps/ogc/ows/request.py @@ -37,6 +37,8 @@ AccessPolicy = TypeVar('AccessPolicy') Service = TypeVar('Service') WPSProcess = TypeVar('WPSProcess') +UUID = TypeVar('UUID') + LOGGER = logging.getLogger('SRVLOG') @@ -64,6 +66,8 @@ def __init__(self, *args, **kwargs): def conformance() -> str: return OGC_CONFORMANCE_NS.OWS_WPS.value + + @staticmethod def parse_get_request(handler) -> WPSRequest: """ HTTP GET request parser @@ -478,11 +482,20 @@ def get_processes_for_request(self, service: Service, idents: Iterable[str], try: return service.get_processes(idents, map_uri) except UnknownProcessError as exc: - raise InvalidParameterValue("Unknown process %s" % exc, "identifier") from None + raise InvalidParameterValue(f"Unknown process '{exc}'", "identifier") from None except Exception as e: LOGGER.critical("Exception:\n%s",traceback.format_exc()) raise NoApplicableCode(str(e), code=500) from None + async def execute(self, service: Service, uuid: UUID, + map_uri: Optional[str]=None) -> bytes: + try: + process = service.get_process(self.identifier, map_uri=map_uri) + except UnknownProcessError as exc: + raise InvalidParameterValue(f"Invalid process '{exc}'", "identifier") from None + + return await service.execute_process(process, self, uuid) + # # Describe # @@ -534,15 +547,9 @@ def _get_dataelement_value(value_el): def _get_rawvalue_value(data, encoding=None): """Return real value of CDATA section""" - - try: - if encoding is None or encoding == "": - return data - elif encoding == 'base64': - return base64.b64decode(data) + if encoding == 'base64': return base64.b64decode(data) - except Exception: - return data + return data def _get_reference_body(body_element): diff --git a/tests/unittests/processing/test_owsexecute.py b/tests/unittests/processing/test_owsexecute.py new file mode 100644 index 0000000..4345baa --- /dev/null +++ b/tests/unittests/processing/test_owsexecute.py @@ -0,0 +1,50 @@ +""" + Test Processing executor +""" +import pytest +from pyqgiswps.app import WPSProcess, Service +from pyqgiswps.tests import HTTPTestCase +from pyqgiswps.executors.processfactory import get_process_factory + +# XXX With EPSG:4326 axes *MUST* be inverted +INPUTGEOMETRY_EXECUTE_POST=""" + + {PROVIDER}:testinputgeometry + + + INPUT + + + + + + +""" + + +class TestsInputGeometry(HTTPTestCase): + + def get_processes(self): + return get_process_factory()._create_qgis_processes() + + def test_input_geometry_execute_post(self): + """ Test processing executor 'Execute' request + """ + uri = ('/ows/?service=WPS&MAP=raster_layer') + body = INPUTGEOMETRY_EXECUTE_POST.format( + PROVIDER='pyqgiswps_test', + DATA='CRS=4326;POINT(-4 48)' + ) + rv = self.client.post(body, path=uri) + assert rv.status_code == 200 + diff --git a/tests/unittests/test_execute.py b/tests/unittests/test_execute.py index 1c6286d..4d70f7f 100644 --- a/tests/unittests/test_execute.py +++ b/tests/unittests/test_execute.py @@ -257,7 +257,7 @@ def test_complex_input_base64_value(): mimeType='application/json'))))) rv = get_inputs_from_xml(request_doc) assert rv['json'][0]['mimeType'] == 'application/json' - json_data = json.loads(rv['json'][0]['data'].decode()) + json_data = json.loads(rv['json'][0]['data']) assert json_data['plot']['Version'] == '0.1'