From f29c9c99656b219209efec66b46818c06ff7433c Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Thu, 9 Nov 2017 12:23:03 +0100 Subject: [PATCH] [tests] Add XYX slippy map to test QGIS server Plus: multi-threading server side (for speed) This is useful for testing various authentication shemes on a slippy-map server (that uses multi-threading in QGIS desktop) --- tests/src/python/qgis_wrapped_server.py | 54 ++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/tests/src/python/qgis_wrapped_server.py b/tests/src/python/qgis_wrapped_server.py index 102480d33a5..549d589c7ed 100644 --- a/tests/src/python/qgis_wrapped_server.py +++ b/tests/src/python/qgis_wrapped_server.py @@ -6,6 +6,11 @@ This script launches a QGIS Server listening on port 8081 or on the port specified on the environment variable QGIS_SERVER_PORT. QGIS_SERVER_HOST (defaults to 127.0.0.1) +A XYZ slippy maps service is also available for multithreading testing: + + ?MAP=/path/to/projects.qgs&SERVICE=XYZ&X=1&Y=0&Z=1&LAYERS=world + + For testing purposes, HTTP Basic can be enabled by setting the following environment variables: @@ -49,9 +54,13 @@ os.environ['QT_HASH_SEED'] = '1' import sys import signal import ssl +import math import urllib.parse from http.server import BaseHTTPRequestHandler, HTTPServer -from qgis.core import QgsApplication +from socketserver import ThreadingMixIn +import threading + +from qgis.core import QgsApplication, QgsCoordinateTransform, QgsCoordinateReferenceSystem from qgis.server import QgsServer, QgsServerRequest, QgsBufferServerRequest, QgsBufferServerResponse QGIS_SERVER_PORT = int(os.environ.get('QGIS_SERVER_PORT', '8081')) @@ -100,6 +109,42 @@ if os.environ.get('QGIS_SERVER_HTTP_BASIC_AUTH') is not None: qgs_server.serverInterface().registerFilter(filter) +def num2deg(xtile, ytile, zoom): + """This returns the NW-corner of the square. Use the function with xtile+1 and/or ytile+1 + to get the other corners. With xtile+0.5 & ytile+0.5 it will return the center of the tile.""" + n = 2.0 ** zoom + lon_deg = xtile / n * 360.0 - 180.0 + lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n))) + lat_deg = math.degrees(lat_rad) + return (lat_deg, lon_deg) + + +class XYZFilter(QgsServerFilter): + """XYZ server, example: ?MAP=/path/to/projects.qgs&SERVICE=XYZ&X=1&Y=0&Z=1&LAYERS=world""" + + def requestReady(self): + handler = self.serverInterface().requestHandler() + if handler.parameter('SERVICE') == 'XYZ': + x = int(handler.parameter('X')) + y = int(handler.parameter('Y')) + z = int(handler.parameter('Z')) + # NW corner + lat_deg, lon_deg = num2deg(x, y, z) + # SE corner + lat_deg2, lon_deg2 = num2deg(x + 1, y + 1, z) + handler.setParameter('SERVICE', 'WMS') + handler.setParameter('REQUEST', 'GetMap') + handler.setParameter('VERSION', '1.3.0') + handler.setParameter('SRS', 'EPSG:4326') + handler.setParameter('HEIGHT', '256') + handler.setParameter('WIDTH', '256') + handler.setParameter('BBOX', "{},{},{},{}".format(lat_deg2, lon_deg, lat_deg, lon_deg2)) + + +xyzfilter = XYZFilter(qgs_server.serverInterface()) +qgs_server.serverInterface().registerFilter(xyzfilter) + + class Handler(BaseHTTPRequestHandler): def do_GET(self, post_body=None): @@ -128,8 +173,13 @@ class Handler(BaseHTTPRequestHandler): return self.do_GET(post_body) +class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): + """Handle requests in a separate thread.""" + pass + + if __name__ == '__main__': - server = HTTPServer((QGIS_SERVER_HOST, QGIS_SERVER_PORT), Handler) + server = ThreadedHTTPServer((QGIS_SERVER_HOST, QGIS_SERVER_PORT), Handler) if https: server.socket = ssl.wrap_socket(server.socket, certfile=QGIS_SERVER_PKI_CERTIFICATE,