From 8f334a9182f16b013f6e46fdfdae53b59cd9e98a Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Mon, 27 Apr 2026 16:05:42 +0200 Subject: [PATCH 1/3] Restructure nominatim URL construction in order to make hostname and protocol overrideable; add tests for Nominatim --- web/client/api/__tests__/Nominatim-test.js | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 web/client/api/__tests__/Nominatim-test.js diff --git a/web/client/api/__tests__/Nominatim-test.js b/web/client/api/__tests__/Nominatim-test.js new file mode 100644 index 0000000000..ecc3bac3eb --- /dev/null +++ b/web/client/api/__tests__/Nominatim-test.js @@ -0,0 +1,167 @@ +/* + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +import Nominatim from '../Nominatim'; +import expect from 'expect'; +import axios from '../../libs/ajax'; +import MockAdapter from 'axios-mock-adapter'; + +let mockAxios; + +describe('Test Nominatim API', () => { + beforeEach(done => { + mockAxios = new MockAdapter(axios); + setTimeout(done); + }); + afterEach(done => { + mockAxios.restore(); + setTimeout(done); + }); + + describe('geocode', () => { + it('should use default host and protocol when no options provided', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('nominatim.openstreetmap.org'); + expect(config.url).toContain('https'); + } catch (e) { + done(e); + } + return [200, []]; + }); + Nominatim.geocode('Bern').then(() => done()).catch(done); + }); + + it('should use custom host from options', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('my-nominatim.example.com'); + expect(config.url).toNotContain('nominatim.openstreetmap.org'); + } catch (e) { + done(e); + } + return [200, []]; + }); + Nominatim.geocode('Bern', {host: 'my-nominatim.example.com'}).then(() => done()).catch(done); + }); + + it('should use custom protocol from options', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('http://'); + expect(config.url).toNotContain('https://'); + } catch (e) { + done(e); + } + return [200, []]; + }); + Nominatim.geocode('Bern', {protocol: 'http'}).then(() => done()).catch(done); + }); + + it('should use custom host and protocol from options', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('http://'); + expect(config.url).toContain('my-nominatim.example.com'); + } catch (e) { + done(e); + } + return [200, []]; + }); + Nominatim.geocode('Bern', { + host: 'my-nominatim.example.com', + protocol: 'http' + }).then(() => done()).catch(done); + }); + + it('should not pass host and protocol as query parameters', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toNotContain('host='); + expect(config.url).toNotContain('protocol='); + } catch (e) { + done(e); + } + return [200, []]; + }); + Nominatim.geocode('Bern', { + host: 'my-nominatim.example.com', + protocol: 'http' + }).then(() => done()).catch(done); + }); + + it('should pass other options as query parameters', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('limit=2'); + expect(config.url).toContain('polygon_geojson=1'); + } catch (e) { + done(e); + } + return [200, []]; + }); + Nominatim.geocode('Bern', {limit: 2, polygon_geojson: 1}).then(() => done()).catch(done); + }); + }); + + describe('reverseGeocode', () => { + it('should use default host and protocol when no options provided', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('nominatim.openstreetmap.org/reverse'); + expect(config.url).toContain('https'); + } catch (e) { + done(e); + } + return [200, {}]; + }); + Nominatim.reverseGeocode({lat: 46.7, lng: 7.6}).then(() => done()).catch(done); + }); + + it('should use custom host for reverse geocode', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('my-nominatim.example.com/reverse'); + expect(config.url).toNotContain('nominatim.openstreetmap.org'); + } catch (e) { + done(e); + } + return [200, {}]; + }); + Nominatim.reverseGeocode({lat: 46.7, lng: 7.6}, { + host: 'my-nominatim.example.com' + }).then(() => done()).catch(done); + }); + + it('should use custom protocol for reverse geocode', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toContain('http://'); + } catch (e) { + done(e); + } + return [200, {}]; + }); + Nominatim.reverseGeocode({lat: 46.7, lng: 7.6}, { + protocol: 'http' + }).then(() => done()).catch(done); + }); + + it('should not pass host and protocol as query parameters in reverse geocode', (done) => { + mockAxios.onGet().reply(config => { + try { + expect(config.url).toNotContain('host='); + expect(config.url).toNotContain('protocol='); + } catch (e) { + done(e); + } + return [200, {}]; + }); + Nominatim.reverseGeocode({lat: 46.7, lng: 7.6}, { + host: 'my-nominatim.example.com', + protocol: 'http' + }).then(() => done()).catch(done); + }); + }); +}); From 1f4027b41bcb3e7c679ee0a3707035d6dd2eadef Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Mon, 27 Apr 2026 16:22:07 +0200 Subject: [PATCH 2/3] Restructure nominatim URL construction in order to make hostname and protocol overrideable --- web/client/api/Nominatim.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/web/client/api/Nominatim.js b/web/client/api/Nominatim.js index 8c48c89a5f..0823c41ab7 100644 --- a/web/client/api/Nominatim.js +++ b/web/client/api/Nominatim.js @@ -1,15 +1,12 @@ /** - * Copyright 2015, GeoSolutions Sas. - * All rights reserved. - * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ import axios from '../libs/ajax'; - import urlUtil from 'url'; const DEFAULT_URL = 'nominatim.openstreetmap.org'; const DEFAULT_REVERSE_URL = 'nominatim.openstreetmap.org/reverse'; +const DEFAULT_PROTOCOL = 'https'; const defaultOptions = { format: 'json', bounded: 0, @@ -21,23 +18,24 @@ const defaultOptions = { */ const Api = { geocode: function(text, options) { - var params = Object.assign({q: text}, defaultOptions, options || {}); + const {host, protocol, ...queryOptions} = options || {}; + var params = Object.assign({q: text}, defaultOptions, queryOptions); var url = urlUtil.format({ - protocol: "https", - host: DEFAULT_URL, + protocol: protocol || DEFAULT_PROTOCOL, + host: host || DEFAULT_URL, query: params }); - return axios.get(url); // TODO the jsonp method returns .promise and .cancel method,the last can be called when user cancel the query + return axios.get(url); }, reverseGeocode: function(coords, options) { - const params = Object.assign({lat: coords.lat, lon: coords.lng}, options || {}, defaultOptions); + const {host, protocol, ...queryOptions} = options || {}; + const params = Object.assign({lat: coords.lat, lon: coords.lng}, queryOptions, defaultOptions); const url = urlUtil.format({ - protocol: "https", - host: DEFAULT_REVERSE_URL, + protocol: protocol || DEFAULT_PROTOCOL, + host: host ? host + '/reverse' : DEFAULT_REVERSE_URL, query: params }); return axios.get(url); } }; - export default Api; From bcddcdf88bb114a42bc630313c1d235bdff1daad Mon Sep 17 00:00:00 2001 From: Wolfgang Kaltz Date: Mon, 27 Apr 2026 16:25:56 +0200 Subject: [PATCH 3/3] restore copyright notice --- web/client/api/Nominatim.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/client/api/Nominatim.js b/web/client/api/Nominatim.js index 0823c41ab7..684797403a 100644 --- a/web/client/api/Nominatim.js +++ b/web/client/api/Nominatim.js @@ -1,4 +1,7 @@ /** + * Copyright 2015-2026, GeoSolutions Sas. + * All rights reserved. + * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */