All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.amazon.lambda.runtime.MockRestEventServer Maven / Gradle / Ivy

package io.quarkus.amazon.lambda.runtime;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;

import io.quarkus.amazon.lambda.http.model.ApiGatewayRequestIdentity;
import io.quarkus.amazon.lambda.http.model.AwsProxyRequest;
import io.quarkus.amazon.lambda.http.model.AwsProxyRequestContext;
import io.quarkus.amazon.lambda.http.model.AwsProxyResponse;
import io.quarkus.amazon.lambda.http.model.Headers;
import io.quarkus.amazon.lambda.http.model.MultiValuedTreeMap;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.RoutingContext;

public class MockRestEventServer extends MockEventServer {
    public static final String CONTINUE = "100-continue";

    private final ObjectWriter eventWriter;
    private final ObjectReader responseReader;

    public MockRestEventServer() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        eventWriter = objectMapper.writerFor(AwsProxyRequest.class);
        responseReader = objectMapper.readerFor(AwsProxyResponse.class);
    }

    @Override
    protected void defaultHandlerSetup() {
        router.route().handler(this::handleHttpRequests);
    }

    public void handleHttpRequests(RoutingContext ctx) {
        String requestId = ctx.request().getHeader(AmazonLambdaApi.LAMBDA_RUNTIME_AWS_REQUEST_ID);
        if (requestId == null) {
            requestId = UUID.randomUUID().toString();
        }
        ctx.put(AmazonLambdaApi.LAMBDA_RUNTIME_AWS_REQUEST_ID, requestId);
        String traceId = ctx.request().getHeader(AmazonLambdaApi.LAMBDA_RUNTIME_AWS_REQUEST_ID);
        if (traceId == null) {
            traceId = UUID.randomUUID().toString();
        }
        ctx.put(AmazonLambdaApi.LAMBDA_TRACE_HEADER_KEY, traceId);
        Buffer body = ctx.getBody();

        AwsProxyRequest event = new AwsProxyRequest();
        event.setRequestContext(new AwsProxyRequestContext());
        event.getRequestContext().setRequestId(requestId);
        event.getRequestContext().setHttpMethod(ctx.request().method().name());
        event.getRequestContext().setIdentity(new ApiGatewayRequestIdentity());
        event.getRequestContext().getIdentity().setSourceIp(ctx.request().connection().remoteAddress().hostAddress());
        event.setHttpMethod(ctx.request().method().name());
        event.setPath(ctx.request().path());
        if (ctx.request().query() != null) {
            event.setMultiValueQueryStringParameters(new MultiValuedTreeMap<>());
            String[] params = ctx.request().query().split("&");
            for (String param : params) {
                if (param.contains("=")) {
                    String[] keyval = param.split("=");
                    try {
                        String value = "";

                        if (keyval.length == 2) {
                            value = URLDecoder.decode(keyval[1], StandardCharsets.UTF_8.name());
                        }

                        event.getMultiValueQueryStringParameters().add(
                                URLDecoder.decode(keyval[0], StandardCharsets.UTF_8.name()),
                                value);
                    } catch (UnsupportedEncodingException e) {
                        log.error("Failed to parse query string", e);
                        ctx.response().setStatusCode(400).end();
                        return;
                    }
                }
            }

        }
        if (ctx.request().headers() != null) {
            event.setMultiValueHeaders(new Headers());
            for (String header : ctx.request().headers().names()) {
                if (header.equalsIgnoreCase("Expect")) {
                    String expect = ctx.request().getHeader("Expect");
                    if (expect != null && expect.equalsIgnoreCase(CONTINUE)) {
                        continue;
                    }
                }
                List values = ctx.request().headers().getAll(header);
                for (String val : values)
                    event.getMultiValueHeaders().add(header, val);
            }
        }
        if (body != null) {
            String ct = ctx.request().getHeader("content-type");
            if (ct == null || isBinary(ct)) {
                String encoded = Base64.getEncoder().encodeToString(body.getBytes());
                event.setBody(encoded);
                event.setIsBase64Encoded(true);
            } else {
                event.setBody(new String(body.getBytes(), StandardCharsets.UTF_8));
            }
        }

        try {
            byte[] mEvent = eventWriter.writeValueAsBytes(event);
            ctx.put(AwsProxyRequest.class.getName(), mEvent);
            log.debugf("Putting message %s into the queue", requestId);
            queue.put(ctx);
        } catch (Exception e) {
            log.error("Publish failure", e);
            ctx.fail(500);
        }
    }

    @Override
    protected String getEventContentType(RoutingContext request) {
        if (request.get(AwsProxyRequest.class.getName()) != null)
            return "application/json";
        return super.getEventContentType(request);
    }

    @Override
    protected Buffer processEventBody(RoutingContext request) {
        byte[] buf = request.get(AwsProxyRequest.class.getName());
        if (buf != null) {
            return Buffer.buffer(buf);
        }
        return super.processEventBody(request);
    }

    @Override
    public void processResponse(RoutingContext ctx, RoutingContext pending, Buffer buffer) {
        if (pending.get(AwsProxyRequest.class.getName()) != null) {
            try {
                AwsProxyResponse res = responseReader.readValue(buffer.getBytes());
                HttpServerResponse response = pending.response();
                if (res.getMultiValueHeaders() != null) {
                    for (Map.Entry> header : res.getMultiValueHeaders().entrySet()) {
                        for (String val : header.getValue()) {
                            response.headers().add(header.getKey(), val);
                        }
                    }
                }
                response.setStatusCode(res.getStatusCode());
                String body = res.getBody();
                if (body != null) {
                    if (res.isBase64Encoded()) {
                        byte[] bytes = Base64.getDecoder().decode(body);
                        response.end(Buffer.buffer(bytes));
                    } else {
                        response.end(body);
                    }
                } else {
                    response.end();
                }

            } catch (IOException e) {
                log.error("Publish failure", e);
                pending.fail(500);
            }
        } else {
            super.processResponse(ctx, pending, buffer);
        }
    }

    private boolean isBinary(String contentType) {
        if (contentType != null) {
            String ct = contentType.toLowerCase(Locale.ROOT);
            return !(ct.startsWith("text") || ct.contains("json") || ct.contains("xml") || ct.contains("yaml"));
        }
        return false;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy