Skip to content

Commit

Permalink
Issue #1060: Add reserved HTTP header "http.query" to replace the que…
Browse files Browse the repository at this point in the history
…ry string.

Signed-off-by: Yufei Cai <yufei.cai@bosch.io>
  • Loading branch information
yufei-cai committed May 26, 2021
1 parent 16dc84c commit 5b5686d
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.text.MessageFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Map;
Expand Down Expand Up @@ -223,7 +224,7 @@ protected CompletionStage<SendResult> publishMessage(final Signal<?> signal,

private HttpRequest createRequest(final HttpPublishTarget publishTarget, final ExternalMessage message) {
final Pair<Iterable<HttpHeader>, ContentType> headersPair = getHttpHeadersPair(message);
final HttpRequest requestWithoutEntity = factory.newRequest(publishTarget).addHeaders(headersPair.first());
final HttpRequest requestWithoutEntity = newRequestWithoutEntity(publishTarget, headersPair.first(), message);
final ContentType contentTypeHeader = headersPair.second();
if (contentTypeHeader != null) {
final HttpEntity.Strict httpEntity =
Expand All @@ -236,15 +237,29 @@ private HttpRequest createRequest(final HttpPublishTarget publishTarget, final E
}
}

private HttpRequest newRequestWithoutEntity(final HttpPublishTarget publishTarget,
final Iterable<HttpHeader> headers, final ExternalMessage message) {
final HttpRequest request = factory.newRequest(publishTarget).addHeaders(headers);
final String httpQuery = message.getHeaders().get(ReservedHeaders.HTTP_QUERY.name);
if (httpQuery != null) {
final Uri uriWithQuery = request.getUri().rawQueryString(httpQuery);
return request.withUri(uriWithQuery);
} else {
return request;
}
}

private static Pair<Iterable<HttpHeader>, ContentType> getHttpHeadersPair(final ExternalMessage message) {
final Collection<HttpHeader> headers = new ArrayList<>(message.getHeaders().size());
ContentType contentType = null;
for (final Map.Entry<String, String> entry : message.getHeaders().entrySet()) {
final HttpHeader httpHeader = HttpHeader.parse(entry.getKey(), entry.getValue());
if (httpHeader instanceof ContentType) {
contentType = (ContentType) httpHeader;
} else {
headers.add(httpHeader);
if (!ReservedHeaders.contains(entry.getKey())) {
final HttpHeader httpHeader = HttpHeader.parse(entry.getKey(), entry.getValue());
if (httpHeader instanceof ContentType) {
contentType = (ContentType) httpHeader;
} else {
headers.add(httpHeader);
}
}
}
return Pair.create(headers, contentType);
Expand Down Expand Up @@ -597,5 +612,23 @@ private static Uri stripUserInfo(final Uri requestUri) {
return requestUri.userInfo("");
}

private enum ReservedHeaders {

HTTP_QUERY("http.query");

private final String name;

ReservedHeaders(final String name) {
this.name = name;
}

private boolean matches(final String headerName) {
return name.equalsIgnoreCase(headerName);
}

private static boolean contains(final String header) {
return Arrays.stream(values()).anyMatch(reservedHeader -> reservedHeader.matches(header));
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.time.ZonedDateTime;
Expand Down Expand Up @@ -791,6 +792,48 @@ public void testAwsRequestSigning() throws Exception {
}};
}


@Test
public void testReservedHeaders() throws Exception {
new TestKit(actorSystem) {{

// GIVEN: reserved headers are set
final Map<String, String> reservedHeaders = Map.of("http.query", "a=b&c=d&e=f");

// WHEN: publisher actor is asked to publish a message with reserved headers
final TestProbe probe = new TestProbe(actorSystem);
setupMocks(probe);
final Target target = decorateTarget(createTestTarget());
final Message<?> message = Message.newBuilder(
MessageHeaders.newBuilder(MessageDirection.FROM, TestConstants.Things.THING_ID, "please-respond")
.build()
).build();
final Signal<?> source = SendThingMessage.of(TestConstants.Things.THING_ID, message, DittoHeaders.empty());
final OutboundSignal outboundSignal =
OutboundSignalFactory.newOutboundSignal(source, Collections.singletonList(target));
final ExternalMessage externalMessage =
ExternalMessageFactory.newExternalMessageBuilder(reservedHeaders)
.withText("payload")
.build();
final Adaptable adaptable = DittoProtocolAdapter.newInstance().toAdaptable(source);
final OutboundSignal.Mapped mapped =
OutboundSignalFactory.newMappedOutboundSignal(outboundSignal, adaptable, externalMessage);
final OutboundSignal.MultiMapped multiMapped =
OutboundSignalFactory.newMultiMappedOutboundSignal(List.of(mapped), getRef());
final Props props = getPublisherActorProps();
final ActorRef publisherActor = childActorOf(props);
publisherCreated(this, publisherActor);
publisherActor.tell(multiMapped, getRef());

// THEN: reserved headers do not appear as HTTP headers
final HttpRequest request = received.take();
assertThat(request.getHeader("http.query")).isEmpty();

// THEN: reserved headers are evaluated
assertThat(request.getUri().queryString(StandardCharsets.UTF_8)).contains("a=b&c=d&e=f");
}};
}

private OutboundSignal.MultiMapped newMultiMappedWithContentType(final Target target,
final ActorRef sender) {
return OutboundSignalFactory.newMultiMappedOutboundSignal(
Expand Down

0 comments on commit 5b5686d

Please sign in to comment.