def test_requestHandler(self): """Test request handler""" headers = {'header-key-1': 'header-value-1', 'header-key-2': 'header-value-2'} request = QgsBufferServerRequest('http://somesite.com/somepath', QgsServerRequest.GetMethod, headers) response = QgsBufferServerResponse() self.server.handleRequest(request, response) self.assertEqual(bytes(response.body()), b'<ServerException>Project file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file</ServerException>\n') self.assertEqual(response.headers(), {'Content-Length': '156', 'Content-Type': 'text/xml; charset=utf-8'}) self.assertEqual(response.statusCode(), 500)
def test_requestHandlerProject(self): """Test request handler with none project""" headers = {'header-key-1': 'header-value-1', 'header-key-2': 'header-value-2'} request = QgsBufferServerRequest('http://somesite.com/somepath', QgsServerRequest.GetMethod, headers) response = QgsBufferServerResponse() self.server.handleRequest(request, response, None) self.assertEqual(bytes(response.body()), b'<ServerException>Project file error</ServerException>\n') self.assertEqual(response.headers(), {'Content-Length': '54', 'Content-Type': 'text/xml; charset=utf-8'}) self.assertEqual(response.statusCode(), 500)
def test_wfs3_field_filters(self): """Test field filters""" project = QgsProject() project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs') # Check not published response = QgsBufferServerResponse() request = QgsBufferServerRequest( 'http://server.qgis.org/wfs3/collections/testlayer3/items?name=two' ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 404) # Not found request = QgsBufferServerRequest( 'http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?name=two' ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) self.compareApi( request, project, 'test_wfs3_collections_items_layer1_with_short_name_eq_two.json')
def test_invalid_args(self): """Test wrong args""" project = QgsProject() project.read(unitTestDataPath('qgis_server') + '/test_project.qgs') request = QgsBufferServerRequest( 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1' ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request self.assertEqual(response.body( ), b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]' ) # Bad request request = QgsBufferServerRequest( 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=10001' ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request self.assertEqual(response.body( ), b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]' ) # Bad request
def _check_red(): req = QgsBufferServerRequest('http://my_server/' + qs) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) result_path = os.path.join(self.temp_dir.path(), 'red.png') with open(result_path, 'wb+') as f: f.write(res.body()) # A full red image is expected image = QImage(result_path) self.assertFalse(image.isGrayscale()) color = image.pixelColor(100, 100) self.assertEqual(color.red(), 255) self.assertEqual(color.green(), 0) self.assertEqual(color.blue(), 0)
def test_statusCode(self): """Test return status HTTP code""" response = QgsBufferServerResponse() response.setStatusCode(222) self.assertEqual(response.statusCode(), 222)
def _assert_status_code(self, status_code, qs, requestMethod=QgsServerRequest.GetMethod, data=None, project=None): request = QgsBufferServerRequest(qs, requestMethod, {}, data) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) assert response.statusCode() == status_code, "%s != %s" % (response.statusCode(), status_code)
def baseDoRequest(self, q): request = self.request # Uppercase REQUEST if 'REQUEST' in [k.upper() for k in q.keys()]: if request.method == 'GET': ows_request = q['REQUEST'].upper() else: if request.content_type == 'application/x-www-form-urlencoded': ows_request = request.POST['REQUEST'].upper() else: ows_request = request.POST['REQUEST'][0].upper() q['REQUEST'] = ows_request # FIXME: proxy or redirect in case of WMS/WFS/XYZ cascading? qgs_project = get_qgs_project(self.project.qgis_file.path) if qgs_project is None: raise Http404('The requested QGIS project could not be loaded!') data = None if request.method == 'GET': method = QgsBufferServerRequest.GetMethod elif request.method == 'POST': method = QgsBufferServerRequest.PostMethod data = request.body elif request.method == 'PUT': method = QgsBufferServerRequest.PutMethod data = request.body elif request.method == 'PATCH': method = QgsBufferServerRequest.PatchMethod data = request.body elif request.method == 'HEAD': method = QgsBufferServerRequest.HeadMethod elif request.method == 'DELETE': method = QgsBufferServerRequest.DeleteMethod else: logger.warning("Request method not supported: %s, assuming GET" % request.method) method = QgsBufferServerRequest.GetMethod headers = {} for header_key in request.headers.keys(): headers[header_key] = request.headers.get(header_key) uri = request.build_absolute_uri(request.path) + '?' + q.urlencode() logger.debug('Calling QGIS Server: %s' % uri) qgs_request = QgsBufferServerRequest(uri, method, headers, data) # Attach user and project to the server object to make them accessible by the # server access control plugins (constraints etc.) QGS_SERVER.user = request.user QGS_SERVER.project = self.project qgs_response = QgsBufferServerResponse() try: QGS_SERVER.handleRequest(qgs_request, qgs_response, qgs_project) except Exception as ex: return HttpResponseServerError( reason="Error handling server request: %s" % ex) response = HttpResponse(bytes(qgs_response.body())) response.status_code = qgs_response.statusCode() for key, value in qgs_response.headers().items(): response[key] = value return response
def test_landing_page(self): request = QgsBufferServerRequest('/') response = QgsBufferServerResponse() self.server.handleRequest(request, response) self.assertTrue(b'html' in bytes(response.body()), response.body()) self.assertEqual(response.statusCode(), 200)
def baseDoRequest(self, q): request = self.request # Uppercase REQUEST if 'REQUEST' in [k.upper() for k in q.keys()]: if request.method == 'GET': ows_request = q['REQUEST'].upper() else: if request.content_type == 'application/x-www-form-urlencoded': ows_request = request.POST['REQUEST'].upper() else: ows_request = request.POST['REQUEST'][0].upper() q['REQUEST'] = ows_request # FIXME: proxy or redirect in case of WMS/WFS/XYZ cascading? qgs_project = get_qgs_project(self.project.qgis_file.path) if qgs_project is None: raise Http404('The requested QGIS project could not be loaded!') data = None if request.method == 'GET': method = QgsBufferServerRequest.GetMethod elif request.method == 'POST': method = QgsBufferServerRequest.PostMethod data = request.body elif request.method == 'PUT': method = QgsBufferServerRequest.PutMethod data = request.body elif request.method == 'PATCH': method = QgsBufferServerRequest.PatchMethod data = request.body elif request.method == 'HEAD': method = QgsBufferServerRequest.HeadMethod elif request.method == 'DELETE': method = QgsBufferServerRequest.DeleteMethod else: logger.warning( "Request method not supported: %s, assuming GET" % request.method) method = QgsBufferServerRequest.GetMethod headers = {} for header_key in request.headers.keys(): headers[header_key] = request.headers.get(header_key) uri = request.build_absolute_uri(request.path) + '?' + q.urlencode() logger.debug('Calling QGIS Server: %s' % uri) qgs_request = QgsBufferServerRequest(uri, method, headers, data) # Attach user and project to the server object to make them accessible by the # server access control plugins (constraints etc.) QGS_SERVER.djrequest = request QGS_SERVER.user = request.user QGS_SERVER.project = self.project # For GetPrint QGIS functions that rely on layers visibility, we need to check # the layers from LAYERS use_ids = QgsServerProjectUtils.wmsUseLayerIds(qgs_project) tree_root = qgs_project.layerTreeRoot() # Loop through the layers and make them visible for layer_name in qgs_request.queryParameter('LAYERS').split(','): layer_name = urllib.parse.unquote(layer_name) layer = None if use_ids: layer = qgs_project.mapLayer(layer_name) else: try: layer = qgs_project.mapLayersByName(layer_name)[0] except: # short name? for l in qgs_project.mapLayers().values(): if l.shortName() == layer_name: layer = l break if layer is None: logger.warning( 'Could not find layer "{}" when configuring OWS call'.format(layer_name)) else: layer_node = tree_root.findLayer(layer) if layer_node is not None: layer_node.setItemVisibilityCheckedParentRecursive(True) else: logger.warning( 'Could not find layer tree node "{}" when configuring OWS call'.format(layer_name)) qgs_response = QgsBufferServerResponse() try: QGS_SERVER.handleRequest(qgs_request, qgs_response, qgs_project) except Exception as ex: return HttpResponseServerError(reason="Error handling server request: %s" % ex) response = HttpResponse(bytes(qgs_response.body())) response.status_code = qgs_response.statusCode() for key, value in qgs_response.headers().items(): response[key] = value return response
def test_atlas(self): """Test atlas""" qs = "?" + "&".join([ "%s=%s" % i for i in list({ 'SERVICE': "WMS", 'VERSION': "1.3.0", 'REQUEST': "GetPrint", 'CRS': 'EPSG:4326', 'FORMAT': 'png', 'LAYERS': 'multiple_pks', 'DPI': 72, 'TEMPLATE': "print1", }.items()) ]) req = QgsBufferServerRequest('http://my_server/' + qs + '&ATLAS_PK=1,2') res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) result_path = os.path.join(self.temp_dir.path(), 'atlas_1_2.png') with open(result_path, 'wb+') as f: f.write(res.body()) # A full red image is expected image = QImage(result_path) self.assertFalse(image.isGrayscale()) color = image.pixelColor(100, 100) self.assertEqual(color.red(), 255) self.assertEqual(color.green(), 0) self.assertEqual(color.blue(), 0) # Forbid 1-1 self._accesscontrol.active['layerFilterSubsetString'] = True self._check_exception(qs + '&ATLAS_PK=1,2', "Atlas error: empty atlas.") self._accesscontrol.active['layerFilterSubsetString'] = False self._accesscontrol.active['layerFilterExpression'] = True self._check_exception(qs + '&ATLAS_PK=1,2', "Atlas error: empty atlas.") # Remove all constraints self._clear_constraints() req = QgsBufferServerRequest('http://my_server/' + qs + '&ATLAS_PK=1,2') res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) result_path = os.path.join(self.temp_dir.path(), 'atlas_1_2.png') with open(result_path, 'wb+') as f: f.write(res.body()) # A full red image is expected image = QImage(result_path) self.assertFalse(image.isGrayscale()) color = image.pixelColor(100, 100) self.assertEqual(color.red(), 255) self.assertEqual(color.green(), 0) self.assertEqual(color.blue(), 0)
def test_wms_getprint_postgres(self): """Test issue GH #41800 """ # Extent for feature where pk1 = 1, pk2 = 2 qs = "?" + "&".join([ "%s=%s" % i for i in list({ 'SERVICE': "WMS", 'VERSION': "1.3.0", 'REQUEST': "GetPrint", 'CRS': 'EPSG:4326', 'FORMAT': 'png', 'LAYERS': 'multiple_pks', 'DPI': 72, 'TEMPLATE': "print1", 'map0:EXTENT': '45.70487804878048621,7.67926829268292099,46.22987804878049189,8.42479674796748235', }.items()) ]) def _check_red(): req = QgsBufferServerRequest('http://my_server/' + qs) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) result_path = os.path.join(self.temp_dir.path(), 'red.png') with open(result_path, 'wb+') as f: f.write(res.body()) # A full red image is expected image = QImage(result_path) self.assertFalse(image.isGrayscale()) color = image.pixelColor(100, 100) self.assertEqual(color.red(), 255) self.assertEqual(color.green(), 0) self.assertEqual(color.blue(), 0) _check_red() # Now activate the rule to exclude the feature where pk1 = 1, pk2 = 2 # A white image is expected self._accesscontrol.active['layerFilterExpression'] = True self._check_white(qs) # Activate the other rule for subset string self._accesscontrol.active['layerFilterExpression'] = False self._accesscontrol.active['layerFilterSubsetString'] = True self._check_white(qs) # Activate the other rule for layer permission self._accesscontrol.active['layerFilterSubsetString'] = False self._accesscontrol.active['layerPermissions'] = True req = QgsBufferServerRequest('http://my_server/' + qs) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 403) # Test attribute table (template print2) with no rule self._accesscontrol.active['layerPermissions'] = False req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2") # Test attribute table with rule self._accesscontrol.active['authorizedLayerAttributes'] = True req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_filtered") # Re-Test attribute table (template print2) with no rule self._accesscontrol.active['authorizedLayerAttributes'] = False req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2") # Test with layer permissions self._accesscontrol.active['layerPermissions'] = True req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 403) # Test with subset string self._accesscontrol.active['layerPermissions'] = False self._accesscontrol.active['layerFilterSubsetString'] = True req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_subset") # Test with filter expression self._accesscontrol.active['layerFilterExpression'] = True self._accesscontrol.active['layerFilterSubsetString'] = False req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_subset") # Test attribute table with attribute filter self._accesscontrol.active['layerFilterExpression'] = False self._accesscontrol.active['authorizedLayerAttributes'] = True req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_filtered") # Clear constraints self._clear_constraints() _check_red() req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2")