OpenLayers OpenLayers

Ticket #491 (closed bug: fixed)

Opened 1 year ago

Last modified 1 year ago

improper URL encoding of LAYERS list in WMS GetMap request

Reported by: openlayers Assigned to:
Priority: minor Milestone: 2.3 Release
Component: Layer.WMS Version: 2.3 RC2
Keywords: GetMap LAYERS list comma URL encoding Cc:
State:

Description

There is in an issue in the way layer lists and style lists are encoded during a WMS GetMap request. Currently, the following code (as in the overviewmap.html example):

    var nasa_wms = new OpenLayers.Layer.WMS( "NASA Global Mosaic",
        "http://wms.jpl.nasa.gov/wms.cgi", {layers: "modis,global_mosaic"} );

generates the following LAYERS parameter in the resulting GetMap requests:

    LAYERS=modis%2Cglobal_mosaic

That is, it URL-encodes the comma. However, this way of encoding does not provide the ability to distinguish between item-separation commas and commas within layer names.

The Web Map Service Implementation Specification version 1.3.0 states:

6.3.2 Reserved characters in HTTP GET URLs

The URL specification (IETF RFC 2396) reserves particular characters as significant and requires that these be escaped when they might conflict with their defined usage. This International Standard explicitly reserves several of those characters for use in the query portion of WMS requests. When the characters '&', '=', ',' and '+' appear in one of the roles defined in Table 1, they shall appear literally in the URL. When those characters appear elsewhere (for example, in the value of a parameter), they shall be encoded as defined in IETF RFC 2396.

Table 1 -- Reserved Characters in WMS Query String

Character Reserved Usage
? Separator indicating start of query string.
& Separator between parameters in query string.
= Separator between name and value of parameter.
, Separator between individual values in list-oriented parameters (such as BBOX, LAYERS and STYLES in the GetMap request).
+ Shorthand representation for a space character.

6.8.2 Parameter lists

Parameters consisting of lists (for example, BBOX, LAYERS and STYLES in WMS GetMap) shall use the comma (",") as the separator between items in the list. Additional white space shall not be used to delimit list items. If a list item value includes a space or comma, it shall be escaped using the URL encoding rules (6.3.2 and IETF RFC 2396).

In other words, the individual layer names (including any commas in the layer names) must be URL-encoded, but the item-separation commas must remain literal. This allows the server to distinguish between item-separating commas and commas within layer names.

That is, the layer list in the above example should be encoded as:

    LAYERS=modis,global_mosaic

Note that this is not at odds with the HTTP URL specification. Section 3.4 of RFC2396 states that the "," character (among others) is a reserved character in the query component of an HTTP URL. It specifically doesn't state what the character is reserved for, allowing individual applications to reserve it for whatever purpose they see fit. The obvious reserved use of a comma is to separate list items, and this is what the WMS specification makes explicit.

The above NASA Global Mosaic example works because that particular server doesn't strictly follow the WMS specification. It decodes the whole value of the LAYERS parameter as a string, and then parses out the comma-separated items. Note, however, that servers that do this will continue to work if the encoding of these list parameters is done as per the WMS specification. But servers that correctly decode the LAYERS parameter as per the WMS specification will not work with layer lists as currently generated by OpenLayers.

I believe changing the OpenLayers.Util.getParameterString() function from:

    OpenLayers.Util.getParameterString = function(params) {
      paramsArray = new Array();

      for (var key in params) {
        var value = params[key];
        if ((value != null) && (typeof value != 'function')) {
            paramsArray.push(encodeURIComponent(key) + "=" +
                             encodeURIComponent(value));
          }
      }

      return paramsArray.join("&");
    };

