Beispiel #1
0
 def get_url_internal_wfs(self, ogc_server, errors):
     # required to do every time to validate the url.
     if ogc_server.auth != main.OGCSERVER_AUTH_NOAUTH:
         url = self.request.route_url("mapserverproxy",
                                      _query={"ogcserver": ogc_server.name})
         url_wfs = url
         url_internal_wfs = get_url2(
             "The OGC server (WFS) '{}'".format(ogc_server.name),
             ogc_server.url_wfs or ogc_server.url,
             self.request,
             errors=errors,
         )
     else:
         url = get_url2("The OGC server '{}'".format(ogc_server.name),
                        ogc_server.url,
                        self.request,
                        errors=errors)
         url_wfs = (get_url2(
             "The OGC server (WFS) '{}'".format(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
Beispiel #2
0
 def _get_wms_url(self):
     ogc_server = self.ogc_server
     errors = set()
     url = get_url2("The OGC server '{}'".format(ogc_server.name),
                    ogc_server.url, self.request, errors)
     if len(errors) > 0:  # pragma: no cover
         LOG.error("\n".join(errors))
     return url
Beispiel #3
0
 def _get_wms_url(self):
     errors = set()
     url = get_url2(
         "The OGC server '{}'".format(self._get_ogc_server().name),
         self._get_ogc_server().url, self.request, errors
     )
     if len(errors) > 0:  # pragma: no cover
         log.error("\n".join(errors))
     return url
Beispiel #4
0
 def _get_wms_url(self):
     errors = set()
     url = get_url2(
         "The OGC server '{}'".format(self._get_ogc_server().name),
         self._get_ogc_server().url, self.request, errors
     )
     if len(errors) > 0:  # pragma: no cover
         log.error("\n".join(errors))
     return url
Beispiel #5
0
 def _get_wfs_url(self):
     ogc_server = self._get_ogc_server()
     errors = set()
     url = get_url2("The OGC server (WFS) '{}'".format(ogc_server.name),
                    ogc_server.url_wfs or ogc_server.url, self.request,
                    errors)
     if len(errors) > 0:  # pragma: no cover
         log.error("\n".join(errors))
     return url
Beispiel #6
0
    def _themes(self, interface="desktop", filter_themes=True, min_levels=1):
        """
        This function returns theme information for the role identified
        by ``role_id``.
        """
        self._load_tree_items()
        errors = set()
        layers = self._layers(interface)

        themes = models.DBSession.query(main.Theme)
        themes = themes.filter(main.Theme.public.is_(True))
        auth_themes = models.DBSession.query(main.Theme)
        auth_themes = auth_themes.filter(main.Theme.public.is_(False))
        auth_themes = auth_themes.join(main.Theme.restricted_roles)
        auth_themes = auth_themes.filter(
            main.Role.id.in_(get_roles_id(self.request)))

        themes = themes.union(auth_themes)

        themes = themes.order_by(main.Theme.ordering.asc())

        if filter_themes and interface is not None:
            themes = themes.join(main.Theme.interfaces)
            themes = themes.filter(main.Interface.name == interface)

        export_themes = []
        for theme in themes.all():
            if re.search("[/?#]", theme.name):
                errors.add("The theme has an unsupported name '{}'.".format(
                    theme.name))
                continue

            children, children_errors = self._get_children(
                theme, layers, min_levels)
            errors |= children_errors

            # Test if the theme is visible for the current user
            if children:
                icon = (get_url2("The Theme '{}'".format(theme.name),
                                 theme.icon, self.request, errors)
                        if theme.icon is not None and theme.icon else
                        self.request.static_url(
                            "/etc/geomapfish/static/images/blank.png"))

                theme_theme = {
                    "id": theme.id,
                    "name": theme.name,
                    "icon": icon,
                    "children": children,
                    "functionalities": self._get_functionalities(theme),
                    "metadata": self._get_metadatas(theme, errors),
                }
                export_themes.append(theme_theme)

        return export_themes, errors
Beispiel #7
0
 def _get_wfs_url(self):
     ogc_server = self.ogc_server
     errors: Set[str] = set()
     url = get_url2(
         "The OGC server (WFS) '{}'".format(ogc_server.name),
         ogc_server.url_wfs or ogc_server.url,
         self.request,
         errors,
     )
     if errors:  # pragma: no cover
         LOG.error("\n".join(errors))
     return url
Beispiel #8
0
    def _fill_wmts(self, layer_theme, layer, errors):
        layer_theme["url"] = get_url2("The WMTS layer '{}'".format(layer.name),
                                      layer.url,
                                      self.request,
                                      errors=errors)

        if layer.style:
            layer_theme["style"] = layer.style
        if layer.matrix_set:
            layer_theme["matrixSet"] = layer.matrix_set

        layer_theme["layer"] = layer.layer
        layer_theme["imageType"] = layer.image_type
Beispiel #9
0
    def apilayers(self):
        try:
            with open('/tmp/jsapilayers.json') as json_file:
                data = json.load(json_file)
                return data
        except Exception as e:
            print("File not found")
        '''
        View to return a list of layers.
        Same as the theme service but in a flat representation.
        '''
        themes, errors = self._themes(None, None, u'main', True, 2, True)

        layers = {}

        # get themes layers
        for theme in themes:
            self._extract_layers(theme, layers)

        # get background layers
        group, errors = self._get_group(None, u'background', None, u'main', 2)
        self._extract_layers(group, layers, True)
        all_errors = set()
        for id in layers:
            url = None
            if 'ogcServer' in layers[id]:
                if 'source for' in layers[id]['ogcServer']:
                    for ogc_server in models.DBSession.query(
                            main.OGCServer).filter(
                                main.OGCServer.name == layers[id]
                                ['ogcServer']).all():
                        # required to do every time to validate the url.
                        if ogc_server.auth != main.OGCSERVER_AUTH_NOAUTH:
                            url = self.request.route_url(
                                "mapserverproxy",
                                _query={"ogcserver": ogc_server.name})
                        else:
                            url = get_url2("The OGC server '{}'".format(
                                ogc_server.name),
                                           ogc_server.url,
                                           self.request,
                                           errors=all_errors)
                    layers[id]['url'] = url
        try:
            with open('/tmp/jsapilayers.json', 'w') as json_file:
                json.dump(layers, json_file)
        except Exception as e:
            print(e)
        return layers
Beispiel #10
0
    def test_get_url2(self):
        from c2cgeoportal_geoportal.lib import get_url2

        request = create_dummy_request({
            "package": "my_project",
            "servers": {
                "srv": "https://example.com/test",
                "srv_alt": "https://example.com/test/",
                "full_url": "https://example.com/test.xml",
            },
        })

        def static_url(path, **kwargs):
            del kwargs  # Unused
            return "http://server.org/" + path

        request.static_url = static_url

        self.assertEqual(
            get_url2("test", "static://pr:st/icon.png", request, set()),
            "http://server.org/pr:st/icon.png")
        self.assertEqual(
            get_url2("test", "static:///icon.png", request, set()),
            "http://server.org//etc/geomapfish/static/icon.png",
        )
        self.assertEqual(
            get_url2("test", "config://srv/icon.png", request, set()),
            "https://example.com/test/icon.png")
        self.assertEqual(get_url2("test", "config://srv/", request, set()),
                         "https://example.com/test/")
        self.assertEqual(get_url2("test", "config://srv", request, set()),
                         "https://example.com/test")
        self.assertEqual(
            get_url2("test", "config://srv/icon.png?test=aaa", request, set()),
            "https://example.com/test/icon.png?test=aaa",
        )
        self.assertEqual(
            get_url2("test", "config://srv_alt/icon.png", request, set()),
            "https://example.com/test/icon.png")
        self.assertEqual(get_url2("test", "config://full_url", request, set()),
                         "https://example.com/test.xml")
        self.assertEqual(
            get_url2("test", "http://example.com/icon.png", request, set()),
            "http://example.com/icon.png")
        self.assertEqual(
            get_url2("test", "https://example.com/icon.png", request, set()),
            "https://example.com/icon.png")
        errors = set()
        self.assertEqual(
            get_url2("test", "config://srv2/icon.png", request, errors=errors),
            None)
        self.assertEqual(
            errors,
            set([
                "test: The server 'srv2' (config://srv2/icon.png) is not found in the config: [srv, srv_alt, full_url]"
            ]),
        )
Beispiel #11
0
    def _layer_attributes(self, url, layer):
        errors = set()

        request = _Request()
        request.registry.settings = self.config
        # Static schema will not be supported
        url = get_url2("Layer", url, request, errors)
        if len(errors) > 0:
            print("\n".join(errors))
            return [], []
        url, headers, kwargs = self._build_url(url)

        if url not in self.wmscap_cache:
            print("Get WMS GetCapabilities for URL: {}".format(url))
            self.wmscap_cache[url] = None

            wms_getcap_url = add_url_params(
                url, {
                    "SERVICE": "WMS",
                    "VERSION": "1.1.1",
                    "REQUEST": "GetCapabilities",
                })
            try:
                print("Get WMS GetCapabilities for URL {},\nwith headers: {}".
                      format(wms_getcap_url,
                             " ".join(["=".join(h) for h in headers.items()])))
                response = requests.get(wms_getcap_url,
                                        headers=headers,
                                        **kwargs)

                try:
                    self.wmscap_cache[url] = WebMapService(
                        None, xml=response.content)
                except Exception as e:
                    print(
                        colorize(
                            "ERROR! an error occurred while trying to "
                            "parse the GetCapabilities document.", RED))
                    print(colorize(str(e), RED))
                    print("URL: {}\nxml:\n{}".format(wms_getcap_url,
                                                     response.text))
                    if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                        raise
            except Exception as e:  # pragma: no cover
                print(colorize(str(e), RED))
                print(
                    colorize(
                        "ERROR! Unable to GetCapabilities from URL: {},\nwith headers: {}"
                        .format(
                            wms_getcap_url,
                            " ".join(["=".join(h) for h in headers.items()])),
                        RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                    raise

        wmscap = self.wmscap_cache[url]

        if url not in self.featuretype_cache:
            print("Get WFS DescribeFeatureType for URL: {}".format(url))
            self.featuretype_cache[url] = None

            wfs_descrfeat_url = add_url_params(
                url, {
                    "SERVICE": "WFS",
                    "VERSION": "1.1.0",
                    "REQUEST": "DescribeFeatureType",
                })
            try:
                response = requests.get(wfs_descrfeat_url,
                                        headers=headers,
                                        **kwargs)
            except Exception as e:  # pragma: no cover
                print(colorize(str(e), RED))
                print(
                    colorize(
                        "ERROR! Unable to DescribeFeatureType from URL: {}".
                        format(wfs_descrfeat_url),
                        RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                else:
                    raise

            if not response.ok:  # pragma: no cover
                print(
                    colorize(
                        "ERROR! DescribeFeatureType from URL {} return the error: {:d} {}"
                        .format(wfs_descrfeat_url, response.status_code,
                                response.reason),
                        RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                else:
                    raise Exception("Aborted")

            try:
                describe = parseString(response.text)
                featurestype = {}
                self.featuretype_cache[url] = featurestype
                for type_element in describe.getElementsByTagNameNS(
                        "http://www.w3.org/2001/XMLSchema", "complexType"):
                    featurestype[type_element.getAttribute(
                        "name")] = type_element
            except ExpatError as e:
                print(
                    colorize(
                        "ERROR! an error occurred while trying to "
                        "parse the DescribeFeatureType document.", RED))
                print(colorize(str(e), RED))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url,
                                                 response.text))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                else:
                    raise
            except AttributeError:
                print(
                    colorize(
                        "ERROR! an error occurred while trying to "
                        "read the Mapfile and recover the themes.", RED))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url,
                                                 response.text))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return [], []
                else:
                    raise
        else:
            featurestype = self.featuretype_cache[url]

        if featurestype is None:
            return [], []

        layers = [layer]
        if wmscap is not None and layer in list(wmscap.contents):
            layer_obj = wmscap[layer]
            if len(layer_obj.layers) > 0:
                layers = [l.name for l in layer_obj.layers]

        attributes = []
        for sub_layer in layers:
            # Should probably be adapted for other king of servers
            type_element = featurestype.get("{}Type".format(sub_layer))
            if type_element is not None:
                for element in type_element.getElementsByTagNameNS(
                        "http://www.w3.org/2001/XMLSchema", "element"):
                    if not element.getAttribute("type").startswith("gml:"):
                        attributes.append(element.getAttribute("name"))

        return attributes, layers
Beispiel #12
0
    async def _wms_getcap_cached(self, ogc_server, _):
        """ _ is just for cache on the role id """

        errors: Set[str] = set()
        url = get_url2("The OGC server '{}'".format(ogc_server.name),
                       ogc_server.url, self.request, errors)
        if errors or url is None:  # pragma: no cover
            return url, None, errors

        # Add functionality params
        sparams = get_mapserver_substitution_params(self.request)
        url = add_url_params(url, sparams)

        url = add_url_params(
            url,
            {
                "SERVICE": "WMS",
                "VERSION": "1.1.1",
                "REQUEST": "GetCapabilities",
                "ROLE_ID": "0",
                "USER_ID": "0",
            },
        )

        LOG.debug("Get WMS GetCapabilities for url: %s", url)

        # Forward request to target (without Host Header)
        headers = dict(self.request.headers)

        # Add headers for Geoserver
        if ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER:
            headers["sec-username"] = "******"
            headers["sec-roles"] = "root"

        if urllib.parse.urlsplit(
                url
        ).hostname != "localhost" and "Host" in headers:  # pragma: no cover
            headers.pop("Host")

        try:
            response = await asyncio.get_event_loop().run_in_executor(
                None, get_http_cached, self.http_options, url, headers)
        except Exception:  # pragma: no cover
            error = "Unable to GetCapabilities from URL {}".format(url)
            errors.add(error)
            LOG.error(error, exc_info=True)
            return url, None, errors

        if not response.ok:  # pragma: no cover
            error = "GetCapabilities from URL {} return the error: {:d} {}".format(
                url, response.status_code, response.reason)
            errors.add(error)
            LOG.error(error)
            return url, None, errors

        # With wms 1.3 it returns text/xml also in case of error :-(
        if response.headers.get("Content-Type",
                                "").split(";")[0].strip() not in [
                                    "application/vnd.ogc.wms_xml",
                                    "text/xml",
                                ]:
            error = "GetCapabilities from URL {} returns a wrong Content-Type: {}\n{}".format(
                url, response.headers.get("Content-Type", ""), response.text)
            errors.add(error)
            LOG.error(error)
            return url, None, errors

        return url, response.content, errors
Beispiel #13
0
    def apilayers_full(self):
        '''
        View to return a list of layers.
        Same as the theme service but in a flat representation.
        '''
        themes, errors = self._themes(None, 1, u'main', True, 2, True)

        layers = {}
        # get themes layers
        for theme in themes:
            self._extract_layers_with_path(theme, layers, [theme['name']])

        # get background layers
        group, errors = self._get_group(None, u'background', None, u'main', 2)

        self._extract_layers(group, layers, True)
        l = []
        registry = get_current_registry()
        dir = registry.queryUtility(ITranslationDirectories, default=[])
        localizer_fr = make_localizer("fr", dir)
        localizer_de = make_localizer("de", dir)
        localizer_en = make_localizer("en", dir)
        localizer_lb = make_localizer("lb", dir)

        client = TranslationStringFactory("geoportailv3_geoportal-client")
        all_errors = set()

        for id in layers:
            url = None
            if 'ogcServer' in layers[id]:
                if 'source for' in layers[id]['ogcServer']:
                    for ogc_server in models.DBSession.query(
                            main.OGCServer).filter(
                                main.OGCServer.name == layers[id]
                                ['ogcServer']).all():
                        # required to do every time to validate the url.
                        if ogc_server.auth != main.OGCSERVER_AUTH_NOAUTH:
                            url = self.request.route_url(
                                "mapserverproxy",
                                _query={"ogcserver": ogc_server.name})
                        else:
                            url = get_url2("The OGC server '{}'".format(
                                ogc_server.name),
                                           ogc_server.url,
                                           self.request,
                                           errors=all_errors)

            entry = models.DBSession.query(
                main.Layer).filter(main.Layer.id == id).one()
            is_public = entry.public

            l.append({
                'id':
                layers[id]['id'],
                'public':
                is_public,
                'name':
                layers[id]['name'],
                'name_fr':
                localizer_fr.translate(client(layers[id]['name'])),
                'name_de':
                localizer_de.translate(client(layers[id]['name'])),
                'name_en':
                localizer_en.translate(client(layers[id]['name'])),
                'name_lb':
                localizer_lb.translate(client(layers[id]['name'])),
                'external_url':
                url,
                'groups':
                layers[id].get('came_from'),
                'metadata_id':
                layers[id]['metadata']['metadata_id']
                if 'metadata_id' in layers[id]['metadata'] else None,
            })
        return l
Beispiel #14
0
    def test_get_url2(self):
        from c2cgeoportal_geoportal.lib import get_url2

        request = create_dummy_request({
            "package": "my_project",
            "servers": {
                "srv": "https://example.com/test",
                "srv_alt": "https://example.com/test/",
                "full_url": "https://example.com/test.xml",
            },
        })

        def static_url(path, **kwargs):
            return "http://server.org/" + path
        request.static_url = static_url

        self.assertEqual(get_url2("test", "static://pr:st/icon.png", request, set()), "http://server.org/pr:st/icon.png")
        self.assertEqual(get_url2("test", "static:///icon.png", request, set()), "http://server.org/my_project_geoportal:static/icon.png")
        self.assertEqual(get_url2("test", "config://srv/icon.png", request, set()), "https://example.com/test/icon.png")
        self.assertEqual(get_url2("test", "config://srv/", request, set()), "https://example.com/test/")
        self.assertEqual(get_url2("test", "config://srv", request, set()), "https://example.com/test")
        self.assertEqual(get_url2("test", "config://srv/icon.png?test=aaa", request, set()), "https://example.com/test/icon.png?test=aaa")
        self.assertEqual(get_url2("test", "config://srv_alt/icon.png", request, set()), "https://example.com/test/icon.png")
        self.assertEqual(get_url2("test", "config://full_url", request, set()), "https://example.com/test.xml")
        self.assertEqual(get_url2("test", "http://example.com/icon.png", request, set()), "http://example.com/icon.png")
        self.assertEqual(get_url2("test", "https://example.com/icon.png", request, set()), "https://example.com/icon.png")
        errors = set()
        self.assertEqual(get_url2("test", "config://srv2/icon.png", request, errors=errors), None)
        self.assertEqual(errors, set(["The server 'srv2' is not found in the config"]))
    def _layer_attributes(self, url, layer):
        errors = set()

        request = _Request()
        request.registry.settings = self.config
        # static schema will not be supported
        url = get_url2("Layer", url, request, errors)
        if len(errors) > 0:
            print("\n".join(errors))
            return []

        wms_getcap_url = add_url_params(url, {
            "SERVICE": "WMS",
            "VERSION": "1.1.1",
            "REQUEST": "GetCapabilities",
        })

        hostname = urlsplit(url).hostname
        if url not in self.wmscap_cache:
            print("Get WMS GetCapabilities for URL: {}".format(url))
            self.wmscap_cache[url] = None

            # forward request to target (without Host Header)
            http = httplib2.Http()
            h = {}
            if hostname == "localhost":  # pragma: no cover
                h["Host"] = self.package["host"]
            try:
                resp, content = http.request(wms_getcap_url, method="GET", headers=h)

                try:
                    self.wmscap_cache[url] = WebMapService(None, xml=content)
                except Exception as e:
                    print(colorize(
                        "ERROR! an error occurred while trying to "
                        "parse the GetCapabilities document.",
                        RED))
                    print(colorize(str(e), RED))
                    print("URL: {}\nxml:\n{}".format(wms_getcap_url, content))
                    if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                        raise
            except Exception as e:  # pragma: no cover
                print(colorize(str(e), RED))
                print(colorize(
                    "ERROR! Unable to GetCapabilities from URL: {}".format(wms_getcap_url),
                    RED,
                ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                    raise

        wmscap = self.wmscap_cache[url]

        wfs_descrfeat_url = add_url_params(url, {
            "SERVICE": "WFS",
            "VERSION": "1.1.0",
            "REQUEST": "DescribeFeatureType",
        })

        if url not in self.featuretype_cache:
            print("Get WFS DescribeFeatureType for URL: {}".format(wfs_descrfeat_url))
            self.featuretype_cache[url] = None

            # forward request to target (without Host Header)
            http = httplib2.Http()
            h = {}
            if hostname == "localhost":  # pragma: no cover
                h["Host"] = self.package["host"]
            try:
                resp, content = http.request(wfs_descrfeat_url, method="GET", headers=h)
            except Exception as e:  # pragma: no cover
                print(colorize(str(e), RED))
                print(colorize(
                    "ERROR! Unable to DescribeFeatureType from URL: {}".format(wfs_descrfeat_url),
                    RED,
                ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise

            if resp.status < 200 or resp.status >= 300:  # pragma: no cover
                print(colorize(
                    "ERROR! DescribeFeatureType from URL {} return the error: {1:d} {}".format(
                        wfs_descrfeat_url, resp.status, resp.reason
                    ),
                    RED,
                ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise Exception("Aborted")

            try:
                describe = parseString(content)
                featurestype = {}
                self.featuretype_cache[url] = featurestype
                for type_element in describe.getElementsByTagNameNS(
                    "http://www.w3.org/2001/XMLSchema", "complexType"
                ):
                    featurestype[type_element.getAttribute("name")] = type_element
            except ExpatError as e:
                print(colorize(
                    "ERROR! an error occurred while trying to "
                    "parse the DescribeFeatureType document.",
                    RED
                ))
                print(colorize(str(e), RED))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url, content))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise
            except AttributeError:
                print(colorize(
                    "ERROR! an error occurred while trying to "
                    "read the Mapfile and recover the themes.",
                    RED
                ))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url, content))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise
        else:
            featurestype = self.featuretype_cache[url]

        if featurestype is None:
            return []

        layers = [layer]
        if wmscap is not None and layer in list(wmscap.contents):
            layer_obj = wmscap[layer]
            if len(layer_obj.layers) > 0:
                layers = [l.name for l in layer_obj.layers]

        attributes = []
        for sub_layer in layers:
            # Should probably be adapted for other king of servers
            type_element = featurestype.get("{}Type".format(sub_layer))
            if type_element is not None:
                for element in type_element.getElementsByTagNameNS(
                    "http://www.w3.org/2001/XMLSchema", "element"
                ):
                    if not element.getAttribute("type").startswith("gml:"):
                        attributes.append(element.getAttribute("name"))

        return attributes, layers
Beispiel #16
0
    def _layer_attributes(self, url, layer):
        errors = set()

        class Registry:
            setting = None

        class Request:
            registry = Registry()

        request = Request()
        request.registry.settings = self.config
        # static schema will not be supported
        url = get_url2("Layer", url, request, errors)
        if len(errors) > 0:
            print("\n".join(errors))
            return []

        wms_getcap_url = add_url_params(url, {
            "SERVICE": "WMS",
            "VERSION": "1.1.1",
            "REQUEST": "GetCapabilities",
        })

        hostname = urlsplit(url).hostname
        if url not in self.wmscap_cache:
            print("Get WMS GetCapabilities for URL: {}".format(url))
            self.wmscap_cache[url] = None

            # forward request to target (without Host Header)
            http = httplib2.Http()
            h = {}
            if hostname == "localhost":  # pragma: no cover
                h["Host"] = self.package["host"]
            try:
                resp, content = http.request(wms_getcap_url,
                                             method="GET",
                                             headers=h)

                try:
                    self.wmscap_cache[url] = WebMapService(None, xml=content)
                except Exception as e:
                    print(
                        colorize(
                            "ERROR! an error occurred while trying to "
                            "parse the GetCapabilities document.", RED))
                    print(colorize(str(e), RED))
                    print("URL: {}\nxml:\n{}".format(wms_getcap_url, content))
                    if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                        raise
            except Exception as e:  # pragma: no cover
                print(colorize(str(e), RED))
                print(
                    colorize(
                        "ERROR! Unable to GetCapabilities from URL: {}".format(
                            wms_getcap_url),
                        RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") != "TRUE":
                    raise

        wmscap = self.wmscap_cache[url]

        wfs_descrfeat_url = add_url_params(
            url, {
                "SERVICE": "WFS",
                "VERSION": "1.1.0",
                "REQUEST": "DescribeFeatureType",
            })

        if url not in self.featuretype_cache:
            print("Get WFS DescribeFeatureType for URL: {}".format(
                wfs_descrfeat_url))
            self.featuretype_cache[url] = None

            # forward request to target (without Host Header)
            http = httplib2.Http()
            h = {}
            if hostname == "localhost":  # pragma: no cover
                h["Host"] = self.package["host"]
            try:
                resp, content = http.request(wfs_descrfeat_url,
                                             method="GET",
                                             headers=h)
            except Exception as e:  # pragma: no cover
                print(colorize(str(e), RED))
                print(
                    colorize(
                        "ERROR! Unable to DescribeFeatureType from URL: {}".
                        format(wfs_descrfeat_url),
                        RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise

            if resp.status < 200 or resp.status >= 300:  # pragma: no cover
                print(
                    colorize(
                        "ERROR! DescribeFeatureType from URL {} return the error: {1:d} {}"
                        .format(wfs_descrfeat_url, resp.status, resp.reason),
                        RED,
                    ))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise Exception("Aborted")

            try:
                describe = parseString(content)
                featurestype = {}
                self.featuretype_cache[url] = featurestype
                for type_element in describe.getElementsByTagNameNS(
                        "http://www.w3.org/2001/XMLSchema", "complexType"):
                    featurestype[type_element.getAttribute(
                        "name")] = type_element
            except ExpatError as e:
                print(
                    colorize(
                        "ERROR! an error occurred while trying to "
                        "parse the DescribeFeatureType document.", RED))
                print(colorize(str(e), RED))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url, content))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise
            except AttributeError:
                print(
                    colorize(
                        "ERROR! an error occurred while trying to "
                        "read the Mapfile and recover the themes.", RED))
                print("URL: {}\nxml:\n{}".format(wfs_descrfeat_url, content))
                if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
                    return []
                else:
                    raise
        else:
            featurestype = self.featuretype_cache[url]

        if featurestype is None:
            return []

        layers = [layer]
        if wmscap is not None and layer in list(wmscap.contents):
            layer_obj = wmscap[layer]
            if len(layer_obj.layers) > 0:
                layers = [l.name for l in layer_obj.layers]

        attributes = []
        for sub_layer in layers:
            # Should probably be adapted for other king of servers
            type_element = featurestype.get("{}Type".format(sub_layer))
            if type_element is not None:
                for element in type_element.getElementsByTagNameNS(
                        "http://www.w3.org/2001/XMLSchema", "element"):
                    if not element.getAttribute("type").startswith("gml:"):
                        attributes.append(element.getAttribute("name"))

        return attributes