Merge branch 'apache-3.2' into apache-3.3

# Conflicts:
#	.editorconfig
#	dubbo-build-tools/pom.xml
#	dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
#	dubbo-dependencies-bom/pom.xml
#	dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml
#	dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml
#	dubbo-native-plugin/pom.xml
#	dubbo-spring-boot/pom.xml
This commit is contained in:
Albumen Kevin 2024-01-19 15:19:31 +08:00
commit c38fa0ac8b
31 changed files with 372 additions and 81 deletions

View File

@ -19,16 +19,58 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
# 4 space indentation
[*.{java,xml}]
indent_style = space
indent_size = 4
indent_style = space
tab_width = 4
max_line_length = 120
insert_final_newline = true
trim_trailing_whitespace = true
[*.java]
ij_java_continuation_indent_size = 8
ij_java_keep_control_statement_in_one_line = false
ij_java_for_brace_force = always
ij_java_if_brace_force = always
ij_java_keep_first_column_comment = false
ij_java_keep_line_breaks = false
ij_java_keep_simple_blocks_in_one_line = true
ij_java_keep_simple_classes_in_one_line = true
ij_java_keep_simple_lambdas_in_one_line = true
ij_java_keep_simple_methods_in_one_line = true
ij_java_keep_blank_lines_in_code = 1
ij_java_keep_blank_lines_in_declarations = 1
ij_java_class_count_to_use_import_on_demand = 999
ij_java_names_count_to_use_import_on_demand = 999
ij_java_imports_layout = org.apache.dubbo.**, |, javax.**, |, java.**, |, *, |, $*
ij_java_insert_inner_class_imports = true
ij_java_space_before_array_initializer_left_brace = true
ij_java_method_parameters_new_line_after_left_paren = true
ij_java_wrap_comments = true
ij_java_wrap_long_lines = true
ij_java_enum_constants_wrap = split_into_lines
ij_java_method_call_chain_wrap = split_into_lines
ij_java_method_parameters_wrap = on_every_item
ij_java_extends_list_wrap = on_every_item
ij_java_extends_keyword_wrap = normal
ij_java_binary_operation_wrap = normal
ij_java_binary_operation_sign_on_next_line = true
[*.json]
tab_width = 2
[*.{yml,yaml}]
indent_size = 2
[*.xml]
ij_xml_attribute_wrap = off
ij_xml_text_wrap = off
ij_xml_keep_blank_lines = 1
[pom.xml]
indent_size = 2
[pom.xml]
indent_size = 2

View File

