header : headers.entrySet()) {
+ conn.setRequestProperty(header.getKey(), header.getValue());
+ }
+
+ conn.setFixedLengthStreamingMode(payload.length);
+ conn.setDoOutput(true);
+
+ try (OutputStream outputStream = conn.getOutputStream()) {
+ outputStream.write(payload);
+ }
+
+ // get response code before closing the stream
+ int responseCode = conn.getResponseCode();
+ // don't need to read the response, close stream to ensure connection re-use
+ closeInputStreamQuietly(conn);
+
+ return responseCode;
+ }
+
+ private int doGet(String endpoint) throws IOException {
+ URL url = createUrl(endpoint);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");
+ conn.setRequestProperty("User-Agent", USER_AGENT);
+
+ int responseCode = conn.getResponseCode();
+ closeInputStreamQuietly(conn);
+
+ return responseCode;
+ }
+
+ private URL createUrl(String endpoint) {
+ try {
+ return new URL(endpoint);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void closeInputStreamQuietly(HttpURLConnection conn) {
+
+ InputStream inputStream;
+ try {
+ inputStream = conn.getInputStream();
+ } catch (IOException e) {
+ return;
+ }
+
+ if (inputStream == null) {
+ return;
+ }
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClient.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClient.java
deleted file mode 100644
index e01d96e12..000000000
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClient.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-import static java.net.HttpURLConnection.HTTP_ACCEPTED;
-import static java.net.HttpURLConnection.HTTP_OK;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-/**
- * LambdaRuntimeClient is a client of the AWS Lambda Runtime HTTP API for custom runtimes.
- *
- * API definition can be found at https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html
- *
- * Copyright (c) 2019 Amazon. All rights reserved.
- */
-public class LambdaRuntimeClient {
-
- private final String hostname;
- private final int port;
- private final String invocationEndpoint;
-
- private static final String DEFAULT_CONTENT_TYPE = "application/json";
- private static final String XRAY_ERROR_CAUSE_HEADER = "Lambda-Runtime-Function-XRay-Error-Cause";
- private static final String ERROR_TYPE_HEADER = "Lambda-Runtime-Function-Error-Type";
- private static final int XRAY_ERROR_CAUSE_MAX_HEADER_SIZE = 1024 * 1024; // 1MiB
-
- public LambdaRuntimeClient(String hostnamePort) {
- Objects.requireNonNull(hostnamePort, "hostnamePort cannot be null");
- String[] parts = hostnamePort.split(":");
- this.hostname = parts[0];
- this.port = Integer.parseInt(parts[1]);
- this.invocationEndpoint = invocationEndpoint();
- }
-
- public InvocationRequest waitForNextInvocation() {
- return NativeClient.next();
- }
-
- public void postInvocationResponse(String requestId, byte[] response) {
- NativeClient.postInvocationResponse(requestId.getBytes(UTF_8), response);
- }
-
- public void postInvocationError(String requestId, byte[] errorResponse, String errorType) throws IOException {
- postInvocationError(requestId, errorResponse, errorType, null);
- }
-
- public void postInvocationError(String requestId, byte[] errorResponse, String errorType, String errorCause)
- throws IOException {
- String endpoint = invocationErrorEndpoint(requestId);
- post(endpoint, errorResponse, errorType, errorCause);
- }
-
- public void getRestoreNext() throws IOException {
- doGet(restoreNextEndpoint(), HTTP_OK);
- }
-
- public int postRestoreError(byte[] errorResponse, String errorType) throws IOException {
- String endpoint = restoreErrorEndpoint();
- return postError(endpoint, errorResponse, errorType, null);
- }
-
- public void postInitError(byte[] errorResponse, String errorType) throws IOException {
- String endpoint = initErrorEndpoint();
- post(endpoint, errorResponse, errorType, null);
- }
-
- private void post(String endpoint, byte[] errorResponse, String errorType, String errorCause) throws IOException {
- URL url = createUrl(endpoint);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestMethod("POST");
- conn.setRequestProperty("Content-Type", DEFAULT_CONTENT_TYPE);
- if (errorType != null && !errorType.isEmpty()) {
- conn.setRequestProperty(ERROR_TYPE_HEADER, errorType);
- }
- if (errorCause != null && errorCause.getBytes().length < XRAY_ERROR_CAUSE_MAX_HEADER_SIZE) {
- conn.setRequestProperty(XRAY_ERROR_CAUSE_HEADER, errorCause);
- }
- conn.setFixedLengthStreamingMode(errorResponse.length);
- conn.setDoOutput(true);
- try (OutputStream outputStream = conn.getOutputStream()) {
- outputStream.write(errorResponse);
- }
-
- int responseCode = conn.getResponseCode();
- if (responseCode != HTTP_ACCEPTED) {
- throw new LambdaRuntimeClientException(endpoint, responseCode);
- }
-
- // don't need to read the response, close stream to ensure connection re-use
- closeQuietly(conn.getInputStream());
- }
-
- private String invocationEndpoint() {
- return getBaseUrl() + "/2018-06-01/runtime/invocation/";
- }
-
- private String invocationErrorEndpoint(String requestId) {
- return invocationEndpoint + requestId + "/error";
- }
-
- private String initErrorEndpoint() {
- return getBaseUrl() + "/2018-06-01/runtime/init/error";
- }
-
- private String restoreErrorEndpoint() {
- return getBaseUrl() + "/2018-06-01/runtime/restore/error";
- }
-
- private String restoreNextEndpoint() {
- return getBaseUrl() + "/2018-06-01/runtime/restore/next";
- }
-
- private String getBaseUrl() {
- return "http://" + hostname + ":" + port;
- }
-
- private int postError(String endpoint,
- byte[] errorResponse,
- String errorType,
- String errorCause) throws IOException {
-
- Map headers = new HashMap<>();
- if (errorType != null && !errorType.isEmpty()) {
- headers.put(ERROR_TYPE_HEADER, errorType);
- }
- if (errorCause != null && errorCause.getBytes().length < XRAY_ERROR_CAUSE_MAX_HEADER_SIZE) {
- headers.put(XRAY_ERROR_CAUSE_HEADER, errorCause);
- }
-
- return doPost(endpoint, DEFAULT_CONTENT_TYPE, headers, errorResponse);
- }
-
- private int doPost(String endpoint,
- String contentType,
- Map headers,
- byte[] payload) throws IOException {
-
- URL url = createUrl(endpoint);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
- conn.setRequestMethod("POST");
- conn.setRequestProperty("Content-Type", contentType);
-
- for (Map.Entry header : headers.entrySet()) {
- conn.setRequestProperty(header.getKey(), header.getValue());
- }
-
- conn.setFixedLengthStreamingMode(payload.length);
- conn.setDoOutput(true);
-
- try (OutputStream outputStream = conn.getOutputStream()) {
- outputStream.write(payload);
- }
-
- // get response code before closing the stream
- int responseCode = conn.getResponseCode();
-
- // don't need to read the response, close stream to ensure connection re-use
- closeInputStreamQuietly(conn);
-
- return responseCode;
- }
-
- private void doGet(String endpoint, int expectedHttpResponseCode) throws IOException {
-
- URL url = createUrl(endpoint);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestMethod("GET");
-
- int responseCode = conn.getResponseCode();
- if (responseCode != expectedHttpResponseCode) {
- throw new LambdaRuntimeClientException(endpoint, responseCode);
- }
-
- closeInputStreamQuietly(conn);
- }
-
- private URL createUrl(String endpoint) {
- try {
- return new URL(endpoint);
- } catch (MalformedURLException e) {
- throw new RuntimeException(e);
- }
- }
-
- private void closeQuietly(InputStream inputStream) {
- if (inputStream == null) return;
- try {
- inputStream.close();
- } catch (IOException e) {
- }
- }
-
- private void closeInputStreamQuietly(HttpURLConnection conn) {
-
- InputStream inputStream;
- try {
- inputStream = conn.getInputStream();
- } catch (IOException e) {
- return;
- }
-
- if (inputStream == null) {
- return;
- }
- try {
- inputStream.close();
- } catch (IOException e) {
- // ignore
- }
- }
-}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClientException.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClientException.java
index 1fc52d2fc..d9f0341ae 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClientException.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClientException.java
@@ -1,11 +1,11 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
-/**
- * Copyright (c) 2019 Amazon. All rights reserved.
- */
public class LambdaRuntimeClientException extends RuntimeException {
public LambdaRuntimeClientException(String message, int responseCode) {
- super(message + "Response code: '" + responseCode + "'.");
+ super(message + " Response code: '" + responseCode + "'.");
}
-
}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClientMaxRetriesExceededException.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClientMaxRetriesExceededException.java
new file mode 100644
index 000000000..467afa25c
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClientMaxRetriesExceededException.java
@@ -0,0 +1,15 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
+
+public class LambdaRuntimeClientMaxRetriesExceededException extends LambdaRuntimeClientException {
+ // 429 is possible; however, that is more appropriate when a server is responding to a spamming client that it wants to rate limit.
+ // In Our case, however, the RIC is a client that is not able to get a response from an upstream server, so 500 is more appropriate.
+ public LambdaRuntimeClientMaxRetriesExceededException(String operationName) {
+ super("Maximum Number of retries have been exceed" + (operationName.equals(null)
+ ? String.format(" for the %s operation.", operationName)
+ : "."), 500);
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
index dd9e35fdf..101aea4d0 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
@@ -1,72 +1,26 @@
-/* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
-
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.InvocationRequest;
+import static com.amazonaws.services.lambda.runtime.api.client.runtimeapi.LambdaRuntimeApiClientImpl.USER_AGENT;
/**
- * This module defines the native Runtime Interface Client which is responsible for all HTTP
+ * This module defines the native Runtime Interface Client which is responsible for HTTP
* interactions with the Runtime API.
*/
class NativeClient {
- private static final String nativeLibPath = "/tmp/.aws-lambda-runtime-interface-client";
- private static final String architecturePathSuffix = "/" + getArchIdentifier();
- // Implementation based on AWS CRT, but adopted to support 64-bit architectures only (ref. https://github.com/awslabs/aws-crt-java/blob/0e9c3db8b07258b57c2503cfc47c787ccef10670/src/main/java/software/amazon/awssdk/crt/CRT.java#L106-L134)
- private static final String supported_arm_architectures = "^(aarch64.*|arm64.*)$";
- private static final String supported_x86_architectures = "^(x8664|amd64|ia32e|em64t|x64|x86_64)$";
- private static final String[] libsToTry = {
- "aws-lambda-runtime-interface-client.glibc.so",
- "aws-lambda-runtime-interface-client.musl.so",
- };
- private static final Throwable[] exceptions = new Throwable[libsToTry.length];
-
- static {
- boolean loaded = false;
- for (int i = 0; !loaded && i < libsToTry.length; ++i) {
- try (InputStream lib = NativeClient.class.getResourceAsStream(
- Paths.get(architecturePathSuffix, libsToTry[i]).toString())) {
- Files.copy(lib, Paths.get(nativeLibPath), StandardCopyOption.REPLACE_EXISTING);
- System.load(nativeLibPath);
- loaded = true;
- } catch (UnsatisfiedLinkError | Exception e) {
- exceptions[i] = e;
- }
- }
- if (!loaded) {
- for (int i = 0; i < libsToTry.length; ++i) {
- System.err.printf("Failed to load the native runtime interface client library %s. Exception: %s\n", libsToTry[i], exceptions[i].getMessage());
- }
- System.exit(-1);
- }
- String userAgent = String.format(
- "aws-lambda-java/%s-%s",
- System.getProperty("java.vendor.version"),
- NativeClient.class.getPackage().getImplementationVersion());
- initializeClient(userAgent.getBytes());
- }
-
- /**
- * @return a string describing the detected architecture the RIC is executing on
- * @throws UnknownPlatformException
- */
- static String getArchIdentifier() {
- String arch = System.getProperty("os.arch");
-
- if (arch.matches(supported_x86_architectures)) {
- return "x86_64";
- } else if (arch.matches(supported_arm_architectures)) {
- return "aarch64";
- }
-
- throw new UnknownPlatformException("architecture not supported: " + arch);
+ static void init(String awsLambdaRuntimeApi) {
+ JniHelper.load();
+ initializeClient(USER_AGENT.getBytes(), awsLambdaRuntimeApi.getBytes());
}
-
- static native void initializeClient(byte[] userAgent);
+
+ static native void initializeClient(byte[] userAgent, byte[] awsLambdaRuntimeApi);
static native InvocationRequest next();
static native void postInvocationResponse(byte[] requestId, byte[] response);
+
}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/RapidErrorType.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/RapidErrorType.java
new file mode 100644
index 000000000..b471ce3f5
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/RapidErrorType.java
@@ -0,0 +1,16 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
+
+public enum RapidErrorType {
+ BadFunctionCode,
+ UserException,
+ BeforeCheckpointError,
+ AfterRestoreError;
+
+ public String getRapidError() {
+ return "Runtime." + this;
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/UnknownPlatformException.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/UnknownPlatformException.java
deleted file mode 100644
index f0b6d76e9..000000000
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/UnknownPlatformException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
-
-/**
- * Copyright (c) 2022 Amazon. All rights reserved.
- */
-public class UnknownPlatformException extends RuntimeException {
-
- public UnknownPlatformException(String message) {
- super(message);
- }
-}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/converters/LambdaErrorConverter.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/converters/LambdaErrorConverter.java
new file mode 100644
index 000000000..a2520bf74
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/converters/LambdaErrorConverter.java
@@ -0,0 +1,32 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi.converters;
+
+import com.amazonaws.services.lambda.runtime.api.client.UserFault;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.ErrorRequest;
+
+public class LambdaErrorConverter {
+ private LambdaErrorConverter() {
+ }
+
+ public static ErrorRequest fromUserFault(UserFault userFault) {
+ // Not setting stacktrace for compatibility with legacy/native runtime
+ return new ErrorRequest(userFault.msg, userFault.exception, null);
+ }
+
+ public static ErrorRequest fromThrowable(Throwable throwable) {
+ String errorMessage = throwable.getLocalizedMessage() == null
+ ? throwable.getClass().getName()
+ : throwable.getLocalizedMessage();
+ String errorType = throwable.getClass().getName();
+
+ StackTraceElement[] trace = throwable.getStackTrace();
+ String[] stackTrace = new String[trace.length];
+ for (int i = 0; i < trace.length; i++) {
+ stackTrace[i] = trace[i].toString();
+ }
+ return new ErrorRequest(errorMessage, errorType, stackTrace);
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/converters/XRayErrorCauseConverter.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/converters/XRayErrorCauseConverter.java
new file mode 100644
index 000000000..7065bc764
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/converters/XRayErrorCauseConverter.java
@@ -0,0 +1,58 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi.converters;
+
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.StackElement;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayErrorCause;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class XRayErrorCauseConverter {
+ private XRayErrorCauseConverter() {
+ }
+
+ public static XRayErrorCause fromThrowable(Throwable throwable) {
+ String workingDirectory = System.getProperty("user.dir");
+ XRayException xRayException = getXRayExceptionFromThrowable(throwable);
+ Collection exceptions = Collections.singletonList(xRayException);
+ Collection paths = Arrays.stream(throwable.getStackTrace()).
+ map(XRayErrorCauseConverter::determineFileName).
+ collect(Collectors.toSet());
+
+ return new XRayErrorCause(workingDirectory, exceptions, paths);
+ }
+
+ static XRayException getXRayExceptionFromThrowable(Throwable throwable) {
+ String message = throwable.getMessage();
+ String type = throwable.getClass().getName();
+ List stack = Arrays.stream(throwable.getStackTrace()).
+ map(XRayErrorCauseConverter::convertStackTraceElement).
+ collect(Collectors.toList());
+ return new XRayException(message, type, stack);
+ }
+
+ static String determineFileName(StackTraceElement e) {
+ String fileName = null;
+ if (e.getFileName() != null) {
+ fileName = e.getFileName();
+ }
+ if (fileName == null) {
+ String className = e.getClassName();
+ fileName = className.substring(className.lastIndexOf('.') + 1) + ".java";
+ }
+ return fileName;
+ }
+
+ static StackElement convertStackTraceElement(StackTraceElement e) {
+ return new StackElement(
+ e.getMethodName(),
+ determineFileName(e),
+ e.getLineNumber());
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/ErrorRequest.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/ErrorRequest.java
new file mode 100644
index 000000000..d5886a67d
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/ErrorRequest.java
@@ -0,0 +1,21 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto;
+
+public class ErrorRequest {
+ public String errorMessage;
+ public String errorType;
+ public String[] stackTrace;
+
+ @SuppressWarnings("unused")
+ public ErrorRequest() {
+ }
+
+ public ErrorRequest(String errorMessage, String errorType, String[] stackTrace) {
+ this.errorMessage = errorMessage;
+ this.errorType = errorType;
+ this.stackTrace = stackTrace;
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/InvocationRequest.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/InvocationRequest.java
similarity index 54%
rename from aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/InvocationRequest.java
rename to aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/InvocationRequest.java
index 89707d49a..656945b41 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/InvocationRequest.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/InvocationRequest.java
@@ -1,12 +1,11 @@
-package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto;
/**
* An invocation request represents the response of the runtime API's next invocation API.
- *
- * Copyright (c) 2019 Amazon. All rights reserved.
*/
public class InvocationRequest {
@@ -42,9 +41,9 @@ public class InvocationRequest {
private String cognitoIdentity;
/**
- * An input stream of the invocation's request body.
+ * The tenant ID associated with the request.
*/
- private InputStream stream;
+ private String tenantId;
private byte[] content;
@@ -52,28 +51,67 @@ public String getId() {
return id;
}
+ public void setId(String id) {
+ this.id = id;
+ }
+
public String getXrayTraceId() {
return xrayTraceId;
}
+ public void setXrayTraceId(String xrayTraceId) {
+ this.xrayTraceId = xrayTraceId;
+ }
+
public String getInvokedFunctionArn() {
return invokedFunctionArn;
}
+ @SuppressWarnings("unused")
+ public void setInvokedFunctionArn(String invokedFunctionArn) {
+ this.invokedFunctionArn = invokedFunctionArn;
+ }
+
public long getDeadlineTimeInMs() {
return deadlineTimeInMs;
}
+ @SuppressWarnings("unused")
+ public void setDeadlineTimeInMs(long deadlineTimeInMs) {
+ this.deadlineTimeInMs = deadlineTimeInMs;
+ }
+
public String getClientContext() {
return clientContext;
}
+ @SuppressWarnings("unused")
+ public void setClientContext(String clientContext) {
+ this.clientContext = clientContext;
+ }
+
public String getCognitoIdentity() {
return cognitoIdentity;
}
- public InputStream getContentAsStream() {
- return new ByteArrayInputStream(content);
+ @SuppressWarnings("unused")
+ public void setCognitoIdentity(String cognitoIdentity) {
+ this.cognitoIdentity = cognitoIdentity;
}
+ public String getTenantId() {
+ return tenantId;
+ }
+
+ public void setTenantId(String tenantId) {
+ this.tenantId = tenantId;
+ }
+
+ public byte[] getContent() {
+ return content;
+ }
+
+ public void setContent(byte[] content) {
+ this.content = content;
+ }
}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/StackElement.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/StackElement.java
new file mode 100644
index 000000000..679f8bf9f
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/StackElement.java
@@ -0,0 +1,21 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto;
+
+public class StackElement {
+ public String label;
+ public String path;
+ public int line;
+
+ @SuppressWarnings("unused")
+ public StackElement() {
+ }
+
+ public StackElement(String label, String path, int line) {
+ this.label = label;
+ this.path = path;
+ this.line = line;
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/XRayErrorCause.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/XRayErrorCause.java
new file mode 100644
index 000000000..cc5bee8a7
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/XRayErrorCause.java
@@ -0,0 +1,24 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto;
+
+import java.util.Collection;
+
+public class XRayErrorCause {
+ public String working_directory;
+ public Collection exceptions;
+ public Collection paths;
+
+ @SuppressWarnings("unused")
+ public XRayErrorCause() {
+
+ }
+
+ public XRayErrorCause(String working_directory, Collection exceptions, Collection paths) {
+ this.working_directory = working_directory;
+ this.exceptions = exceptions;
+ this.paths = paths;
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/XRayException.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/XRayException.java
new file mode 100644
index 000000000..2b17fd5f2
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/XRayException.java
@@ -0,0 +1,23 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto;
+
+import java.util.List;
+
+public class XRayException {
+ public String message;
+ public String type;
+ public List stack;
+
+ @SuppressWarnings("unused")
+ public XRayException() {
+ }
+
+ public XRayException(String message, String type, List stack) {
+ this.message = message;
+ this.type = type;
+ this.stack = stack;
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/ConcurrencyConfig.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/ConcurrencyConfig.java
new file mode 100644
index 000000000..a768e240e
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/ConcurrencyConfig.java
@@ -0,0 +1,50 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package com.amazonaws.services.lambda.runtime.api.client.util;
+
+import com.amazonaws.services.lambda.runtime.api.client.ReservedRuntimeEnvironmentVariables;
+import com.amazonaws.services.lambda.runtime.api.client.UserFault;
+import com.amazonaws.services.lambda.runtime.api.client.logging.LambdaContextLogger;
+import com.amazonaws.services.lambda.runtime.logging.LogFormat;
+import com.amazonaws.services.lambda.runtime.logging.LogLevel;
+
+public class ConcurrencyConfig {
+ private final int numberOfPlatformThreads;
+ private final String INVALID_CONFIG_MESSAGE_PREFIX = String.format("User configured %s is invalid.", ReservedRuntimeEnvironmentVariables.AWS_LAMBDA_MAX_CONCURRENCY);
+
+ public ConcurrencyConfig(LambdaContextLogger logger) {
+ this(logger, new EnvReader());
+ }
+
+ public ConcurrencyConfig(LambdaContextLogger logger, EnvReader envReader) {
+ int readNumOfPlatformThreads = 0;
+ try {
+ String readLambdaMaxConcurrencyEnvVar = envReader.getEnv(ReservedRuntimeEnvironmentVariables.AWS_LAMBDA_MAX_CONCURRENCY);
+
+ if (readLambdaMaxConcurrencyEnvVar != null) {
+ readNumOfPlatformThreads = Integer.parseInt(readLambdaMaxConcurrencyEnvVar);
+ }
+ } catch (Exception e) {
+ String message = String.format("%s\n%s", INVALID_CONFIG_MESSAGE_PREFIX, UserFault.trace(e));
+ logger.log(message, logger.getLogFormat() == LogFormat.JSON ? LogLevel.ERROR : LogLevel.UNDEFINED);
+ throw e;
+ }
+
+ this.numberOfPlatformThreads = readNumOfPlatformThreads;
+ }
+
+ public String getConcurrencyConfigMessage() {
+ return String.format("Starting %d concurrent function handler threads.", this.numberOfPlatformThreads);
+ }
+
+ public boolean isMultiConcurrent() {
+ return this.numberOfPlatformThreads >= 1;
+ }
+
+ public int getNumberOfPlatformThreads() {
+ return numberOfPlatformThreads;
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/EnvReader.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/EnvReader.java
index 968119aca..840bd440c 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/EnvReader.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/EnvReader.java
@@ -1,4 +1,7 @@
-/* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
package com.amazonaws.services.lambda.runtime.api.client.util;
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/LambdaOutputStream.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/LambdaOutputStream.java
index 556859a27..22d01b0aa 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/LambdaOutputStream.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/LambdaOutputStream.java
@@ -1,9 +1,12 @@
-/* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
package com.amazonaws.services.lambda.runtime.api.client.util;
-import java.io.OutputStream;
import java.io.IOException;
+import java.io.OutputStream;
public class LambdaOutputStream extends OutputStream {
private final OutputStream inner;
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/UnsafeUtil.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/UnsafeUtil.java
index f9351c94c..f11d4357c 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/UnsafeUtil.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/util/UnsafeUtil.java
@@ -1,10 +1,12 @@
-/* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
package com.amazonaws.services.lambda.runtime.api.client.util;
-import sun.misc.Unsafe;
-
import java.lang.reflect.Field;
+import sun.misc.Unsafe;
/**
* Utilities for easy access to sun.misc.Unsafe
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc
index dd4fdb22e..1cfcfbb1d 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc
@@ -53,9 +53,16 @@ RUN /usr/bin/c++ -c \
-I${JAVA_HOME}/include/linux \
-I ./deps/artifacts/include \
com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp -o com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o && \
+ /usr/bin/c++ -c \
+ -std=gnu++11 \
+ -fPIC \
+ -I${JAVA_HOME}/include \
+ -I${JAVA_HOME}/include/linux \
+ -I ./deps/artifacts/include \
+ com_amazonaws_services_lambda_crac_DNSManager.cpp -o com_amazonaws_services_lambda_crac_DNSManager.o && \
/usr/bin/c++ -shared \
-std=gnu++11 \
- -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o \
+ -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o com_amazonaws_services_lambda_crac_DNSManager.o \
-L ./deps/artifacts/lib64/ \
-L ./deps/artifacts/lib/ \
-laws-lambda-runtime \
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl
index e15f6adc5..64725c140 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl
@@ -54,9 +54,16 @@ RUN /usr/bin/c++ -c \
-I${JAVA_HOME}/include/linux \
-I ./deps/artifacts/include \
com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp -o com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o && \
+ /usr/bin/c++ -c \
+ -std=gnu++11 \
+ -fPIC \
+ -I${JAVA_HOME}/include \
+ -I${JAVA_HOME}/include/linux \
+ -I ./deps/artifacts/include \
+ com_amazonaws_services_lambda_crac_DNSManager.cpp -o com_amazonaws_services_lambda_crac_DNSManager.o && \
/usr/bin/c++ -shared \
-std=gnu++11 \
- -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o \
+ -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o com_amazonaws_services_lambda_crac_DNSManager.o \
-L ./deps/artifacts/lib/ \
-laws-lambda-runtime \
-lcurl \
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh b/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh
index 56d617c36..b7dbb5a80 100755
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/bash -x
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
set -euo pipefail
@@ -6,46 +6,125 @@ set -euo pipefail
SRC_DIR=$(dirname "$0")
DST_DIR=${1}
MULTI_ARCH=${2}
+BUILD_OS=${3}
+BUILD_ARCH=${4}
CURL_VERSION=7.83.1
-# Not using associative arrays to maintain bash 3 compatibility with building on MacOS
-# MacOS ships with bash 3 and associative arrays require bash 4+
-# Declaring a map as an array with the column character as a separator :
-declare -a ARCHITECTURES_TO_PLATFORM=(
- "x86_64:linux/amd64"
- "aarch64:linux/arm64/v8"
-)
-
-declare -a TARGETS=("glibc" "musl")
-
-for pair in "${ARCHITECTURES_TO_PLATFORM[@]}"; do
- arch=${pair%%:*}
- platform=${pair#*:}
-
- if [[ "${MULTI_ARCH}" != "true" ]] && [[ "$(arch)" != "${arch}" ]]; then
- echo "multi arch build not requested and host arch is $(arch), so skipping ${arch}:${platform} ..."
- continue
- fi
-
- mkdir -p "${DST_DIR}/classes/${arch}"
-
- for target in "${TARGETS[@]}"; do
- echo "Compiling the native library for target ${target} on architecture ${arch} using Docker platform ${platform}"
- artifact="${DST_DIR}/classes/${arch}/aws-lambda-runtime-interface-client.${target}.so"
-
- if [[ "${MULTI_ARCH}" == "true" ]]; then
- docker build --platform="${platform}" -f "${SRC_DIR}/Dockerfile.${target}" --build-arg CURL_VERSION=${CURL_VERSION} "${SRC_DIR}" -o - | tar -xOf - src/aws-lambda-runtime-interface-client.so > "${artifact}"
- else
- echo "multi-arch not requestsed, assuming this is a workaround to goofyness when docker buildx is enabled on Linux CI environments."
- echo "enabling docker buildx often updates the docker api version, so assuming that docker cli is also too old to use --output type=tar, so doing alternative build-tag-run approach"
- docker build --platform="${platform}" -t "lambda-java-jni-lib-${target}-${arch}" -f "${SRC_DIR}/Dockerfile.${target}" --build-arg CURL_VERSION=${CURL_VERSION} "${SRC_DIR}"
- docker run --rm --entrypoint /bin/cat "lambda-java-jni-lib-${target}-${arch}" /src/aws-lambda-runtime-interface-client.so > "${artifact}"
- fi
-
- [ -f "${artifact}" ]
- if ! file -b "${artifact}" | tr '-' '_' | tee /dev/stderr | grep -q "${arch}"; then
- echo "${artifact} did not appear to be the correct architecture, check that Docker buildx is enabled"
- exit 1
- fi
- done
-done
+function get_docker_platform() {
+ arch=$1
+
+ if [ "${arch}" == "x86_64" ]; then
+ echo "linux/amd64"
+ elif [ "${arch}" == "aarch_64" ]; then
+ echo "linux/arm64/v8"
+ else
+ echo "UNKNOWN_DOCKER_PLATFORM"
+ fi
+}
+
+function get_target_os() {
+ libc_impl=$1
+
+ if [ "${libc_impl}" == "glibc" ]; then
+ echo "linux"
+ elif [ "${libc_impl}" == "musl" ]; then
+ echo "linux_musl"
+ else
+ echo "UNKNOWN_OS"
+ fi
+}
+
+function build_for_libc_arch() {
+ libc_impl=$1
+ arch=$2
+ artifact=$3
+
+ docker_platform=$(get_docker_platform ${arch})
+
+ echo "Compiling the native library with libc implementation \`${libc_impl}\` on architecture \`${arch}\` using Docker platform \`${docker_platform}\`"
+
+ if [[ "${MULTI_ARCH}" == "true" ]]; then
+ docker build --platform="${docker_platform}" -f "${SRC_DIR}/Dockerfile.${libc_impl}" \
+ --build-arg CURL_VERSION=${CURL_VERSION} "${SRC_DIR}" -o - \
+ | tar -xOf - src/aws-lambda-runtime-interface-client.so > "${artifact}"
+ else
+ echo "multi-arch not requested, assuming this is a workaround to goofyness when docker buildx is enabled on Linux CI environments."
+ echo "enabling docker buildx often updates the docker api version, so assuming that docker cli is also too old to use --output type=tar, so doing alternative build-tag-run approach"
+ image_name="lambda-java-jni-lib-${libc_impl}-${arch}"
+
+ # GitHub actions is using dockerx build under the hood. We need to pass --load option to be able to run the image
+ # This args is NOT part of the classic docker build command, so we need to check against a GitHub Action env var not to make local build crash.
+ if [[ "${GITHUB_RUN_ID:+isset}" == "isset" ]]; then
+ EXTRA_LOAD_ARG="--load"
+ else
+ EXTRA_LOAD_ARG=""
+ fi
+
+ docker build --platform="${docker_platform}" \
+ -t "${image_name}" \
+ -f "${SRC_DIR}/Dockerfile.${libc_impl}" \
+ --build-arg CURL_VERSION=${CURL_VERSION} "${SRC_DIR}" ${EXTRA_LOAD_ARG}
+
+ echo "Docker image has been successfully built"
+
+ docker run --rm --entrypoint /bin/cat "${image_name}" \
+ /src/aws-lambda-runtime-interface-client.so > "${artifact}"
+ fi
+
+ [ -f "${artifact}" ]
+
+ # file -b ${artifact} produces lines like this:
+ # x86_64: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=582888b42da34895828e1281cbbae15d279175b7, not stripped
+ # aarch_64: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=fa54218974fb2c17772b6acf22467a2c67a87011, not stripped
+ # we need to ensure it has the expected architecture in it
+ #
+ # cut -d "," -f2 will extract second field (' x86-64' or ' ARM aarch64')
+ # tr -d '-' removes '-', so we'll have (' x8664' or ' ARM aarch64')
+ # grep -q is for quiet mode, no output
+ # ${arch//_} removes '_' chars from the `aarch` variable, (aarch_64 => aarch64, x86_64 => x8664)
+ if ! file -b "${artifact}" | cut -d "," -f2 | tr -d '-' | grep -q "${arch//_}"; then
+ echo "${artifact} did not appear to be the correct architecture, check that Docker buildx is enabled"
+ exit 1
+ fi
+}
+
+function get_target_artifact() {
+ target_os=$1
+ target_arch=$2
+
+ target_file="${DST_DIR}/classes/jni/libaws-lambda-jni.${target_os}-${target_arch}.so"
+ target_dir=$(dirname "$target_file")
+ mkdir -p "$target_dir"
+ echo "$target_file"
+}
+
+
+
+if [ -n "$BUILD_OS" ] && [ -n "$BUILD_ARCH" ]; then
+ # build for the specified arch and libc implementation
+ libc_impl="glibc"
+ if [ "$BUILD_OS" == "linux_musl" ]; then
+ libc_impl="musl"
+ fi
+ target_artifact=$(get_target_artifact "$BUILD_OS" "$BUILD_ARCH")
+ build_for_libc_arch "$libc_impl" "$BUILD_ARCH" "$target_artifact"
+else
+ # build for all architectures and libc implementations
+ declare -a ARCHITECTURES=("x86_64" "aarch_64")
+ declare -a LIBC_IMPLS=("glibc" "musl")
+
+ for arch in "${ARCHITECTURES[@]}"; do
+
+ if [[ "${MULTI_ARCH}" != "true" ]] && [[ "$(arch)" != "${arch}" ]]; then
+ echo "multi arch build not requested and host arch is $(arch), so skipping ${arch}..."
+ continue
+ fi
+
+ for libc_impl in "${LIBC_IMPLS[@]}"; do
+ target_os=$(get_target_os $libc_impl)
+ target_artifact=$(get_target_artifact "$target_os" "$arch")
+ build_for_libc_arch "$libc_impl" "$arch" "$target_artifact"
+ done
+
+ done
+fi
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.cpp b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.cpp
new file mode 100644
index 000000000..ccf5481b9
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.cpp
@@ -0,0 +1,27 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+#include
+#include "macro.h"
+#include "com_amazonaws_services_lambda_crac_DNSManager.h"
+
+JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_crac_DNSManager_clearCache
+ (JNIEnv *env, jclass thisClass) {
+ jclass iNetAddressClass;
+ jclass concurrentMap;
+ jfieldID cacheFieldID;
+ jobject cacheObj;
+ jmethodID clearMethodID;
+ CHECK_EXCEPTION(env, iNetAddressClass = env->FindClass("java/net/InetAddress"));
+ CHECK_EXCEPTION(env, concurrentMap = env->FindClass("java/util/concurrent/ConcurrentMap"));
+ CHECK_EXCEPTION(env, cacheFieldID = env->GetStaticFieldID(iNetAddressClass, "cache", "Ljava/util/concurrent/ConcurrentMap;"));
+ CHECK_EXCEPTION(env, cacheObj = (jobject) env->GetStaticObjectField(iNetAddressClass, cacheFieldID));
+ CHECK_EXCEPTION(env, clearMethodID = env->GetMethodID(concurrentMap, "clear", "()V"));
+ CHECK_EXCEPTION(env, env->CallVoidMethod(cacheObj, clearMethodID));
+ return;
+
+ ERROR:
+ // we need to fail silently here
+ env->ExceptionClear();
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.h b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.h
new file mode 100644
index 000000000..f26639ba9
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.h
@@ -0,0 +1,19 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+#include
+
+#ifndef _Included_com_amazonaws_services_lambda_crac_DNSManager
+#define _Included_com_amazonaws_services_lambda_crac_DNSManager
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_crac_DNSManager_clearCache
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
index 87fa9f028..f06796616 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
@@ -1,27 +1,13 @@
/*
- * Copyright 2019-present Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
#include
+#include "macro.h"
#include "com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h"
#include "aws/lambda-runtime/runtime.h"
#include "aws/lambda-runtime/version.h"
-#define CHECK_EXCEPTION(env, expr) \
- expr; \
- if ((env)->ExceptionOccurred()) \
- goto ERROR;
-
static aws::lambda_runtime::runtime * CLIENT = nullptr;
static jint JNI_VERSION = JNI_VERSION_1_8;
@@ -34,6 +20,7 @@ static jfieldID contentField;
static jfieldID clientContextField;
static jfieldID cognitoIdentityField;
static jfieldID xrayTraceIdField;
+static jfieldID tenantIdField;
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
@@ -44,7 +31,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
}
jclass tempInvocationRequestClassRef;
- tempInvocationRequestClassRef = env->FindClass("com/amazonaws/services/lambda/runtime/api/client/runtimeapi/InvocationRequest");
+ tempInvocationRequestClassRef = env->FindClass("com/amazonaws/services/lambda/runtime/api/client/runtimeapi/dto/InvocationRequest");
invocationRequestClass = (jclass) env->NewGlobalRef(tempInvocationRequestClassRef);
env->DeleteLocalRef(tempInvocationRequestClassRef);
@@ -55,6 +42,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
xrayTraceIdField = env->GetFieldID(invocationRequestClass , "xrayTraceId", "Ljava/lang/String;");
clientContextField = env->GetFieldID(invocationRequestClass , "clientContext", "Ljava/lang/String;");
cognitoIdentityField = env->GetFieldID(invocationRequestClass , "cognitoIdentity", "Ljava/lang/String;");
+ tenantIdField = env->GetFieldID(invocationRequestClass, "tenantId", "Ljava/lang/String;");
return JNI_VERSION;
}
@@ -83,9 +71,9 @@ static std::string toNativeString(JNIEnv *env, jbyteArray jArray) {
return nativeString;
}
-JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_initializeClient(JNIEnv *env, jobject thisObject, jbyteArray userAgent) {
+JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_initializeClient(JNIEnv *env, jobject thisObject, jbyteArray userAgent, jbyteArray awsLambdaRuntimeApi) {
std::string user_agent = toNativeString(env, userAgent);
- std::string endpoint(getenv("AWS_LAMBDA_RUNTIME_API"));
+ std::string endpoint = toNativeString(env, awsLambdaRuntimeApi);
CLIENT = new aws::lambda_runtime::runtime(endpoint, user_agent);
}
@@ -120,6 +108,10 @@ JNIEXPORT jobject JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_
CHECK_EXCEPTION(env, env->SetObjectField(invocationRequest, cognitoIdentityField, env->NewStringUTF(response.cognito_identity.c_str())));
}
+ if(response.tenant_id != ""){
+ CHECK_EXCEPTION(env, env->SetObjectField(invocationRequest, tenantIdField, env->NewStringUTF(response.tenant_id.c_str())));
+ }
+
bytes = reinterpret_cast(response.payload.c_str());
CHECK_EXCEPTION(env, jArray = env->NewByteArray(response.payload.length()));
CHECK_EXCEPTION(env, env->SetByteArrayRegion(jArray, 0, response.payload.length(), bytes));
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
index 28a6f444a..7219109b0 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
@@ -1,3 +1,7 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
#include
#ifndef _Included_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient
@@ -7,7 +11,7 @@ extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_initializeClient
- (JNIEnv *, jobject, jbyteArray);
+ (JNIEnv *, jobject, jbyteArray, jbyteArray);
JNIEXPORT jobject JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_next
(JNIEnv *, jobject);
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/include/aws/lambda-runtime/runtime.h b/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/include/aws/lambda-runtime/runtime.h
index 94e1e22cb..c4868c1ba 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/include/aws/lambda-runtime/runtime.h
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/include/aws/lambda-runtime/runtime.h
@@ -61,6 +61,11 @@ struct invocation_request {
*/
std::chrono::time_point deadline;
+ /**
+ * Tenant ID of the current invocation.
+ */
+ std::string tenant_id;
+
/**
* The number of milliseconds left before lambda terminates the current execution.
*/
@@ -167,7 +172,6 @@ class runtime {
private:
std::string const m_user_agent_header;
std::array const m_endpoints;
- CURL* const m_curl_handle;
};
inline std::chrono::milliseconds invocation_request::get_time_remaining() const
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/src/runtime.cpp b/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/src/runtime.cpp
index 91750840f..84a84b439 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/src/runtime.cpp
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/deps/aws-lambda-cpp-0.2.7/src/runtime.cpp
@@ -40,6 +40,8 @@ static constexpr auto CLIENT_CONTEXT_HEADER = "lambda-runtime-client-context";
static constexpr auto COGNITO_IDENTITY_HEADER = "lambda-runtime-cognito-identity";
static constexpr auto DEADLINE_MS_HEADER = "lambda-runtime-deadline-ms";
static constexpr auto FUNCTION_ARN_HEADER = "lambda-runtime-invoked-function-arn";
+static constexpr auto TENANT_ID_HEADER = "lambda-runtime-aws-tenant-id";
+thread_local static CURL* m_curl_handle = curl_easy_init();
enum Endpoints {
INIT,
@@ -162,63 +164,62 @@ runtime::runtime(std::string const& endpoint) : runtime(endpoint, "AWS_Lambda_Cp
runtime::runtime(std::string const& endpoint, std::string const& user_agent)
: m_user_agent_header("User-Agent: " + user_agent), m_endpoints{{endpoint + "/2018-06-01/runtime/init/error",
endpoint + "/2018-06-01/runtime/invocation/next",
- endpoint + "/2018-06-01/runtime/invocation/"}},
- m_curl_handle(curl_easy_init())
+ endpoint + "/2018-06-01/runtime/invocation/"}}
{
- if (!m_curl_handle) {
+ if (!lambda_runtime::m_curl_handle) {
logging::log_error(LOG_TAG, "Failed to acquire curl easy handle for next.");
}
}
runtime::~runtime()
{
- curl_easy_cleanup(m_curl_handle);
+ curl_easy_cleanup(lambda_runtime::m_curl_handle);
}
void runtime::set_curl_next_options()
{
// lambda freezes the container when no further tasks are available. The freezing period could be longer than the
// request timeout, which causes the following get_next request to fail with a timeout error.
- curl_easy_reset(m_curl_handle);
- curl_easy_setopt(m_curl_handle, CURLOPT_TIMEOUT, 0L);
- curl_easy_setopt(m_curl_handle, CURLOPT_CONNECTTIMEOUT, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_NOSIGNAL, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_TCP_NODELAY, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_reset(lambda_runtime::m_curl_handle);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_TIMEOUT, 0L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_CONNECTTIMEOUT, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_NOSIGNAL, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_TCP_NODELAY, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
- curl_easy_setopt(m_curl_handle, CURLOPT_HTTPGET, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_URL, m_endpoints[Endpoints::NEXT].c_str());
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HTTPGET, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_URL, m_endpoints[Endpoints::NEXT].c_str());
- curl_easy_setopt(m_curl_handle, CURLOPT_WRITEFUNCTION, write_data);
- curl_easy_setopt(m_curl_handle, CURLOPT_HEADERFUNCTION, write_header);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_WRITEFUNCTION, write_data);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HEADERFUNCTION, write_header);
- curl_easy_setopt(m_curl_handle, CURLOPT_PROXY, "");
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_PROXY, "");
#ifndef NDEBUG
- curl_easy_setopt(m_curl_handle, CURLOPT_VERBOSE, 1);
- curl_easy_setopt(m_curl_handle, CURLOPT_DEBUGFUNCTION, rt_curl_debug_callback);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_DEBUGFUNCTION, rt_curl_debug_callback);
#endif
}
void runtime::set_curl_post_result_options()
{
- curl_easy_reset(m_curl_handle);
- curl_easy_setopt(m_curl_handle, CURLOPT_TIMEOUT, 0L);
- curl_easy_setopt(m_curl_handle, CURLOPT_CONNECTTIMEOUT, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_NOSIGNAL, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_TCP_NODELAY, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ curl_easy_reset(lambda_runtime::m_curl_handle);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_TIMEOUT, 0L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_CONNECTTIMEOUT, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_NOSIGNAL, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_TCP_NODELAY, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
- curl_easy_setopt(m_curl_handle, CURLOPT_POST, 1L);
- curl_easy_setopt(m_curl_handle, CURLOPT_READFUNCTION, read_data);
- curl_easy_setopt(m_curl_handle, CURLOPT_WRITEFUNCTION, write_data);
- curl_easy_setopt(m_curl_handle, CURLOPT_HEADERFUNCTION, write_header);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_POST, 1L);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_READFUNCTION, read_data);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_WRITEFUNCTION, write_data);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HEADERFUNCTION, write_header);
- curl_easy_setopt(m_curl_handle, CURLOPT_PROXY, "");
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_PROXY, "");
#ifndef NDEBUG
- curl_easy_setopt(m_curl_handle, CURLOPT_VERBOSE, 1);
- curl_easy_setopt(m_curl_handle, CURLOPT_DEBUGFUNCTION, rt_curl_debug_callback);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_DEBUGFUNCTION, rt_curl_debug_callback);
#endif
}
@@ -226,15 +227,15 @@ runtime::next_outcome runtime::get_next()
{
http::response resp;
set_curl_next_options();
- curl_easy_setopt(m_curl_handle, CURLOPT_WRITEDATA, &resp);
- curl_easy_setopt(m_curl_handle, CURLOPT_HEADERDATA, &resp);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_WRITEDATA, &resp);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HEADERDATA, &resp);
curl_slist* headers = nullptr;
headers = curl_slist_append(headers, m_user_agent_header.c_str());
- curl_easy_setopt(m_curl_handle, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HTTPHEADER, headers);
logging::log_debug(LOG_TAG, "Making request to %s", m_endpoints[Endpoints::NEXT].c_str());
- CURLcode curl_code = curl_easy_perform(m_curl_handle);
+ CURLcode curl_code = curl_easy_perform(lambda_runtime::m_curl_handle);
logging::log_debug(LOG_TAG, "Completed request to %s", m_endpoints[Endpoints::NEXT].c_str());
curl_slist_free_all(headers);
@@ -246,13 +247,13 @@ runtime::next_outcome runtime::get_next()
{
long resp_code;
- curl_easy_getinfo(m_curl_handle, CURLINFO_RESPONSE_CODE, &resp_code);
+ curl_easy_getinfo(lambda_runtime::m_curl_handle, CURLINFO_RESPONSE_CODE, &resp_code);
resp.set_response_code(static_cast(resp_code));
}
{
char* content_type = nullptr;
- curl_easy_getinfo(m_curl_handle, CURLINFO_CONTENT_TYPE, &content_type);
+ curl_easy_getinfo(lambda_runtime::m_curl_handle, CURLINFO_CONTENT_TYPE, &content_type);
resp.set_content_type(content_type);
}
@@ -301,6 +302,10 @@ runtime::next_outcome runtime::get_next()
req.payload.c_str(),
static_cast(req.get_time_remaining().count()));
}
+
+ if (resp.has_header(TENANT_ID_HEADER)) {
+ req.tenant_id = resp.get_header(TENANT_ID_HEADER);
+ }
return next_outcome(req);
}
@@ -322,7 +327,7 @@ runtime::post_outcome runtime::do_post(
invocation_response const& handler_response)
{
set_curl_post_result_options();
- curl_easy_setopt(m_curl_handle, CURLOPT_URL, url.c_str());
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_URL, url.c_str());
logging::log_info(LOG_TAG, "Making request to %s", url.c_str());
curl_slist* headers = nullptr;
@@ -343,11 +348,11 @@ runtime::post_outcome runtime::do_post(
std::pair ctx{payload, 0};
aws::http::response resp;
- curl_easy_setopt(m_curl_handle, CURLOPT_WRITEDATA, &resp);
- curl_easy_setopt(m_curl_handle, CURLOPT_HEADERDATA, &resp);
- curl_easy_setopt(m_curl_handle, CURLOPT_READDATA, &ctx);
- curl_easy_setopt(m_curl_handle, CURLOPT_HTTPHEADER, headers);
- CURLcode curl_code = curl_easy_perform(m_curl_handle);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_WRITEDATA, &resp);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HEADERDATA, &resp);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_READDATA, &ctx);
+ curl_easy_setopt(lambda_runtime::m_curl_handle, CURLOPT_HTTPHEADER, headers);
+ CURLcode curl_code = curl_easy_perform(lambda_runtime::m_curl_handle);
curl_slist_free_all(headers);
if (curl_code != CURLE_OK) {
@@ -361,11 +366,11 @@ runtime::post_outcome runtime::do_post(
}
long http_response_code;
- curl_easy_getinfo(m_curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code);
+ curl_easy_getinfo(lambda_runtime::m_curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code);
if (!is_success(aws::http::response_code(http_response_code))) {
logging::log_error(
- LOG_TAG, "Failed to post handler success response. Http response code: %ld.", http_response_code);
+ LOG_TAG, "Failed to post handler success response. Http response code: %ld. %s", http_response_code, resp.get_body().c_str());
return aws::http::response_code(http_response_code);
}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/macro.h b/aws-lambda-java-runtime-interface-client/src/main/jni/macro.h
new file mode 100644
index 000000000..df5759afe
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/macro.h
@@ -0,0 +1,14 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+#ifndef _Included_macros
+#define _Included_macros
+
+#define CHECK_EXCEPTION(env, expr) \
+ expr; \
+ if ((env)->ExceptionOccurred()) \
+ goto ERROR;
+
+#endif
diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java
index b81660730..7a7653dc2 100644
--- a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java
+++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java
@@ -1,22 +1,36 @@
/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- */
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
package com.amazonaws.services.lambda.crac;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
import org.mockito.ArgumentMatchers;
import org.mockito.InOrder;
import org.mockito.Mockito;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.doThrow;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.JniHelper;
+
+@DisabledOnOs(OS.MAC)
public class ContextImplTest {
private Resource throwsWithSuppressedException, noop, noop2, throwsException, throwCustomException;
+ @BeforeAll
+ public static void jniLoad() {
+ JniHelper.load();
+ }
+
@BeforeEach
public void setup() throws Exception {
diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/DNSCacheManagerTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/DNSCacheManagerTest.java
new file mode 100644
index 000000000..5eb6f749f
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/DNSCacheManagerTest.java
@@ -0,0 +1,124 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package com.amazonaws.services.lambda.crac;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.JniHelper;
+
+import java.util.Map;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.lang.reflect.Field;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+@DisabledOnOs(OS.MAC)
+public class DNSCacheManagerTest {
+
+ static String CACHE_FIELD_NAME = "cache";
+
+ // this should have no effect, as the DNS cache is cleared explicitly in these tests
+ static {
+ java.security.Security.setProperty("networkaddress.cache.ttl" , "10000");
+ java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "10000");
+ }
+
+ @BeforeAll
+ public static void jniLoad() {
+ JniHelper.load();
+ }
+
+ @BeforeEach
+ public void setup() {
+ Core.resetGlobalContext();
+ DNSManager.clearCache();
+ }
+
+ static class StatefulResource implements Resource {
+
+ int state = 0;
+
+ @Override
+ public void afterRestore(Context extends Resource> context) {
+ state += 1;
+ }
+
+ @Override
+ public void beforeCheckpoint(Context extends Resource> context) {
+ state += 2;
+ }
+
+ int getValue() {
+ return state;
+ }
+ }
+
+ @Test
+ public void positiveDnsCacheShouldBeEmpty() throws CheckpointException, RestoreException, UnknownHostException, ReflectiveOperationException {
+ int baselineDNSEntryCount = getDNSEntryCount();
+
+ StatefulResource resource = new StatefulResource();
+ Core.getGlobalContext().register(resource);
+
+ String[] hosts = {"www.stackoverflow.com", "www.amazon.com", "www.yahoo.com"};
+ for(String singleHost : hosts) {
+ InetAddress address = InetAddress.getByName(singleHost);
+ }
+ // n hosts -> n DNS entries
+ assertEquals(hosts.length, getDNSEntryCount() - baselineDNSEntryCount);
+
+ // this should call the native static method clearDNSCache
+ Core.getGlobalContext().beforeCheckpoint(null);
+
+ // cache should be cleared
+ assertEquals(0, getDNSEntryCount());
+ }
+
+ @Test
+ public void negativeDnsCacheShouldBeEmpty() throws CheckpointException, RestoreException, UnknownHostException, ReflectiveOperationException {
+ int baselineDNSEntryCount = getDNSEntryCount();
+
+ StatefulResource resource = new StatefulResource();
+ Core.getGlobalContext().register(resource);
+
+ String invalidHost = "not.a.valid.host";
+ try {
+ InetAddress address = InetAddress.getByName(invalidHost);
+ fail();
+ } catch(UnknownHostException uhe) {
+ // this is actually fine
+ }
+
+ // 1 host -> 1 DNS entry
+ assertEquals(1, getDNSEntryCount() - baselineDNSEntryCount);
+
+ // this should the native static method clearDNSCache
+ Core.getGlobalContext().beforeCheckpoint(null);
+
+ // cache should be cleared
+ assertEquals(0, getDNSEntryCount());
+ }
+
+ // helper functions to access the cache via reflection (see maven-surefire-plugin command args)
+ protected static Map, ?> getDNSCache() throws ReflectiveOperationException {
+ Class klass = InetAddress.class;
+ Field acf = klass.getDeclaredField(CACHE_FIELD_NAME);
+ acf.setAccessible(true);
+ Object addressCache = acf.get(null);
+ return (Map, ?>) acf.get(addressCache);
+ }
+
+ protected static int getDNSEntryCount() throws ReflectiveOperationException {
+ Map, ?> cache = getDNSCache();
+ return cache.size();
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/AWSLambdaTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/AWSLambdaTest.java
new file mode 100644
index 000000000..49b59c2cd
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/AWSLambdaTest.java
@@ -0,0 +1,578 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package com.amazonaws.services.lambda.runtime.api.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOError;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.LambdaRuntimeApiClientImpl;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.LambdaRuntimeClientMaxRetriesExceededException;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.InvocationRequest;
+import com.amazonaws.services.lambda.runtime.api.client.util.ConcurrencyConfig;
+import com.amazonaws.services.lambda.runtime.api.client.util.EnvReader;
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.api.client.logging.LambdaContextLogger;
+import com.amazonaws.services.lambda.runtime.logging.LogFormat;
+import com.amazonaws.services.lambda.runtime.logging.LogLevel;
+import software.amazon.awssdk.utilslite.SdkInternalThreadLocal;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+class AWSLambdaTest {
+
+ private static final String CONCURRENT_TRACE_ID_KEY = "AWS_LAMBDA_X_TRACE_ID";
+
+ private static class SampleHandler implements RequestHandler