mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[elasticsearch/proxy] strip _ query string param
With elasticsearch starting to validate query string parameters, we need to stop sending the extra "_" query string paramters (used to cache-bust in browsers). The changes are larger than "necessary" because the url parsing and formatting logic was updated to use the bonafide `url.parse` and `url.format` methods, rather than a series of specialized string mutations. The tests for this code were also expanded as a part of this effort.
This commit is contained in:
parent
e78c829574
commit
d7bcab9f96
2 changed files with 109 additions and 32 deletions
|
@ -1,5 +1,6 @@
|
|||
import expect from 'expect.js';
|
||||
import mapUri from '../map_uri';
|
||||
import { get, defaults } from 'lodash';
|
||||
import sinon from 'sinon';
|
||||
|
||||
describe('plugins/elasticsearch', function () {
|
||||
|
@ -7,6 +8,16 @@ describe('plugins/elasticsearch', function () {
|
|||
|
||||
let request;
|
||||
|
||||
function stubServer(settings) {
|
||||
const values = defaults(settings || {}, {
|
||||
'elasticsearch.url': 'http://localhost:9200',
|
||||
'elasticsearch.requestHeadersWhitelist': ['authorization'],
|
||||
'elasticsearch.customHeaders': {}
|
||||
});
|
||||
const config = { get: (key, def) => get(values, key, def) };
|
||||
return { config: () => config };
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
request = {
|
||||
path: '/elasticsearch/some/path',
|
||||
|
@ -23,10 +34,9 @@ describe('plugins/elasticsearch', function () {
|
|||
});
|
||||
|
||||
it('sends custom headers if set', function () {
|
||||
const get = sinon.stub();
|
||||
get.withArgs('elasticsearch.requestHeadersWhitelist').returns([]);
|
||||
get.withArgs('elasticsearch.customHeaders').returns({ foo: 'bar' });
|
||||
const server = { config: () => ({ get }) };
|
||||
const server = stubServer({
|
||||
'elasticsearch.customHeaders': { foo: 'bar' }
|
||||
});
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
|
@ -35,10 +45,10 @@ describe('plugins/elasticsearch', function () {
|
|||
});
|
||||
|
||||
it('sends configured custom headers even if the same named header exists in request', function () {
|
||||
const get = sinon.stub();
|
||||
get.withArgs('elasticsearch.requestHeadersWhitelist').returns(['x-my-custom-header']);
|
||||
get.withArgs('elasticsearch.customHeaders').returns({'x-my-custom-header': 'asconfigured'});
|
||||
const server = { config: () => ({ get }) };
|
||||
const server = stubServer({
|
||||
'elasticsearch.requestHeadersWhitelist': ['x-my-custom-header'],
|
||||
'elasticsearch.customHeaders': {'x-my-custom-header': 'asconfigured'}
|
||||
});
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
|
@ -47,10 +57,9 @@ describe('plugins/elasticsearch', function () {
|
|||
});
|
||||
|
||||
it('only proxies the whitelisted request headers', function () {
|
||||
const get = sinon.stub();
|
||||
get.withArgs('elasticsearch.requestHeadersWhitelist').returns(['x-my-custom-HEADER', 'Authorization']);
|
||||
get.withArgs('elasticsearch.customHeaders').returns({});
|
||||
const server = { config: () => ({ get }) };
|
||||
const server = stubServer({
|
||||
'elasticsearch.requestHeadersWhitelist': ['x-my-custom-HEADER', 'Authorization'],
|
||||
});
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
|
@ -61,10 +70,9 @@ describe('plugins/elasticsearch', function () {
|
|||
});
|
||||
|
||||
it('proxies no headers if whitelist is set to []', function () {
|
||||
const get = sinon.stub();
|
||||
get.withArgs('elasticsearch.requestHeadersWhitelist').returns([]);
|
||||
get.withArgs('elasticsearch.customHeaders').returns({});
|
||||
const server = { config: () => ({ get }) };
|
||||
const server = stubServer({
|
||||
'elasticsearch.requestHeadersWhitelist': [],
|
||||
});
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
|
@ -73,10 +81,11 @@ describe('plugins/elasticsearch', function () {
|
|||
});
|
||||
|
||||
it('proxies no headers if whitelist is set to no value', function () {
|
||||
const get = sinon.stub();
|
||||
get.withArgs('elasticsearch.requestHeadersWhitelist').returns([ null ]); // This is how Joi returns it
|
||||
get.withArgs('elasticsearch.customHeaders').returns({});
|
||||
const server = { config: () => ({ get }) };
|
||||
const server = stubServer({
|
||||
// joi converts `elasticsearch.requestHeadersWhitelist: null` into
|
||||
// an array with a null inside because of the `array().single()` rule.
|
||||
'elasticsearch.requestHeadersWhitelist': [ null ],
|
||||
});
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
|
@ -84,5 +93,47 @@ describe('plugins/elasticsearch', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('strips the /elasticsearch prefix from the path', () => {
|
||||
request.path = '/elasticsearch/es/path';
|
||||
const server = stubServer();
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
expect(upstreamUri).to.be('http://localhost:9200/es/path');
|
||||
});
|
||||
});
|
||||
|
||||
it('extends the es.url path', function () {
|
||||
request.path = '/elasticsearch/index/type';
|
||||
const server = stubServer({ 'elasticsearch.url': 'https://localhost:9200/base-path' });
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
expect(upstreamUri).to.be('https://localhost:9200/base-path/index/type');
|
||||
});
|
||||
});
|
||||
|
||||
it('extends the es.url query string', function () {
|
||||
request.path = '/elasticsearch/*';
|
||||
request.query = { foo: 'bar' };
|
||||
const server = stubServer({ 'elasticsearch.url': 'https://localhost:9200/?base=query' });
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
expect(upstreamUri).to.be('https://localhost:9200/*?foo=bar&base=query');
|
||||
});
|
||||
});
|
||||
|
||||
it('filters the _ querystring param', function () {
|
||||
request.path = '/elasticsearch/*';
|
||||
request.query = { _: Date.now() };
|
||||
const server = stubServer();
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
expect(upstreamUri).to.be('http://localhost:9200/*');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,22 +1,48 @@
|
|||
import querystring from 'querystring';
|
||||
import { resolve } from 'url';
|
||||
import { defaults, omit, trimLeft, trimRight } from 'lodash';
|
||||
import { parse as parseUrl, format as formatUrl, resolve } from 'url';
|
||||
import filterHeaders from './filter_headers';
|
||||
import setHeaders from './set_headers';
|
||||
|
||||
export default function mapUri(server, prefix) {
|
||||
|
||||
const config = server.config();
|
||||
|
||||
function joinPaths(pathA, pathB) {
|
||||
return trimRight(pathA, '/') + '/' + trimLeft(pathB, '/');
|
||||
}
|
||||
|
||||
return function (request, done) {
|
||||
const path = request.path.replace('/elasticsearch', '');
|
||||
let url = config.get('elasticsearch.url');
|
||||
if (path) {
|
||||
if (/\/$/.test(url)) url = url.substring(0, url.length - 1);
|
||||
url += path;
|
||||
const {
|
||||
protocol: esUrlProtocol,
|
||||
slashes: esUrlHasSlashes,
|
||||
auth: esUrlAuth,
|
||||
hostname: esUrlHostname,
|
||||
port: esUrlPort,
|
||||
pathname: esUrlBasePath,
|
||||
query: esUrlQuery
|
||||
} = parseUrl(config.get('elasticsearch.url'), true);
|
||||
|
||||
// copy most url components directly from the elasticsearch.url
|
||||
const mappedUrlComponents = {
|
||||
protocol: esUrlProtocol,
|
||||
slashes: esUrlHasSlashes,
|
||||
auth: esUrlAuth,
|
||||
hostname: esUrlHostname,
|
||||
port: esUrlPort
|
||||
};
|
||||
|
||||
// pathname
|
||||
const reqSubPath = request.path.replace('/elasticsearch', '');
|
||||
mappedUrlComponents.pathname = joinPaths(esUrlBasePath, reqSubPath);
|
||||
|
||||
// querystring
|
||||
const mappedQuery = defaults(omit(request.query, '_'), esUrlQuery || {});
|
||||
if (Object.keys(mappedQuery).length) {
|
||||
mappedUrlComponents.query = mappedQuery;
|
||||
}
|
||||
const query = querystring.stringify(request.query);
|
||||
if (query) url += '?' + query;
|
||||
|
||||
const filteredHeaders = filterHeaders(request.headers, config.get('elasticsearch.requestHeadersWhitelist'));
|
||||
const customHeaders = setHeaders(filteredHeaders, config.get('elasticsearch.customHeaders'));
|
||||
done(null, url, customHeaders);
|
||||
const mappedHeaders = setHeaders(filteredHeaders, config.get('elasticsearch.customHeaders'));
|
||||
const mappedUrl = formatUrl(mappedUrlComponents);
|
||||
done(null, mappedUrl, mappedHeaders);
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue