Skip to content

SparkJava request.body() consumes payload in first defined before() filter #373

Open
@balodza

Description

@balodza

To help us debug your issue fill in the basic information below using the options provided

Serverless Java Container version: 1.5.1

Implementations: Spark

Framework version: 2.9.2

Frontend service: REST API

Deployment method: Lambda, Request is sent with AwsProxyRequest

Scenario

Previously we were using combination : SparkJava 2.9.2 + AwsServerless 1.3.1 and everything was working fine.
Just few days ago we tried to upgrade AwsServerless to 1.5.1 and noticed that POST works incorrectly.

Expected behavior

request.body() should be available for getting any number of times in filters, handlers.
It was working fine in 1.3.1

Actual behavior

request.body() returns value only in first specified filter. Then it returns "" (empty String)
It stopped working after we updated to 1.5.1

Steps to reproduce

To reproduce the issue, simply run RequestStreamLambdaHandler.main() with no any prerequisites.
Just check the version in build.gradle before debug.

apply plugin: 'java'
apply plugin: 'idea'

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.sparkjava:spark-core:2.9.2'
    //compile 'com.amazonaws.serverless:aws-serverless-java-container-spark:1.3.1'
    compile 'com.amazonaws.serverless:aws-serverless-java-container-spark:1.5.1'
}

RequestStreamLambdaHandler.java

package hello;

import com.amazonaws.serverless.exceptions.ContainerInitializationException;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.spark.SparkLambdaContainerHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import spark.Request;
import spark.Response;
import spark.Spark;

import static spark.Spark.before;
import static spark.Spark.post;

public class RequestStreamLambdaHandler implements RequestStreamHandler {
    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        SparkLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
        try {
                handler = SparkLambdaContainerHandler.getAwsProxyHandler();
                defineBaseResources();                
                Spark.awaitInitialization();
            } catch (ContainerInitializationException e) {
                return;
            }

        handler.proxyStream(inputStream, outputStream, context);
    }

    public void defineBaseResources() {
        // define base routes
        before("/*", this::beforeFilter1);
        before("/*", this::beforeFilter2);
        before("/*", this::beforeFilter3);
        
        post("/post-request", this::handlePost);        
    }

    private Request handlePost(Request req, Response res) {
        System.out.println("POST Handler Request Body: " + req.body());
        return req;
    }

    protected void beforeFilter1(Request req, Response res) {
        System.out.println("Filter 1 Request Body: " + req.body());
    }

    protected void beforeFilter2(Request req, Response res) {
        System.out.println("Filter 2 Request Body: " + req.body());
    }

    protected void beforeFilter3(Request req, Response res) {
        System.out.println("Filter 3 Request Body: " + req.body());
    }

    public static void main(String[] args) throws Exception {
        String body = "{\"path\": \"/post-request\","
                + "    \"httpMethod\": \"POST\","
                + "    \"requestContext\": {"
                + "        \"identity\": {}"              
                + "    },"
                + "    \"body\":\"{\\\"field1\\\":\\\"value1\\\"}\""                
                + "}";
        
        
        RequestStreamLambdaHandler handler = new RequestStreamLambdaHandler();
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        handler.handleRequest(new ByteArrayInputStream(body.getBytes()), baos, null);
    }
}

Full log output

Paste the full log output from the Lambda function's CloudWatch logs

Log while 1.3.1 is used :

> Task :RequestStreamLambdaHandler.main()
Filter 1 Request Body: {"field1":"value1"}
Filter 2 Request Body: {"field1":"value1"}
Filter 3 Request Body: {"field1":"value1"}
POST Handler Request Body: {"field1":"value1"}

Log while 1.5.1 is used :

> Task :RequestStreamLambdaHandler.main()
Filter 1 Request Body: {"field1":"value1"}
Filter 2 Request Body: 
Filter 3 Request Body: 
POST Handler Request Body: 

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions