def report_get(self) -> pyramid.response.Response: """ Get the PDF. """ url = Url("{0!s}/report/{1!s}".format( self.config["print_url"], self.request.matchdict.get("ref"))) if self.config.get("print_get_redirect", False): raise HTTPFound(location=url.url()) return self._proxy_response("print", url)
async def _wfs_get_features_type( self, wfs_url: Url, ogc_server_name: str, preload: bool = False ) -> Tuple[Optional[etree.Element], Set[str]]: errors = set() wfs_url.add_query( { "SERVICE": "WFS", "VERSION": "1.0.0", "REQUEST": "DescribeFeatureType", "ROLE_IDS": "0", "USER_ID": "0", } ) LOG.debug("WFS DescribeFeatureType for the URL: %s", wfs_url) # forward request to target (without Host Header) headers = dict(self.request.headers) if wfs_url.hostname != "localhost" and "Host" in headers: headers.pop("Host") headers = restrict_headers(headers, self.headers_whitelist, self.headers_blacklist) try: content, _ = await asyncio.get_event_loop().run_in_executor( None, get_http_cached, self.http_options, wfs_url, headers ) except requests.exceptions.RequestException as exception: error = ( f"Unable to get WFS DescribeFeatureType from the URL '{wfs_url.url()}' for " f"OGC server {ogc_server_name}, " + ( f"return the error: {exception.response.status_code} {exception.response.reason}" if exception.response is not None else f"{exception}" ) ) errors.add(error) LOG.exception(error) return None, errors except Exception: error = ( f"Unable to get WFS DescribeFeatureType from the URL {wfs_url} for " f"OGC server {ogc_server_name}" ) errors.add(error) LOG.exception(error) return None, errors if preload: return None, errors try: return lxml.XML(content), errors except Exception as e: errors.add( f"Error '{e!s}' on reading DescribeFeatureType from URL {wfs_url}:\n{content.decode()}" ) return None, errors
def test_url_encode3(self): url = Url("http://example.com/toto?%C3%A0=%C3%A9") url.add_query({"1": "2"}) self.assertEqual(url.scheme, "http") self.assertEqual(url.netloc, "example.com") self.assertEqual(url.path, "/toto") self.assertEqual(url.fragment, "") self.assertEqual(url.query, {"à": "é", "1": "2"})
def report_get(self) -> pyramid.response.Response: """Get the PDF.""" url = Url( f"{self.request.get_organization_print_url()}/report/{self.request.matchdict.get('ref')}" ) if self.request.registry.settings.get("print_get_redirect", False): raise HTTPFound(location=url.url()) return self._proxy_response("print", url)
def test_url_port(self): url = Url("http://example.com:8480/toto") url.add_query({"1": "2"}) self.assertEqual(url.scheme, "http") self.assertEqual(url.hostname, "example.com") self.assertEqual(url.netloc, "example.com:8480") self.assertEqual(url.path, "/toto") self.assertEqual(url.fragment, "") self.assertEqual(url.query, {"1": "2"})
def test_url(self): url = Url("http://test/") url.add_query({"Name": "Bob", "Age": "18", "Nationality": "Việt Nam"}) self.assertEqual(url.scheme, "http") self.assertEqual(url.netloc, "test") self.assertEqual(url.path, "/") self.assertEqual(url.fragment, "") self.assertEqual(url.query, { "Name": "Bob", "Age": "18", "Nationality": "Việt Nam" })
def _build_url(self, url: Url) -> Tuple[Url, Dict[str, str], Dict[str, Any]]: hostname = url.hostname host_map = self.config.get("lingua_extractor", {}).get("host_map", {}) if hostname in host_map: map_ = host_map[hostname] if "netloc" in map_: url.netloc = map_["netloc"] if "scheme" in map_: url.scheme = map_["scheme"] kwargs = {"verify": map_["verify"]} if "verify" in map_ else {} return url, map_.get("headers", {}), kwargs return url, {}, {}
def report_create(self) -> pyramid.response.Response: """ Create PDF. """ return self._proxy_response( "print", Url("{}/report.{}".format(self.config["print_url"], self.request.matchdict.get("format"))), )
def status(self) -> pyramid.response.Response: """ PDF status. """ return self._proxy_response( "print", Url("{}/status/{}.json".format(self.config["print_url"], self.request.matchdict.get("ref"))), )
def filter_capabilities(content: str, wms: bool, url: Url, headers: Dict[str, str], request: pyramid.request.Request) -> str: """Filter the WMS/WFS capabilities.""" wms_structure_ = wms_structure(url, headers.get("Host"), request) ogc_server_ids = (get_ogc_server_wms_url_ids(request) if wms else get_ogc_server_wfs_url_ids(request)).get(url.url()) gmf_private_layers = copy.copy(get_private_layers(ogc_server_ids)) for id_ in list(get_protected_layers(request, ogc_server_ids).keys()): if id_ in gmf_private_layers: del gmf_private_layers[id_] private_layers = set() for gmf_layer in list(gmf_private_layers.values()): for ogc_layer in gmf_layer.layer.split(","): private_layers.add(ogc_layer) if ogc_layer in wms_structure_: private_layers.update(wms_structure_[ogc_layer]) parser = defusedxml.expatreader.create_parser(forbid_external=False) # skip inclusion of DTDs parser.setFeature(xml.sax.handler.feature_external_ges, False) parser.setFeature(xml.sax.handler.feature_external_pes, False) result = StringIO() downstream_handler = XMLGenerator(result, "utf-8") filter_handler = _CapabilitiesFilter(parser, downstream_handler, "Layer" if wms else "FeatureType", layers_blacklist=private_layers) filter_handler.parse(StringIO(content)) # type: ignore return result.getvalue()
def dev(self) -> pyramid.response.Response: path = self.THEME_RE.sub("", self.request.path_info) if self.request.path.endswith("/dynamic.js"): return HTTPFound(location=self.request.route_url( "dynamic", _query=self.request.params)) return self._proxy_response( "dev", Url(f"{self.dev_url.rstrip('/')}/{path.lstrip('/')}"))
def _capabilities(self, templates: List[str], query_string: Dict[str, str], method: str, referrer: str) -> Tuple[requests.Response, str]: del query_string # Just for caching del method # Just for caching del referrer # Just for caching # get URL _url = self.request.get_organization_print_url() + "/capabilities.json" response = self._proxy(Url(_url)) response.raise_for_status() if self.request.method == "GET": try: capabilities = response.json() except json.decoder.JSONDecodeError: LOG.exception("Unable to parse capabilities: %s", response.text) raise HTTPBadGateway(response.text) # pylint: disable=raise-missing-from capabilities["layouts"] = list( layout for layout in capabilities["layouts"] if layout["name"] in templates) pretty = self.request.params.get("pretty", "false") == "true" content = json.dumps(capabilities, separators=None if pretty else (",", ":"), indent=4 if pretty else None) else: content = "" return response, content
def cancel(self) -> pyramid.response.Response: """PDF cancel.""" return self._proxy_response( "print", Url(f"{self.request.get_organization_print_url()}/cancel/{self.request.matchdict.get('ref')}" ), )
def status(self) -> pyramid.response.Response: """PDF status.""" return self._proxy_response( "print", Url(f"{self.request.get_organization_print_url()}/status/{self.request.matchdict.get('ref')}.json" ), )
def report_create(self) -> pyramid.response.Response: """Create PDF.""" return self._proxy_response( "print", Url(f"{ self.request.get_organization_print_url()}/report.{self.request.matchdict.get('format')}" ), )
def get_url_internal_wfs( self, ogc_server: main.OGCServer, errors: Set[str] ) -> Tuple[Optional[Url], Optional[Url], Optional[Url]]: # required to do every time to validate the url. if ogc_server.auth != main.OGCSERVER_AUTH_NOAUTH: url: Optional[Url] = Url( self.request.route_url("mapserverproxy", _query={"ogcserver": ogc_server.name}) ) url_wfs: Optional[Url] = url url_internal_wfs = get_url2( f"The OGC server (WFS) '{ogc_server.name}'", ogc_server.url_wfs or ogc_server.url, self.request, errors=errors, ) else: url = get_url2(f"The OGC server '{ogc_server.name}'", ogc_server.url, self.request, errors=errors) url_wfs = ( get_url2( f"The OGC server (WFS) '{ogc_server.name}'", ogc_server.url_wfs, self.request, errors=errors, ) if ogc_server.url_wfs is not None else url ) url_internal_wfs = url_wfs return url_internal_wfs, url, url_wfs
async def _wms_get_features_type( self, wfs_url: Url, preload: bool = False) -> Tuple[Optional[etree.Element], Set[str]]: errors = set() wfs_url.add_query({ "SERVICE": "WFS", "VERSION": "1.0.0", "REQUEST": "DescribeFeatureType", "ROLE_ID": "0", "USER_ID": "0", }) LOG.debug("WFS DescribeFeatureType for base URL: %s", wfs_url) # forward request to target (without Host Header) headers = dict(self.request.headers) if wfs_url.hostname != "localhost" and "Host" in headers: headers.pop("Host") try: response = await asyncio.get_event_loop().run_in_executor( None, get_http_cached, self.http_options, wfs_url, headers) except Exception: errors.add("Unable to get DescribeFeatureType from URL {}".format( wfs_url)) return None, errors if not response.ok: errors.add( "DescribeFeatureType from URL {} return the error: {:d} {}". format(wfs_url, response.status_code, response.reason)) return None, errors if preload: return None, errors try: return lxml.XML(response.text.encode("utf-8")), errors except Exception as e: errors.add( "Error '{}' on reading DescribeFeatureType from URL {}:\n{}". format(str(e), wfs_url, response.text)) return None, errors
def wms_structure(wms_url: Url, host: str, request: pyramid.request.Request) -> Dict[str, List[str]]: """Get a simple serializable structure of the WMS capabilities.""" url = wms_url.clone().add_query({ "SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetCapabilities" }) # Forward request to target (without Host Header) headers = {} if url.hostname == "localhost" and host is not None: headers["Host"] = host try: response = requests.get(url.url(), headers=headers, **request.registry.settings.get( "http_options", {})) except Exception: LOG.exception("Unable to GetCapabilities from wms_url '%s'", wms_url) raise HTTPBadGateway( # pylint: disable=raise-missing-from "Unable to GetCapabilities, see logs for details") if not response.ok: raise HTTPBadGateway( f"GetCapabilities from wms_url {url.url()} return the error: " f"{response.status_code:d} {response.reason}") try: wms = WebMapService(None, xml=response.content) result: Dict[str, List[str]] = {} def _fill(name: str, parent: ContentMetadata) -> None: if parent is None: return if parent.name not in result: result[parent.name] = [] result[parent.name].append(name) _fill(name, parent.parent) for layer in list(wms.contents.values()): _fill(layer.name, layer.parent) return result except AttributeError: error = "WARNING! an error occurred while trying to read the mapfile and recover the themes." error = f"{error}\nurl: {wms_url}\nxml:\n{response.text}" LOG.exception(error) raise HTTPBadGateway(error) # pylint: disable=raise-missing-from except SyntaxError: error = "WARNING! an error occurred while trying to read the mapfile and recover the themes." error = f"{error}\nurl: {wms_url}\nxml:\n{response.text}" LOG.exception(error) raise HTTPBadGateway(error) # pylint: disable=raise-missing-from
def _do_print(self, spec: Dict[str, Any]) -> pyramid.response.Response: """ Create and get report PDF. """ headers = dict(self.request.headers) headers["Content-Type"] = "application/json" response = self._proxy( Url("{0!s}/buildreport.{1!s}".format(self.config["print_url"], spec["outputFormat"])), method="POST", body=dumps(spec).encode("utf-8"), headers=headers, ) return self._build_response(response, response.content, Cache.NO, "pdfreport")
def _proxy_callback( self, cache_control: Cache, url: Url, params: Dict[str, str], **kwargs: Any ) -> Response: if self.request.matched_route.name.endswith("_path"): if self.request.matchdict["path"] == ("favicon.ico",): return HTTPFound("/favicon.ico") url = url.clone() url.path = self.request.path response = self._proxy(url=url, params=params, **kwargs) content = response.content if self.lower_params.get("request") == "getcapabilities": content = filter_capabilities( response.text, self.lower_params.get("service") == "wms", url, self.request.headers, self.request, ).encode("utf-8") content_type = response.headers["Content-Type"] return self._build_response(response, content, cache_control, "mapserver", content_type=content_type)
def wms_structure(wms_url: Url, host: str, request: pyramid.request.Request) -> Dict[str, List[str]]: url = wms_url.clone().add_query({"SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetCapabilities"}) # Forward request to target (without Host Header) headers = dict() if url.hostname == "localhost" and host is not None: headers["Host"] = host try: response = requests.get( url.url(), headers=headers, **request.registry.settings.get("http_options", {}) ) except Exception: raise HTTPBadGateway("Unable to GetCapabilities from wms_url {}".format(wms_url)) if not response.ok: raise HTTPBadGateway( "GetCapabilities from wms_url {} return the error: {:d} {}".format( url.url(), response.status_code, response.reason ) ) try: wms = WebMapService(None, xml=response.content) result: Dict[str, List[str]] = {} def _fill(name: str, parent: ContentMetadata) -> None: if parent is None: return if parent.name not in result: result[parent.name] = [] result[parent.name].append(name) _fill(name, parent.parent) for layer in list(wms.contents.values()): _fill(layer.name, layer.parent) return result except AttributeError: error = "WARNING! an error occurred while trying to read the mapfile and recover the themes." error = "{0!s}\nurl: {1!s}\nxml:\n{2!s}".format(error, wms_url, response.text) LOG.exception(error) raise HTTPBadGateway(error) except SyntaxError: error = "WARNING! an error occurred while trying to read the mapfile and recover the themes." error = "{0!s}\nurl: {1!s}\nxml:\n{2!s}".format(error, wms_url, response.text) LOG.exception(error) raise HTTPBadGateway(error)
def filter_wfst_capabilities(content: str, wfs_url: Url, request: pyramid.request.Request) -> str: """Filter the WTS capabilities.""" writable_layers: Set[str] = set() ogc_server_ids = get_ogc_server_wfs_url_ids(request).get(wfs_url.url()) for gmf_layer in list( get_writable_layers(request, ogc_server_ids).values()): writable_layers |= set(gmf_layer.layer.split(",")) parser = defusedxml.expatreader.create_parser(forbid_external=False) # skip inclusion of DTDs parser.setFeature(xml.sax.handler.feature_external_ges, False) parser.setFeature(xml.sax.handler.feature_external_pes, False) result = StringIO() downstream_handler = XMLGenerator(result, "utf-8") filter_handler = _CapabilitiesFilter(parser, downstream_handler, "FeatureType", layers_whitelist=writable_layers) filter_handler.parse(StringIO(content)) # type: ignore return result.getvalue()
def get_report(self) -> pyramid.response.Response: self.layername = self.request.matchdict["layername"] layer_config = self.config["layers"].get(self.layername) multiple = layer_config.get("multiple", False) ids = self.request.matchdict["ids"] if multiple: ids = ids.split(",") if layer_config is None: raise HTTPBadRequest("Layer not found") features_ids = ([self.layername + "." + id_ for id_ in ids] if multiple else [self.layername + "." + ids]) if layer_config["check_credentials"]: # FIXME: support of mapserver groups ogc_server = (models.DBSession.query(main.OGCServer).filter( main.OGCServer.name == layer_config["ogc_server"]).one()) ogc_server_ids = [ogc_server] private_layers_object = get_private_layers(ogc_server_ids) private_layers_names = [ private_layers_object[oid].name for oid in private_layers_object ] protected_layers_object = get_protected_layers( self.request.user, ogc_server_ids) protected_layers_names = [ protected_layers_object[oid].name for oid in protected_layers_object ] if self.layername in private_layers_names and self.layername not in protected_layers_names: raise HTTPForbidden srs = layer_config["srs"] mapserv_url = self.request.route_url( "mapserverproxy", _query={"ogcserver": layer_config["ogc_server"]}) url = Url(mapserv_url) url.add_query({ "service": "WFS", "version": "1.1.0", "outputformat": "gml3", "request": "GetFeature", "typeName": self.layername, "featureid": ",".join(features_ids), "srsName": srs, }) vector_request_url = url.url() spec = layer_config["spec"] if spec is None: spec = { "layout": self.layername, "outputFormat": "pdf", "attributes": { "ids": [{ "id": id_ } for id_ in ids] } if multiple else { "id": id }, } map_config = layer_config.get("map") if map_config is not None: spec["attributes"]["map"] = self._build_map( mapserv_url, vector_request_url, srs, map_config) maps_config = layer_config.get("maps") if maps_config is not None: spec["attributes"]["maps"] = [] for map_config in maps_config: spec["attributes"]["maps"].append( self._build_map(mapserv_url, vector_request_url, srs, map_config)) else: datasource = layer_config.get("datasource", True) if multiple and datasource: data = dumps(layer_config["data"]) data_list = [ loads( data % { "layername": self.layername, "id": id_, "srs": srs, "mapserv_url": mapserv_url, "vector_request_url": vector_request_url, }) for id_ in ids ] self.walker(spec, "%(datasource)s", data_list) spec = loads( dumps(spec) % { "layername": self.layername, "srs": srs, "mapserv_url": mapserv_url, "vector_request_url": vector_request_url, }) elif multiple: spec = loads( dumps(spec) % { "layername": self.layername, "ids": ",".join(ids), "srs": srs, "mapserv_url": mapserv_url, "vector_request_url": vector_request_url, }) else: spec = loads( dumps(spec) % { "layername": self.layername, "id": ids, "srs": srs, "mapserv_url": mapserv_url, "vector_request_url": vector_request_url, }) return self._do_print(spec)
def _proxy( self, url: Url, params: Optional[Dict[str, str]] = None, method: Optional[str] = None, cache: bool = False, body: Optional[bytes] = None, headers: Optional[Dict[str, str]] = None, ) -> requests.models.Response: # Get query string params = dict(self.request.params) if params is None else params url = url.clone().add_query(params, True) LOG.debug("Send query to URL:\n%s.", url) if method is None: method = self.request.method headers = dict(self.request.headers if headers is None else headers) # Forward request to target (without Host Header). # The original Host will be added back by pyramid. if url.hostname not in self.host_forward_host and "Host" in headers: headers.pop("Host") # Forward the request tracking ID to the other service. This will allow to follow the logs belonging # to a single request coming from the user headers.setdefault("X-Request-ID", self.request.c2c_request_id) # If we really want to respect the specification, we should chain with the content of the previous # proxy, see also: # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded forwarded = { "for": self.request.client_addr, "proto": self.request.scheme } if "Host" in self.request.headers: forwarded["host"] = self.request.headers["Host"] forwarded_str = ";".join(["=".join(e) for e in forwarded.items()]) if "Forwarded" in headers: headers["Forwarded"] = ",".join( [headers["Forwarded"], forwarded_str]) else: headers["Forwarded"] = forwarded_str # Set alternative "X-Forwarded" headers for forwarded_elements in reversed(headers["Forwarded"].split(",")): for element in forwarded_elements.split(";"): key, value = element.split("=") header_key = f"X-Forwarded-{key.capitalize()}" header_value = headers.get(header_key) headers[ header_key] = value if header_value is None else ", ".join( [header_value, value]) if not cache: headers["Cache-Control"] = "no-cache" if method in ("POST", "PUT") and body is None: body = self.request.body headers = restrict_headers(headers, self.headers_whitelist, self.headers_blacklist) try: if method in ("POST", "PUT"): response = requests.request(method, url.url(), data=body, headers=headers, **self.http_options) else: response = requests.request(method, url.url(), headers=headers, **self.http_options) except Exception: errors = [ "Error '%s' while getting the URL:", "%s", "Method: %s", "--- With headers ---", "%s" ] args1 = [ sys.exc_info()[0], url, method, "\n".join([ f"{h}: {v if h not in ('Authorization', 'Cookies') else '***'}" for h, v in list(headers.items()) ]), ] if method in ("POST", "PUT") and body is not None: errors += ["--- Query with body ---", "%s"] args1.append(body.decode("utf-8")) LOG.exception("\n".join(errors), *args1) raise HTTPBadGateway( # pylint: disable=raise-missing-from "Error on backend, See logs for detail") if not response.ok: errors = [ "Error '%s' in response of URL:", "%s", "Status: %d", "Method: %s", "--- With headers ---", "%s", ] args2: List[Union[str, int]] = [ response.reason, url.url(), response.status_code, method, "\n".join([ f"{h}: {v if h not in ('Authorization', 'Cookies') else '***'}" for h, v in list(headers.items()) ]), ] if method in ("POST", "PUT") and body is not None: errors += ["--- Query with body ---", "%s"] args2.append(body.decode("utf-8")) errors += ["--- Return content ---", "%s"] args2.append(response.text) LOG.error("\n".join(errors), *args2) raise exception_response(response.status_code) if not response.headers.get("Content-Type", "").startswith("image/"): LOG.debug("Get result for URL: %s:\n%s.", url, body) return response
def test_url_noparam(self): url = Url("http://example.com/") url.add_query({}) self.assertEqual(url.url(), "http://example.com/")
def cancel(self) -> pyramid.response.Response: """ PDF cancel. """ return self._proxy_response( "print", Url("{}/cancel/{}".format(self.config["print_url"], self.request.matchdict.get("ref"))))
def test_url_update(self): url = Url("http://test:123/toto?map=123#456") url.hostname = "example" assert url.netloc == "example:123" assert url.port == 123 assert url.url() == "http://example:123/toto?map=123#456" url = Url("http://test:123/toto?map=123#456") url.netloc = "example" assert url.hostname == "example" assert url.port is None assert url.url() == "http://example/toto?map=123#456" url = Url("http://test:123/toto?map=123#456") url.netloc = "example:234" assert url.hostname == "example" assert url.port == 234 assert url.url() == "http://example:234/toto?map=123#456" url = Url("http://test:123/toto?map=123#456") url.port = 345 assert url.netloc == "test:345" assert url.hostname == "test" assert url.url() == "http://test:345/toto?map=123#456" url = Url("http://test:123/toto?map=123#456") url.port = None assert url.netloc == "test" assert url.hostname == "test" assert url.url() == "http://test/toto?map=123#456"
def _proxy( self, url: Url, params: Dict[str, str] = None, method: str = None, cache: bool = False, body: bytes = None, headers: Dict[str, str] = None, ) -> pyramid.response.Response: # Get query string params = dict(self.request.params) if params is None else params url = url.clone().add_query(params, True) LOG.debug("Send query to URL:\n%s.", url) if method is None: method = self.request.method if headers is None: headers = dict(self.request.headers) # Forward request to target (without Host Header) if url.hostname not in self.host_forward_host and "Host" in headers: headers.pop("Host") # Forward the request tracking ID to the other service. This will allow to follow the logs belonging # to a single request coming from the user headers.setdefault("X-Request-ID", self.request.c2c_request_id) # If we releay want to respect the specification, we should chain with the content of the previous # proxy, see also: # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded forwarded = { "for": self.request.client_addr, "proto": self.request.scheme } if "Host" in self.request.headers: forwarded["host"] = self.request.headers["Host"] forwarded_str = ";".join(["=".join(e) for e in forwarded.items()]) if "Forwarded" in headers: headers["Forwarded"] = ",".join( [headers["Forwarded"], forwarded_str]) else: headers["Forwarded"] = forwarded_str if not cache: headers["Cache-Control"] = "no-cache" if method in ("POST", "PUT") and body is None: body = self.request.body try: if method in ("POST", "PUT"): response = requests.request(method, url.url(), data=body, headers=headers, **self.http_options) else: response = requests.request(method, url.url(), headers=headers, **self.http_options) except Exception: errors = [ "Error '%s' while getting the URL:", "%s", "Method: %s", "--- With headers ---", "%s" ] args1 = [ sys.exc_info()[0], url, method, "\n".join([ "{}: {}".format( h, v if h not in ("Authorization", "Cookies") else "***") for h, v in list(headers.items()) ]), ] if method in ("POST", "PUT") and body is not None: errors += ["--- Query with body ---", "%s"] args1.append(body.decode("utf-8")) LOG.error("\n".join(errors), *args1, exc_info=True) raise HTTPBadGateway("Error on backend, See logs for detail") if not response.ok: errors = [ "Error '%s' in response of URL:", "%s", "Status: %d", "Method: %s", "--- With headers ---", "%s", ] args2: List[Union[str, int]] = [ response.reason, url.url(), response.status_code, method, "\n".join([ "{}: {}".format( h, v if h not in ("Authorization", "Cookies") else "***") for h, v in list(headers.items()) ]), ] if method in ("POST", "PUT") and body is not None: errors += ["--- Query with body ---", "%s"] args2.append(body.decode("utf-8")) errors += ["--- Return content ---", "%s"] args2.append(response.text) LOG.error("\n".join(errors), *args2) raise exception_response(response.status_code) return response
def _get_wfs_url(self, errors: Set[str]) -> Optional[Url]: return Url(self.settings.get("tinyows_url"))
def __init__(self, server_iface: qgis.server.QgsServerInterface): super().__init__(server_iface) self.server_iface = server_iface self.initialized = False try: config.init( os.environ.get("GEOMAPFISH_CONFIG", "/etc/qgisserver/geomapfish.yaml")) c2cwsgiutils.broadcast.init() DBSession = create_session_factory( # noqa: ignore=N806 config.get("sqlalchemy_slave.url"), config.get_config().get("sqlalchemy", {})) if "GEOMAPFISH_OGCSERVER" in os.environ: self.single = True self.ogcserver_accesscontrol = OGCServerAccessControl( server_iface, os.environ["GEOMAPFISH_OGCSERVER"], os.environ["QGIS_PROJECT_FILE"], config.get("srid"), DBSession, ) LOG.info("Use OGC server named '%s'.", os.environ["GEOMAPFISH_OGCSERVER"]) self.initialized = True elif "GEOMAPFISH_ACCESSCONTROL_CONFIG" in os.environ: self.single = False self.ogcserver_accesscontrols = {} with open(os.environ["GEOMAPFISH_ACCESSCONTROL_CONFIG"], encoding="utf-8") as ac_config_file: ac_config = yaml.safe_load(ac_config_file.read()) for map_, map_config in ac_config.get("map_config").items(): map_config["access_control"] = OGCServerAccessControl( server_iface, map_config["ogc_server"], map_, config.get("srid"), DBSession) self.ogcserver_accesscontrols[map_] = map_config LOG.info("Use config '%s'.", os.environ["GEOMAPFISH_ACCESSCONTROL_CONFIG"]) self.initialized = True elif "GEOMAPFISH_ACCESSCONTROL_BASE_URL" in os.environ: self.ogcserver_accesscontrols = {} single_ogc_server = None base_url = Url(os.environ["GEOMAPFISH_ACCESSCONTROL_BASE_URL"]) session = DBSession() try: from c2cgeoportal_commons.models.main import ( # pylint: disable=import-outside-toplevel OGCServer, ) for ogcserver in session.query(OGCServer).all(): errors: Set[str] = set() url = get_url2( f"The OGC server '{ogcserver.name}'", ogcserver.url, None, errors, config.get_config().get("servers", {}), ) if errors: LOG.warning( "Ignoring OGC server '%s', get error on parsing URL:\n%s", ogcserver.name, "\n".join(errors), ) continue if url is None: LOG.warning( "Ignoring OGC server '%s', the URL is None", ogcserver.name) continue if (base_url.scheme == url.scheme and base_url.netloc == url.netloc and base_url.path == url.path): query = url.query_lower if "map" not in query: if single_ogc_server is None: single_ogc_server = ogcserver LOG.debug( "OGC server '%s', 'map' is not in the parameters => single server?", ogcserver.name, ) else: LOG.error( "OGC server '%s', 'map' is not in the parameters and we already have a single OCG server '%s'", ogcserver.name, single_ogc_server.name, ) continue map_ = url.query_lower["map"] self.ogcserver_accesscontrols[map_] = { "ogcserver": ogcserver.name, "access_control": OGCServerAccessControl( server_iface, ogcserver.name, map_, config.get("srid"), DBSession, ogcserver=ogcserver, ), } LOG.info("OGC server '%s' registered for map", ogcserver.name) else: LOG.debug( "Ignoring OGC server '%s', Don't match the base URL '%s' and '%s'", ogcserver.name, base_url, url, ) if self.ogcserver_accesscontrols and single_ogc_server is not None: if os.environ.get("QGIS_PROJECT_FILE"): LOG.error( "We have OGC servers with and without parameter MAP and a value in QGIS_PROJECT_FILE, fallback to single OGC server mode." ) self.ogcserver_accesscontrols = {} else: LOG.error( "We have OGC servers with and without parameter MAP but no value in QGIS_PROJECT_FILE, fallback to multiple OGC server mode." ) single_ogc_server = None if single_ogc_server is not None: self.single = True self.ogcserver_accesscontrol = OGCServerAccessControl( server_iface, single_ogc_server.name, os.environ["QGIS_PROJECT_FILE"], config.get("srid"), DBSession, single_ogc_server, ) LOG.info("Use OGC server named '%s'.", single_ogc_server.name) else: self.single = False self.initialized = True finally: session.close() else: LOG.error( "The environment variable 'GEOMAPFISH_OGCSERVER', 'GEOMAPFISH_ACCESSCONTROL_CONFIG' " "or 'GEOMAPFISH_ACCESSCONTROL_BASE_URL' should be defined.", ) except Exception: # pylint: disable=broad-except LOG.error("Cannot setup GeoMapFishAccessControl", exc_info=True) server_iface.registerAccessControl( self, int(os.environ.get("GEOMAPFISH_POSITION", 100)))