29
29
import io .cloudevents .http .HttpMessageFactory ;
30
30
import java .io .BufferedReader ;
31
31
import java .io .IOException ;
32
+ import java .io .InputStreamReader ;
32
33
import java .io .Reader ;
33
34
import java .lang .reflect .Type ;
35
+ import java .nio .charset .StandardCharsets ;
34
36
import java .time .OffsetDateTime ;
35
37
import java .time .format .DateTimeFormatter ;
36
38
import java .util .ArrayList ;
37
39
import java .util .Arrays ;
38
- import java .util .Collections ;
39
40
import java .util .List ;
40
41
import java .util .Map ;
42
+ import java .util .Objects ;
41
43
import java .util .Optional ;
42
44
import java .util .TreeMap ;
43
45
import java .util .logging .Level ;
44
46
import java .util .logging .Logger ;
45
- import javax .servlet .http .HttpServlet ;
46
- import javax .servlet .http .HttpServletRequest ;
47
- import javax .servlet .http .HttpServletResponse ;
47
+ import org .eclipse .jetty .http .HttpField ;
48
+ import org .eclipse .jetty .http .HttpHeader ;
49
+ import org .eclipse .jetty .http .HttpStatus ;
50
+ import org .eclipse .jetty .io .Content ;
51
+ import org .eclipse .jetty .server .Handler ;
52
+ import org .eclipse .jetty .server .Request ;
53
+ import org .eclipse .jetty .server .Response ;
54
+ import org .eclipse .jetty .util .Callback ;
48
55
49
56
/** Executes the user's background function. */
50
- public final class BackgroundFunctionExecutor extends HttpServlet {
57
+ public final class BackgroundFunctionExecutor extends Handler . Abstract {
51
58
private static final Logger logger = Logger .getLogger ("com.google.cloud.functions.invoker" );
52
59
53
60
private final FunctionExecutor <?> functionExecutor ;
@@ -175,8 +182,10 @@ static Optional<Type> backgroundFunctionTypeArgument(
175
182
.findFirst ();
176
183
}
177
184
178
- private static Event parseLegacyEvent (HttpServletRequest req ) throws IOException {
179
- try (BufferedReader bodyReader = req .getReader ()) {
185
+ private static Event parseLegacyEvent (Request req ) throws IOException {
186
+ try (BufferedReader bodyReader = new BufferedReader (
187
+ new InputStreamReader (Content .Source .asInputStream (req ),
188
+ Objects .requireNonNullElse (Request .getCharset (req ), StandardCharsets .ISO_8859_1 )))) {
180
189
return parseLegacyEvent (bodyReader );
181
190
}
182
191
}
@@ -223,7 +232,7 @@ private static Context contextFromCloudEvent(CloudEvent cloudEvent) {
223
232
* for the various triggers. CloudEvents are ones that follow the standards defined by <a
224
233
* href="https://cloudevents.io">cloudevents.io</a>.
225
234
*
226
- * @param <CloudEventDataT> the type to be used in the {@link Unmarshallers} call when
235
+ * @param <CloudEventDataT> the type to be used in the {code Unmarshallers} call when
227
236
* unmarshalling this event, if it is a CloudEvent.
228
237
*/
229
238
private abstract static class FunctionExecutor <CloudEventDataT > {
@@ -320,20 +329,23 @@ void serviceCloudEvent(CloudEvent cloudEvent) throws Exception {
320
329
321
330
/** Executes the user's background function. This can handle all HTTP methods. */
322
331
@ Override
323
- public void service ( HttpServletRequest req , HttpServletResponse res ) throws IOException {
324
- String contentType = req .getContentType ( );
332
+ public boolean handle ( Request req , Response res , Callback callback ) throws Exception {
333
+ String contentType = req .getHeaders (). get ( HttpHeader . CONTENT_TYPE );
325
334
try {
326
335
if ((contentType != null && contentType .startsWith ("application/cloudevents+json" ))
327
- || req .getHeader ("ce-specversion" ) != null ) {
336
+ || req .getHeaders (). get ("ce-specversion" ) != null ) {
328
337
serviceCloudEvent (req );
329
338
} else {
330
339
serviceLegacyEvent (req );
331
340
}
332
- res .setStatus (HttpServletResponse .SC_OK );
341
+ res .setStatus (HttpStatus .OK_200 );
342
+ callback .succeeded ();
333
343
} catch (Throwable t ) {
334
- res .setStatus (HttpServletResponse .SC_INTERNAL_SERVER_ERROR );
335
344
logger .log (Level .SEVERE , "Failed to execute " + functionExecutor .functionName (), t );
345
+ res .setStatus (HttpStatus .INTERNAL_SERVER_ERROR_500 );
346
+ callback .succeeded ();
336
347
}
348
+ return true ;
337
349
}
338
350
339
351
private enum CloudEventKind {
@@ -347,10 +359,11 @@ private enum CloudEventKind {
347
359
* @param <CloudEventT> a fake type parameter, which corresponds to the type parameter of {@link
348
360
* FunctionExecutor}.
349
361
*/
350
- private <CloudEventT > void serviceCloudEvent (HttpServletRequest req ) throws Exception {
362
+ private <CloudEventT > void serviceCloudEvent (Request req ) throws Exception {
351
363
@ SuppressWarnings ("unchecked" )
352
364
FunctionExecutor <CloudEventT > executor = (FunctionExecutor <CloudEventT >) functionExecutor ;
353
- byte [] body = req .getInputStream ().readAllBytes ();
365
+
366
+ byte [] body = Content .Source .asByteArrayAsync (req , -1 ).get ();
354
367
MessageReader reader = HttpMessageFactory .createReaderFromMultimap (headerMap (req ), body );
355
368
// It's important not to set the context ClassLoader earlier, because MessageUtils will use
356
369
// ServiceLoader.load(EventFormat.class) to find a handler to deserialize a binary CloudEvent
@@ -364,17 +377,16 @@ private <CloudEventT> void serviceCloudEvent(HttpServletRequest req) throws Exce
364
377
// https://github.com/cloudevents/sdk-java/pull/259.
365
378
}
366
379
367
- private static Map <String , List <String >> headerMap (HttpServletRequest req ) {
380
+ private static Map <String , List <String >> headerMap (Request req ) {
368
381
Map <String , List <String >> headerMap = new TreeMap <>(String .CASE_INSENSITIVE_ORDER );
369
- for (String header : Collections .list (req .getHeaderNames ())) {
370
- for (String value : Collections .list (req .getHeaders (header ))) {
371
- headerMap .computeIfAbsent (header , unused -> new ArrayList <>()).add (value );
372
- }
382
+ for (HttpField field : req .getHeaders ()) {
383
+ headerMap .computeIfAbsent (field .getName (), unused -> new ArrayList <>())
384
+ .addAll (field .getValueList ());
373
385
}
374
386
return headerMap ;
375
387
}
376
388
377
- private void serviceLegacyEvent (HttpServletRequest req ) throws Exception {
389
+ private void serviceLegacyEvent (Request req ) throws Exception {
378
390
Event event = parseLegacyEvent (req );
379
391
runWithContextClassLoader (() -> functionExecutor .serviceLegacyEvent (event ));
380
392
}
0 commit comments