• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geosolutions-it / MapStore2 / 14797665772

02 May 2025 02:55PM UTC coverage: 76.933% (-0.06%) from 76.991%
14797665772

Pull #11067

github

web-flow
Merge 99dcd7f92 into d28bf7035
Pull Request #11067: Fix #10966 basic auth for services

30858 of 48053 branches covered (64.22%)

104 of 172 new or added lines in 24 files covered. (60.47%)

3 existing lines in 3 files now uncovered.

38384 of 49893 relevant lines covered (76.93%)

35.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.09
/web/client/components/map/openlayers/plugins/WMSLayer.js
1
/*
2
 * Copyright 2017, GeoSolutions Sas.
3
 * All rights reserved.
4
 *
5
 * This source code is licensed under the BSD-style license found in the
6
 * LICENSE file in the root directory of this source tree.
7
 */
8

9
import Layers from '../../../../utils/openlayers/Layers';
10
import isNil from 'lodash/isNil';
11
import isEqual from 'lodash/isEqual';
12
import union from 'lodash/union';
13
import isArray from 'lodash/isArray';
14
import assign from 'object-assign';
15
import axios from '../../../../libs/ajax';
16
import CoordinatesUtils from '../../../../utils/CoordinatesUtils';
17
import { getProjection } from '../../../../utils/ProjectionUtils';
18
import { getConfigProp } from '../../../../utils/ConfigUtils';
19

20
import {optionsToVendorParams} from '../../../../utils/VendorParamsUtils';
21
import {/* getCredentials, */addAuthenticationToSLD, addAuthenticationParameter, getAuthenticationHeaders} from '../../../../utils/SecurityUtils';
22

23
import ImageLayer from 'ol/layer/Image';
24
import ImageWMS from 'ol/source/ImageWMS';
25
import {get} from 'ol/proj';
26
import TileLayer from 'ol/layer/Tile';
27
import TileWMS from 'ol/source/TileWMS';
28

29
import VectorTileSource from 'ol/source/VectorTile';
30
import VectorTileLayer from 'ol/layer/VectorTile';
31

32
import { isVectorFormat } from '../../../../utils/VectorTileUtils';
33
import { isValidResponse } from '../../../../utils/WMSUtils';
34
import { OL_VECTOR_FORMATS, applyStyle } from '../../../../utils/openlayers/VectorTileUtils';
35

36
import { proxySource, getWMSURLs, wmsToOpenlayersOptions, toOLAttributions, generateTileGrid } from '../../../../utils/openlayers/WMSUtils';
37

38
const loadFunction = (options, headers) => function(image, src) {
50✔
39
    // fixes #3916, see https://gis.stackexchange.com/questions/175057/openlayers-3-wms-styling-using-sld-body-and-post-request
40
    let img = image.getImage();
51✔
41
    let newSrc = proxySource(options.forceProxy, src);
50✔
42

43
    if (typeof window.btoa === 'function' && src.length >= (options.maxLengthUrl || getConfigProp('miscSettings')?.maxURLLength || Infinity)) {
50✔
44
        // GET ALL THE PARAMETERS OUT OF THE SOURCE URL**
45
        let [url, ...dataEntries] = src.split("&");
5✔
46
        url = proxySource(options.forceProxy, url);
5✔
47

48
        // SET THE PROPER HEADERS AND FINALLY SEND THE PARAMETERS
49
        axios.post(url, "&" + dataEntries.join("&"), {
5✔
50
            headers: {
51
                "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
52
                ...headers
53
            },
54
            responseType: 'arraybuffer'
55
        }).then(response => {
56
            if (response.status === 200) {
5!
57
                const uInt8Array = new Uint8Array(response.data);
5✔
58
                let i = uInt8Array.length;
5✔
59
                const binaryString = new Array(i);
5✔
60
                while (i--) {
5✔
61
                    binaryString[i] = String.fromCharCode(uInt8Array[i]);
×
62
                }
63
                const dataImg = binaryString.join('');
5✔
64
                const type = response.headers['content-type'];
5✔
65
                if (type.indexOf('image') === 0) {
5!
66
                    img.src = 'data:' + type + ';base64,' + window.btoa(dataImg);
5✔
67
                }
68
            }
69
        }).catch(e => {
70
            console.error(e);
×
71
        });
72
    } else {
73
        if (headers) {
45✔
74
            axios.get(newSrc, {
4✔
75
                headers,
76
                responseType: 'blob'
77
            }).then(response => {
78
                if (isValidResponse(response)) {
4!
79
                    image.getImage().src = URL.createObjectURL(response.data);
4✔
80
                } else {
81
                    // #10701 this is needed to trigger the imageloaderror event
82
                    // in ol otherwise this event is not triggered if you assign
83
                    // the xml content of the exception to the src attribute
84
                    image.getImage().src = null;
×
85
                    console.error("error: " + response.data);
×
86
                }
87
            }).catch(e => {
88
                image.getImage().src = null;
4✔
89
                console.error(e);
4✔
90
            });
91
        } else {
92
            img.src = newSrc;
41✔
93
        }
94
    }
95
};
96

