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_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 _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 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 testMultiplePks(self): """Test issue GH #41786""" vl = QgsVectorLayer(self.vlconn_multiplepks, 'someData', 'postgres') self.assertTrue(vl.isValid()) p = QgsProject() p.addMapLayers([vl]) json_features_url = ( 'http://qgis/?SERVICE=WMS&REQUEST=GetFeatureInfo&' + 'LAYERS=someData&STYLES=&' + 'INFO_FORMAT=application/json&' + 'SRS=EPSG%3A4326&' + 'QUERY_LAYERS=someData&X=-1&Y=-1&' + 'FEATURE_COUNT=100&') req = QgsBufferServerRequest(json_features_url) res = QgsBufferServerResponse() self.server.handleRequest(req, res, p) j = json.loads(bytes(res.body()).decode('utf8')) self.assertEqual( j, { 'features': [{ 'geometry': None, 'id': 'someData.1@@1', 'properties': { 'name': '1-1', 'pk1': 1, 'pk2': 1 }, 'type': 'Feature' }, { 'geometry': None, 'id': 'someData.1@@2', 'properties': { 'name': '1-2', 'pk1': 1, 'pk2': 2 }, 'type': 'Feature' }], 'type': 'FeatureCollection' })
def ows_server(request): register_django_provider() query_string = request.build_absolute_uri() project_path = os.path.join(os.path.dirname(__file__), 'test.qgs') qgis_project = QgsProject() qgis_project.read(project_path) qgis_request = QgsBufferServerRequest(query_string) qgis_response = QgsBufferServerResponse() server = QgsServer() server.handleRequest(qgis_request, qgis_response, qgis_project) body = bytes(qgis_response.body()) response = HttpResponse(body) for k, v in qgis_response.headers().items(): response[k] = v return response
def test_landing_page_json(self): """Test landing page in JSON format""" request = QgsBufferServerRequest('http://server.qgis.org/index.json') response = QgsBufferServerResponse() self.server.handleRequest(request, response) j_actual = 'Content-Type: application/json\n\n' j_actual += bytes(response.body()).decode('utf8)') if not os.environ.get('TRAVIS', False): expected_path = os.path.join( unitTestDataPath('qgis_server'), 'landingpage', 'test_landing_page_with_pg_index.json') else: expected_path = os.path.join(unitTestDataPath('qgis_server'), 'landingpage', 'test_landing_page_index.json') j_expected = open(expected_path).read() self.compareProjects(j_actual, j_expected, expected_path)
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 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 compareApi(self, request, project, reference_file): response = QgsBufferServerResponse() # Add json to accept it reference_file is JSON if reference_file.endswith('.json'): request.setHeader('Accept', 'application/json') self.server.handleRequest(request, response, project) result = bytes(response.body()).decode( 'utf8') if reference_file.endswith('html') else self.dump(response) path = unitTestDataPath('qgis_server') + '/api/' + reference_file if self.regeregenerate_api_reference: f = open(path.encode('utf8'), 'w+', encoding='utf8') f.write(result) f.close() print("Reference file %s regenerated!" % path.encode('utf8')) def __normalize_json(content): reference_content = content.split('\n') j = ''.join(reference_content[reference_content.index('') + 1:]) # Do not test timeStamp j = json.loads(j) try: j['timeStamp'] = '2019-07-05T12:27:07Z' except: pass json_content = json.dumps(j) headers_content = '\n'.join( reference_content[:reference_content.index('') + 1]) return headers_content + '\n' + json_content with open(path.encode('utf8'), 'r', encoding='utf8') as f: if reference_file.endswith('json'): self.assertEqual(__normalize_json(result), __normalize_json(f.read())) else: self.assertEqual(f.read(), result) return response
def test_project_json(self): """Test landing page project call in JSON format""" # Get hashes for test projects request = QgsBufferServerRequest('http://server.qgis.org/index.json') request.setHeader('Accept', 'application/json') response = QgsBufferServerResponse() self.server.handleRequest(request, response) j = json.loads(bytes(response.body())) test_projects = { p['id']: p['title'].replace(' ', '_') for p in j['projects'] } for identifier, name in test_projects.items(): request = QgsBufferServerRequest('http://server.qgis.org/map/' + identifier) request.setHeader('Accept', 'application/json') self.compareApi(request, None, 'test_project_{}.json'.format( name.replace('.', '_')), subdir='landingpage')
def test_getcapabilities_advertised_url(self): server = QgsServer() request = QgsServerRequest() projectPath = os.path.join(self.testdata_path, 'test_project.qgs') request.setUrl( QUrl('http://localhost/qgis_mapserv.fcgi?MAP=' + projectPath + '&SERVICE=WMS&REQUEST=GetCapabilities')) request.setOriginalUrl(QUrl('http://localhost/wms/test_project')) response = QgsBufferServerResponse() server.handleRequest(request, response) response.flush() headers = [] rh = response.headers() rk = sorted(rh.keys()) for k in rk: headers.append(("%s: %s" % (k, rh[k])).encode('utf-8')) reference_path = os.path.join(self.testdata_path, 'wms_getcapabilities_rewriting.txt') f = open(reference_path, 'rb') expected = f.read() self.assertXMLEqual( b"\n".join(headers) + b"\n\n" + bytes(response.body()), expected)
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_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_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.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_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_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))
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_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 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 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 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