Skip to content

Commit

Permalink
[Maps] fix vector tile URL not properly encoded (#126208)
Browse files Browse the repository at this point in the history
* [Maps] fix vector tile URL not properly encoded

* clean up variable name

* tslint

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
nreese and kibanamachine authored Feb 23, 2022
1 parent bc35610 commit 548edca
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 19 deletions.
40 changes: 40 additions & 0 deletions x-pack/plugins/maps/common/mvt_request_body.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { decodeMvtResponseBody, encodeMvtResponseBody } from './mvt_request_body';

test('Should encode shape into URI safe string and decode back to original shape', () => {
const searchRequest = {
docvalue_fields: [],
size: 10000,
_source: false,
script_fields: {},
stored_fields: ['geopoint'],
runtime_mappings: {
'day of week': {
type: 'keyword',
script: {
source:
"ZonedDateTime input = doc['ISSUE_DATE'].value;\nString output = input.format(DateTimeFormatter.ofPattern('e')) + ' ' + input.format(DateTimeFormatter.ofPattern('E'));\nemit(output);",
},
},
},
query: {
bool: {
must: [],
filter: [],
should: [],
must_not: [],
},
},
};
const encodedSearchRequest = encodeMvtResponseBody(searchRequest);
expect(encodedSearchRequest).toBe(
`(_source%3A!f%2Cdocvalue_fields%3A!()%2Cquery%3A(bool%3A(filter%3A!()%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A('day%20of%20week'%3A(script%3A(source%3A'ZonedDateTime%20input%20%3D%20doc%5B!'ISSUE_DATE!'%5D.value%3B%0AString%20output%20%3D%20input.format(DateTimeFormatter.ofPattern(!'e!'))%20%2B%20!'%20!'%20%2B%20input.format(DateTimeFormatter.ofPattern(!'E!'))%3B%0Aemit(output)%3B')%2Ctype%3Akeyword))%2Cscript_fields%3A()%2Csize%3A10000%2Cstored_fields%3A!(geopoint))`
);
expect(decodeMvtResponseBody(encodedSearchRequest)).toEqual(searchRequest);
});
17 changes: 17 additions & 0 deletions x-pack/plugins/maps/common/mvt_request_body.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { RisonValue } from 'rison-node';
import rison from 'rison-node';

export function decodeMvtResponseBody(encodedRequestBody: string): object {
return rison.decode(decodeURIComponent(encodedRequestBody)) as object;
}

export function encodeMvtResponseBody(unencodedRequestBody: object): string {
return encodeURIComponent(rison.encode(unencodedRequestBody as RisonValue));
}
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ describe('ESGeoGridSource', () => {
const tileUrl = await mvtGeogridSource.getTileUrl(vectorSourceRequestMeta, '1234');

expect(tileUrl).toEqual(
"rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&gridPrecision=8&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':())))&requestType=point&token=1234"
"rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&gridPrecision=8&requestBody=(foobar%3AES_DSL_PLACEHOLDER%2Cparams%3A('0'%3A('0'%3Aindex%2C'1'%3A(fields%3A()))%2C'1'%3A('0'%3Asize%2C'1'%3A0)%2C'2'%3A('0'%3Afilter%2C'1'%3A!())%2C'3'%3A('0'%3Aquery)%2C'4'%3A('0'%3Aindex%2C'1'%3A(fields%3A()))%2C'5'%3A('0'%3Aquery%2C'1'%3A(language%3AKQL%2Cquery%3A''))%2C'6'%3A('0'%3Aaggs%2C'1'%3A())))&requestType=point&token=1234"
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import React, { ReactElement } from 'react';

import { i18n } from '@kbn/i18n';
import rison from 'rison-node';
import { Feature } from 'geojson';
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { makeESBbox } from '../../../../common/elasticsearch_util';
Expand All @@ -26,6 +25,7 @@ import {
SOURCE_TYPES,
VECTOR_SHAPE_TYPE,
} from '../../../../common/constants';
import { encodeMvtResponseBody } from '../../../../common/mvt_request_body';
import { getDataSourceLabel, getDataViewLabel } from '../../../../common/i18n_getters';
import { AbstractESAggSource } from '../es_agg_source';
import { DataRequestAbortError } from '../../util/data_request';
Expand Down Expand Up @@ -447,9 +447,6 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo
const indexPattern = await this.getIndexPattern();
const searchSource = await this.makeSearchSource(searchFilters, 0);
searchSource.setField('aggs', this.getValueAggsDsl(indexPattern));
const dsl = searchSource.getSearchRequestBody();

const risonDsl = rison.encode(dsl);

const mvtUrlServicePath = getHttp().basePath.prepend(
`/${GIS_API_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`
Expand All @@ -462,7 +459,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo
?geometryFieldName=${this._descriptor.geoField}\
&index=${indexPattern.title}\
&gridPrecision=${this._getGeoGridPrecisionResolutionDelta()}\
&requestBody=${risonDsl}\
&requestBody=${encodeMvtResponseBody(searchSource.getSearchRequestBody())}\
&requestType=${requestType}\
&token=${refreshToken}`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('ESSearchSource', () => {
});
const tileUrl = await esSearchSource.getTileUrl(searchFilters, '1234');
expect(tileUrl).toBe(
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&token=1234`
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar%3AES_DSL_PLACEHOLDER%2Cparams%3A('0'%3A('0'%3Aindex%2C'1'%3A(fields%3A()%2Ctitle%3A'foobar-title-*'))%2C'1'%3A('0'%3Asize%2C'1'%3A1000)%2C'2'%3A('0'%3Afilter%2C'1'%3A!())%2C'3'%3A('0'%3Aquery)%2C'4'%3A('0'%3Aindex%2C'1'%3A(fields%3A()%2Ctitle%3A'foobar-title-*'))%2C'5'%3A('0'%3Aquery%2C'1'%3A(language%3AKQL%2Cquery%3A'tooltipField%3A%20foobar'))%2C'6'%3A('0'%3AfieldsFromSource%2C'1'%3A!(tooltipField%2CstyleField))%2C'7'%3A('0'%3Asource%2C'1'%3A!(tooltipField%2CstyleField))))&token=1234`
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import _ from 'lodash';
import React, { ReactElement } from 'react';
import rison from 'rison-node';
import { i18n } from '@kbn/i18n';
import { GeoJsonProperties, Geometry, Position } from 'geojson';
import { type Filter, buildPhraseFilter } from '@kbn/es-query';
Expand All @@ -27,6 +26,7 @@ import {
PreIndexedShape,
TotalHits,
} from '../../../../common/elasticsearch_util';
import { encodeMvtResponseBody } from '../../../../common/mvt_request_body';
// @ts-expect-error
import { UpdateSourceEditor } from './update_source_editor';
import {
Expand Down Expand Up @@ -836,17 +836,14 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
searchSource.setField('sort', this._buildEsSort());
}

const dsl = searchSource.getSearchRequestBody();
const risonDsl = rison.encode(dsl);

const mvtUrlServicePath = getHttp().basePath.prepend(
`/${GIS_API_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`
);

return `${mvtUrlServicePath}\
?geometryFieldName=${this._descriptor.geoField}\
&index=${indexPattern.title}\
&requestBody=${risonDsl}\
&requestBody=${encodeMvtResponseBody(searchSource.getSearchRequestBody())}\
&token=${refreshToken}`;
}

Expand Down
10 changes: 3 additions & 7 deletions x-pack/plugins/maps/server/mvt/mvt_routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 2.0.
*/

import rison from 'rison-node';
import { Stream } from 'stream';
import { schema } from '@kbn/config-schema';
import { CoreStart, KibanaRequest, KibanaResponseFactory, Logger } from 'src/core/server';
Expand All @@ -17,6 +16,7 @@ import {
MVT_GETGRIDTILE_API_PATH,
RENDER_AS,
} from '../../common/constants';
import { decodeMvtResponseBody } from '../../common/mvt_request_body';
import { getEsTile } from './get_tile';
import { getEsGridTile } from './get_grid_tile';

Expand Down Expand Up @@ -57,8 +57,6 @@ export function initMVTRoutes({

const abortController = makeAbortController(request);

const requestBodyDSL = rison.decode(query.requestBody as string);

const gzippedTile = await getEsTile({
url: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`,
core,
Expand All @@ -69,7 +67,7 @@ export function initMVTRoutes({
y: parseInt((params as any).y, 10) as number,
z: parseInt((params as any).z, 10) as number,
index: query.index as string,
requestBody: requestBodyDSL as any,
requestBody: decodeMvtResponseBody(query.requestBody as string) as any,
abortController,
});

Expand Down Expand Up @@ -105,8 +103,6 @@ export function initMVTRoutes({

const abortController = makeAbortController(request);

const requestBodyDSL = rison.decode(query.requestBody as string);

const gzipTileStream = await getEsGridTile({
url: `${API_ROOT_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`,
core,
Expand All @@ -117,7 +113,7 @@ export function initMVTRoutes({
y: parseInt((params as any).y, 10) as number,
z: parseInt((params as any).z, 10) as number,
index: query.index as string,
requestBody: requestBodyDSL as any,
requestBody: decodeMvtResponseBody(query.requestBody as string) as any,
requestType: query.requestType as RENDER_AS.POINT | RENDER_AS.GRID,
gridPrecision: parseInt(query.gridPrecision, 10),
abortController,
Expand Down

0 comments on commit 548edca

Please sign in to comment.