97
const createLayer = (options, map, mapId) => {
1✔
98
    // the useForElevation in wms types will be deprecated
99
    // as support for existing configuration
100
    // we can use this fallback
101
    if (options.useForElevation) {
54✔
102
        return Layers.createLayer('elevation', {
4✔
103
            ...options,
104
            provider: 'wms'
105
        }, map, mapId);
106
    }
107
    const urls = getWMSURLs(isArray(options.url) ? options.url : [options.url]);
50✔
108
    const queryParameters = wmsToOpenlayersOptions(options) || {};
50!
109
    urls.forEach(url => addAuthenticationParameter(url, queryParameters, options.securityToken));
52✔
110
    const headers = getAuthenticationHeaders(urls[0], options.securityToken, options.security);
50✔
111
    const vectorFormat = isVectorFormat(options.format);
50✔
112

113
    if (options.singleTile && !vectorFormat) {
50✔
114
        return new ImageLayer({
8✔
115
            msId: options.id,
116
            opacity: options.opacity !== undefined ? options.opacity : 1,
8✔
117
            visible: options.visibility !== false,
118
            zIndex: options.zIndex,
119
            minResolution: options.minResolution,
120
            maxResolution: options.maxResolution,
121
            source: new ImageWMS({
122
                url: urls[0],
123
                crossOrigin: options.crossOrigin,
124
                attributions: toOLAttributions(options.credits),
125
                params: queryParameters,
126
                ratio: options.ratio || 1,
15✔
127
                imageLoadFunction: loadFunction(options, headers)
128
            })
129
        });
130
    }
131
    const sourceOptions = {
42✔
132
        attributions: toOLAttributions(options.credits),
133
        urls: urls,
134
        crossOrigin: options.crossOrigin,
135
        params: queryParameters,
136
        tileGrid: generateTileGrid(options, map),
137
        tileLoadFunction: loadFunction(options, headers)
138
    };
139

140
    const wmsSource = new TileWMS({ ...sourceOptions });
42✔
141
    const layerConfig = {
42✔
142
        msId: options.id,
143
        opacity: options.opacity !== undefined ? options.opacity : 1,
42✔
144
        visible: options.visibility !== false,
145
        zIndex: options.zIndex,
146
        minResolution: options.minResolution,
147
        maxResolution: options.maxResolution
148
    };
149
    let layer;
150
    if (vectorFormat) {
42✔
151
        layer = new VectorTileLayer({
5✔
152
            ...layerConfig,
153
            source: new VectorTileSource({
154
                ...sourceOptions,
155
                format: new OL_VECTOR_FORMATS[options.format]({
156
                    layerName: '_layer_'
157
                }),
158
                tileUrlFunction: (tileCoord, pixelRatio, projection) => wmsSource.tileUrlFunction(tileCoord, pixelRatio, projection)
×
159
            })
160
        });
161
    } else {
162

163
        layer = new TileLayer({
37✔
164
            ...layerConfig,
165
            source: wmsSource
166
        });
167
    }
168
    layer.set('map', map);
42✔
169
    if (vectorFormat) {
42✔
170
        layer.set('wmsSource', wmsSource);
5✔
171
        if (options.vectorStyle) {
5✔
172
            applyStyle(options.vectorStyle, layer, map);
2✔
173
        }
174
    }
175
    return layer;
42✔
176
};
177

178
const mustCreateNewLayer = (oldOptions, newOptions) => {
1✔
179
    return (oldOptions.singleTile !== newOptions.singleTile
17✔
180
        || oldOptions.securityToken !== newOptions.securityToken
181
        || oldOptions.ratio !== newOptions.ratio
182
        // no way to remove attribution when credits are removed, so have re-create the layer is needed. Seems to be solved in OL v5.3.0, due to the ol commit 9b8232f65b391d5d381d7a99a7cd070fc36696e9 (https://github.com/openlayers/openlayers/pull/7329)
183
        || oldOptions.credits !== newOptions.credits && !newOptions.credits
184
        || isVectorFormat(oldOptions.format) !== isVectorFormat(newOptions.format)
185
        || isVectorFormat(oldOptions.format) && isVectorFormat(newOptions.format) && oldOptions.format !== newOptions.format
186
        || oldOptions.localizedLayerStyles !== newOptions.localizedLayerStyles
187
        || oldOptions.tileSize !== newOptions.tileSize
188
        || oldOptions.forceProxy !== newOptions.forceProxy
189
        || oldOptions.tileGridStrategy !== newOptions.tileGridStrategy
190
        || !isEqual(oldOptions.tileGrids, newOptions.tileGrids)
191
    );
192
};
193

