mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Ban call of URLEncoder.encode/URLDecoder.decode(String,String)
Add ArchUnit rules to ban the use of `URLEncoder` calls with String charsets and use `Charset` calls instead. See gh-38740
This commit is contained in:
parent
ae79a7c00f
commit
8cb8999772
@ -18,6 +18,8 @@ package org.springframework.boot.build.architecture;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -60,6 +62,7 @@ import org.gradle.api.tasks.TaskAction;
|
|||||||
* {@link Task} that checks for architecture problems.
|
* {@link Task} that checks for architecture problems.
|
||||||
*
|
*
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
|
* @author Yanming Zhou
|
||||||
*/
|
*/
|
||||||
public abstract class ArchitectureCheck extends DefaultTask {
|
public abstract class ArchitectureCheck extends DefaultTask {
|
||||||
|
|
||||||
@ -71,7 +74,8 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
|||||||
allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(),
|
allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(),
|
||||||
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
|
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
|
||||||
noClassesShouldCallStepVerifierStepVerifyComplete(),
|
noClassesShouldCallStepVerifierStepVerifyComplete(),
|
||||||
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList());
|
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList(),
|
||||||
|
noClassesShouldCallURLEncoderWithStringEncoding(), noClassesShouldCallURLDecoderWithStringEncoding());
|
||||||
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
|
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +194,20 @@ public abstract class ArchitectureCheck extends DefaultTask {
|
|||||||
.because("java.util.stream.Stream.toList() should be used instead");
|
.because("java.util.stream.Stream.toList() should be used instead");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArchRule noClassesShouldCallURLEncoderWithStringEncoding() {
|
||||||
|
return ArchRuleDefinition.noClasses()
|
||||||
|
.should()
|
||||||
|
.callMethod(URLEncoder.class, "encode", String.class, String.class)
|
||||||
|
.because("java.net.URLEncoder.encode(String s, Charset charset) should be used instead");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArchRule noClassesShouldCallURLDecoderWithStringEncoding() {
|
||||||
|
return ArchRuleDefinition.noClasses()
|
||||||
|
.should()
|
||||||
|
.callMethod(URLDecoder.class, "decode", String.class, String.class)
|
||||||
|
.because("java.net.URLDecoder.decode(String s, Charset charset) should be used instead");
|
||||||
|
}
|
||||||
|
|
||||||
public void setClasses(FileCollection classes) {
|
public void setClasses(FileCollection classes) {
|
||||||
this.classes = classes;
|
this.classes = classes;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -159,7 +160,7 @@ final class ChangeableUrls implements Iterable<URL> {
|
|||||||
urls.add(referenced);
|
urls.add(referenced);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
referenced = new URL(jarUrl, URLDecoder.decode(entry, "UTF-8"));
|
referenced = new URL(jarUrl, URLDecoder.decode(entry, StandardCharsets.UTF_8));
|
||||||
if (new File(referenced.getFile()).exists()) {
|
if (new File(referenced.getFile()).exists()) {
|
||||||
urls.add(referenced);
|
urls.add(referenced);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2022 the original author or authors.
|
* Copyright 2012-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -20,6 +20,7 @@ import java.io.File;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import jakarta.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -80,7 +81,7 @@ class SpringBootMockServletContextTests implements ServletContextAware {
|
|||||||
};
|
};
|
||||||
URL resource = context.getResource("/");
|
URL resource = context.getResource("/");
|
||||||
assertThat(resource).isNotNull();
|
assertThat(resource).isNotNull();
|
||||||
File file = new File(URLDecoder.decode(resource.getPath(), "UTF-8"));
|
File file = new File(URLDecoder.decode(resource.getPath(), StandardCharsets.UTF_8));
|
||||||
assertThat(file).exists().isDirectory();
|
assertThat(file).exists().isDirectory();
|
||||||
String[] contents = file.list((dir, name) -> !(".".equals(name) || "..".equals(name)));
|
String[] contents = file.list((dir, name) -> !(".".equals(name) || "..".equals(name)));
|
||||||
assertThat(contents).isNotNull();
|
assertThat(contents).isNotNull();
|
||||||
|
@ -20,12 +20,12 @@ import java.io.File;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -225,9 +225,9 @@ public class PropertiesLauncher extends Launcher {
|
|||||||
return getFileResource(config);
|
return getFileResource(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String handleUrl(String path) throws UnsupportedEncodingException {
|
private String handleUrl(String path) {
|
||||||
if (path.startsWith("jar:file:") || path.startsWith("file:")) {
|
if (path.startsWith("jar:file:") || path.startsWith("file:")) {
|
||||||
path = URLDecoder.decode(path, "UTF-8");
|
path = URLDecoder.decode(path, StandardCharsets.UTF_8);
|
||||||
if (path.startsWith("file:")) {
|
if (path.startsWith("file:")) {
|
||||||
path = path.substring("file:".length());
|
path = path.substring("file:".length());
|
||||||
if (path.startsWith("//")) {
|
if (path.startsWith("//")) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2022 the original author or authors.
|
* Copyright 2012-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -20,12 +20,12 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.net.URLStreamHandler;
|
import java.net.URLStreamHandler;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.Permission;
|
import java.security.Permission;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -318,14 +318,9 @@ final class JarURLConnection extends java.net.JarURLConnection {
|
|||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
int c = source.charAt(i);
|
int c = source.charAt(i);
|
||||||
if (c > 127) {
|
if (c > 127) {
|
||||||
try {
|
String encoded = URLEncoder.encode(String.valueOf((char) c), StandardCharsets.UTF_8);
|
||||||
String encoded = URLEncoder.encode(String.valueOf((char) c), "UTF-8");
|
|
||||||
write(encoded, outputStream);
|
write(encoded, outputStream);
|
||||||
}
|
}
|
||||||
catch (UnsupportedEncodingException ex) {
|
|
||||||
throw new IllegalStateException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
if (c == '%') {
|
if (c == '%') {
|
||||||
if ((i + 2) >= length) {
|
if ((i + 2) >= length) {
|
||||||
|
@ -20,6 +20,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -553,7 +554,7 @@ public class UndertowServletWebServerFactory extends AbstractServletWebServerFac
|
|||||||
|
|
||||||
private URLResource getMetaInfResource(URL resourceJar, String path) {
|
private URLResource getMetaInfResource(URL resourceJar, String path) {
|
||||||
try {
|
try {
|
||||||
String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), "UTF-8");
|
String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), StandardCharsets.UTF_8);
|
||||||
URL resourceUrl = new URL(resourceJar + "META-INF/resources" + urlPath);
|
URL resourceUrl = new URL(resourceJar + "META-INF/resources" + urlPath);
|
||||||
URLResource resource = new URLResource(resourceUrl, path);
|
URLResource resource = new URLResource(resourceUrl, path);
|
||||||
if (resource.getContentLength() < 0) {
|
if (resource.getContentLength() < 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user