Skip to content

Commit dd21236

Browse files
authored
Request body blocking for netty (#377)
* add blocking for req body in netty 4.0 * add blocking for req body in netty 4.1
1 parent ab163de commit dd21236

File tree

8 files changed

+134
-1
lines changed

8 files changed

+134
-1
lines changed

instrumentation/netty/netty-4.0/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/netty/v4_0/AttributeKeys.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ public class AttributeKeys {
3333
public static final AttributeKey<Map<String, String>> REQUEST_HEADERS =
3434
io.opentelemetry.javaagent.instrumentation.netty.v4_0.AttributeKeys.attributeKey(
3535
AttributeKeys.class.getName() + ".request-headers");
36+
37+
public static final AttributeKey<?> REQUEST =
38+
io.opentelemetry.javaagent.instrumentation.netty.v4_0.AttributeKeys.attributeKey(
39+
"io.opentelemetry.javaagent.instrumentation.netty.v4_0.AttributeKeys.http-server-request");
3640
}

instrumentation/netty/netty-4.0/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/netty/v4_0/server/HttpServerBlockingRequestHandler.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import io.netty.channel.ChannelHandlerContext;
2222
import io.netty.channel.ChannelInboundHandlerAdapter;
2323
import io.netty.handler.codec.http.DefaultFullHttpResponse;
24+
import io.netty.handler.codec.http.HttpContent;
2425
import io.netty.handler.codec.http.HttpRequest;
2526
import io.netty.handler.codec.http.HttpResponseStatus;
2627
import io.netty.util.Attribute;
2728
import io.netty.util.ReferenceCountUtil;
2829
import io.opentelemetry.api.trace.Span;
2930
import io.opentelemetry.context.Context;
3031
import io.opentelemetry.javaagent.instrumentation.hypertrace.netty.v4_0.AttributeKeys;
32+
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
3133
import java.util.Map;
3234
import org.hypertrace.agent.filter.FilterRegistry;
3335

@@ -55,6 +57,14 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
5557
return;
5658
}
5759
}
60+
if (msg instanceof HttpContent) {
61+
if (FilterRegistry.getFilter().evaluateRequestBody(span, null, null)) {
62+
Attribute<?> requestAttr = channel.attr(AttributeKeys.REQUEST);
63+
HttpRequest req = ((HttpRequestAndChannel) (requestAttr.get())).request();
64+
forbidden(ctx, req);
65+
return;
66+
}
67+
}
5868
ctx.fireChannelRead(msg);
5969
}
6070

instrumentation/netty/netty-4.0/src/test/java/io/opentelemetry/javaagent/instrumentation/hypertrace/netty/v4_0/server/AbstractNetty40ServerInstrumentationTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,39 @@ public void blocking() throws IOException, TimeoutException, InterruptedExceptio
171171
spanData
172172
.getAttributes()
173173
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_BODY)));
174+
175+
RequestBody requestBody = blockedRequestBody(true, 3000, 75);
176+
Request request2 =
177+
new Request.Builder()
178+
.url(String.format("http://localhost:%d/post", port))
179+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
180+
.post(requestBody)
181+
.build();
182+
183+
try (Response response = httpClient.newCall(request2).execute()) {
184+
Assertions.assertEquals(403, response.code());
185+
Assertions.assertTrue(response.body().string().isEmpty());
186+
}
187+
188+
List<List<SpanData>> traces2 = TEST_WRITER.getTraces();
189+
TEST_WRITER.waitForTraces(2);
190+
Assertions.assertEquals(2, traces2.size());
191+
List<SpanData> trace2 = traces2.get(1);
192+
Assertions.assertEquals(1, trace2.size());
193+
SpanData spanData2 = trace2.get(0);
194+
195+
Assertions.assertEquals(
196+
REQUEST_HEADER_VALUE,
197+
spanData2
198+
.getAttributes()
199+
.get(HypertraceSemanticAttributes.httpRequestHeader(REQUEST_HEADER_NAME)));
200+
Assertions.assertNull(
201+
spanData2
202+
.getAttributes()
203+
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_HEADER_NAME)));
204+
Assertions.assertNull(
205+
spanData2
206+
.getAttributes()
207+
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_BODY)));
174208
}
175209
}

instrumentation/netty/netty-4.1/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/netty/v4_1/AttributeKeys.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ public class AttributeKeys {
3131

3232
public static final AttributeKey<Map<String, String>> REQUEST_HEADERS =
3333
AttributeKey.valueOf(AttributeKeys.class, "request-headers");
34+
35+
public static final AttributeKey<?> REQUEST =
36+
AttributeKey.valueOf(
37+
"io.opentelemetry.javaagent.instrumentation.netty.v4_1.server.NettyServerSingletons#http-server-request");
3438
}

