Skip to content
Merged
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 @@ -131,6 +131,8 @@ public abstract class AbstractGrpcTelemetryExporterTest<T, U extends Message> {

private static final AtomicInteger grpcEncodingServerAttempts = new AtomicInteger();

private static volatile String grpcEncodingServerEncoding = "brotli";

@RegisterExtension
@Order(1)
static final SelfSignedCertificateExtension certificate = new SelfSignedCertificateExtension();
Expand Down Expand Up @@ -243,7 +245,8 @@ private static <R extends Message> void handleExport(
}
}

// A minimal server that returns grpc-encoding: brotli to test unsupported encoding handling.
// A minimal server that returns a configurable grpc-encoding to test encoding handling.
// The encoding is controlled via grpcEncodingServerEncoding (defaults to "brotli").
// Both OkHttpGrpcSender (our code) and UpstreamGrpcSender (grpc-java framework) reject unknown
// encodings and fail the export with INTERNAL status.
@RegisterExtension
Expand All @@ -261,7 +264,7 @@ protected void configure(ServerBuilder sb) {
return HttpResponse.of(
ResponseHeaders.builder(HttpStatus.OK)
.contentType(MediaType.parse("application/grpc+proto"))
.add("grpc-encoding", "brotli")
.add("grpc-encoding", grpcEncodingServerEncoding)
.add("grpc-status", "0")
.build(),
HttpData.wrap(frame));
Expand Down Expand Up @@ -329,6 +332,7 @@ void reset() {
attempts.set(0);
httpRequests.clear();
grpcEncodingServerAttempts.set(0);
grpcEncodingServerEncoding = "brotli";
}

@Test
Expand Down Expand Up @@ -461,6 +465,36 @@ void unsupportedGrpcMessageEncoding() {
}
}

// Verifies that a response with flag=1 and grpc-encoding: identity is rejected with INTERNAL.
// Although identity is advertised in grpc-accept-encoding (meaning "no encoding applied"),
// a server setting the compressed flag to 1 is contradictory and should not be accepted.
@Test
@SuppressLogger(GrpcExporter.class)
void identityGrpcMessageEncodingWithCompressedFlagRejected() {
grpcEncodingServerEncoding = "identity";
try (TelemetryExporter<T> testExporter =
exporterBuilder()
.setEndpoint(grpcEncodingServer.httpUri().toString())
.setRetryPolicy(null)
.build()) {
CompletableResultCode result =
testExporter
.export(Collections.singletonList(generateFakeTelemetry()))
.join(10, TimeUnit.SECONDS);
assertThat(result.isSuccess()).isFalse();
assertThat(grpcEncodingServerAttempts).hasValue(1);
assertThat(result.getFailureThrowable())
.isInstanceOfSatisfying(
FailedExportException.GrpcExportException.class,
ex ->
assertThat(requireNonNull(ex.getResponse()))
.satisfies(
grpcResponse ->
assertThat(grpcResponse.getStatusCode())
.isEqualTo(GrpcStatusCode.INTERNAL)));
}
}

@Test
void multipleItems() {
List<T> telemetry = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,25 @@ void responseBodyBoundsGzipCompressed() throws IOException {
.hasMessageContaining("HTTP response body exceeded limit of"));
}

@Test
void identityResponseContentEncoding() {
// Server responds with Content-Encoding: identity, which means no encoding. The export should
// succeed just like a response with no Content-Encoding header.
AbstractMessageLite<?, ?> responseBody = exporter.exportResponse(0);
httpErrors.add(
HttpResponse.of(
ResponseHeaders.builder(HttpStatus.OK)
.contentType(MediaType.PLAIN_TEXT_UTF_8)
.add("Content-Encoding", "identity")
.build(),
HttpData.wrap(responseBody.toByteArray())));
CompletableResultCode result =
exporter
.export(Collections.singletonList(generateFakeTelemetry()))
.join(10, TimeUnit.SECONDS);
assertThat(result.isSuccess()).isTrue();
}

@Test
@SuppressLogger(HttpExporter.class)
void unsupportedResponseContentEncoding() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,9 @@ private HttpResponse toHttpResponse(java.net.http.HttpResponse<InputStream> resp
: (int) (maxResponseBodySize + 1);

String contentEncoding = response.headers().firstValue("Content-Encoding").orElse(null);
if (contentEncoding != null && !"gzip".equalsIgnoreCase(contentEncoding)) {
if (contentEncoding != null
&& !"gzip".equalsIgnoreCase(contentEncoding)
&& !"identity".equalsIgnoreCase(contentEncoding)) {
throw new UnsupportedContentEncodingException(
"Unsupported Content-Encoding: " + contentEncoding);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ private void handleResponse(
Response response, Consumer<HttpResponse> onResponse, Consumer<Throwable> onError) {
try (ResponseBody body = response.body()) {
String contentEncoding = response.header("Content-Encoding");
if (contentEncoding != null && !"gzip".equalsIgnoreCase(contentEncoding)) {
if (contentEncoding != null
&& !"gzip".equalsIgnoreCase(contentEncoding)
&& !"identity".equalsIgnoreCase(contentEncoding)) {
onError.accept(new IOException("Unsupported Content-Encoding: " + contentEncoding));
return;
}
Expand Down
Loading