diff --git a/x-pack/plugins/maps/server/mvt/get_grid_tile.ts b/x-pack/plugins/maps/server/mvt/get_grid_tile.ts index 754fdb9c1f4d2..620971d3097dd 100644 --- a/x-pack/plugins/maps/server/mvt/get_grid_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_grid_tile.ts @@ -7,6 +7,7 @@ import { CoreStart, Logger } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; +import { IncomingHttpHeaders } from 'http'; import { Stream } from 'stream'; import { RENDER_AS } from '../../common/constants'; import { isAbortError } from './util'; @@ -40,7 +41,7 @@ export async function getEsGridTile({ renderAs: RENDER_AS; gridPrecision: number; abortController: AbortController; -}): Promise { +}): Promise<{ stream: Stream | null; headers?: IncomingHttpHeaders }> { try { const path = `/${encodeURIComponent(index)}/_mvt/${geometryFieldName}/${z}/${x}/${y}`; const body = { @@ -80,13 +81,13 @@ export async function getEsGridTile({ } ); - return tile.body as Stream; + return { stream: tile.body as Stream, headers: tile.headers }; } catch (e) { if (!isAbortError(e)) { // These are often circuit breaking exceptions // Should return a tile with some error message logger.warn(`Cannot generate ES-grid-tile for ${z}/${x}/${y}: ${e.message}`); } - return null; + return { stream: null }; } } diff --git a/x-pack/plugins/maps/server/mvt/get_tile.ts b/x-pack/plugins/maps/server/mvt/get_tile.ts index 7e9bc01c5c317..669ca7e20fc4c 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.ts @@ -7,6 +7,7 @@ import { CoreStart, Logger } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; +import { IncomingHttpHeaders } from 'http'; import { Stream } from 'stream'; import { isAbortError } from './util'; import { makeExecutionContext } from '../../common/execution_context'; @@ -36,7 +37,7 @@ export async function getEsTile({ logger: Logger; requestBody: any; abortController: AbortController; -}): Promise { +}): Promise<{ stream: Stream | null; headers?: IncomingHttpHeaders }> { try { const path = `/${encodeURIComponent(index)}/_mvt/${geometryFieldName}/${z}/${x}/${y}`; @@ -80,13 +81,13 @@ export async function getEsTile({ } ); - return tile.body as Stream; + return { stream: tile.body as Stream, headers: tile.headers }; } catch (e) { if (!isAbortError(e)) { // These are often circuit breaking exceptions // Should return a tile with some error message logger.warn(`Cannot generate ES-grid-tile for ${z}/${x}/${y}: ${e.message}`); } - return null; + return { stream: null }; } } diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index dde68bd0d1335..e5b3d69fcb3a3 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -6,6 +6,7 @@ */ import { Stream } from 'stream'; +import { IncomingHttpHeaders } from 'http'; import { schema } from '@kbn/config-schema'; import { CoreStart, KibanaRequest, KibanaResponseFactory, Logger } from 'src/core/server'; import { IRouter } from 'src/core/server'; @@ -57,7 +58,7 @@ export function initMVTRoutes({ const abortController = makeAbortController(request); - const gzippedTile = await getEsTile({ + const { stream, headers } = await getEsTile({ url: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`, core, logger, @@ -71,7 +72,7 @@ export function initMVTRoutes({ abortController, }); - return sendResponse(response, gzippedTile); + return sendResponse(response, stream, headers); } ); @@ -103,7 +104,7 @@ export function initMVTRoutes({ const abortController = makeAbortController(request); - const gzipTileStream = await getEsGridTile({ + const { stream, headers } = await getEsGridTile({ url: `${API_ROOT_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`, core, logger, @@ -119,20 +120,27 @@ export function initMVTRoutes({ abortController, }); - return sendResponse(response, gzipTileStream); + return sendResponse(response, stream, headers); } ); } -function sendResponse(response: KibanaResponseFactory, gzipTileStream: Stream | null) { +function sendResponse( + response: KibanaResponseFactory, + gzipTileStream: Stream | null, + headers?: IncomingHttpHeaders +) { const cacheControl = `public, max-age=${CACHE_TIMEOUT_SECONDS}`; const lastModified = `${new Date().toUTCString()}`; - if (gzipTileStream) { + if (gzipTileStream && headers) { + // use the content-encoding and content-length headers from elasticsearch if they exist + const { 'content-length': contentLength, 'content-encoding': contentEncoding } = headers; return response.ok({ body: gzipTileStream, headers: { 'content-disposition': 'inline', - 'content-encoding': 'gzip', + ...(contentLength && { 'content-length': contentLength }), + ...(contentEncoding && { 'content-encoding': contentEncoding }), 'Content-Type': 'application/x-protobuf', 'Cache-Control': cacheControl, 'Last-Modified': lastModified,