@ -18,7 +18,49 @@ env:
'
jobs:
check-format:
name: Check if code needs formatting
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Maven
uses: actions/setup-java@v4
with:
java-version: 21
distribution: zulu
- name: Check if code aligns with code style
id: check
run: mvn --log-file mvn.log spotless:check
continue-on-error: true
- name: Upload checkstyle result
uses: actions/upload-artifact@v4
with:
name: checkstyle-result
path: mvn.log
- name: Generate Summary for successful run
if: ${{ steps.check.outcome == 'success' }}
run: |
echo ":ballot_box_with_check: Kudos! No formatting issues found!" >> $GITHUB_STEP_SUMMARY
- name: Generate Summary for failed run
if: ${{ steps.check.outcome == 'failure' }}
run: |
echo "## :negative_squared_cross_mark: Formatting issues found!" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
cat mvn.log | grep "ERROR" | sed 's/Check if code needs formatting Check if code aligns with code style [0-9A-Z:.-]\+//' | sed 's/\[ERROR] //' | head -n -11 >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "Please run \`mvn spotless:apply\` to fix the formatting issues." >> $GITHUB_STEP_SUMMARY
- name: Fail if code needs formatting
if: ${{ steps.check.outcome == 'failure' }}
uses: actions/github-script@v7.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
core.setFailed("Formatting issues found!")
license:
name: "Check License"
needs: check-format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
@ -43,6 +85,8 @@ jobs:
mode: check
build-source:
name: "Build Dubbo"
needs: check-format
runs-on: ubuntu-latest
outputs:
version: ${{ steps.dubbo-version.outputs.version }}
@ -98,6 +142,7 @@ jobs:
unit-test-prepare:
name: "Preparation for Unit Test"
needs: check-format
runs-on: ubuntu-latest
strategy:
fail-fast: false
@ -146,7 +191,7 @@ jobs:
echo "--- End Print Rsa Public Key"
unit-test:
needs: [build-source, unit-test-prepare]
needs: [check-format, build-source, unit-test-prepare]
name: "Unit Test On ubuntu-latest"
runs-on: ubuntu-latest
strategy:
@ -212,6 +257,7 @@ jobs:
path: "**/target/site/**/jacoco.xml"
samples-test-prepare:
needs: check-format
runs-on: ubuntu-latest
env:
JOB_COUNT: 3
@ -229,7 +275,7 @@ jobs:
name: samples-test-list
path: test/jobs
samples-test-job:
needs: [build-source, samples-test-prepare]
needs: [check-format, build-source, samples-test-prepare]
name: "Samples Test on ubuntu-latest (JobId: ${{matrix.job_id}})"
runs-on: ubuntu-latest
timeout-minutes: 90
@ -296,7 +342,7 @@ jobs:
name: samples-test-result
path: test/jobs/*-result*
samples-test-result:
needs: [samples-test-job]
needs: [check-format, samples-test-job]
if: always()
runs-on: ubuntu-latest
env:
@ -315,6 +361,7 @@ jobs:
run: ./test/scripts/merge-test-results.sh
integration-test-prepare:
needs: check-format
runs-on: ubuntu-latest
env:
JOB_COUNT: 3
@ -332,7 +379,7 @@ jobs:
name: test-list
path: test/jobs
integration-test-job:
needs: [build-source, integration-test-prepare]
needs: [check-format, build-source, integration-test-prepare]
name: "Integration Test on ubuntu-latest (JobId: ${{matrix.job_id}})"
runs-on: ubuntu-latest
timeout-minutes: 90
@ -399,7 +446,7 @@ jobs:
name: test-result
path: test/jobs/*-result*
integration-test-result:
needs: [integration-test-job]
needs: [check-format, integration-test-job]
if: always()
runs-on: ubuntu-latest
env:
@ -419,7 +466,7 @@ jobs:
jacoco-result-merge:
runs-on: ubuntu-latest
needs: [integration-test-result, samples-test-result, unit-test]
needs: [check-format, integration-test-result, samples-test-result, unit-test]
steps:
- uses: actions/checkout@v3
with:
@ -475,6 +522,7 @@ jobs:
verbose: true
error-code-inspecting:
needs: check-format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
@ -513,6 +561,7 @@ jobs:
path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt
native-image-inspecting:
needs: check-format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

2
NOTICE
View File

@ -1,5 +1,5 @@
Apache Dubbo
Copyright 2018-2023 The Apache Software Foundation
Copyright 2018-2024 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

View File

@ -5,13 +5,15 @@
Below is a table that shows versions that we accept security fixes.
| Version | Supported |
| ------- | ------------------ |
| 3.0.x | :white_check_mark: |
| 2.7.x | :white_check_mark: |
| 2.6.x | :white_check_mark: |
|---------| ------------------ |
| 3.3.x | :white_check_mark: |
| 3.2.x | :white_check_mark: |
| 3.1.x | :white_check_mark: |
| 3.0.x | :x: |
| 2.7.x | :x: |
| 2.6.x | :x: |
| 2.5.x | :x: |
## Reporting a Vulnerability
The Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its software projects. Apache Dubbo is highly sensitive and forthcoming to issues pertaining to its features and functionality.

View File

@ -69,8 +69,10 @@ public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
return invokeWithContext(invoker, invocation);
} catch (RpcException e) {
if (e.isNoInvokerAvailableAfterFilter()) {
log.debug("No available provider for service" + getUrl().getServiceKey() + " on group "
+ invoker.getUrl().getGroup() + ", will continue to try another group.");
log.debug(
"No available provider for service" + getUrl().getServiceKey() + " on group "
+ invoker.getUrl().getGroup() + ", will continue to try another group.",
e);
} else {
throw e;
}
@ -93,7 +95,21 @@ public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
for (final Invoker<T> invoker : invokers) {
RpcInvocation subInvocation = new RpcInvocation(invocation, invoker);
subInvocation.setAttachment(Constants.ASYNC_KEY, "true");
results.put(invoker.getUrl().getServiceKey(), invokeWithContext(invoker, subInvocation));
try {
results.put(invoker.getUrl().getServiceKey(), invokeWithContext(invoker, subInvocation));
} catch (RpcException e) {
if (e.isNoInvokerAvailableAfterFilter()) {
log.warn(
LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER,
e.getCause().getMessage(),
"",
"No available provider for service" + getUrl().getServiceKey() + " on group "
+ invoker.getUrl().getGroup() + ", will continue to try another group.",
e);
} else {
throw e;
}
}
}
Object result;

View File

@ -159,13 +159,13 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
if (!guard.tryAcquire()) {
return;
}
// To avoid multiple dump, check again
if (System.currentTimeMillis() - lastPrintTime < TEN_MINUTES_MILLS) {
return;
}
ExecutorService pool = Executors.newSingleThreadExecutor();
ExecutorService pool = null;
try {
// To avoid multiple dump, check again
if (System.currentTimeMillis() - lastPrintTime < TEN_MINUTES_MILLS) {
return;
}
pool = Executors.newSingleThreadExecutor();
pool.execute(() -> {
String dumpPath = getDumpPath();
@ -190,12 +190,14 @@ public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
logger.error(COMMON_UNEXPECTED_CREATE_DUMP, "", "", "dump jStack error", t);
} finally {
lastPrintTime = System.currentTimeMillis();
guard.release();
}
});
} finally {
guard.release();
// must shutdown thread pool ,if not will lead to OOM
pool.shutdown();
if (pool != null) {
pool.shutdown();
}
}
}

View File

@ -395,11 +395,11 @@ public abstract class AbstractServiceConfig extends AbstractInterfaceConfig {
this.payload = payload;
}
@Parameter(excluded = true, attribute = false)
public Boolean getUseJavaPackageAsPath() {
return useJavaPackageAsPath;
}
@Parameter(excluded = true)
public void setUseJavaPackageAsPath(Boolean useJavaPackageAsPath) {
this.useJavaPackageAsPath = useJavaPackageAsPath;
}

View File

@ -38,8 +38,11 @@ class URLStrParserTest {
testCases.add("dubbo://192.168.1.1");
testCases.add("dubbo://192.168.1.1?");
testCases.add("dubbo://127.0.0.1?test=中文测试");
testCases.add(
"dubbo://admin:admin123@192.168.1.41:28113/org.test.api.DemoService$Iface?anyhost=true&application=demo-service&dubbo=2.6.1&generic=false&interface=org.test.api.DemoService$Iface&methods=orbCompare,checkText,checkPicture&pid=65557&revision=1.4.17&service.filter=bootMetrics&side=provider&status=server&threads=200&timestamp=1583136298859&version=1.0.0");
testCases.add("dubbo://admin:admin123@192.168.1.41:28113/org.test.api"
+ ".DemoService$Iface?anyhost=true&application=demo-service&dubbo=2.6.1&generic=false&interface=org"
+ ".test.api.DemoService$Iface&methods=orbCompare,checkText,checkPicture&pid=65557&revision=1.4"
+ ".17&service.filter=bootMetrics&side=provider&status=server&threads=200&timestamp=1583136298859"
+ "&version=1.0.0");
// super long text test
testCases.add("dubbo://192.168.1.1/" + RandomString.make(10240));
testCases.add("file:/path/to/file.txt");
@ -57,8 +60,8 @@ class URLStrParserTest {
errorEncodedCases.add("dubbo%3a192.168.1.1%3fabc%3dabc");
errorEncodedCases.add("%3a%2f%2f192.168.1.1%3fabc%3dabc");
errorEncodedCases.add("%3a%2f192.168.1.1%3fabc%3dabc");
errorEncodedCases.add(
"dubbo%3a%2f%2f127.0.0.1%3ftest%3d%e2%96%b2%e2%96%bc%e2%97%80%e2%96%b6%e2%86%90%e2%86%91%e2%86%92%e2%86%93%e2%86%94%e2%86%95%e2%88%9e%c2%b1%e9%be%98%e9%9d%90%e9%bd%89%9%d%b");
errorEncodedCases.add("dubbo%3a%2f%2f127.0.0.1%3ftest%3d%e2%96%b2%e2%96%bc%e2%97%80%e2%96%b6%e2%86%90%e2%86"
+ "%91%e2%86%92%e2%86%93%e2%86%94%e2%86%95%e2%88%9e%c2%b1%e9%be%98%e9%9d%90%e9%bd%89%9%d%b");
}
@Test
@ -93,4 +96,17 @@ class URLStrParserTest {
assertThat(url2.getParameter("timeout"), equalTo("5678"));
assertThat(url2.getParameter("default.timeout"), equalTo("5678"));
}
@Test
void testPond() {
String str = "https://a#@b";
URL url1 = URL.valueOf(str);
URL url2 = URLStrParser.parseDecodedStr(str);
Assertions.assertEquals("https", url1.getProtocol());
Assertions.assertEquals("https", url2.getProtocol());
Assertions.assertEquals("a", url1.getHost());
Assertions.assertEquals("a", url2.getHost());
}
}

View File

@ -35,7 +35,7 @@
<skip_maven_deploy>true</skip_maven_deploy>
<spring-boot.version>2.7.18</spring-boot.version>
<spring-boot-maven-plugin.version>2.7.18</spring-boot-maven-plugin.version>
<micrometer-core.version>1.12.1</micrometer-core.version>
<micrometer-core.version>1.12.2</micrometer-core.version>
</properties>
<dependencyManagement>

View File

@ -99,13 +99,13 @@
<httpclient_version>4.5.14</httpclient_version>
<httpcore_version>4.4.16</httpcore_version>
<fastjson_version>1.2.83</fastjson_version>
<fastjson2_version>2.0.44</fastjson2_version>
<fastjson2_version>2.0.45</fastjson2_version>
<zookeeper_version>3.7.2</zookeeper_version>
<curator_version>5.1.0</curator_version>
<curator_test_version>2.12.0</curator_test_version>
<jedis_version>3.10.0</jedis_version>
<hessian_version>4.0.66</hessian_version>
<protobuf-java_version>3.25.1</protobuf-java_version>
<protobuf-java_version>3.25.2</protobuf-java_version>
<javax_annotation-api_version>1.3.2</javax_annotation-api_version>
<servlet_version>3.1.0</servlet_version>
<jetty_version>9.4.53.v20231009</jetty_version>
@ -119,25 +119,25 @@
<snakeyaml_version>2.2</snakeyaml_version>
<commons_lang3_version>3.14.0</commons_lang3_version>
<envoy_api_version>0.1.35</envoy_api_version>
<micrometer.version>1.12.1</micrometer.version>
<micrometer.version>1.12.2</micrometer.version>
<opentelemetry.version>1.26.0</opentelemetry.version>
<zipkin-reporter.version>2.16.4</zipkin-reporter.version>
<micrometer-tracing.version>1.2.1</micrometer-tracing.version>
<micrometer-tracing.version>1.2.2</micrometer-tracing.version>
<t_digest.version>3.3</t_digest.version>
<prometheus_client.version>0.16.0</prometheus_client.version>
<reactive.version>1.0.4</reactive.version>
<reactor.version>3.6.1</reactor.version>
<reactor.version>3.6.2</reactor.version>
<rxjava.version>2.2.21</rxjava.version>
<okhttp_version>3.14.9</okhttp_version>
<rs_api_version>2.1.1</rs_api_version>
<resteasy_version>3.15.6.Final</resteasy_version>
<codehaus-jackson_version>1.9.13</codehaus-jackson_version>
<tomcat_embed_version>8.5.97</tomcat_embed_version>
<tomcat_embed_version>8.5.98</tomcat_embed_version>
<nacos_version>2.2.4</nacos_version>
<sentinel.version>1.8.6</sentinel.version>
<seata.version>1.6.1</seata.version>
<grpc.version>1.60.1</grpc.version>
<grpc.version>1.61.0</grpc.version>
<grpc_contrib_verdion>0.8.1</grpc_contrib_verdion>
<jprotoc_version>1.2.2</jprotoc_version>
<mustache_version>0.9.10</mustache_version>
@ -147,7 +147,7 @@
<log4j_version>1.2.17</log4j_version>
<logback_version>1.2.13</logback_version>
<!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
<log4j2_version>2.22.0</log4j2_version>
<log4j2_version>2.22.1</log4j2_version>
<commons_io_version>2.15.1</commons_io_version>
<commons-codec_version>1.16.0</commons-codec_version>
@ -178,9 +178,9 @@
<jackson_version>2.16.1</jackson_version>
<mortbay_jetty_version>6.1.26</mortbay_jetty_version>
<portlet_version>2.0</portlet_version>
<maven_flatten_version>1.5.0</maven_flatten_version>
<maven_flatten_version>1.6.0</maven_flatten_version>
<commons_compress_version>1.25.0</commons_compress_version>
<spotless-maven-plugin.version>2.41.1</spotless-maven-plugin.version>
<spotless-maven-plugin.version>2.42.0</spotless-maven-plugin.version>
<spotless.action>check</spotless.action>
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>

View File

@ -32,11 +32,11 @@
<properties>
<revision>3.3.0-beta.2-SNAPSHOT</revision>
<maven_flatten_version>1.5.0</maven_flatten_version>
<maven_flatten_version>1.6.0</maven_flatten_version>
<slf4j_version>1.7.36</slf4j_version>
<curator5_version>5.1.0</curator5_version>
<zookeeper_version>3.8.3</zookeeper_version>
<spotless-maven-plugin.version>2.41.1</spotless-maven-plugin.version>
<spotless-maven-plugin.version>2.42.0</spotless-maven-plugin.version>
<spotless.action>check</spotless.action>
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>

View File

@ -32,11 +32,11 @@
<properties>
<revision>3.3.0-beta.2-SNAPSHOT</revision>
<maven_flatten_version>1.5.0</maven_flatten_version>
<maven_flatten_version>1.6.0</maven_flatten_version>
<slf4j_version>1.7.36</slf4j_version>
<curator_version>4.3.0</curator_version>
<zookeeper_version>3.4.14</zookeeper_version>
<spotless-maven-plugin.version>2.41.1</spotless-maven-plugin.version>
<spotless-maven-plugin.version>2.42.0</spotless-maven-plugin.version>
<spotless.action>check</spotless.action>
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>

View File

@ -32,7 +32,7 @@
</modules>
<properties>
<spotless-maven-plugin.version>2.41.1</spotless-maven-plugin.version>
<spotless-maven-plugin.version>2.42.0</spotless-maven-plugin.version>
<spotless.action>check</spotless.action>
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>

View File

@ -28,7 +28,7 @@
<packaging>pom</packaging>
<properties>
<spotless-maven-plugin.version>2.41.1</spotless-maven-plugin.version>
<spotless-maven-plugin.version>2.42.0</spotless-maven-plugin.version>
<spotless.action>check</spotless.action>
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>

View File

@ -49,7 +49,7 @@
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.10.2</version>
<version>3.11.0</version>
<scope>provided</scope>
</dependency>

View File

@ -32,7 +32,6 @@ import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.ProviderFirstParams;
import org.apache.dubbo.rpc.model.ScopeModel;
import java.util.ArrayList;
@ -41,7 +40,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
@ -319,20 +317,6 @@ public abstract class CacheableFailbackRegistry extends FailbackRegistry {
return new DubboServiceAddressURL(address, param, consumerURL, null);
}
protected URL removeParamsFromConsumer(URL consumer) {
Set<ProviderFirstParams> providerFirstParams = consumer.getOrDefaultApplicationModel()
.getExtensionLoader(ProviderFirstParams.class)
.getSupportedExtensionInstances();
if (CollectionUtils.isEmpty(providerFirstParams)) {
return consumer;
}
for (ProviderFirstParams paramsFilter : providerFirstParams) {
consumer = consumer.removeParameters(paramsFilter.params());
}
return consumer;
}
private String stripOffVariableKeys(String rawProvider) {
String[] keys = getVariableKeys();
if (keys == null || keys.length == 0) {

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.timer.HashedWheelTimer;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.ProviderFirstParams;
import org.apache.dubbo.registry.retry.FailedRegisteredTask;
import org.apache.dubbo.registry.retry.FailedSubscribedTask;
import org.apache.dubbo.registry.retry.FailedUnregisteredTask;
@ -178,6 +179,20 @@ public abstract class FailbackRegistry extends AbstractRegistry {
}
}
protected URL removeParamsFromConsumer(URL consumer) {
Set<ProviderFirstParams> providerFirstParams = consumer.getOrDefaultApplicationModel()
.getExtensionLoader(ProviderFirstParams.class)
.getSupportedExtensionInstances();
if (CollectionUtils.isEmpty(providerFirstParams)) {
return consumer;
}
for (ProviderFirstParams paramsFilter : providerFirstParams) {
consumer = consumer.removeParameters(paramsFilter.params());
}
return consumer;
}
ConcurrentMap<URL, FailedRegisteredTask> getFailedRegistered() {
return failedRegistered;
}

View File

@ -124,8 +124,9 @@ public class MultipleRegistry extends AbstractRegistry {
referenceRegistries.put(tmpUrl, registryMap.get(tmpUrl));
continue;
}
final URL registryUrl =
URL.valueOf(tmpUrl).addParameterIfAbsent(CHECK_KEY, url.getParameter(CHECK_KEY, "true"));
final URL registryUrl = URL.valueOf(tmpUrl)
.addParametersIfAbsent(url.getParameters())
.addParameterIfAbsent(CHECK_KEY, url.getParameter(CHECK_KEY, "true"));
Registry registry = registryFactory.getRegistry(registryUrl);
registryMap.put(tmpUrl, registry);
referenceRegistries.put(tmpUrl, registry);

View File

@ -576,6 +576,7 @@ public class NacosRegistry extends FailbackRegistry {
}
private List<URL> toUrlWithEmpty(URL consumerURL, Collection<Instance> instances) {
consumerURL = removeParamsFromConsumer(consumerURL);
List<URL> urls = buildURLs(consumerURL, instances);
// Nacos does not support configurators and routers from registry, so all notifications are of providers type.
if (urls.size() == 0 && !getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, DEFAULT_ENABLE_EMPTY_PROTECTION)) {

View File

@ -190,4 +190,51 @@ public class RestClientTest {
strings.toArray(new String[0]),
requestTemplate.getParam("param").toArray(new String[0]));
}
@Test
void testBuildURL() throws Exception {
int port = NetUtils.getAvailablePort();
URL url = new ServiceConfigURL(
"http", "localhost", port, new String[] {Constants.BIND_PORT_KEY, String.valueOf(port)});
HttpServer httpServer = new JettyHttpServer(url, new HttpHandler<HttpServletRequest, HttpServletResponse>() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setCharacterEncoding("UTF-8");
response.getWriter().write(request.getQueryString());
}
});
RequestTemplate requestTemplate = new RequestTemplate(null, "POST", "localhost:" + port);
requestTemplate.addParam("name", "李强");
requestTemplate.addParam("age", "18");
requestTemplate.path("/hello/world");
// When using the OKHttpRestClient, parameters will be encoded with UTF-8 and appended to the URL
RestClient restClient = new OKHttpRestClient(new HttpClientConfig());
CompletableFuture<RestResult> send = restClient.send(requestTemplate);
RestResult restResult = send.get();
assertThat(new String(restResult.getBody()), is("name=%E6%9D%8E%E5%BC%BA&age=18"));
// When using the HttpClientRestClient, parameters will be encoded with UTF-8 and appended to the URL
restClient = new HttpClientRestClient(new HttpClientConfig());
send = restClient.send(requestTemplate);
restResult = send.get();
assertThat(new String(restResult.getBody()), is("name=%E6%9D%8E%E5%BC%BA&age=18"));
// When using the URLConnectionRestClient, parameters won't be encoded and still appended to the URL
restClient = new URLConnectionRestClient(new HttpClientConfig());
send = restClient.send(requestTemplate);
restResult = send.get();
assertThat(new String(restResult.getBody(), StandardCharsets.UTF_8), is("name=李强&age=18"));
}
}

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.filter;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.extension.DisableInject;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
@ -140,7 +141,8 @@ public class ExceptionFilter implements Filter, Filter.Listener {
}
// For test purpose
public void setLogger(ErrorTypeAwareLogger logger) {
@DisableInject
public void mockLogger(ErrorTypeAwareLogger logger) {
this.logger = logger;
}
}

View File

@ -63,7 +63,7 @@ class ExceptionFilterTest {
exceptionFilter.invoke(invoker, invocation);
} catch (RpcException e) {
assertEquals("TestRpcException", e.getMessage());
exceptionFilter.setLogger(failsafeLogger);
exceptionFilter.mockLogger(failsafeLogger);
exceptionFilter.onError(e, invoker, invocation);
}

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;
import org.apache.dubbo.common.utils.ProtobufUtils;
import org.apache.dubbo.remoting.utils.UrlUtils;
import java.io.ByteArrayInputStream;
@ -40,6 +41,10 @@ public class DefaultParamDeepCopyUtil implements ParamDeepCopyUtil {
@Override
@SuppressWarnings({"unchecked"})
public <T> T copy(URL url, Object src, Class<T> targetClass, Type type) {
// TODO: maybe we have better way to do this
if (src != null && ProtobufUtils.isProtobufClass(src.getClass())) {
return (T) src;
}
Serialization serialization = url.getOrDefaultFrameworkModel()
.getExtensionLoader(Serialization.class)
.getExtension(UrlUtils.serializationOrDefault(url));

View File

@ -44,6 +44,8 @@ public interface RestConstant {
String CONNECTION = "Connection";
String CONTENT_TYPE = "Content-Type";
String TEXT_PLAIN = "text/plain";
String ACCEPT_CHARSET = "Accept-Charset";
String WEIGHT_IDENTIFIER = ";q=";
String ACCEPT = "Accept";
String DEFAULT_ACCEPT = "*/*";
String REST_HEADER_PREFIX = "rest-service-";
@ -55,6 +57,7 @@ public interface RestConstant {
String MAX_REQUEST_SIZE_PARAM = "max.request.size";
String IDLE_TIMEOUT_PARAM = "idle.timeout";
String KEEP_ALIVE_TIMEOUT_PARAM = "keep.alive.timeout";
String DEFAULT_CHARSET = "UTF-8";
String JSON_CHECK_LEVEL = "jsonCheckLevel";
String JSON_CHECK_LEVEL_DISABLED = "disabled";

View File

@ -17,14 +17,19 @@
package org.apache.dubbo.rpc.protocol.rest.request;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.protocol.rest.constans.RestConstant;
import org.apache.dubbo.rpc.protocol.rest.deploy.ServiceDeployer;
import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.rpc.protocol.rest.constans.RestConstant.DEFAULT_CHARSET;
/**
* request facade for different request
*
@ -55,6 +60,24 @@ public abstract class RequestFacade<T> {
protected void initParameters() {
String requestURI = getRequestURI();
String decodedRequestURI = null;
try {
String enc = DEFAULT_CHARSET;
ArrayList<String> charset = headers.get(RestConstant.ACCEPT_CHARSET);
// take the highest priority charset
String[] parsed = DataParseUtils.parseAcceptCharset(charset);
if (parsed != null && parsed.length > 0) {
enc = parsed[0].toUpperCase();
}
decodedRequestURI = URLDecoder.decode(requestURI, enc);
} catch (Throwable t) {
// do nothing, try best to deliver
}
if (StringUtils.isNotEmpty(decodedRequestURI)) {
requestURI = decodedRequestURI;
}
if (requestURI != null && requestURI.contains("?")) {

View File

@ -16,6 +16,8 @@
*/
package org.apache.dubbo.rpc.protocol.rest.util;
import org.apache.dubbo.common.lang.Nullable;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.common.utils.StringUtils;
@ -29,9 +31,16 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.StringTokenizer;
import java.util.TreeMap;
import static org.apache.dubbo.rpc.protocol.rest.constans.RestConstant.WEIGHT_IDENTIFIER;
public class DataParseUtils {
@ -209,4 +218,32 @@ public class DataParseUtils {
public static String[] toStringArray(Collection<String> collection) {
return collection == null ? null : collection.toArray(new String[collection.size()]);
}
@Nullable
public static String[] parseAcceptCharset(List<String> acceptCharsets) {
if (CollectionUtils.isEmpty(acceptCharsets)) {
return new String[0];
}
SortedMap<Float, Set<String>> encodings = new TreeMap<>(Comparator.reverseOrder());
float defaultWeight = 1.0f;
for (String acceptCharset : acceptCharsets) {
String[] charsets = acceptCharset.split(",");
for (String charset : charsets) {
charset = charset.trim();
float weight = defaultWeight;
String enc = charset;
if (charset.contains(WEIGHT_IDENTIFIER)) {
String[] split = charset.split(WEIGHT_IDENTIFIER);
enc = split[0];
weight = Float.parseFloat(split[1]);
}
encodings.computeIfAbsent(weight, k -> new HashSet<>()).add(enc);
}
}
List<String> result = new ArrayList<>();
encodings.values().forEach(result::addAll);
return result.toArray(new String[0]);
}
}

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.protocol.rest;
import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -57,4 +58,14 @@ public class DataParseUtilsTest {
Assertions.assertEquals(1, convert);
}
@Test
void testParseAcceptCharset() {
String[] parsed = DataParseUtils.parseAcceptCharset(Arrays.asList("iso-8859-1"));
Assertions.assertTrue(Arrays.equals(parsed, new String[] {"iso-8859-1"}));
parsed = DataParseUtils.parseAcceptCharset(Arrays.asList("utf-8, iso-8859-1;q=0.5"));
Assertions.assertTrue(Arrays.equals(parsed, new String[] {"utf-8", "iso-8859-1"}));
parsed = DataParseUtils.parseAcceptCharset(Arrays.asList("utf-8, iso-8859-1;q=0.5, *;q=0.1", "utf-16;q=0.5"));
Assertions.assertEquals("utf-8", parsed[0]);
}
}

View File

@ -30,6 +30,9 @@ import io.netty.handler.codec.http.HttpVersion;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
public class NettyRequestFacadeTest {
@Test
@ -95,4 +98,36 @@ public class NettyRequestFacadeTest {
Assertions.assertEquals("GET", nettyRequestFacade.getMethod());
}
@Test
void testChineseDecoding() {
String uri = "/hello/world?name=%E6%9D%8E%E5%BC%BA&age=18";
DefaultFullHttpRequest defaultFullHttpRequest =
new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);
defaultFullHttpRequest.headers().add("Accept-Charset", "utf-8, iso-8859-1;q=0.5, *;q=0.1");
defaultFullHttpRequest.headers().add("Accept-Charset", "utf-16;q=0.3");
NettyRequestFacade nettyRequestFacade = new NettyRequestFacade(defaultFullHttpRequest, null);
assertThat(nettyRequestFacade.getPath(), is("/hello/world"));
assertThat(nettyRequestFacade.getParameter("name"), is("李强"));
assertThat(nettyRequestFacade.getParameter("age"), is("18"));
// Applying the decode method to the URI is acceptable, even if the URI is not encoded.
uri = "/hello/world?name=lily&age=18";
defaultFullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);
nettyRequestFacade = new NettyRequestFacade(defaultFullHttpRequest, null);
assertThat(nettyRequestFacade.getPath(), is("/hello/world"));
assertThat(nettyRequestFacade.getParameter("name"), is("lily"));
assertThat(nettyRequestFacade.getParameter("age"), is("18"));
// When using URLConnectionRestClient, the URI won't be encoded, but it's still acceptable.
uri = "/hello/world?name=李强&age=18";
defaultFullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);
nettyRequestFacade = new NettyRequestFacade(defaultFullHttpRequest, null);
assertThat(nettyRequestFacade.getPath(), is("/hello/world"));
assertThat(nettyRequestFacade.getParameter("name"), is("李强"));
assertThat(nettyRequestFacade.getParameter("age"), is("18"));
}
}

