Skip to content

Commit 82ca81a

Browse files
authored
autoDetectCORS option for proxy config (geosolutions-it#3675)
* autoDetectCORS option for proxy config * Updated axios version to support automatic CORS detection
1 parent 9159b11 commit 82ca81a

5 files changed

Lines changed: 70 additions & 5 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
"@turf/polygon-to-linestring": "4.1.0",
8888
"ag-grid": "3.3.3",
8989
"ag-grid-react": "3.3.1",
90-
"axios": "0.11.1",
90+
"axios": "0.18.0",
9191
"b64-to-blob": "1.2.19",
9292
"babel-polyfill": "6.8.0",
9393
"babel-standalone": "6.7.7",

web/client/libs/__tests__/ajax-test.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const axios = require('../ajax');
1111
const SecurityUtils = require('../../utils/SecurityUtils');
1212
const assign = require('object-assign');
1313
const urlUtil = require('url');
14+
const MockAdapter = require("axios-mock-adapter");
15+
let mockAxios;
1416

1517
const userA = {
1618
User: {
@@ -79,6 +81,10 @@ const authenticationRules = [
7981

8082
describe('Tests ajax library', () => {
8183
afterEach(() => {
84+
if (mockAxios) {
85+
mockAxios.restore();
86+
mockAxios = null;
87+
}
8288
expect.restoreSpies();
8389
});
8490

@@ -379,7 +385,6 @@ describe('Tests ajax library', () => {
379385
it('does not set withCredentials on the request', (done)=> {
380386
expect.spyOn(SecurityUtils, 'isAuthenticationActivated').andReturn(true);
381387
expect.spyOn(SecurityUtils, 'getAuthenticationRules').andReturn(authenticationRules);
382-
383388
axios.get('http://www.skipBrowserCredentials.com/geoserver?parameter1=value1&parameter2=value2').then(() => {
384389
done();
385390
}).catch( (exception) => {
@@ -388,4 +393,42 @@ describe('Tests ajax library', () => {
388393
done();
389394
});
390395
});
396+
397+
it('does test for CORS if autoDetectCORS is true', (done) => {
398+
mockAxios = new MockAdapter(axios);
399+
mockAxios.onGet().reply(200, {}, {
400+
"allow-control-allow-origin": "*"
401+
});
402+
axios
403+
.get("http://testcors/", {
404+
proxyUrl: {
405+
url: "/proxy/?url=",
406+
useCORS: [],
407+
autoDetectCORS: true
408+
}
409+
})
410+
.then(response => {
411+
expect(response.config).toExist();
412+
expect(response.config.url).toExist();
413+
expect(response.config.url).toNotContain("proxy/?url=");
414+
done();
415+
});
416+
});
417+
418+
it('revert to proxy if autoDetectCORS is true but CORS is not enabled on server', (done) => {
419+
mockAxios = new MockAdapter(axios);
420+
axios.get('http://testcors/', {
421+
timeout: 1,
422+
proxyUrl: {
423+
url: '/proxy/?url=',
424+
useCORS: [],
425+
autoDetectCORS: true
426+
}
427+
}).catch((response) => {
428+
expect(response.config).toExist();
429+
expect(response.config.url).toExist();
430+
expect(response.config.url).toContain('proxy/?url=');
431+
done();
432+
});
433+
});
391434
});

web/client/libs/ajax.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
const axios = require('axios');
10+
const url = require('url');
1011
const ConfigUtils = require('../utils/ConfigUtils');
1112

1213
const SecurityUtils = require('../utils/SecurityUtils');
@@ -31,6 +32,8 @@ function addHeaderToAxiosConfig(axiosConfig, headerName, headerValue) {
3132
axiosConfig.headers = assign({}, axiosConfig.headers, {[headerName]: headerValue});
3233
}
3334

35+
const corsDisabled = [];
36+
3437
/**
3538
* Internal helper that will add to the axios config object the correct
3639
* authentication method based on the request URL.
@@ -107,12 +110,15 @@ axios.interceptors.request.use(config => {
107110
let proxyUrl = ConfigUtils.getProxyUrl(config);
108111
if (proxyUrl) {
109112
let useCORS = [];
113+
let autoDetectCORS = false;
110114
if (isObject(proxyUrl)) {
111115
useCORS = proxyUrl.useCORS || [];
116+
autoDetectCORS = proxyUrl.autoDetectCORS || false;
112117
proxyUrl = proxyUrl.url;
113118
}
114119
const isCORS = useCORS.reduce((found, current) => found || uri.indexOf(current) === 0, false);
115-
if (!isCORS) {
120+
const cannotUseCORS = corsDisabled.reduce((found, current) => found || uri.indexOf(current) === 0, false);
121+
if (!isCORS && (!autoDetectCORS || cannotUseCORS)) {
116122
const parsedUri = urlUtil.parse(uri, true, true);
117123
config.url = proxyUrl + encodeURIComponent(
118124
urlUtil.format(
@@ -123,10 +129,26 @@ axios.interceptors.request.use(config => {
123129
)
124130
);
125131
config.params = undefined;
132+
} else if (autoDetectCORS) {
133+
config.autoDetectCORS = true;
126134
}
127135
}
128136
}
129137
return config;
130138
});
131139

140+
axios.interceptors.response.use(response => response, (error) => {
141+
if (error.config && error.config.autoDetectCORS) {
142+
const urlParts = url.parse(error.config.url);
143+
const baseUrl = urlParts.protocol + "//" + urlParts.host + urlParts.pathname;
144+
if (corsDisabled.indexOf(baseUrl) === -1) {
145+
corsDisabled.push(baseUrl);
146+
return new Promise((resolve, reject) => {
147+
axios({ ...error.config, autoDetectCORS: false}).then(resolve).catch(reject);
148+
});
149+
}
150+
}
151+
return Promise.reject(error.response ? {...error.response, originalError: error} : error);
152+
});
153+
132154
module.exports = axios;

web/client/plugins/MetadataExplorer.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const catalogSelector = createSelector([
5151
format: newformat,
5252
newService,
5353
currentLocale,
54-
records: CatalogUtils.getCatalogRecords(selectedFormat, result, options)
54+
records: result && CatalogUtils.getCatalogRecords(selectedFormat, result, options) || []
5555
}));
5656

5757
const catalogClose = () => {

web/client/utils/SecurityUtils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const SecurityUtils = {
2727
* Gets security state form the store.
2828
*/
2929
getSecurityInfo() {
30-
return this.store.getState().security;
30+
return this.store && this.store.getState().security || {};
3131
},
3232

3333
/**

0 commit comments

Comments
 (0)