Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DT-898 Defaulting to binary HTTP body payloads #66

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,11 @@ private JsonNode _syncGetPartyPrompt() {
HttpRequest.newBuilder().uri(uri).timeout(Duration.ofHours(1)).GET();
orchestratorAuthHeader.forEach(
(name, values) -> values.forEach(value -> httpRequestBuilder.header(name, value)));
String stringResponseBody =
byte[] byteArrayResponseBody =
HttpClient.newHttpClient()
.send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofString())
.send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray())
.body();
return new ConformanceMessageBody(stringResponseBody).getJsonBody();
return new ConformanceMessageBody(byteArrayResponseBody).getJsonBody();
}

private void _handleNextActionPrompt() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
package org.dcsa.conformance.core.traffic;

import static org.dcsa.conformance.core.toolkit.JsonToolkit.OBJECT_MAPPER;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import lombok.Getter;
import lombok.ToString;

import static org.dcsa.conformance.core.toolkit.JsonToolkit.OBJECT_MAPPER;

@Getter
@ToString
public class ConformanceMessageBody {
private final boolean isCorrectJson;
private final boolean isRawByteArray;
private final byte[] byteArrayBody;
private final String stringBody;
private final JsonNode jsonBody;
private final boolean isCorrectJson;

public ConformanceMessageBody(byte[] byteArrayBody) {
this.isRawByteArray = true;
this.byteArrayBody = byteArrayBody == null ? new byte[0] : byteArrayBody;
this.stringBody = new String(this.byteArrayBody, StandardCharsets.UTF_8);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work if the content is not valid UTF-8 (which is likely for the use-cases that need raw byte transfers)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding, we're not allowed to change things like indentation or newline type, but the content type of these messages must remain UTF-8 even when they use JWS/JWE -- in fact the latter elements are Base64-encoded as ASCII, which is a subset of UTF-8.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I specifically need support for https://app.swaggerhub.com/apis/dcsaorg/DCSA_EBL_PINT/3.0.0-Beta-1#/Transfer%20additional%20document/put_v3_envelopes__envelopeReference__additional_documents__documentChecksum_, which is about transferring additional documentation.

Said documentation can be any file including but not limited to PDF and will be transferred in the application/octet-stream stream. The validation will need to assert this stream matches the expected checksum, which is why we need binary transfers. However, there is no rule stating that the content will be a valid UTF-8 byte sequence. In fact, for a PDF, a zip file, scanned images, it will very likely not be valid UTF-8.

boolean isCorrectJson;
JsonNode jsonBody;
try {
jsonBody = OBJECT_MAPPER.readTree(this.stringBody);
isCorrectJson = true;
} catch (JsonProcessingException e) {
jsonBody = OBJECT_MAPPER.createObjectNode();
isCorrectJson = false;
}
this.isCorrectJson = isCorrectJson;
this.jsonBody = jsonBody;
}

public ConformanceMessageBody(String stringBody) {
this.isRawByteArray = false;
this.stringBody = stringBody == null ? "" : stringBody;
this.byteArrayBody = this.stringBody.getBytes(StandardCharsets.UTF_8);
boolean isCorrectJson;
JsonNode jsonBody;
try {
Expand All @@ -31,23 +54,32 @@ public ConformanceMessageBody(String stringBody) {
}

public ConformanceMessageBody(JsonNode jsonBody) {
this.isRawByteArray = false;
this.isCorrectJson = true;
this.jsonBody = jsonBody;
this.stringBody = jsonBody.toPrettyString();
this.byteArrayBody = this.stringBody.getBytes(StandardCharsets.UTF_8);
}

public ObjectNode toJson() {
/* package local */ ObjectNode toJson() {
ObjectNode objectNode = OBJECT_MAPPER.createObjectNode();
objectNode.put("isRawByteArray", isRawByteArray);
objectNode.put("isCorrectJson", isCorrectJson);
if (isCorrectJson) {
if (isRawByteArray) {
objectNode.put("byteArrayBody", Base64.getEncoder().encodeToString(byteArrayBody));
} else if (isCorrectJson) {
objectNode.set("jsonBody", jsonBody);
} else {
objectNode.put("stringBody", stringBody);
}
return objectNode;
}

public static ConformanceMessageBody fromJson(ObjectNode objectNode) {
/* package local */ static ConformanceMessageBody fromJson(ObjectNode objectNode) {
boolean isRawByteArray = objectNode.path("isRawByteArray").asBoolean();
if (isRawByteArray) {
return new ConformanceMessageBody(Base64.getDecoder().decode(objectNode.get("byteArrayBody").asText()));
}
boolean isCorrectJson = objectNode.get("isCorrectJson").asBoolean();
if (isCorrectJson) {
return new ConformanceMessageBody(objectNode.get("jsonBody"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -41,7 +43,7 @@ public APIGatewayProxyResponseEvent handleRequest(
Objects.requireNonNullElse(
event.getMultiValueQueryStringParameters(), Collections.emptyMap()),
event.getMultiValueHeaders(),
event.getBody()),
event.getBody().getBytes(StandardCharsets.UTF_8)),
LambdaToolkit.createDeferredSandboxTaskConsumer(persistenceProvider));

Map<String, List<String>> responseHeaders = conformanceWebResponse.getValueListHeaders();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public void notifyNextActionParty() {
: Map.of(
counterpartConfiguration.getAuthHeaderName(),
List.of(counterpartConfiguration.getAuthHeaderValue())),
""));
new byte[]{}));
}

public JsonNode handleGetPartyPrompt(String partyName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ public static ConformanceWebResponse handleRequest(
deferredSandboxTaskConsumer,
sandboxId,
partyName,
webRequest.body());
webRequest.bodyBytes());
} else if (remainingUri.startsWith("/api")) {
return _handlePartyInboundConformanceRequest(
persistenceProvider, deferredSandboxTaskConsumer, sandboxId, partyName, webRequest);
Expand Down Expand Up @@ -469,7 +469,7 @@ private static ConformanceWebResponse _handlePartyInboundConformanceRequest(
party.getName(),
party.getRole(),
webRequest.headers(),
new ConformanceMessageBody(webRequest.body()),
new ConformanceMessageBody(webRequest.bodyBytes()),
System.currentTimeMillis()));
conformanceRequestReference.set(conformanceRequest);
conformanceResponseReference.set(party.handleRequest(conformanceRequest));
Expand Down Expand Up @@ -571,9 +571,9 @@ private static ConformanceResponse _syncHttpRequest(ConformanceRequest conforman
.message()
.headers()
.forEach((name, values) -> values.forEach(value -> httpRequestBuilder.header(name, value)));
HttpResponse<String> httpResponse =
HttpResponse<byte[]> httpResponse =
HttpClient.newHttpClient()
.send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofString());
.send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
ConformanceResponse conformanceResponse =
conformanceRequest.createResponse(
httpResponse.statusCode(),
Expand Down Expand Up @@ -686,7 +686,7 @@ private static ConformanceWebResponse _handlePostPartyInput(
Consumer<JsonNode> deferredSandboxTaskConsumer,
String sandboxId,
String partyName,
String input) {
byte[] inputBytes) {
new OrchestratorTask(
persistenceProvider,
conformanceWebRequest ->
Expand All @@ -695,7 +695,7 @@ private static ConformanceWebResponse _handlePostPartyInput(
sandboxId,
"handling input from party " + partyName,
orchestrator ->
orchestrator.handlePartyInput(new ConformanceMessageBody(input).getJsonBody()))
orchestrator.handlePartyInput(new ConformanceMessageBody(inputBytes).getJsonBody()))
.run();
return new ConformanceWebResponse(200, JsonToolkit.JSON_UTF_8, Collections.emptyMap(), "{}");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.util.Base64;
import java.util.Collection;
import java.util.Map;
import org.dcsa.conformance.core.toolkit.JsonToolkit;
Expand All @@ -13,15 +15,15 @@ public record ConformanceWebRequest(
String url,
Map<String, ? extends Collection<String>> queryParameters,
Map<String, ? extends Collection<String>> headers,
String body) {
byte[] bodyBytes) {

public ObjectNode toJson() {
ObjectNode objectNode =
OBJECT_MAPPER
.createObjectNode()
.put("method", method)
.put("url", url)
.put("body", body);
.put("bodyBytes", Base64.getEncoder().encodeToString(bodyBytes));
objectNode.set(
"queryParameters", JsonToolkit.mapOfStringToStringCollectionToJson(queryParameters));
objectNode.set("headers", JsonToolkit.mapOfStringToStringCollectionToJson(headers));
Expand All @@ -35,6 +37,6 @@ public static ConformanceWebRequest fromJson(ObjectNode objectNode) {
JsonToolkit.mapOfStringToStringCollectionFromJson(
(ArrayNode) objectNode.get("queryParameters")),
JsonToolkit.mapOfStringToStringCollectionFromJson((ArrayNode) objectNode.get("headers")),
objectNode.get("url").asText());
Base64.getDecoder().decode(objectNode.get("bodyBytes").asText()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import jakarta.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
Expand Down Expand Up @@ -214,7 +215,9 @@ public void handleWebuiRequest(
persistenceProvider,
deferredSandboxTaskConsumer)
.handleRequest(
"spring-boot-env", JsonToolkit.stringToJsonNode(_getRequestBody(servletRequest)))
"spring-boot-env",
JsonToolkit.stringToJsonNode(
new String(_getRequestBodyBytes(servletRequest), StandardCharsets.UTF_8)))
.toPrettyString());
}

Expand Down Expand Up @@ -250,7 +253,7 @@ public void handleRequest(
requestUrl,
_getQueryParameters(servletRequest),
requestHeaders,
_getRequestBody(servletRequest)),
_getRequestBodyBytes(servletRequest)),
deferredSandboxTaskConsumer);

_writeResponse(
Expand Down Expand Up @@ -294,8 +297,8 @@ private static void _writeResponse(
}

@SneakyThrows
private static String _getRequestBody(HttpServletRequest request) {
return request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
private static byte[] _getRequestBodyBytes(HttpServletRequest request) {
return request.getInputStream().readAllBytes();
}

@GetMapping(value = "/")
Expand Down
Loading