3030import io .cloudevents .http .HttpMessageFactory ;
3131import java .io .BufferedReader ;
3232import java .io .IOException ;
33+ import java .io .InputStreamReader ;
3334import java .io .Reader ;
3435import java .lang .reflect .Type ;
36+ import java .nio .charset .StandardCharsets ;
3537import java .time .OffsetDateTime ;
3638import java .time .format .DateTimeFormatter ;
3739import java .util .ArrayList ;
3840import java .util .Arrays ;
39- import java .util .Collections ;
4041import java .util .List ;
4142import java .util .Map ;
43+ import java .util .Objects ;
4244import java .util .Optional ;
4345import java .util .TreeMap ;
4446import java .util .logging .Level ;
4547import java .util .logging .Logger ;
46- import javax .servlet .http .HttpServlet ;
47- import javax .servlet .http .HttpServletRequest ;
48- import javax .servlet .http .HttpServletResponse ;
48+ import org .eclipse .jetty .http .HttpField ;
49+ import org .eclipse .jetty .http .HttpHeader ;
50+ import org .eclipse .jetty .http .HttpStatus ;
51+ import org .eclipse .jetty .io .Content ;
52+ import org .eclipse .jetty .server .Handler ;
53+ import org .eclipse .jetty .server .Request ;
54+ import org .eclipse .jetty .server .Response ;
55+ import org .eclipse .jetty .util .Callback ;
4956
5057/** Executes the user's background function. */
51- public final class BackgroundFunctionExecutor extends HttpServlet {
58+ public final class BackgroundFunctionExecutor extends Handler . Abstract {
5259 private static final Logger logger = Logger .getLogger ("com.google.cloud.functions.invoker" );
5360
5461 private final FunctionExecutor <?> functionExecutor ;
@@ -177,8 +184,13 @@ static Optional<Type> backgroundFunctionTypeArgument(
177184 .findFirst ();
178185 }
179186
180- private static Event parseLegacyEvent (HttpServletRequest req ) throws IOException {
181- try (BufferedReader bodyReader = req .getReader ()) {
187+ private static Event parseLegacyEvent (Request req ) throws IOException {
188+ try (BufferedReader bodyReader =
189+ new BufferedReader (
190+ new InputStreamReader (
191+ Content .Source .asInputStream (req ),
192+ Objects .requireNonNullElse (
193+ Request .getCharset (req ), StandardCharsets .ISO_8859_1 )))) {
182194 return parseLegacyEvent (bodyReader );
183195 }
184196 }
@@ -225,7 +237,7 @@ private static Context contextFromCloudEvent(CloudEvent cloudEvent) {
225237 * for the various triggers. CloudEvents are ones that follow the standards defined by <a
226238 * href="https://cloudevents.io">cloudevents.io</a>.
227239 *
228- * @param <CloudEventDataT> the type to be used in the {@link Unmarshallers} call when
240+ * @param <CloudEventDataT> the type to be used in the {code Unmarshallers} call when
229241 * unmarshalling this event, if it is a CloudEvent.
230242 */
231243 private abstract static class FunctionExecutor <CloudEventDataT > {
@@ -322,23 +334,25 @@ void serviceCloudEvent(CloudEvent cloudEvent) throws Exception {
322334
323335 /** Executes the user's background function. This can handle all HTTP methods. */
324336 @ Override
325- public void service ( HttpServletRequest req , HttpServletResponse res ) throws IOException {
326- String contentType = req .getContentType ( );
337+ public boolean handle ( Request req , Response res , Callback callback ) throws Exception {
338+ String contentType = req .getHeaders (). get ( HttpHeader . CONTENT_TYPE );
327339 try {
328340 executionIdUtil .storeExecutionId (req );
329341 if ((contentType != null && contentType .startsWith ("application/cloudevents+json" ))
330- || req .getHeader ("ce-specversion" ) != null ) {
342+ || req .getHeaders (). get ("ce-specversion" ) != null ) {
331343 serviceCloudEvent (req );
332344 } else {
333345 serviceLegacyEvent (req );
334346 }
335- res .setStatus (HttpServletResponse .SC_OK );
347+ res .setStatus (HttpStatus .OK_200 );
348+ callback .succeeded ();
336349 } catch (Throwable t ) {
337- res .setStatus (HttpServletResponse .SC_INTERNAL_SERVER_ERROR );
338350 logger .log (Level .SEVERE , "Failed to execute " + functionExecutor .functionName (), t );
351+ Response .writeError (req , res , callback , HttpStatus .INTERNAL_SERVER_ERROR_500 , null );
339352 } finally {
340353 executionIdUtil .removeExecutionId ();
341354 }
355+ return true ;
342356 }
343357
344358 private enum CloudEventKind {
@@ -352,10 +366,14 @@ private enum CloudEventKind {
352366 * @param <CloudEventT> a fake type parameter, which corresponds to the type parameter of {@link
353367 * FunctionExecutor}.
354368 */
355- private <CloudEventT > void serviceCloudEvent (HttpServletRequest req ) throws Exception {
369+ private <CloudEventT > void serviceCloudEvent (Request req ) throws Exception {
356370 @ SuppressWarnings ("unchecked" )
357371 FunctionExecutor <CloudEventT > executor = (FunctionExecutor <CloudEventT >) functionExecutor ;
358- byte [] body = req .getInputStream ().readAllBytes ();
372+
373+ // Read the entire request body into a byte array.
374+ // TODO: this method is deprecated for removal, use the method introduced by
375+ // https://github.com/jetty/jetty.project/pull/13939 when it is released.
376+ byte [] body = Content .Source .asByteArrayAsync (req , -1 ).get ();
359377 MessageReader reader = HttpMessageFactory .createReaderFromMultimap (headerMap (req ), body );
360378 // It's important not to set the context ClassLoader earlier, because MessageUtils will use
361379 // ServiceLoader.load(EventFormat.class) to find a handler to deserialize a binary CloudEvent
@@ -369,17 +387,17 @@ private <CloudEventT> void serviceCloudEvent(HttpServletRequest req) throws Exce
369387 // https://github.com/cloudevents/sdk-java/pull/259.
370388 }
371389
372- private static Map <String , List <String >> headerMap (HttpServletRequest req ) {
390+ private static Map <String , List <String >> headerMap (Request req ) {
373391 Map <String , List <String >> headerMap = new TreeMap <>(String .CASE_INSENSITIVE_ORDER );
374- for (String header : Collections . list ( req .getHeaderNames () )) {
375- for ( String value : Collections . list ( req . getHeaders ( header ))) {
376- headerMap .computeIfAbsent (header , unused -> new ArrayList <>()). add ( value );
377- }
392+ for (HttpField field : req .getHeaders ( )) {
393+ headerMap
394+ .computeIfAbsent (field . getName () , unused -> new ArrayList <>())
395+ . addAll ( field . getValueList ());
378396 }
379397 return headerMap ;
380398 }
381399
382- private void serviceLegacyEvent (HttpServletRequest req ) throws Exception {
400+ private void serviceLegacyEvent (Request req ) throws Exception {
383401 Event event = parseLegacyEvent (req );
384402 runWithContextClassLoader (() -> functionExecutor .serviceLegacyEvent (event ));
385403 }
0 commit comments