.. index:: 
   single: WFS Client

.. _wfs_client:

*****************************************************************************
 WFS Client
*****************************************************************************

:Author: Jean-François Doyon
:Contact: jdoyon at nrcan.gc.ca
:Author: Jeff McKenna
:Contact: jmckenna at gatewaygeomatics.com
:Last Updated: 2015-05-21

.. contents::
    :depth: 2
    :backlinks: top

Introduction
============

MapServer can retrieve and display data from a WFS server.  The
following document explains how to display data from a WFS server
using the MapServer `CONNECTIONTYPE` `WFS`.

WFS can also be accessed through OGR (`CONNECTIONTYPE` `OGR`).
See the :ref:`OGR` documentation for datails.

A WFS ( Web Feature Service ) publishes feature-level geospatial data
to the web.  This means that it is possible to use this data as a data
source to render a map.  In effect, this is not unlike having a
shapefile accessible over the web, only it's not a shapefile, it's
XML-Encoded geospatial data (GML to be exact), including both geometry
AND attribute information.

WFS-Related Information
-----------------------

Although in-depth understanding of WFS and GML is neither necessary
nor required in order to implement a MapServer application that reads
remote WFS data, it is recommended to at least get acquainted with the
concepts and basic functionality of both.  Here are the official
references (including a newly added OGC workshop with MapServer):

- `OGC Web Feature Service Implementation Specification`_.
- `Geography Markup Language Implementation Specification`_.
- `MapServer OGC Web Services Workshop package`_.

.. _`OGC Web Feature Service Implementation Specification`: https://portal.opengeospatial.org/files/?artifact_id=7176
.. _`Geography Markup Language Implementation Specification`: https://portal.opengeospatial.org/files/?artifact_id=7174
.. _`MapServer OGC Web Services Workshop package`: http://mapserver.github.io/ms-ogc-workshop/

Software Requirements
---------------------

In order to enable MapServer to serve WFS, it MUST be compiled against
certain libraries:

- PROJ.4: The reprojection library. Version 4.4.3 or greater is
  required.
- GDAL/OGR: I/O support libraries. Version 1.1.8 or greater is
  required.
- LibCURL: Used to help MapServer act as an HTTP client. Version 7.10
  or greater is required.

Please see the MapServer UNIX Compilation and Installation HOWTO for
detailed instructions on compiling mapserver with support for these
libraries and features.  For Windows users, look on the MapServer
website to see if there are any binaries available that meet these
requirements.

.. index:: 
   pair: WFS Client; Mapfile

Setting up a WFS-client Mapfile
===============================

Storing Temporary Files
-----------------------

You must set the :ref:`IMAGEPATH <web>` parameter in your mapfile
since MapServer uses this directory to store temporary files
downloaded from the remote WFS server.  **Windows** users must specify
a full path for IMAGEPATH, such as: *IMAGEPATH "C:/tmp/ms_tmp/"*

.. code-block:: mapfile

    MAP
      ...
      WEB
        IMAGEPATH "/tmp/ms_tmp/"
        IMAGEURL ...
      END
      ...
    END 
  
WFS Layer
---------

A WFS layer is a regular mapfile layer, which can use CLASS objects,
with expressions, etc.

As of MapServer 4.4, the suggested method to define a WFS Client layer
is through the CONNECTION parameter and the layer's METADATA.  The
necessary mapfile parameters are defined below:

- *CONNECTIONTYPE*: must be "wfs"

- *CONNECTION*: The URL to the WFS
  Server. e.g. https://demo.mapserver.org/cgi-bin/wfs?  The path to the
  mapfile on the WFS server is required if it was required in the
  GetCapabilities request e.g. you would have to specify the MAP
  parameter in the CONNECTION for the following server:
  `http://map.ns.ec.gc.ca/MapServer/mapserv.exe?MAP=/mapserver/services/envdat/config.map`_
  `&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities`_

.. index:: 
   triple: WFS Client; LAYER; METADATA

- *METADATA*: The LAYER's must contain a METADATA object with the
  following parameters:

  - *wfs_connectiontimeout* (optional): The maximum time to wait for a
    remote WFS layer to load, set in seconds (default is 30
    seconds). This metadata can be added at the layer level so that it
    affects only that layer, or it can be added at the map level (in
    the web object) so that it affects all of the layers. Note that
    wfs_connectiontimeout at the layer level has priority over the map
    level.

  - *wfs_filter*: This can be included to include a filter encoding
    parameter in the getFeature request (see the :ref:`Filter Encoding
    Howto <filter_encoding>` for more information on filtering).  The
    content of the wfs_filter is a valid filter encoding element.
    
    .. _`http://map.ns.ec.gc.ca/MapServer/mapserv.exe?MAP=/mapserver/services/envdat/config.map`: http://map.ns.ec.gc.ca/MapServer/mapserv.exe?MAP=/mapserver/services/envdat/config.map&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities
    .. _`&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities`: http://map.ns.ec.gc.ca/MapServer/mapserv.exe?MAP=/mapserver/services/envdat/config.map&SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities

    .. code-block:: mapfile

      ...
      METADATA
        "wfs_filter"   "<PropertyIsGreaterThan><PropertyName>POP_RANGE</PropertyName>
                        <Literal>4</Literal></PropertyIsGreaterThan>"
      END
      ...

  - *wfs_geometryname* (optional): The name of the geometry column 
    used for spatial filtering in the filter parameter (Geometry by 
    default). This parameter is used for ArcGIS or GeoServer WFS 
    services as several geometry column can be chosen (or with a 
    different default name to Geometry).
  - *wfs_latlongboundingbox* (optional): The bounding box of this
    layer in geographic coordinates in the format "lon_min lat_min
    lon_max lat_max". If it is set then MapServer will request the
    layer only when the map view overlaps that bounding box. You
    normally get this from the server's capabilities output.
  - *wfs_maxfeatures* (optional): Limit the number of GML features to
    return.  Sensible values are integers greater than 0.  If 0 is
    specified, no features will be returned.
  - *wfs_request_method* (optional): Can be set to "GET" to do a Get
    request to WFS servers that do not support Post requests.  The
    default method in MapServer is Post.
    
    .. code-block:: mapfile
    
      ...
      METADATA
        "wfs_request_method"   "GET"
      END
      ...

  - *wfs_typename* (required): the <Name> of the layer found in the
    GetCapabilities.  An example GetCapabilities request is:
    `https://demo.mapserver.org/cgi-bin/wfs?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities`__
    
    __ https://demo.mapserver.org/cgi-bin/wfs?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetCapabilities
  
  - *wfs_version* (required): WFS version, currently "1.0.0"
  