to:

    OpenLayers.Util.getParameterString = function(params) {
      paramsArray = new Array();

      for (var key in params) {
        var value = params[key];
        if ((value != null) && (typeof value != 'function')) {
          var encodedValue;
          if (typeof value == 'object' && value.constructor == Array) {
            /* value is an array; encode items and separate with "," */
            var encodedItemArray = new Array();
            for (var itemIndex=0; itemIndex<value.length; itemIndex++) {
              encodedItemArray.push(encodeURIComponent(value[itemIndex]));
            }
            encodedValue = encodedItemArray.join(",");
          }
          else {
            /* value is a string; simply encode */
            encodedValue = encodeURIComponent(value);
          }
          paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
        }
      }

      return paramsArray.join("&");
    };

will be sufficient to do the trick. Then, the javascript code of the above example should be changed to:

    var nasa_wms = new OpenLayers.Layer.WMS( "NASA Global Mosaic",
        "http://wms.jpl.nasa.gov/wms.cgi",
        {layers: ["modis", "global_mosaic"]} );

This indicates that there are two WMS layers called "modis" and "global_mosaic" rather than a single WMS layer called "modis,global_mosaic".

Because this change is being made to the lower-level Util module, it works with any parameter whose value is a list.

You can test this change on the CubeWerx WMS at "http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi?CONFIG=simple". This server correctly decodes the LAYERS parameter as per the WMS specification, and thus will not work with layer lists as currently generated by OpenLayers.

(Note that the BBOX parameter is also being generated incorrectly by OpenLayers, for the same reason. Fixing this would either require changing the Bounds.toBBOX() function to return an array, or writing a Bounds.toBBOXArray() function.)

Please feel free to contact me if you'd like to discuss this further.

-- Keith Pomakis (pomakis@pobox,com), 2007-01-30

Attachments

491.patch (1.6 kB) - added by crschmidt on 02/16/07 14:53:59.
491.2.patch (2.9 kB) - added by crschmidt on 02/16/07 15:24:36.

Change History

(in reply to: ↑ description ) 01/30/07 15:39:37 changed by openlayers

I should have provided a live test case.

The following will not work:

    new OpenLayers.Layer.WMS( "CubeWerx",
        "http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi?CONFIG=simple", 
        {layers: "OCEANSEA_1M:Foundation,COASTL_1M:Foundation"} );

because it generates the following GetMap request parameter:

    LAYERS=OCEANSEA_1M%3AFoundation%2CCOASTL_1M%3AFoundation

which, according to the WMS specification, is a request for a single layer called "OCEANSEA_1M:Foundation,COASTL_1M:Foundation".

With the fix I have suggested, however, the following will work:

    new OpenLayers.Layer.WMS( "CubeWerx",
        "http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi?CONFIG=simple",
        {layers: ["OCEANSEA_1M:Foundation", "COASTL_1M:Foundation"]} );

because it will generate the following GetMap request parameter:

    LAYERS=OCEANSEA_1M%3AFoundation,COASTL_1M%3AFoundation

which is a request for two layers: "OCEANSEA_1M:Foundation" and "COASTL_1M:Foundation".

-- Keith Pomakis (pomakis@pobox,com), 2007-01-30

01/30/07 15:43:12 changed by openlayers

Argh, there is a (barely noticable) typo in my e-mail address. I can be contacted at "pomakis@pobox.com".

02/16/07 14:48:37 changed by crschmidt

  • milestone set to 2.3 Release.

02/16/07 14:53:59 changed by crschmidt

  • attachment 491.patch added.

02/16/07 14:56:36 changed by crschmidt

  • keywords changed from GetMap LAYERS list comma URL encoding to GetMap LAYERS list comma URL encoding review.

02/16/07 15:24:36 changed by crschmidt

  • attachment 491.2.patch added.

02/16/07 15:31:36 changed by sderle

approved, please commit to trunk.

02/16/07 15:40:41 changed by crschmidt

  • keywords changed from GetMap LAYERS list comma URL encoding review to GetMap LAYERS list comma URL encoding pullup.

Committed in r2232 .

02/19/07 11:26:44 changed by euzuro

  • keywords changed from GetMap LAYERS list comma URL encoding pullup to GetMap LAYERS list comma URL encoding.
  • status changed from new to closed.
  • resolution set to fixed.