instrumentation/netty/netty-4.1/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/netty/v4_1/server/HttpServerBlockingRequestHandler.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import io.netty.channel.ChannelHandlerContext;
2222
import io.netty.channel.ChannelInboundHandlerAdapter;
2323
import io.netty.handler.codec.http.DefaultFullHttpResponse;
24+
import io.netty.handler.codec.http.HttpContent;
2425
import io.netty.handler.codec.http.HttpRequest;
2526
import io.netty.handler.codec.http.HttpResponseStatus;
2627
import io.netty.util.Attribute;
2728
import io.netty.util.ReferenceCountUtil;
2829
import io.opentelemetry.api.trace.Span;
2930
import io.opentelemetry.context.Context;
3031
import io.opentelemetry.javaagent.instrumentation.hypertrace.netty.v4_1.AttributeKeys;
32+
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
3133
import java.util.Map;
3234
import org.hypertrace.agent.filter.FilterRegistry;
3335

@@ -55,6 +57,14 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
5557
return;
5658
}
5759
}
60+
if (msg instanceof HttpContent) {
61+
if (FilterRegistry.getFilter().evaluateRequestBody(span, null, null)) {
62+
Attribute<?> requestAttr = channel.attr(AttributeKeys.REQUEST);
63+
HttpRequest req = ((HttpRequestAndChannel) (requestAttr.get())).request();
64+
forbidden(ctx, req);
65+
return;
66+
}
67+
}
5868
ctx.fireChannelRead(msg);
5969
}
6070

instrumentation/netty/netty-4.1/src/test/java/io/opentelemetry/javaagent/instrumentation/hypertrace/netty/v4_1/server/AbstractNetty41ServerInstrumentationTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,39 @@ public void blocking() throws IOException, TimeoutException, InterruptedExceptio
171171
spanData
172172
.getAttributes()
173173
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_BODY)));
174+
175+
RequestBody requestBody = blockedRequestBody(true, 3000, 75);
176+
Request request2 =
177+
new Request.Builder()
178+
.url(String.format("http://localhost:%d/post", port))
179+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
180+
.post(requestBody)
181+
.build();
182+
183+
try (Response response = httpClient.newCall(request2).execute()) {
184+
Assertions.assertEquals(403, response.code());
185+
Assertions.assertTrue(response.body().string().isEmpty());
186+
}
187+
188+
List<List<SpanData>> traces2 = TEST_WRITER.getTraces();
189+
TEST_WRITER.waitForTraces(2);
190+
Assertions.assertEquals(2, traces2.size());
191+
List<SpanData> trace2 = traces2.get(1);
192+
Assertions.assertEquals(1, trace2.size());
193+
SpanData spanData2 = trace2.get(0);
194+
195+
Assertions.assertEquals(
196+
REQUEST_HEADER_VALUE,
197+
spanData2
198+
.getAttributes()
199+
.get(HypertraceSemanticAttributes.httpRequestHeader(REQUEST_HEADER_NAME)));
200+
Assertions.assertNull(
201+
spanData2
202+
.getAttributes()
203+
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_HEADER_NAME)));
204+
Assertions.assertNull(
205+
spanData2
206+
.getAttributes()
207+
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_BODY)));
174208
}
175209
}

testing-common/src/testFixtures/java/org/hypertrace/agent/testing/AbstractInstrumenterTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,31 @@ public void writeTo(BufferedSink sink) throws IOException {
155155
}
156156
};
157157
}
158+
159+
public static RequestBody blockedRequestBody(
160+
final boolean chunked, final long size, final int writeSize) {
161+
final byte[] buffer = new byte[writeSize];
162+
Arrays.fill(buffer, (byte) 'x');
163+
164+
return new RequestBody() {
165+
@Override
166+
public MediaType contentType() {
167+
return MediaType.get("application/json; charset=utf-8");
168+
}
169+
170+
@Override
171+
public long contentLength() throws IOException {
172+
return chunked ? -1L : size;
173+
}
174+
175+
@Override
176+
public void writeTo(BufferedSink sink) throws IOException {
177+
sink.write("{\"block=true\":\"".getBytes());
178+
for (int count = 0; count < size; count += writeSize) {
179+
sink.write(buffer, 0, (int) Math.min(size - count, writeSize));
180+
}
181+
sink.write("\"}".getBytes());
182+
}
183+
};
184+
}
158185
}

testing-common/src/testFixtures/java/org/hypertrace/agent/testing/mockfilter/MockFilter.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package org.hypertrace.agent.testing.mockfilter;
1818

19+
import io.opentelemetry.api.common.AttributeKey;
1920
import io.opentelemetry.api.trace.Span;
21+
import io.opentelemetry.sdk.trace.ReadableSpan;
2022
import java.util.Map;
2123
import org.hypertrace.agent.filter.api.Filter;
2224

@@ -37,6 +39,14 @@ public boolean evaluateRequestHeaders(Span span, Map<String, String> headers) {
3739

3840
@Override
3941
public boolean evaluateRequestBody(Span span, String body, Map<String, String> headers) {
40-
return body.contains("block=true");
42+
if (body != null && body.contains("block=true")) {
43+
return true;
44+
}
45+
if (span instanceof ReadableSpan) {
46+
String spanReqBody =
47+
((ReadableSpan) span).getAttribute(AttributeKey.stringKey("http.request.body"));
48+
return spanReqBody != null && spanReqBody.contains("block=true");
49+
}
50+
return false;
4151
}
4252
}

0 commit comments

Comments
 (0)