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