View File

@ -36,10 +36,10 @@
</modules>
<properties>
<micrometer.version>1.12.1</micrometer.version>
<micrometer-tracing.version>1.2.1</micrometer-tracing.version>
<opentelemetry.version>1.33.0</opentelemetry.version>
<zipkin-reporter.version>2.17.1</zipkin-reporter.version>
<micrometer.version>1.12.2</micrometer.version>
<micrometer-tracing.version>1.2.2</micrometer-tracing.version>
<opentelemetry.version>1.34.1</opentelemetry.version>
<zipkin-reporter.version>2.17.2</zipkin-reporter.version>
<prometheus-client.version>0.16.0</prometheus-client.version>
</properties>

View File

@ -33,7 +33,7 @@
<curator5.version>4.2.0</curator5.version>
<commons.compress.version>1.25.0</commons.compress.version>
<junit.platform.launcher.version>1.9.3</junit.platform.launcher.version>
<commons.exec.version>1.3</commons.exec.version>
<commons.exec.version>1.4.0</commons.exec.version>
<async.http.client.version>2.12.3</async.http.client.version>
</properties>

View File

@ -130,8 +130,8 @@
<!-- Maven plugins -->
<maven_jar_version>3.3.0</maven_jar_version>
<maven_surefire_version>3.2.3</maven_surefire_version>
<maven_failsafe_version>3.2.3</maven_failsafe_version>
<maven_surefire_version>3.2.5</maven_surefire_version>
<maven_failsafe_version>3.2.5</maven_failsafe_version>
<maven_deploy_version>2.8.2</maven_deploy_version>
<maven_compiler_version>3.12.1</maven_compiler_version>
<maven_source_version>3.3.0</maven_source_version>
@ -139,7 +139,7 @@
<maven_jetty_version>9.4.53.v20231009</maven_jetty_version>
<maven_checkstyle_version>3.3.1</maven_checkstyle_version>
<maven_jacoco_version>0.8.11</maven_jacoco_version>
<maven_flatten_version>1.5.0</maven_flatten_version>
<maven_flatten_version>1.6.0</maven_flatten_version>
<maven_enforce_version>3.4.1</maven_enforce_version>
<maven_antrun_version>3.1.0</maven_antrun_version>
<maven_os_plugin_version>1.7.1</maven_os_plugin_version>
@ -147,7 +147,7 @@
<protobuf-protoc_version>3.22.3</protobuf-protoc_version>
<grpc_version>1.54.0</grpc_version>
<spotless-maven-plugin.version>2.41.1</spotless-maven-plugin.version>
<spotless-maven-plugin.version>2.42.0</spotless-maven-plugin.version>
<spotless.action>check</spotless.action>
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>