Skip to content

Commit

Permalink
Merge pull request #581 from jam01/grizzly-refactor
Browse files Browse the repository at this point in the history
Grizzly Http Server refactor
  • Loading branch information
Sergei Malafeev authored Jul 12, 2020
2 parents 06a58cc + d3bfd68 commit 7bfc990
Show file tree
Hide file tree
Showing 19 changed files with 296 additions and 513 deletions.
7 changes: 0 additions & 7 deletions opentracing-specialagent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -470,13 +470,6 @@
<optional>true</optional>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentracing.contrib.specialagent.rule</groupId>
<artifactId>mule-4-http-service</artifactId>
<version>${project.version}</version>
<optional>true</optional>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentracing.contrib.specialagent.rule</groupId>
<artifactId>mule-4-module-artifact</artifactId>
Expand Down
16 changes: 2 additions & 14 deletions rule/grizzly-http-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<properties>
<sa.rule.name>grizzly:http-server</sa.rule.name>
<min.version>2.3.35</min.version>
<version.opentracing.grizzly>0.1.3</version.opentracing.grizzly>
<version.opentracing.grizzly>0.2.0</version.opentracing.grizzly>
</properties>
<build>
<plugins>
Expand All @@ -42,15 +42,10 @@
<passes>
<pass>
<dependencies>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-framework</artifactId>
<version>org.glassfish.grizzly:grizzly-framework:[${min.version},]</version>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-http</artifactId>
<version>org.glassfish.grizzly:grizzly-framework:[${min.version},]</version>
<version>org.glassfish.grizzly:grizzly-http:[${min.version},]</version>
</dependency>
</dependencies>
</pass>
Expand All @@ -76,13 +71,6 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-framework</artifactId>
<version>${min.version}</version>
<optional>true</optional>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-http</artifactId>
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.opentracing.contrib.specialagent.rule.grizzly.http.server;

import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import io.opentracing.contrib.grizzly.http.server.GizzlyHttpRequestPacketAdapter;
import io.opentracing.contrib.grizzly.http.server.GrizzlyServerSpanDecorator;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
import io.opentracing.util.GlobalTracer;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import org.glassfish.grizzly.http.HttpContent;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.HttpResponsePacket;

public class HttpServerFilterIntercept {
public static void onHandleReadExit(
final Object ctxObj,
Object toReturn) {

FilterChainContext ctx = (FilterChainContext) ctxObj;

// If not continuing to process
// See: org.glassfish.grizzly.filterchain.InvokeAction.TYPE
// If we have have already started a span for this request
if (!(ctx.getMessage() instanceof HttpContent) || ((NextAction) toReturn).type() != 0 || SpanAssociations.get().hasSpanFor(ctx)) {
return;
}

Tracer tracer = GlobalTracer.get();
final HttpRequestPacket request = (HttpRequestPacket) ((HttpContent) ctx.getMessage()).getHttpHeader();

TextMap adapter = new GizzlyHttpRequestPacketAdapter(request);
SpanContext extractedContext = tracer.extract(Format.Builtin.HTTP_HEADERS,
adapter);

final Span span = tracer.buildSpan("HTTP::" + request.getMethod().getMethodString())
.ignoreActiveSpan()
.asChildOf(extractedContext)
.start();

GrizzlyServerSpanDecorator.STANDARD_TAGS.onRequest(request, span);
ctx.addCompletionListener(new SpanCompletionListener(span));
SpanAssociations.get().associateSpan(ctx, span);
}

public static void onPrepareResponse(
final Object ctx,
final Object response) {
Span toTag = SpanAssociations.get().retrieveSpan(ctx);
if (toTag != null) {
GrizzlyServerSpanDecorator.STANDARD_TAGS.onResponse((HttpResponsePacket) response, toTag);
}
}

public static class SpanCompletionListener implements FilterChainContext.CompletionListener {
private final Span span;

public SpanCompletionListener(Span span) {
this.span = span;
}

@Override
public void onComplete(FilterChainContext context) {
span.finish();
SpanAssociations.get().dispose(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package io.opentracing.contrib.specialagent.rule.grizzly.http.server;

import io.opentracing.contrib.specialagent.Level;
import io.opentracing.contrib.specialagent.Logger;
import io.opentracing.Scope;
import io.opentracing.contrib.specialagent.AgentRule;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.utility.JavaModule;

import static net.bytebuddy.matcher.ElementMatchers.*;

public class HttpServerFilterRule extends AgentRule {
public static final Logger logger = Logger.getLogger(HttpServerFilterRule.class);
private static final String FILTER_CHAIN_CONTEXT = "org.glassfish.grizzly.filterchain.FilterChainContext";
private static final String HANDLE_READ = "handleRead";

@Override
public AgentBuilder buildAgentChainedGlobal1(final AgentBuilder builder) {
return builder
.type(named("org.glassfish.grizzly.http.HttpServerFilter"))
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
return builder.visit(advice(typeDescription).to(HandleReadAdvice.class).on(named(HANDLE_READ)
.and(takesArgument(0, named(FILTER_CHAIN_CONTEXT)))));
}
})
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
return builder.visit(advice(typeDescription).to(PrepareResponseAdvice.class).on(named("prepareResponse")
.and(takesArgument(0, named(FILTER_CHAIN_CONTEXT)))
.and(takesArgument(2, named("org.glassfish.grizzly.http.HttpResponsePacket")))));
}
})

.type(hasSuperClass(named("org.glassfish.grizzly.filterchain.BaseFilter"))
// common http server filters
.and(not(named("org.glassfish.grizzly.filterchain.TransportFilter")
.or(named("org.glassfish.grizzly.nio.transport.TCPNIOTransportFilter"))
.or(named("org.glassfish.grizzly.http.HttpServerFilter"))
.or(named("org.glassfish.grizzly.http.HttpCodecFilter"))
.or(named("org.glassfish.grizzly.utils.IdleTimeoutFilter"))
// common http client filters
.or(named("com.ning.http.client.providers.grizzly.AsyncHttpClientFilter"))
.or(named("org.glassfish.grizzly.websockets.WebSocketClientFilter"))
.or(hasSuperClass(named("org.glassfish.grizzly.http.HttpClientFilter"))))))
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
return builder.visit(advice(typeDescription).to(WorkerHandleReadAdvice.class).on(named(HANDLE_READ)
.and(takesArgument(0, named(FILTER_CHAIN_CONTEXT)))));
}
});
}

public static class HandleReadAdvice {
@Advice.OnMethodExit
public static void onExit(
final @ClassName String className,
final @Advice.Origin String origin,
@Advice.Argument(0) final Object ctx,
@Advice.Return Object toReturn) {
if (isAllowed(className, origin))
HttpServerFilterIntercept.onHandleReadExit(ctx, toReturn);
}
}

public static class WorkerHandleReadAdvice {
@Advice.OnMethodEnter
public static void onEnter(
final @ClassName String className,
final @Advice.Origin String origin,
final @Advice.This Object thiz,
@Advice.Argument(value = 0, typing = Assigner.Typing.DYNAMIC) final Object ctx,
@Advice.Local("scope") Scope scope) {

if (hackShouldFilter(thiz))
return;

if (isAllowed(className, origin))
scope = WorkerFilterIntercept.onHandleReadEnter(ctx);
}

@Advice.OnMethodExit
public static void onExit(
final @ClassName String className,
final @Advice.Origin String origin,
final @Advice.This Object thiz,
@Advice.Local("scope") Scope scope) {

if (hackShouldFilter(thiz))
return;

if (isAllowed(className, origin))
WorkerFilterIntercept.onHandleReadExit(scope);
}
}

public static class PrepareResponseAdvice {
@Advice.OnMethodExit
public static void onExit(
final @ClassName String className,
final @Advice.Origin String origin,
@Advice.Argument(value = 0, typing = Assigner.Typing.DYNAMIC) final Object ctx,
@Advice.Argument(value = 2, typing = Assigner.Typing.DYNAMIC) final Object response) {

if (isAllowed(className, origin))
HttpServerFilterIntercept.onPrepareResponse(ctx, response);
}

}

public static boolean hackShouldFilter(Object thiz) {
// TODO: 7/11/20 figure out why these are not filtered at TypeDescription
logger.log(Level.FINER, "Checking predicate for potential worker filter " + thiz.getClass().getName());
return "com.ning.http.client.providers.grizzly.AsyncHttpClientFilter".equals(thiz.getClass().getName()) ||
"org.glassfish.grizzly.websockets.WebSocketClientFilter".equals(thiz.getClass().getName());
}
}
Loading

0 comments on commit 7bfc990

Please sign in to comment.