Skip to content

Commit b8d9d73

Browse files
committed
feat: 支持org.apache.httpcomponents:fluent-hc全版本增加traceId
1 parent 7a5346c commit b8d9d73

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/service/HttpClient.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
package io.dongtai.iast.core.handler.hookpoint.service;
22

3-
import java.util.*;
3+
import java.util.Arrays;
4+
import java.util.HashSet;
5+
import java.util.Set;
46

57
public class HttpClient {
8+
69
private static final String JAVA_NET_URL_CONN = "sun.net.www.protocol.http.HttpURLConnection.connect()";
710
private static final String JAVA_NET_URL_CONN_GET_INPUT_STREAM = "sun.net.www.protocol.http.HttpURLConnection.getInputStream()";
811
private static final String JAVA_NET_URL_CONN_GET_OUTPUT_STREAM = "sun.net.www.protocol.http.HttpURLConnection.getOutputStream()";
12+
13+
// 草这都是哪个GA里的类啊鬼能知道啊...
914
private static final String APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI = " org.apache.commons.httpclient.HttpMethodBase.setURI(org.apache.commons.httpclient.URI)".substring(1);
1015
private static final String APACHE_HTTP_CLIENT_EXECUTE = " org.apache.http.impl.client.CloseableHttpClient.doExecute(org.apache.http.HttpHost,org.apache.http.HttpRequest,org.apache.http.protocol.HttpContext)".substring(1);
16+
17+
// GA: org.apache.httpcomponents:fluent-hc
18+
private static final String APACHE_HTTP_HTTPCOMPONENTS_EXECUTE = " org.apache.http.client.fluent.Request.execute()".substring(1);
19+
1120
private static final String APACHE_HTTP_CLIENT5_EXECUTE = " org.apache.hc.client5.http.impl.classic.CloseableHttpClient.doExecute(org.apache.hc.core5.http.HttpHost,org.apache.hc.core5.http.ClassicHttpRequest,org.apache.hc.core5.http.protocol.HttpContext)".substring(1);
1221
private static final String OKHTTP_CALL_EXECUTE = "com.squareup.okhttp.Call.execute()";
1322
private static final String OKHTTP_CALL_ENQUEUE = "com.squareup.okhttp.Call.enqueue(com.squareup.okhttp.Callback)";
@@ -33,6 +42,7 @@ public class HttpClient {
3342
JAVA_NET_URL_CONN_GET_OUTPUT_STREAM,
3443
APACHE_LEGACY_HTTP_CLIENT_REQUEST_SET_URI,
3544
APACHE_HTTP_CLIENT_EXECUTE,
45+
APACHE_HTTP_HTTPCOMPONENTS_EXECUTE,
3646
APACHE_HTTP_CLIENT5_EXECUTE,
3747
OKHTTP_CALL_EXECUTE,
3848
OKHTTP_CALL_ENQUEUE,
@@ -78,6 +88,10 @@ public static boolean matchApacheHttp4(String signature) {
7888
public static boolean matchApacheHttp5(String signature) {
7989
return APACHE_HTTP_CLIENT5_EXECUTE.equals(signature);
8090
}
91+
92+
public static boolean matchApacheHttpComponents(String signature) {
93+
return APACHE_HTTP_HTTPCOMPONENTS_EXECUTE.equals(signature);
94+
}
8195

8296
public static boolean matchOkhttp(String signature) {
8397
return OKHTTP_SIGNATURE.contains(signature);

dongtai-core/src/main/java/io/dongtai/iast/core/handler/hookpoint/service/trace/HttpService.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public void addTrace(MethodEvent event, PolicyNode policyNode) {
4040
traceId = addTraceToApacheHttpClientLegacy(event);
4141
} else if (HttpClient.matchOkhttp(this.matchedSignature)) {
4242
traceId = addTraceToOkhttp(event);
43+
} else if (HttpClient.matchApacheHttpComponents(this.matchedSignature)) {
44+
traceId = addTraceToApacheHttpComponents(event);
4345
}
4446

4547
if (traceId != null && !traceId.isEmpty()) {
@@ -273,13 +275,66 @@ private void addHeaderToOkhttp(MethodEvent event, Map<String, String> headers) {
273275
}
274276
}
275277

278+
/**
279+
* 添加traceId到Apache HttpComponents的请求上
280+
*
281+
* @param event
282+
* @return
283+
*/
284+
private String addTraceToApacheHttpComponents(MethodEvent event) {
285+
Object obj = event.objectInstance;
286+
if (obj == null) {
287+
return null;
288+
}
289+
try {
290+
String className = obj.getClass().getName();
291+
if (!HttpClient.matchApacheHttpComponents(className)) {
292+
return null;
293+
}
294+
295+
// 关于库的版本兼容性:
296+
// 在GA org.apache.httpcomponents:fluent-hc的[4.4, 4.5.14]这个区间的版本里的request字段是这个org.apache.http.client.fluent.InternalHttpRequest类型
297+
// private final InternalHttpRequest request;
298+
// 然后org.apache.http.client.fluent.InternalHttpRequest这个类继承的org.apache.http.message.AbstractHttpMessage上有个setHeader方法:
299+
// @Override // org.apache.http.HttpMessage
300+
// public void setHeader(String name, String value) {
301+
// Args.notNull(name, "Header name");
302+
// this.headergroup.updateHeader(new BasicHeader(name, value));
303+
// }
304+
// 另外一提,org.apache.http.message.AbstractHttpMessage是在httpcomponents-httpcore:httpcore下的,它自从4.0-alpha5版本被添加了之后就没有变更过
305+
//
306+
// 在GA org.apache.httpcomponents:fluent-hc的[4.2, 4.4) 版本区间的request字段是org.apache.http.client.methods.HttpRequestBase类型,这个类属于依赖中的org.apache.httpcomponents:httpclient
307+
// private final HttpRequestBase request;
308+
// 在org.apache.httpcomponents:httpclient的[4.0.1, 4.2.6]版本区间,org.apache.http.client.methods.HttpRequestBase这个类是继承的org.apache.http.message.AbstractHttpMessage,此条分支可以与上面的合并
309+
// org.apache.httpcomponents:httpclient的[4.3, 4.5.14]区间内是继承的org.apache.http.client.methods.AbstractExecutionAwareRequest
310+
// org.apache.http.client.methods.AbstractExecutionAwareRequest自从4.3.4版本被添加依赖,一直继承的org.apache.http.message.AbstractHttpMessage,此条分支又可以与上面合并
311+
// 所有版本的实现最终都会直接继承或者间接继承到org.apache.http.message.AbstractHttpMessage,所以下面的操作才可以统一
312+
313+
Field reqField = obj.getClass().getDeclaredField("request");
314+
reqField.setAccessible(true);
315+
Object internalHttpRequest = reqField.get(obj);
316+
Method setHeaderMethod = internalHttpRequest.getClass().getMethod("setHeader", String.class, String.class);
317+
318+
// 然后把追踪的头加上
319+
final String traceId = ContextManager.nextTraceId();
320+
setHeaderMethod.invoke(internalHttpRequest, ContextManager.getHeaderKey(), traceId);
321+
setHeaderMethod.invoke(internalHttpRequest, ContextManager.getParentKey(), String.valueOf(EngineManager.getAgentId()));
322+
return traceId;
323+
} catch (Throwable e) {
324+
DongTaiLog.debug("add traceId header to apache http components failed: {}, {}", e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : "");
325+
}
326+
return null;
327+
}
328+
276329
public static boolean validate(MethodEvent event) {
277330
if (HttpClient.matchJavaNetUrl(event.signature)) {
278331
return validateURLConnection(event);
279332
} else if (HttpClient.matchApacheHttp4(event.signature) || HttpClient.matchApacheHttp5(event.signature)) {
280333
return validateApacheHttpClient(event);
281334
} else if (HttpClient.matchOkhttp(event.signature)) {
282335
return validateOkhttp(event);
336+
} else if (HttpClient.matchApacheHttpComponents(event.signature)) {
337+
return validateApacheHttpComponents(event);
283338
}
284339
return true;
285340
}
@@ -377,4 +432,37 @@ public static boolean validateOkhttp(MethodEvent event) {
377432
}
378433
return false;
379434
}
435+
436+
/**
437+
* 验证是否是合法的
438+
*
439+
* @param event
440+
* @return
441+
*/
442+
public static boolean validateApacheHttpComponents(MethodEvent event) {
443+
Object obj = event.objectInstance;
444+
if (obj == null) {
445+
return false;
446+
}
447+
try {
448+
String className = obj.getClass().getName();
449+
if (!HttpClient.matchApacheHttpComponents(className)) {
450+
return false;
451+
}
452+
453+
// 关于类的版本兼容性,详见 #addTraceToApacheHttpComponents方法
454+
Field reqField = obj.getClass().getDeclaredField("request");
455+
reqField.setAccessible(true);
456+
Object internalHttpRequest = reqField.get(obj);
457+
Object header = internalHttpRequest.getClass().getMethod("getFirstHeader", String.class).invoke(internalHttpRequest, ContextManager.getHeaderKey());
458+
// traceId header not exists
459+
if (header == null) {
460+
return true;
461+
}
462+
} catch (Throwable e) {
463+
DongTaiLog.debug("validate apache http components failed: {}, {}", e.getMessage(), e.getCause() != null ? e.getCause().getMessage() : "");
464+
}
465+
return false;
466+
}
467+
380468
}

0 commit comments

Comments
 (0)