-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support AWS Lambda Function URLs (#598)
* Support Lambda Http APIs Function URLS * Refactoring * Remove outPrintLn * Remove unused imports * - Local Session not working on AWS Lambda Http function. - Added UnitTests - Bump SDK version * Remove comment * Remove unneeded code * Address @iroqueta review
- Loading branch information
Showing
15 changed files
with
501 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
com.gx.serverless.test.test_services_rest | ||
com.gx.serverless.test.receivenumber_services_rest | ||
com.gx.serverless.test.sessionset_services_rest | ||
com.genexus.serverless.proxy.test.jersey.EchoJerseyResource |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
...rless/src/main/java/com/genexus/cloud/serverless/aws/handler/LambdaApplicationHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.genexus.cloud.serverless.aws.handler; | ||
|
||
import com.genexus.ApplicationContext; | ||
import com.genexus.specific.java.Connect; | ||
import com.genexus.util.IniFile; | ||
|
||
import javax.ws.rs.core.Application; | ||
|
||
public class LambdaApplicationHelper { | ||
private static final String GX_APPLICATION_CLASS = "GXApplication"; | ||
private static final String GX_APPLICATION_CONFIG = "client.cfg"; | ||
|
||
public static Application initialize() throws Exception { | ||
Connect.init(); | ||
IniFile config = com.genexus.ConfigFileFinder.getConfigFile(null, GX_APPLICATION_CONFIG, null); | ||
String className = config.getProperty("Client", "PACKAGE", null); | ||
Class<?> cls = Class.forName(className.isEmpty() ? GX_APPLICATION_CLASS : String.format("%s.%s", className, GX_APPLICATION_CLASS)); | ||
Application app = (Application) cls.getDeclaredConstructor().newInstance(); | ||
ApplicationContext appContext = ApplicationContext.getInstance(); | ||
appContext.setServletEngine(true); | ||
appContext.setServletEngineDefaultPath(""); | ||
com.genexus.Application.init(cls); | ||
return app; | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
...rverless/src/main/java/com/genexus/cloud/serverless/aws/handler/LambdaHttpApiHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package com.genexus.cloud.serverless.aws.handler; | ||
|
||
import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler; | ||
import com.amazonaws.serverless.proxy.model.AwsProxyResponse; | ||
import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; | ||
import com.amazonaws.services.lambda.runtime.Context; | ||
import com.amazonaws.services.lambda.runtime.RequestHandler; | ||
import com.genexus.cloud.serverless.aws.LambdaHandler; | ||
import com.genexus.cloud.serverless.aws.handler.internal.GxJerseyLambdaContainerHandlerFactory; | ||
import com.genexus.diagnostics.core.ILogger; | ||
import com.genexus.specific.java.LogManager; | ||
import org.glassfish.jersey.server.ResourceConfig; | ||
|
||
import java.util.Map; | ||
|
||
public class LambdaHttpApiHandler implements RequestHandler<HttpApiV2ProxyRequest, AwsProxyResponse> { | ||
private static final String BASE_REST_PATH = "/rest/"; | ||
public static JerseyLambdaContainerHandler<HttpApiV2ProxyRequest, AwsProxyResponse> handler = null; | ||
private static ILogger logger = null; | ||
private static ResourceConfig jerseyApplication = null; | ||
|
||
public LambdaHttpApiHandler() throws Exception { | ||
if (LambdaHttpApiHandler.jerseyApplication == null) { | ||
JerseyLambdaContainerHandler.getContainerConfig().setDefaultContentCharset("UTF-8"); | ||
logger = LogManager.initialize(".", LambdaHandler.class); | ||
LambdaHttpApiHandler.jerseyApplication = ResourceConfig.forApplication(LambdaApplicationHelper.initialize()); | ||
|
||
if (jerseyApplication.getClasses().size() == 0) { | ||
logger.error("No HTTP endpoints found for this application"); | ||
} | ||
|
||
handler = GxJerseyLambdaContainerHandlerFactory.getHttpApiV2ProxyHandler(LambdaHttpApiHandler.jerseyApplication); | ||
} | ||
} | ||
|
||
@Override | ||
public AwsProxyResponse handleRequest(HttpApiV2ProxyRequest awsProxyRequest, Context context) { | ||
if (logger.isDebugEnabled()) { | ||
dumpRequest(awsProxyRequest); | ||
} | ||
|
||
String path = awsProxyRequest.getRawPath(); | ||
prepareRequest(awsProxyRequest); | ||
|
||
logger.debug("Before handle Request"); | ||
|
||
awsProxyRequest.setRawPath(path.replace(BASE_REST_PATH, "/")); | ||
AwsProxyResponse response = handler.proxy(awsProxyRequest, context); | ||
|
||
int statusCode = response.getStatusCode(); | ||
logger.debug("After handle Request - Status Code: " + statusCode); | ||
|
||
if (statusCode >= 404 && statusCode <= 599) { | ||
logger.warn(String.format("Request could not be handled (%d): %s", response.getStatusCode(), path)); | ||
} | ||
return response; | ||
} | ||
|
||
private void prepareRequest(HttpApiV2ProxyRequest awsProxyRequest) { | ||
Map<String, String> headers = awsProxyRequest.getHeaders(); | ||
|
||
if (headers == null) { | ||
return; | ||
} | ||
|
||
// In Jersey lambda context, the Referer Header has a special meaning. So we copy it to another Header. | ||
String referer = headers.get("Referer"); | ||
if (referer != null && !referer.isEmpty()) { | ||
headers.put("GX-Referer", referer); | ||
} | ||
} | ||
|
||
private void dumpRequest(HttpApiV2ProxyRequest awsProxyRequest) { | ||
String lineSeparator = System.lineSeparator(); | ||
String reqData = String.format("Path: %s", awsProxyRequest.getRawPath()) + lineSeparator; | ||
reqData += String.format("Method: %s", awsProxyRequest.getRequestContext().getHttp().getMethod()) + lineSeparator; | ||
reqData += String.format("QueryString: %s", awsProxyRequest.getRawQueryString()) + lineSeparator; | ||
reqData += String.format("Body: %sn", awsProxyRequest.getBody()) + lineSeparator; | ||
logger.debug(reqData); | ||
} | ||
|
||
} |
46 changes: 46 additions & 0 deletions
46
...genexus/cloud/serverless/aws/handler/internal/GxAwsHttpApiV2HttpServletRequestReader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.genexus.cloud.serverless.aws.handler.internal; | ||
|
||
import com.amazonaws.serverless.exceptions.InvalidRequestEventException; | ||
import com.amazonaws.serverless.proxy.RequestReader; | ||
import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpApiV2ProxyHttpServletRequest; | ||
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest; | ||
import com.amazonaws.serverless.proxy.model.AwsProxyRequest; | ||
import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext; | ||
import com.amazonaws.serverless.proxy.model.ContainerConfig; | ||
import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; | ||
import com.amazonaws.services.lambda.runtime.Context; | ||
|
||
import javax.servlet.http.HttpServletRequest; | ||
import javax.ws.rs.core.SecurityContext; | ||
|
||
public class GxAwsHttpApiV2HttpServletRequestReader extends RequestReader<HttpApiV2ProxyRequest, HttpServletRequest> { | ||
static final String INVALID_REQUEST_ERROR = "The incoming event is not a valid HTTP API v2 proxy request"; | ||
|
||
@Override | ||
public HttpServletRequest readRequest(HttpApiV2ProxyRequest request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config) throws InvalidRequestEventException { | ||
if (request.getRequestContext() == null || request.getRequestContext().getHttp().getMethod() == null || request.getRequestContext().getHttp().getMethod().equals("")) { | ||
throw new InvalidRequestEventException(INVALID_REQUEST_ERROR); | ||
} | ||
|
||
// clean out the request path based on the container config | ||
request.setRawPath(stripBasePath(request.getRawPath(), config)); | ||
|
||
AwsHttpApiV2ProxyHttpServletRequest servletRequest = new AwsHttpApiV2ProxyHttpServletRequest(request, lambdaContext, securityContext, config); | ||
|
||
AwsProxyRequestContext rContext = new AwsProxyRequestContext(); | ||
rContext.setRequestId(request.getRequestContext().getRequestId()); | ||
servletRequest.setAttribute(API_GATEWAY_CONTEXT_PROPERTY, rContext); | ||
servletRequest.setAttribute(HTTP_API_CONTEXT_PROPERTY, request.getRequestContext()); | ||
servletRequest.setAttribute(HTTP_API_STAGE_VARS_PROPERTY, request.getStageVariables()); | ||
servletRequest.setAttribute(HTTP_API_EVENT_PROPERTY, request); | ||
servletRequest.setAttribute(LAMBDA_CONTEXT_PROPERTY, lambdaContext); | ||
servletRequest.setAttribute(JAX_SECURITY_CONTEXT_PROPERTY, securityContext); | ||
|
||
return servletRequest; | ||
} | ||
|
||
@Override | ||
protected Class<? extends HttpApiV2ProxyRequest> getRequestClass() { | ||
return HttpApiV2ProxyRequest.class; | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
.../genexus/cloud/serverless/aws/handler/internal/GxJerseyLambdaContainerHandlerFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.genexus.cloud.serverless.aws.handler.internal; | ||
|
||
import com.amazonaws.serverless.proxy.*; | ||
import com.amazonaws.serverless.proxy.internal.servlet.*; | ||
import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler; | ||
import com.amazonaws.serverless.proxy.model.AwsProxyResponse; | ||
import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest; | ||
|
||
import javax.ws.rs.core.Application; | ||
|
||
public class GxJerseyLambdaContainerHandlerFactory { | ||
public static JerseyLambdaContainerHandler<HttpApiV2ProxyRequest, AwsProxyResponse> getHttpApiV2ProxyHandler(Application jaxRsApplication) { | ||
JerseyLambdaContainerHandler<HttpApiV2ProxyRequest, AwsProxyResponse> newHandler = new JerseyLambdaContainerHandler<>( | ||
HttpApiV2ProxyRequest.class, | ||
AwsProxyResponse.class, | ||
new GxAwsHttpApiV2HttpServletRequestReader(), | ||
new AwsProxyHttpServletResponseWriter(true), | ||
new AwsHttpApiV2SecurityContextWriter(), | ||
new AwsProxyExceptionHandler(), | ||
jaxRsApplication); | ||
newHandler.initialize(); | ||
return newHandler; | ||
} | ||
} |
Oops, something went wrong.