194
Layers.registerType('wms', {
1✔
195
    create: createLayer,
196
    update: (layer, newOptions, oldOptions, map) => {
197
        const newIsVector = isVectorFormat(newOptions.format);
17✔
198

199
        if (mustCreateNewLayer(oldOptions, newOptions)) {
17✔
200
            // TODO: do we need to clean anything before re-creating stuff from scratch?
201
            return createLayer(newOptions, map);
6✔
202
        }
203
        let needsRefresh = false;
11✔
204
        if (newIsVector && newOptions.vectorStyle && !isEqual(newOptions.vectorStyle, oldOptions.vectorStyle || {})) {
11!
205
            applyStyle(newOptions.vectorStyle, layer, map);
×
206
            needsRefresh = true;
×
207
        }
208

209
        const wmsSource = layer.get('wmsSource') || layer.getSource();
11✔
210
        const vectorSource = newIsVector ? layer.getSource() : null;
11!
211

212
        if (oldOptions.srs !== newOptions.srs) {
11!
213
            const normalizedSrs = CoordinatesUtils.normalizeSRS(newOptions.srs, newOptions.allowedSRS);
×
214
            const extent = get(normalizedSrs).getExtent() || getProjection(normalizedSrs).extent;
×
215
            if (newOptions.singleTile && !newIsVector) {
×
216
                layer.setExtent(extent);
×
217
            } else {
218
                const tileGrid = generateTileGrid(newOptions, map);
×
219
                wmsSource.tileGrid = tileGrid;
×
220
                if (vectorSource) {
×
221
                    vectorSource.tileGrid = tileGrid;
×
222
                }
223
            }
224
            needsRefresh = true;
×
225
        }
226

227
        if (oldOptions.credits !== newOptions.credits && newOptions.credits) {
11✔
228
            wmsSource.setAttributions(toOLAttributions(newOptions.credits));
3✔
229
            needsRefresh = true;
3✔
230
        }
231

232
        let changed = false;
11✔
233
        let oldParams;
234
        let newParams;
235
        if (oldOptions && wmsSource && wmsSource.updateParams) {
11!
236
            if (oldOptions.params && newOptions.params) {
11✔
237
                changed = union(
4✔
238
                    Object.keys(oldOptions.params),
239
                    Object.keys(newOptions.params)
240
                ).reduce((found, param) => {
241
                    if (newOptions.params[param] !== oldOptions.params[param]) {
5✔
242
                        return true;
3✔
243
                    }
244
                    return found;
2✔
245
                }, false);
246
            } else if ((!oldOptions.params && newOptions.params) || (oldOptions.params && !newOptions.params)) {
7!
247
                changed = true;
×
248
            }
249
            oldParams = wmsToOpenlayersOptions(oldOptions);
11✔
250
            newParams = wmsToOpenlayersOptions(newOptions);
11✔
251
            changed = changed || ["LAYERS", "STYLES", "FORMAT", "TRANSPARENT", "TILED", "VERSION", "_v_", "CQL_FILTER", "SLD", "VIEWPARAMS"].reduce((found, param) => {
11✔
252
                if (oldParams[param] !== newParams[param]) {
80✔
253
                    return true;
2✔
254
                }
255
                return found;
78✔
256
            }, false);
257

258
            needsRefresh = needsRefresh || changed;
11✔
259
        }
260

261
        if (oldOptions.minResolution !== newOptions.minResolution) {
11✔
262
            layer.setMinResolution(newOptions.minResolution === undefined ? 0 : newOptions.minResolution);
1!
263
        }
264
        if (oldOptions.maxResolution !== newOptions.maxResolution) {
11✔
265
            layer.setMaxResolution(newOptions.maxResolution === undefined ? Infinity : newOptions.maxResolution);
1!
266
        }
267
        if (!isEqual(oldOptions.security, newOptions.security)) {
11!
NEW
268
            const urls = getWMSURLs(isArray(newOptions.url) ? newOptions.url : [newOptions.url]);
×
NEW
269
            const headers = getAuthenticationHeaders(urls[0], newOptions.securityToken, newOptions.security);
×
NEW
270
            wmsSource.setTileLoadFunction(loadFunction(newOptions, headers));
×
NEW
271
            wmsSource.refresh();
×
272
        }
273
        if (needsRefresh) {
11✔
274
            // forces tile cache drop
275
            // this prevents old cached tiles at lower zoom levels to be
276
            // rendered during new params load
277
            wmsSource?.tileCache?.pruneExceptNewestZ?.();
8✔
278
            if (vectorSource) {
8!
279
                vectorSource.clear();
×
280
                vectorSource.refresh();
×
281
            }
282

283
            if (changed) {
8✔
284
                const params = assign(newParams, addAuthenticationToSLD(optionsToVendorParams(newOptions) || {}, newOptions));
5✔
285

286
                wmsSource.updateParams(assign(params, Object.keys(oldParams || {}).reduce((previous, key) => {
5!
287
                    return !isNil(params[key]) ? previous : assign(previous, {
45✔
288
                        [key]: undefined
289
                    });
290
                }, {})));
291
            }
292
        }
293
        return null;
11✔
294
    }
295
});
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc