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 5c1c1cea9b50c..34cdc6062b835 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({ requestType: RENDER_AS.GRID | RENDER_AS.POINT; gridPrecision: number; abortController: AbortController; -}): Promise { +}): Promise<{ stream: Stream | null; headers?: IncomingHttpHeaders }> { try { const path = `/${encodeURIComponent(index)}/_mvt/${geometryFieldName}/${z}/${x}/${y}`; const body = { @@ -78,13 +79,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 c79b127d70874..bf9cecad8b168 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}`; @@ -79,13 +80,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 5fdaea9ab66df..3f279f156d341 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,