.. Note:: Each of the above metadata can also be referred to as
          'ows_*' instead of 'wfs_*'.  MapServer tries the 'wfs_*'
          metadata first, and if not found it tries the corresponding
          'ows_*' name.  Using this reduces the amount of duplication
          in mapfiles that support multiple OGC interfaces since
          "ows_*" metadata can be used almost everywhere for common
          metadata items shared by multiple OGC interfaces.
          
Optional Layer Parameters and Metadata
**************************************

- **"wfs_auth_username" metadata**
  - msEncrypt-style authorization string.  Empty strings are also
  accepted.

  .. code-block:: mapfile

    METADATA
      "wfs_auth_username" "foo"
      "wfs_auth_password" "{FF88CFDAAE1A5E33}"
    END

- **"wfs_auth_type" metadata**
  - Authorization type.  Supported types include:

    - basic
    - digest
    - ntlm
    - any (the underlying http library picks the best among the
      options supported by the remote server)
    - anysafe (the underlying http library picks only safe methods
      among the options supported by the remote server)

  .. code-block:: mapfile

    METADATA
      "wfs_auth_type" "ntlm"
    END

- **"wfs_connectiontimeout" metadata** 

  - the maximum time to wait for a remote WFS layer to load, set in
    seconds (default is 30 seconds). This metadata can be added at the
    layer level so that it affects only that layer, or it can be added
    at the map level (in the web object) so that it affects all of the
    layers.  Note that wfs_connectiontimeout at the layer level has
    priority over the map level.

  .. code-block:: mapfile

    METADATA
      ...
      "wfs_connectiontimeout" "60"
      ...
    END  

- **"wfs_proxy_auth_type" metadata**
  - the authorization type to use for a proxy connection.  Supported
  types include:

    - basic
    - digest
    - ntlm
    - any (the underlying http library picks the best among the
      opotions supported by the remote server)
    - anysafe (the underlying http library picks only safe methods
      among the options supported by the remote server)

  .. code-block:: mapfile

    METADATA
      "wfs_proxy_auth_type" "ntlm"
    END 

- **"wfs_proxy_host" metadata**
  - the hostname of the proxy to use, in "dot-quad" format, with an
  optional port component (e.g. '192.168.2.10:8080').

  .. code-block:: mapfile

    METADATA
      "wfs_proxy_host" "192.168.2.10"
    END 

- **"wfs_proxy_port" metadata**
  - the port to use for a proxy connection.

  .. code-block:: mapfile

    METADATA
      "wfs_proxy_port" "8080"
    END   

- **"wfs_proxy_type" metadata**
  - the type of the proxy connection.  Valid values are 'http' and
  'socks5', which are case sensitive.

  .. code-block:: mapfile

    METADATA
      "wfs_proxy_type" "http"
    END 

- **"wfs_proxy_username" metadata**
  - msEncrypt-style string for a proxy connection.  Empty strings are
  also accepted.

  .. code-block:: mapfile

    METADATA
      "wfs_proxy_username" "foo"
      "wfs_proxy_password" "{FF88CFDAAE1A5E33}"
    END 
          
Example WFS Layer
-----------------

.. code-block:: mapfile

    LAYER
      NAME "continents"
      TYPE POLYGON
      STATUS ON
      CONNECTION "https://demo.mapserver.org/cgi-bin/wfs?"
      CONNECTIONTYPE WFS
      METADATA
        "wfs_typename"          "continents"
        "wfs_version"           "1.0.0"
        "wfs_connectiontimeout" "60"
        "wfs_maxfeatures"       "10"
      END
      PROJECTION
        "init=epsg:4326"
      END
      CLASS
        NAME "Continents"
        STYLE
	  COLOR 255 128 128
	  OUTLINECOLOR 96 96 96 
        END
      END
    END # Layer
    
Connection - deprecated
-----------------------

As of MapServer v4.4 the method of specifying all of the connection
information in the CONNECTION parameter has beendeprecated.  The
preferred method is mentioned above.  If the metadata is not provided,
VERSION, SERVICE, and TYPENAME will be fetched from the CONNECTION, as
shown below

.. code-block:: mapfile

    CONNECTION    "https://demo.mapserver.org/cgi-bin/wfs?SERVICE=WFS&VERSION=1.0.0&TYPENAME=continents"
    
TODO / Known Limitations
========================

1. Temporary WFS (gml) files are written to the IMAGEPATH directory,
   but this could become a security concern since it makes the raw GML
   data downloadable by someone who could guess the gml filename.  We
   should consider having a "wfs_cache_dir" metadata that, if it is
   set will define a directory where temp files should be written.
   The default would still be to use the value of IMAGEPATH if
   "wfs_tmpdir" is not set.
