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 _execute_request(self, qs, requestMethod=QgsServerRequest.GetMethod, data=None): request = QgsBufferServerRequest(qs, requestMethod, {}, data) response = QgsBufferServerResponse() self._server.handleRequest(request, response) headers = [] rh = response.headers() rk = sorted(rh.keys()) for k in rk: headers.append(("%s: %s" % (k, rh[k])).encode('utf-8')) return b"\n".join(headers) + b"\n\n", bytes(response.body())
def test_responseHeaders(self): """Test response headers""" headers = {'header-key-1': 'header-value-1', 'header-key-2': 'header-value-2'} response = QgsBufferServerResponse() for k, v in headers.items(): response.setHeader(k, v) for k, v in response.headers().items(): self.assertEqual(headers[k], v) response.removeHeader('header-key-1') self.assertEqual(response.headers(), {'header-key-2': 'header-value-2'}) response.setHeader('header-key-1', 'header-value-1') for k, v in response.headers().items(): self.assertEqual(headers[k], v)
def do_GET(self, post_body=None): # CGI vars: headers = {} for k, v in self.headers.items(): headers['HTTP_%s' % k.replace(' ', '-').replace('-', '_').replace(' ', '-').upper()] = v request = QgsBufferServerRequest(self.path, (QgsServerRequest.PostMethod if post_body is not None else QgsServerRequest.GetMethod), headers, post_body) response = QgsBufferServerResponse() qgs_server.handleRequest(request, response) headers_dict = response.headers() try: self.send_response(int(headers_dict['Status'].split(' ')[0])) except: self.send_response(200) for k, v in headers_dict.items(): self.send_header(k, v) self.end_headers() self.wfile.write(response.body()) return
def do_GET(self, post_body=None): # CGI vars: headers = {} for k, v in self.headers.items(): headers['HTTP_%s' % k.replace(' ', '-').replace('-', '_').replace(' ', '-').upper()] = v if not self.path.startswith('http'): self.path = "%s://%s:%s%s" % ('https' if https else 'http', QGIS_SERVER_HOST, self.server.server_port, self.path) request = QgsBufferServerRequest(self.path, (QgsServerRequest.PostMethod if post_body is not None else QgsServerRequest.GetMethod), headers, post_body) response = QgsBufferServerResponse() qgs_server.handleRequest(request, response) headers_dict = response.headers() try: self.send_response(int(headers_dict['Status'].split(' ')[0])) except: self.send_response(200) for k, v in headers_dict.items(): self.send_header(k, v) self.end_headers() self.wfile.write(response.body()) return
def _check_links(params, method='GET'): data = urlencode(params) if method == 'GET': env = { 'SERVER_NAME': 'www.myserver.com', 'REQUEST_URI': '/aproject/', 'QUERY_STRING': data, 'REQUEST_METHOD': 'GET', } else: env = { 'SERVER_NAME': 'www.myserver.com', 'REQUEST_URI': '/aproject/', 'REQUEST_BODY': data, 'CONTENT_LENGTH': str(len(data)), 'REQUEST_METHOD': 'POST', } self._set_env(env) request = QgsFcgiServerRequest() response = QgsBufferServerResponse() self.server.handleRequest(request, response) self.assertFalse(b'ServiceExceptionReport' in response.body()) if method == 'POST': self.assertEqual(request.data(), data.encode('utf8')) else: original_url = request.originalUrl().toString() self.assertTrue(original_url.startswith('http://www.myserver.com/aproject/')) self.assertEqual(original_url.find(urlencode({'MAP': params['map']})), -1) exp = re.compile(r'href="([^"]+)"', re.DOTALL | re.MULTILINE) elems = exp.findall(bytes(response.body()).decode('utf8')) self.assertTrue(len(elems) > 0) for href in elems: self.assertTrue(href.startswith('http://www.myserver.com/aproject/')) self.assertEqual(href.find(urlencode({'MAP': params['map']})), -1)
def test_wms_getprint_maptheme_multiple_maps(self): """Test template points has 4 layers: points_black, points_red, points_green, points_blue the template has two maps (from top to bottom) map1 and map0 using respectively the 4points-red and 4points-green map themes """ project = self.project # No LAYERS specified params = { 'SERVICE': 'WMS', 'VERSION': '1.3.0', 'REQUEST': 'GetPrint', 'TEMPLATE': 'points', 'FORMAT': 'png', 'map0:EXTENT': '44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833', 'CRS': 'EPSG:4326', 'DPI': '72', 'map1:EXTENT': '44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833' } response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Expected: green and red # map1 (top map) self._assertRed(image.pixelColor(325, 184)) # RED self._assertWhite(image.pixelColor(474, 184)) # GREEN self._assertWhite(image.pixelColor(332, 262)) # BLUE self._assertWhite(image.pixelColor(485, 258)) # BLACK # map0 (bottom map) self._assertWhite(image.pixelColor(315, 461)) # RED self._assertGreen(image.pixelColor(475, 473)) # GREEN self._assertWhite(image.pixelColor(329, 553)) # BLUE self._assertWhite(image.pixelColor(481, 553)) # BLACK # Black LAYERS params["LAYERS"] = "points_black" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Expected black # map1 (top map) self._assertWhite(image.pixelColor(325, 184)) # RED self._assertWhite(image.pixelColor(474, 184)) # GREEN self._assertWhite(image.pixelColor(332, 262)) # BLUE self._assertBlack(image.pixelColor(485, 258)) # BLACK # map0 (bottom map) self._assertWhite(image.pixelColor(315, 461)) # RED self._assertWhite(image.pixelColor(475, 473)) # GREEN self._assertWhite(image.pixelColor(329, 553)) # BLUE self._assertBlack(image.pixelColor(481, 553)) # BLACK # Black map0:LAYERS del params["LAYERS"] params["map0:LAYERS"] = "points_black" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Expected black on map0, green on map1 # map1 (top map) self._assertRed(image.pixelColor(325, 184)) # RED self._assertWhite(image.pixelColor(474, 184)) # GREEN self._assertWhite(image.pixelColor(332, 262)) # BLUE self._assertWhite(image.pixelColor(485, 258)) # BLACK # map0 (bottom map) self._assertWhite(image.pixelColor(315, 461)) # RED self._assertWhite(image.pixelColor(475, 473)) # GREEN self._assertWhite(image.pixelColor(329, 553)) # BLUE self._assertBlack(image.pixelColor(481, 553)) # BLACK # Conflicting information: Black LAYERS and Green map0:LAYERS # The second gets precedence on map0 while LAYERS is applied to map1 params["map0:LAYERS"] = "points_blue" params["LAYERS"] = "points_black" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Expected green on map0, black on map1 # map1 (top map) self._assertWhite(image.pixelColor(325, 184)) # RED self._assertWhite(image.pixelColor(474, 184)) # GREEN self._assertWhite(image.pixelColor(332, 262)) # BLUE self._assertBlack(image.pixelColor(485, 258)) # BLACK # map0 (bottom map) self._assertWhite(image.pixelColor(315, 461)) # RED self._assertWhite(image.pixelColor(475, 473)) # GREEN self._assertBlue(image.pixelColor(329, 553)) # BLUE self._assertWhite(image.pixelColor(481, 553)) # BLACK
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 test_responseHeaders(self): """Test response headers""" headers = { 'header-key-1': 'header-value-1', 'header-key-2': 'header-value-2' } response = QgsBufferServerResponse() for k, v in headers.items(): response.setHeader(k, v) for k, v in response.headers().items(): self.assertEqual(headers[k], v) response.removeHeader('header-key-1') self.assertEqual(response.headers(), {'header-key-2': 'header-value-2'}) response.setHeader('header-key-1', 'header-value-1') for k, v in response.headers().items(): self.assertEqual(headers[k], v)
def test_write(self): """Test that writing on the buffer sets the body""" # Set as str response = QgsBufferServerResponse() response.write('Greetings from Essen Linux Hotel 2017 Hack Fest!') self.assertEqual(bytes(response.body()), b'') response.finish() self.assertEqual(bytes(response.body()), b'Greetings from Essen Linux Hotel 2017 Hack Fest!') self.assertEqual(response.headers(), {'Content-Length': '48'}) # Set as a byte array response = QgsBufferServerResponse() response.write(b'Greetings from Essen Linux Hotel 2017 Hack Fest!') self.assertEqual(bytes(response.body()), b'') response.finish() self.assertEqual(bytes(response.body()), b'Greetings from Essen Linux Hotel 2017 Hack Fest!')
def test_statusCode(self): """Test return status HTTP code""" response = QgsBufferServerResponse() response.setStatusCode(222) self.assertEqual(response.statusCode(), 222)
def testOgcApiHandler(self): """Test OGC API Handler""" project = QgsProject() project.read(unitTestDataPath('qgis_server') + '/test_project_api.qgs') request = QgsBufferServerRequest('http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1') response = QgsBufferServerResponse() ctx = QgsServerApiContext('/services/api1', request, response, project, self.server.serverInterface()) h = Handler1() self.assertTrue(h.staticPath(ctx).endswith('/resources/server/api/ogc/static')) self.assertEqual(h.path(), QtCore.QRegularExpression("/handlerone")) self.assertEqual(h.description(), 'The first handler ever') self.assertEqual(h.operationId(), 'handlerOne') self.assertEqual(h.summary(), 'First of its name') self.assertEqual(h.linkTitle(), 'Handler One Link Title') self.assertEqual(h.linkType(), QgsServerOgcApi.data) with self.assertRaises(QgsServerApiBadRequestException) as ex: h.handleRequest(ctx) self.assertEqual(str(ex.exception), 'Missing required argument: \'value1\'') r = ctx.response() self.assertEqual(r.data(), '') with self.assertRaises(QgsServerApiBadRequestException) as ex: h.values(ctx) self.assertEqual(str(ex.exception), 'Missing required argument: \'value1\'') # Add handler to API and test for /api2 ctx = QgsServerApiContext('/services/api2', request, response, project, self.server.serverInterface()) api = QgsServerOgcApi(self.server.serverInterface(), '/api2', 'apitwo', 'a second api', '1.2') api.registerHandler(h) # Add a second handler (will be tested later) h2 = Handler2() api.registerHandler(h2) ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api1')) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) self.assertEqual(str(ex.exception), 'Requested URI does not match any registered API handler') ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2')) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) self.assertEqual(str(ex.exception), 'Requested URI does not match any registered API handler') ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2/handlerone')) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) self.assertEqual(str(ex.exception), 'Missing required argument: \'value1\'') ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2/handlerone?value1=not+a+double')) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) self.assertEqual(str(ex.exception), 'Argument \'value1\' could not be converted to Double') ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2/handlerone?value1=1.2345')) params = h.values(ctx) self.assertEqual(params, {'value1': 1.2345}) api.executeRequest(ctx) self.assertEqual(json.loads(bytes(ctx.response().data()))['value1'], 1.2345) # Test path fragments extraction ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345')) params = h2.values(ctx) self.assertEqual(params, {'code1': '00', 'value1': 1.2345, 'value2': None}) # Test string encoding ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345&value2=a%2Fstring%20some')) params = h2.values(ctx) self.assertEqual(params, {'code1': '00', 'value1': 1.2345, 'value2': 'a/string some'}) # Test links self.assertEqual(h2.href(ctx), 'http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345&value2=a%2Fstring%20some') self.assertEqual(h2.href(ctx, '/extra'), 'http://www.qgis.org/services/api2/handlertwo/00/555/extra?value1=1.2345&value2=a%2Fstring%20some') self.assertEqual(h2.href(ctx, '/extra', 'json'), 'http://www.qgis.org/services/api2/handlertwo/00/555/extra.json?value1=1.2345&value2=a%2Fstring%20some') # Test template path self.assertTrue(h2.templatePath(ctx).endswith('/resources/server/api/ogc/templates/services/api2/handlerTwo.html'))
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_wms_getprint_maptheme_highlight(self): """Test templates green and red have 2 layers: red and green template red: follow map theme red template green: follow map theme green template blank: no map theme """ project = self.project params = { 'SERVICE': 'WMS', 'VERSION': '1.3.0', 'REQUEST': 'GetPrint', 'TEMPLATE': 'blank', 'FORMAT': 'png', 'LAYERS': '', 'map0:EXTENT': '44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368', 'map0:LAYERS': 'red', 'CRS': 'EPSG:4326', 'DPI': '72', 'map0:HIGHLIGHT_GEOM': self.polygon, 'map0:HIGHLIGHT_SYMBOL': r'<StyledLayerDescriptor><UserStyle><FeatureTypeStyle><Rule><PolygonSymbolizer><Fill><CssParameter name="fill">%230000FF</CssParameter></Fill></PolygonSymbolizer></Rule></FeatureTypeStyle></UserStyle></StyledLayerDescriptor>' } response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight without layers params["TEMPLATE"] = "blank" params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme (issue GH #34178) params["TEMPLATE"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme (issue GH #34178) params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme, but add LAYERS (issue GH #34178) params["TEMPLATE"] = "green" params["LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100))
def _test_error(uri): request = QgsBufferServerRequest(uri) request.setHeader('Accept', 'application/json') 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')
def test_wms_getprint_maptheme(self): """Test project has 2 layer: red and green and three templates: red: follow map theme red green: follow map theme green blank: no map theme """ tmp_dir = QTemporaryDir() shutil.copyfile( os.path.join(unitTestDataPath('qgis_server'), 'test_project_mapthemes.qgs'), os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs')) shutil.copyfile( os.path.join(unitTestDataPath('qgis_server'), 'test_project_mapthemes.gpkg'), os.path.join(tmp_dir.path(), 'test_project_mapthemes.gpkg')) project = QgsProject() self.assertTrue( project.read( os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs'))) params = { "SERVICE": "WMS", "VERSION": "1.3", "REQUEST": "GetPrint", "TEMPLATE": "blank", "FORMAT": "png", "LAYERS": "", "map0:EXTENT": "44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368", "map0:LAYERS": "red", "CRS": "EPSG:4326", "DPI": '72' } polygon = 'POLYGON((7.09769689415099325 44.92867722467413216, 7.37818833364500737 44.92867722467413216, 7.37818833364500737 45.0714498943264914, 7.09769689415099325 45.0714498943264914, 7.09769689415099325 44.92867722467413216))' ###################################################### # Template map theme tests, no HIGHLIGHT # blank template, specified layer is red response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # blank template, specified layer is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertGreen(image.pixelColor(100, 100)) # red template, no specified layers params["map0:LAYERS"] = "" params["TEMPLATE"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # green template, no specified layers params["map0:LAYERS"] = "" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertGreen(image.pixelColor(100, 100)) # green template, specified layer is red # This is a conflict situation: the green template map is set to follow green theme # but we tell the server to render the red layer, red is what we get. params["map0:LAYERS"] = "red" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) ###################################################### # Start HIGHLIGHT tests params["TEMPLATE"] = "blank" params["map0:LAYERS"] = "red" params["map0:HIGHLIGHT_GEOM"] = polygon params[ "map0:HIGHLIGHT_SYMBOL"] = r'<StyledLayerDescriptor><UserStyle><FeatureTypeStyle><Rule><PolygonSymbolizer><Fill><CssParameter name="fill">%230000FF</CssParameter></Fill></PolygonSymbolizer></Rule></FeatureTypeStyle></UserStyle></StyledLayerDescriptor>' response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight without layers params["TEMPLATE"] = "blank" params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme (issue GH #34178) params["TEMPLATE"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme (issue GH #34178) params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme, but add LAYERS (issue GH #34178) params["TEMPLATE"] = "green" params["LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100))
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 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 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")
def test_wms_getprint_maptheme(self): """Test templates green and red have 2 layers: red and green template red: follow map theme red template green: follow map theme green template blank: no map theme """ project = self.project params = { "SERVICE": "WMS", "VERSION": "1.3.0", "REQUEST": "GetPrint", "TEMPLATE": "blank", "FORMAT": "png", "LAYERS": "", "map0:EXTENT": "44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368", "map0:LAYERS": "red", "CRS": "EPSG:4326", "DPI": '72' } ###################################################### # Template map theme tests, no HIGHLIGHT # blank template, specified layer is red response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # blank template, specified layer is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertGreen(image.pixelColor(100, 100)) # red template, no specified layers params["map0:LAYERS"] = "" params["TEMPLATE"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # green template, no specified layers params["map0:LAYERS"] = "" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertGreen(image.pixelColor(100, 100)) # green template, specified layer is red # This is a conflict situation: the green template map is set to follow green theme # but we tell the server to render the red layer, red is what we get. params["map0:LAYERS"] = "red" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # Same situation as above but LAYERS is not map0 prefixed params["LAYERS"] = "red" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # Same as above but we have a conflict situation: we pass both LAYERS # and map0:LAYERS, the second must prevail because it is more specific params["LAYERS"] = "red" params["map0:LAYERS"] = "green" params["TEMPLATE"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertGreen(image.pixelColor(100, 100))
def compareContentType(self, url, headers, content_type): request = QgsBufferServerRequest(url, headers=headers) response = QgsBufferServerResponse() self.server.handleRequest(request, response, QgsProject()) self.assertEqual(response.headers()['Content-Type'], content_type)
def test_wms_getprint_legend(self): """Test project has 2 layer: red and green and five templates: red: follow map theme red green: follow map theme green blank: no map theme full: follow map theme full with both layer falsegreen : follow map theme falsegreen (visible layer : green but with blue style) """ tmp_dir = QTemporaryDir() shutil.copyfile( os.path.join(unitTestDataPath('qgis_server'), 'test_project_legend.qgs'), os.path.join(tmp_dir.path(), 'test_project_legend.qgs')) shutil.copyfile( os.path.join(unitTestDataPath('qgis_server'), 'test_project_legend.gpkg'), os.path.join(tmp_dir.path(), 'test_project_legend.gpkg')) project = QgsProject() self.assertTrue( project.read( os.path.join(tmp_dir.path(), 'test_project_legend.qgs'))) params = { "SERVICE": "WMS", "VERSION": "1.3", "REQUEST": "GetPrint", "TEMPLATE": "blank", "FORMAT": "png", "LAYERS": "", "map0:EXTENT": "778000,5600000,836000,5650000", "map0:SCALE": "281285", "map0:LAYERS": "red", "CRS": "EPSG:3857", "DPI": '72' } ###################################################### # Template legend tests # Legend symbol are displayed at coordinates : # First item : 600 x , 40 y # Second item : 600 x , 60 y # blank template, no theme, no LAYERS, specified map0:LAYERS is red response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # blank template, no LAYERS, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # blank template params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertGreen(image.pixelColor(600, 60)) # red template, red theme, specified map0:LAYERS is red params["TEMPLATE"] = "red" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # red template, red theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # red template, red theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # green template, green theme, specified map0:LAYERS is red params["TEMPLATE"] = "green" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # green template, green theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # green template, green theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, specified map0:LAYERS is red params["TEMPLATE"] = "full" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Both red and green layers are displayed self._assertRed(image.pixelColor(600, 40)) self._assertGreen(image.pixelColor(600, 60)) # falsegreen template, falsegreen theme (green layer is blue), specified map0:LAYERS is red params["TEMPLATE"] = "falsegreen" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer (in blue) is displayed, there is no second item self._assertBlue(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer (in blue) is displayed, there is no second item self._assertBlue(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60))