diff --git a/.github/workflows/plugins-test.yaml b/.github/workflows/plugins-test.yaml
index c9e59464f0403d2f783ff869e4ab748c26dc6bbc..eaff3f0da57a9e4547889699e56298be1da9cece 100644
--- a/.github/workflows/plugins-test.yaml
+++ b/.github/workflows/plugins-test.yaml
@@ -264,6 +264,8 @@ jobs:
run: bash test/plugin/run.sh spring-4.1.x-scenario
- name: Run solrj 7.x (12)
run: bash test/plugin/run.sh solrj-7.x-scenario
+ - name: Run httpclient 2.0-3.1 (5)
+ run: bash test/plugin/run.sh httpclient-3.x-scenario
- name: Run httpclient 4.3.x-4.5.x (14)
run: bash test/plugin/run.sh httpclient-4.3.x-scenario
- name: Run httpasyncclient 4.0-4.1.3 (7)
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9ac2c057cef85634903f3a450c3daf15cc8029be
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/pom.xml
@@ -0,0 +1,50 @@
+
+
+
+
+ 4.0.0
+
+
+ org.apache.skywalking
+ apm-sdk-plugin
+ 7.0.0-SNAPSHOT
+
+
+ apm-httpclient-3.x-plugin
+ SkyWalking Java Agent for commons-httpclient (http://hc.apache.org/httpclient-3.x/)
+ jar
+
+ httpclient-3.x-plugin
+
+
+ UTF-8
+ 3.1
+
+
+
+
+ commons-httpclient
+ commons-httpclient
+ ${commons-httpclient.version}
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/HttpClientExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/HttpClientExecuteInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..600fb83a9e48637c73a58f2035b308b57fac65c5
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/HttpClientExecuteInterceptor.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.httpclient.v3;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.httpclient.HostConfiguration;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.URIException;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+/**
+ * @author kezhenxu94
+ */
+public class HttpClientExecuteInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(
+ final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final MethodInterceptResult result) throws Throwable {
+
+ final HttpClient client = (HttpClient) objInst;
+
+ HostConfiguration hostConfiguration = (HostConfiguration) allArguments[0];
+ if (hostConfiguration == null) {
+ hostConfiguration = client.getHostConfiguration();
+ }
+
+ final HttpMethod httpMethod = (HttpMethod) allArguments[1];
+ final String remotePeer = httpMethod.getURI().getHost() + ":" + httpMethod.getURI().getPort();
+
+ final URI uri = httpMethod.getURI();
+ final String requestURI = getRequestURI(uri);
+
+ final ContextCarrier contextCarrier = new ContextCarrier();
+ final AbstractSpan span = ContextManager.createExitSpan(requestURI, contextCarrier, remotePeer);
+
+ span.setComponent(ComponentsDefine.HTTPCLIENT);
+ Tags.URL.set(span, uri.toString());
+ Tags.HTTP.METHOD.set(span, httpMethod.getName());
+ SpanLayer.asHttp(span);
+
+ for (CarrierItem next = contextCarrier.items(); next.hasNext(); ) {
+ next = next.next();
+ httpMethod.addRequestHeader(next.getHeadKey(), next.getHeadValue());
+ }
+ }
+
+ @Override
+ public Object afterMethod(
+ final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final Object ret) {
+
+ if (ret != null) {
+ final int statusCode = (Integer) ret;
+ final AbstractSpan span = ContextManager.activeSpan();
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ Tags.STATUS_CODE.set(span, Integer.toString(statusCode));
+ }
+ }
+
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(
+ final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class>[] argumentsTypes,
+ final Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+
+ private String getRequestURI(URI uri) throws URIException {
+ String requestPath = uri.getPath();
+ return requestPath != null && requestPath.length() > 0 ? requestPath : "/";
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/define/HttpClientInstrumentation.java b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/define/HttpClientInstrumentation.java
new file mode 100644
index 0000000000000000000000000000000000000000..22bb50604a8c1d07002b84725218e13db81c5b28
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/httpclient/v3/define/HttpClientInstrumentation.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.httpclient.v3.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * @author kezhenxu94
+ */
+public class HttpClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String ENHANCE_CLASS = "org.apache.commons.httpclient.HttpClient";
+ private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.httpclient.v3.HttpClientExecuteInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return null;
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("executeMethod")
+ .and(takesArguments(3))
+ .and(takesArgument(0, named("org.apache.commons.httpclient.HostConfiguration")))
+ .and(takesArgument(1, named("org.apache.commons.httpclient.HttpMethod")))
+ .and(takesArgument(2, named("org.apache.commons.httpclient.HttpState")));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000000000000000000000000000000000..8a706a69602cca9aeb7175699809faa60082ec2d
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/httpclient-3.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+httpclient-3.x=org.apache.skywalking.apm.plugin.httpclient.v3.define.HttpClientInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index f054e9aeefb07a5ffa2299e98143cf0d33e84cd5..0f9043e0f0a7541da4b7a8c95c6912fceb43f553 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -81,6 +81,7 @@
pulsar-pluginnetty-socketio-pluginarmeria-0.84.x-plugin
+ httpclient-3.x-pluginpom
diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md b/docs/en/setup/service-agent/java-agent/Supported-list.md
index 2e1ad4c817254b1a53176424daf3b3cc413a06ed..463b55e901a3df3b80518e0afa0a95b61f2de94d 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -19,7 +19,7 @@
* [Feign](https://github.com/OpenFeign/feign) 9.x
* [Netflix Spring Cloud Feign](https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-starter-feign) 1.1.x, 1.2.x, 1.3.x
* [Okhttp](https://github.com/square/okhttp) 3.x
- * [Apache httpcomponent HttpClient](http://hc.apache.org/) 4.2, 4.3
+ * [Apache httpcomponent HttpClient](http://hc.apache.org/) 2.0 -> 3.1, 4.2, 4.3
* [Spring RestTemplete](https://github.com/spring-projects/spring-framework) 4.x
* [Jetty Client](http://www.eclipse.org/jetty/) 9
* [Apache httpcomponent AsyncClient](https://hc.apache.org/httpcomponents-asyncclient-dev/) 4.x
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/httpclient-3.x-scenario/config/expectedData.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..85ea877df422a3f831b1cc70b023d3690fc34da9
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/config/expectedData.yaml
@@ -0,0 +1,86 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+registryItems:
+ applications:
+ - {httpclient-3.x-scenario: 2}
+ instances:
+ - {httpclient-3.x-scenario: 1}
+ operationNames:
+ - httpclient-3.x-scenario: [/httpclient-3.x-scenario/case/httpclient,
+ /httpclient-3.x-scenario/case/context-propagate]
+ heartbeat: []
+segmentItems:
+ - applicationCode: httpclient-3.x-scenario
+ segmentSize: ge 3
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /httpclient-3.x-scenario/case/context-propagate
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 1
+ componentName: ''
+ isError: false
+ spanType: Entry
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: url, value: 'http://localhost:8080/httpclient-3.x-scenario/case/context-propagate'}
+ - {key: http.method, value: GET}
+ refs:
+ - {parentEndpointId: 0, parentEndpoint: /httpclient-3.x-scenario/case/httpclient,
+ networkAddressId: 0, entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1,
+ parentTraceSegmentId: not null, parentServiceInstanceId: 1,
+ networkAddress: 'localhost:8080', entryEndpoint: /httpclient-3.x-scenario/case/httpclient,
+ entryServiceInstanceId: 1}
+ - segmentId: not null
+ spans:
+ - operationName: /httpclient-3.x-scenario/case/context-propagate
+ operationId: 0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 2
+ componentName: ''
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ peerId: 0
+ tags:
+ - {key: url, value: 'http://localhost:8080/httpclient-3.x-scenario/case/context-propagate'}
+ - {key: http.method, value: GET}
+ - operationName: /httpclient-3.x-scenario/case/httpclient
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 1
+ componentName: ''
+ isError: false
+ spanType: Entry
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: url, value: 'http://localhost:8080/httpclient-3.x-scenario/case/httpclient'}
+ - {key: http.method, value: GET}
\ No newline at end of file
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/configuration.yml b/test/plugin/scenarios/httpclient-3.x-scenario/configuration.yml
new file mode 100644
index 0000000000000000000000000000000000000000..053a7d81ff5cc055e54b9b79534c1a3bc292a933
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/configuration.yml
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+type: tomcat
+entryService: http://localhost:8080/httpclient-3.x-scenario/case/httpclient
+healthCheck: http://localhost:8080/httpclient-3.x-scenario/healthCheck
+framework: httpclient
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/pom.xml b/test/plugin/scenarios/httpclient-3.x-scenario/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..258ca1405c9dfc0c15f29d88f632f122878c0196
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/pom.xml
@@ -0,0 +1,76 @@
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ httpclient-3.x-scenario
+ 5.0.0
+ war
+
+
+ UTF-8
+ 1.8
+
+ httpclient
+ 3.1
+
+
+ skywalking-httpclient-3.x-scenario
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ provided
+
+
+ org.apache.logging.log4j
+ log4j-api
+ 2.8.1
+
+
+ org.apache.logging.log4j
+ log4j-core
+ 2.8.1
+
+
+ commons-httpclient
+ commons-httpclient
+ ${test.framework.version}
+
+
+
+
+ httpclient-3.x-scenario
+
+
+ maven-compiler-plugin
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/CaseServlet.java b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/CaseServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a0d3e94c2791a60214cc4a3b9ed3cc9512583de
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/CaseServlet.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.httpclient;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.methods.GetMethod;
+
+/**
+ * @author kezhenxu94
+ */
+public class CaseServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ MultiThreadedHttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
+ HttpClient client = new HttpClient(httpConnectionManager);
+
+ HttpMethod httpGet = new GetMethod("http://localhost:8080" + req.getContextPath() + "/case/context-propagate");
+ int statusCode = client.executeMethod(httpGet);
+
+ try (PrintWriter printWriter = resp.getWriter()) {
+ printWriter.write("success: " + statusCode);
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ doGet(req, resp);
+ }
+
+}
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/HealthCheckServlet.java b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/HealthCheckServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..03ebd4376c46c5bb9a6d433204044473f3b1046b
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/HealthCheckServlet.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.apm.testcase.httpclient;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author kezhenxu94
+ */
+public class HealthCheckServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ try (PrintWriter writer = resp.getWriter()) {
+ writer.write("Success");
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ doGet(req, resp);
+ }
+}
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/ServletForContextPropagate.java b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/ServletForContextPropagate.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8ace2b3cd4ccf3fefd0a14b383838ccf6983e8f
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/httpclient/ServletForContextPropagate.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.httpclient;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author kezhenxu94
+ */
+public class ServletForContextPropagate extends HttpServlet {
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ resp.setContentType("application/json");
+ try (PrintWriter out = resp.getWriter()) {
+ out.print("{'test':'test'}");
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ doGet(req, resp);
+ }
+}
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/src/main/webapp/WEB-INF/web.xml b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..363f2244c94aaceefcb83516d6eb1c4bd3136d62
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,54 @@
+
+
+ skywalking-httpclient-scenario
+
+
+ caseServlet
+ org.apache.skywalking.apm.testcase.httpclient.CaseServlet
+
+
+
+ healthCheck
+ org.apache.skywalking.apm.testcase.httpclient.HealthCheckServlet
+
+
+
+ healthCheck
+ /healthCheck
+
+
+
+ caseServlet
+ /case/httpclient
+
+
+
+ servletForContextPropagate
+ org.apache.skywalking.apm.testcase.httpclient.ServletForContextPropagate
+
+
+
+ servletForContextPropagate
+ /case/context-propagate
+
+
diff --git a/test/plugin/scenarios/httpclient-3.x-scenario/support-version.list b/test/plugin/scenarios/httpclient-3.x-scenario/support-version.list
new file mode 100644
index 0000000000000000000000000000000000000000..558af0ffa58d639bd173b347ebf37e02628c86c1
--- /dev/null
+++ b/test/plugin/scenarios/httpclient-3.x-scenario/support-version.list
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+2.0
+2.0.2
+3.0
+3.0.1
+3.1
\ No newline at end of file