Issue #3708 - use StringUtil alternatives for known slow JVM impls.

+ StringUtil.replace()
+ StringUtil.replaceFirst()
+ StringUtil.sanitizeFileSystemPath()

Change existing usages of String.replace() to either
use new StringUtil.replace() or other methods elsewhere
that better suit that specific need.

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
Joakim Erdfelt 2019-06-11 11:25:50 -05:00
parent da4f116c63
commit 33fe55c339
24 changed files with 347 additions and 202 deletions

View File

@ -28,6 +28,7 @@ import java.util.regex.Pattern;
import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.AntClassLoader;
import org.eclipse.jetty.util.PatternMatcher; import org.eclipse.jetty.util.PatternMatcher;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppClassLoader; import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
@ -88,7 +89,7 @@ public class AntWebInfConfiguration extends WebInfConfiguration
} }
catch (URISyntaxException e) catch (URISyntaxException e)
{ {
containerUris[i] = new URI(u.toString().replaceAll(" ", "%20")); containerUris[i] = new URI(URIUtil.encodeSpaces(u.toString()));
} }
i++; i++;
} }

View File

@ -88,7 +88,7 @@ public class HttpSenderOverFCGI extends HttpSender
for (HttpField field : headers) for (HttpField field : headers)
{ {
String name = field.getName(); String name = field.getName();
String fcgiName = "HTTP_" + name.replaceAll("-", "_").toUpperCase(Locale.ENGLISH); String fcgiName = "HTTP_" + name.replace('-', '_').toUpperCase(Locale.ENGLISH);
fcgiHeaders.add(fcgiName, field.getValue()); fcgiHeaders.add(fcgiName, field.getValue());
} }

View File

@ -24,7 +24,6 @@ import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.FilterConfig; import javax.servlet.FilterConfig;
@ -35,6 +34,8 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.util.StringUtil;
/** /**
* Inspired by nginx's try_files functionality. * Inspired by nginx's try_files functionality.
* <p> * <p>
@ -132,7 +133,7 @@ public class TryFilesFilter implements Filter
path += info; path += info;
if (!path.startsWith("/")) if (!path.startsWith("/"))
path = "/" + path; path = "/" + path;
return value.replaceAll("\\$path", path); return StringUtil.replace(value, "$path", path);
} }
@Override @Override

View File

@ -196,7 +196,7 @@ public class MimeTypes
int charset=type.toString().indexOf(";charset="); int charset=type.toString().indexOf(";charset=");
if (charset>0) if (charset>0)
{ {
String alt=type.toString().replace(";charset=","; charset="); String alt = StringUtil.replace(type.toString(), ";charset=", "; charset=");
CACHE.put(alt,type); CACHE.put(alt,type);
TYPES.put(alt,type.asBuffer()); TYPES.put(alt,type.asBuffer());
} }

View File

@ -0,0 +1,119 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@Fork(value = 3)
@State(Scope.Benchmark)
@Warmup(iterations = 4, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 4, time = 1, timeUnit = TimeUnit.SECONDS)
public class StringReplaceBenchmark
{
@Param({"3", "100", "1000"})
int size;
@Param({"0", "1", "3", "50"})
int matches;
String input;
@Setup(Level.Trial)
public void setupTrial() throws Exception
{
String pattern = "abc";
StringBuilder str = new StringBuilder();
while (str.length() < size)
{
str.append(pattern);
}
if (matches > 0)
{
int partSize = (int)((double)str.length() / (double)matches);
for (int i = 0; i < matches; i++)
{
str.insert((i * partSize), "'");
}
}
input = str.toString();
}
@Benchmark
public void testJavaStringReplace_Growth(Blackhole blackhole)
{
blackhole.consume(input.replace("'", "FOOBAR"));
}
@Benchmark
public void testJavaStringReplace_Same(Blackhole blackhole)
{
blackhole.consume(input.replace("'", "X"));
}
@Benchmark
public void testJavaStringReplace_Reduce(Blackhole blackhole)
{
blackhole.consume(input.replace("'", ""));
}
@Benchmark
public void testJettyStringUtilReplace_Growth(Blackhole blackhole)
{
blackhole.consume(StringUtil.replace(input, "'", "FOOBAR"));
}
@Benchmark
public void testJettyStringUtilReplace_Same(Blackhole blackhole)
{
blackhole.consume(StringUtil.replace(input, "'", "X"));
}
@Benchmark
public void testJettyStringUtilReplace_Reduce(Blackhole blackhole)
{
blackhole.consume(StringUtil.replace(input, "'", ""));
}
public static void main(String[] args) throws RunnerException
{
Options opt = new OptionsBuilder()
.include(StringReplaceBenchmark.class.getSimpleName())
// .addProfiler(GCProfiler.class)
.forks(1)
.build();
new Runner(opt).run();
}
}

View File

@ -27,10 +27,10 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.eclipse.jetty.util.StringUtil;
/** /**
* MongoUtils * MongoUtils
@ -69,23 +69,23 @@ public class MongoUtils
throw new IllegalStateException(valueToDecode.getClass().toString()); throw new IllegalStateException(valueToDecode.getClass().toString());
} }
} }
public static String decodeName(String name) public static String decodeName(String name)
{ {
return name.replace("%2E",".").replace("%25","%"); String cleaned = name;
cleaned = StringUtil.replace(cleaned, "%2E", ".");
cleaned = StringUtil.replace(cleaned, "%25", "%");
return cleaned;
} }
public static String encodeName(String name) public static String encodeName(String name)
{ {
return name.replace("%","%25").replace(".","%2E"); String cleaned = name;
cleaned = StringUtil.replace(cleaned, "%", "%25");
cleaned = StringUtil.replace(cleaned, ".", "%2E");
return cleaned;
} }
public static Object encodeName(Object value) throws IOException public static Object encodeName(Object value) throws IOException
{ {
if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date) if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date)

View File

@ -35,6 +35,7 @@ import java.util.regex.Pattern;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.Util; import org.eclipse.jetty.osgi.boot.utils.Util;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker; import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -339,7 +340,7 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
} }
catch (URISyntaxException e) catch (URISyntaxException e)
{ {
uri = new URI(url.toString().replaceAll(" ", "%20")); uri = new URI(URIUtil.encodeSpaces(url.toString()));
} }
String key = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; String key = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath;
resourceMap.put(key + ";" + fragment.getSymbolicName(), Resource.newResource(uri)); resourceMap.put(key + ";" + fragment.getSymbolicName(), Resource.newResource(uri));

View File

@ -43,7 +43,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent; import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener; import javax.servlet.AsyncListener;
@ -670,7 +669,7 @@ public class ProxyServletTest
// Make the request to the proxy, it should transparently forward to the server // Make the request to the proxy, it should transparently forward to the server
ContentResponse response = client.newRequest("localhost", proxyConnector.getLocalPort()) ContentResponse response = client.newRequest("localhost", proxyConnector.getLocalPort())
.path((prefix + target).replaceAll("//", "/")) .path((prefix + target).replace("//", "/"))
.timeout(5, TimeUnit.SECONDS) .timeout(5, TimeUnit.SECONDS)
.send(); .send();
assertEquals(200, response.getStatus()); assertEquals(200, response.getStatus());

View File

@ -37,6 +37,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -454,13 +455,7 @@ public class AttributeNormalizer
// leftover // leftover
expanded.append(str.substring(offset)); expanded.append(str.substring(offset));
// special case for "$$" return StringUtil.replace(expanded.toString(), "$$", "$");
if (expanded.indexOf("$$") >= 0)
{
return expanded.toString().replaceAll("\\$\\$","\\$");
}
return expanded.toString();
} }
private String getString(String property) private String getString(String property)

View File

@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.annotation.Name;
/** /**
@ -93,7 +94,7 @@ public class RedirectRegexRule extends RegexRule
for (int g = 1; g <= matcher.groupCount(); g++) for (int g = 1; g <= matcher.groupCount(); g++)
{ {
String group = matcher.group(g); String group = matcher.group(g);
target = target.replaceAll("\\$" + g, group); target = StringUtil.replace(target, "$" + g, group);
} }
target = response.encodeRedirectURL(target); target = response.encodeRedirectURL(target);
@ -110,6 +111,11 @@ public class RedirectRegexRule extends RegexRule
@Override @Override
public String toString() public String toString()
{ {
return String.format("%s[%d>%s]", super.toString(), _statusCode, _location); StringBuilder str = new StringBuilder();
str.append(super.toString());
str.append('[').append(_statusCode);
str.append('>').append(_location);
str.append(']');
return str.toString();
} }
} }

View File

@ -20,11 +20,11 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException; import java.io.IOException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.annotation.Name;
/** /**
@ -96,15 +96,22 @@ public class RewriteRegexRule extends RegexRule implements Rule.ApplyURI
group=""; group="";
else else
group = Matcher.quoteReplacement(group); group = Matcher.quoteReplacement(group);
target=target.replaceAll("\\$"+g,group); String dollarGroup = "$" + g;
if (query!=null) target = StringUtil.replace(target, dollarGroup, group);
query=query.replaceAll("\\$"+g,group); if (query != null)
query = StringUtil.replace(query, dollarGroup, group);
} }
if (query!=null) if (query!=null)
{ {
if (_queryGroup) if (_queryGroup)
query=query.replace("$Q",request.getQueryString()==null?"":request.getQueryString()); {
String replacement = "";
if (request.getQueryString() != null)
replacement = request.getQueryString();
query = StringUtil.replace(query, "$Q", replacement);
}
request.setAttribute("org.eclipse.jetty.rewrite.handler.RewriteRegexRule.Q",query); request.setAttribute("org.eclipse.jetty.rewrite.handler.RewriteRegexRule.Q",query);
} }

View File

@ -140,7 +140,8 @@ public class PropertyUserStore extends UserStore implements PathWatcher.Listener
int bang_slash = uri.indexOf("!/"); int bang_slash = uri.indexOf("!/");
if (colon < 0 || bang_slash < 0 || colon > bang_slash) if (colon < 0 || bang_slash < 0 || colon > bang_slash)
throw new IllegalArgumentException("Not resolved JarFile resource: " + uri); throw new IllegalArgumentException("Not resolved JarFile resource: " + uri);
String entry_path = uri.substring(colon + 2).replace("!/", "__").replace('/', '_').replace('.', '_');
String entry_path = StringUtil.sanitizeFileSystemPath(uri.substring(colon + 2));
Path tmpDirectory = Files.createTempDirectory("users_store"); Path tmpDirectory = Files.createTempDirectory("users_store");
tmpDirectory.toFile().deleteOnExit(); tmpDirectory.toFile().deleteOnExit();

View File

@ -52,12 +52,10 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http.Syntax;
import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -237,7 +235,7 @@ public class Response implements HttpServletResponse
if (i >= 0) if (i >= 0)
{ {
httpOnly = true; httpOnly = true;
comment = comment.replace(HTTP_ONLY_COMMENT, "").trim(); comment = StringUtil.replace(comment.trim(), HTTP_ONLY_COMMENT, "");
if (comment.length() == 0) if (comment.length() == 0)
comment = null; comment = null;
} }

View File

@ -164,7 +164,7 @@ public class DefaultHandler extends AbstractHandler
{ {
writer.append("<a href=\"").append(href).append("\">"); writer.append("<a href=\"").append(href).append("\">");
} }
writer.append(contextPath.replaceAll("%", "&#37;")); writer.append(StringUtil.replace(contextPath, "%", "&#37;"));
if (context.isRunning()) if (context.isRunning())
{ {
writer.append("</a>"); writer.append("</a>");

View File

@ -18,13 +18,9 @@
package org.eclipse.jetty.servlet; package org.eclipse.jetty.servlet;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import java.io.IOException; import java.io.IOException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -38,6 +34,9 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class ResponseHeadersTest public class ResponseHeadersTest
{ {
public static class SimulateUpgradeServlet extends HttpServlet public static class SimulateUpgradeServlet extends HttpServlet
@ -144,7 +143,7 @@ public class ResponseHeadersTest
assertThat("Response Code",response.getStatus(),is(200)); assertThat("Response Code",response.getStatus(),is(200));
assertThat("Response Header Content-Type",response.get("Content-Type"),is("text/plain;charset=UTF-8")); assertThat("Response Header Content-Type",response.get("Content-Type"),is("text/plain;charset=UTF-8"));
String expected = actualPathInfo.replaceAll("%0A", " "); // replace OBS fold with space String expected = actualPathInfo.replace("%0A", " "); // replace OBS fold with space
expected = URLDecoder.decode(expected, "utf-8"); // decode the rest expected = URLDecoder.decode(expected, "utf-8"); // decode the rest
expected = expected.trim(); // trim whitespace at start/end expected = expected.trim(); // trim whitespace at start/end
assertThat("Response Header X-example", response.get("X-Example"), is(expected)); assertThat("Response Header X-example", response.get("X-Example"), is(expected));

View File

@ -26,7 +26,6 @@ import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.FilterConfig; import javax.servlet.FilterConfig;
@ -368,8 +367,8 @@ public class CrossOriginFilter implements Filter
private String parseAllowedWildcardOriginToRegex(String allowedOrigin) private String parseAllowedWildcardOriginToRegex(String allowedOrigin)
{ {
String regex = allowedOrigin.replace(".", "\\."); String regex = StringUtil.replace(allowedOrigin, ".", "\\.");
return regex.replace("*", ".*"); // we want to be greedy here to match multiple subdomains, thus we use .* return StringUtil.replace(regex, "*", ".*"); // we want to be greedy here to match multiple subdomains, thus we use .*
} }
private boolean isSimpleRequest(HttpServletRequest request) private boolean isSimpleRequest(HttpServletRequest request)

View File

@ -26,14 +26,13 @@ import java.util.List;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
/** Fast String Utilities. /**
* Fast String Utilities.
* *
* These string utilities provide both convenience methods and * These string utilities provide both convenience methods and
* performance improvements over most standard library versions. The * performance improvements over most standard library versions. The
* main aim of the optimizations is to avoid object creation unless * main aim of the optimizations is to avoid object creation unless
* absolutely required. * absolutely required.
*
*
*/ */
public class StringUtil public class StringUtil
{ {
@ -62,8 +61,7 @@ public class StringUtil
CHARSETS.put("iso-8859-1",__ISO_8859_1); CHARSETS.put("iso-8859-1",__ISO_8859_1);
CHARSETS.put("iso_8859_1",__ISO_8859_1); CHARSETS.put("iso_8859_1",__ISO_8859_1);
} }
/* ------------------------------------------------------------ */
/** Convert alternate charset names (eg utf8) to normalized /** Convert alternate charset names (eg utf8) to normalized
* name (eg UTF-8). * name (eg UTF-8).
* @param s the charset to normalize * @param s the charset to normalize
@ -74,8 +72,7 @@ public class StringUtil
String n=CHARSETS.get(s); String n=CHARSETS.get(s);
return (n==null)?s:n; return (n==null)?s:n;
} }
/* ------------------------------------------------------------ */
/** Convert alternate charset names (eg utf8) to normalized /** Convert alternate charset names (eg utf8) to normalized
* name (eg UTF-8). * name (eg UTF-8).
* @param s the charset to normalize * @param s the charset to normalize
@ -88,9 +85,7 @@ public class StringUtil
String n=CHARSETS.get(s,offset,length); String n=CHARSETS.get(s,offset,length);
return (n==null)?s.substring(offset,offset+length):n; return (n==null)?s.substring(offset,offset+length):n;
} }
/* ------------------------------------------------------------ */
public static final char[] lowercases = { public static final char[] lowercases = {
'\000','\001','\002','\003','\004','\005','\006','\007', '\000','\001','\002','\003','\004','\005','\006','\007',
'\010','\011','\012','\013','\014','\015','\016','\017', '\010','\011','\012','\013','\014','\015','\016','\017',
@ -109,7 +104,6 @@ public class StringUtil
'\160','\161','\162','\163','\164','\165','\166','\167', '\160','\161','\162','\163','\164','\165','\166','\167',
'\170','\171','\172','\173','\174','\175','\176','\177' }; '\170','\171','\172','\173','\174','\175','\176','\177' };
/* ------------------------------------------------------------ */
/** /**
* fast lower case conversion. Only works on ascii (not unicode) * fast lower case conversion. Only works on ascii (not unicode)
* @param s the string to convert * @param s the string to convert
@ -122,7 +116,6 @@ public class StringUtil
char[] c = null; char[] c = null;
int i=s.length(); int i=s.length();
// look for first conversion // look for first conversion
while (i-->0) while (i-->0)
{ {
@ -138,7 +131,6 @@ public class StringUtil
} }
} }
} }
while (i-->0) while (i-->0)
{ {
if(c[i]<=127) if(c[i]<=127)
@ -148,8 +140,43 @@ public class StringUtil
return c==null?s:new String(c); return c==null?s:new String(c);
} }
/**
* Replace all characters from input string that are known to have
* special meaning in various filesytems.
*
* <p>
* This will replace all of the following characters
* with a "{@code _}" (underscore).
* </p>
* <ul>
* <li>Control Characters</li>
* <li>Anything not 7-bit printable ASCII</li>
* <li>Special characters "{@code !|/.,:&><\?*"}"</li>
* </ul>
*
* @param str the raw input string
* @return the sanitized output string.
*/
public static String sanitizeFileSystemPath(String str)
{
char[] chars = str.toCharArray();
int len = chars.length;
for (int i = 0; i < len; i++)
{
char c = chars[i];
if ((c <= 0x1F) || // control characters
(c >= 0x7F) || // over 7-bit printable ASCII
(c == '!') || (c == '|') || (c == '.') ||
(c == ':') || (c == '>') || (c == '<') ||
(c == '?') || (c == '/') || (c == '\\') ||
(c == '*') || (c == '"') || (c == '&'))
{
chars[i] = '_';
}
}
return String.valueOf(chars);
}
/* ------------------------------------------------------------ */
public static boolean startsWithIgnoreCase(String s,String w) public static boolean startsWithIgnoreCase(String s,String w)
{ {
if (w==null) if (w==null)
@ -174,13 +201,11 @@ public class StringUtil
} }
return true; return true;
} }
/* ------------------------------------------------------------ */
public static boolean endsWithIgnoreCase(String s,String w) public static boolean endsWithIgnoreCase(String s,String w)
{ {
if (w==null) if (w==null)
return true; return true;
if (s==null) if (s==null)
return false; return false;
@ -206,8 +231,7 @@ public class StringUtil
} }
return true; return true;
} }
/* ------------------------------------------------------------ */
/** /**
* returns the next index of a character from the chars string * returns the next index of a character from the chars string
* @param s the input string to search * @param s the input string to search
@ -221,10 +245,13 @@ public class StringUtil
return i; return i;
return -1; return -1;
} }
/* ------------------------------------------------------------ */
/** /**
* replace substrings within string. * Replace substrings within string.
* <p>
* Fast replacement for {@code java.lang.String#}{@link String#replace(CharSequence, CharSequence)}
* </p>
*
* @param s the input string * @param s the input string
* @param sub the string to look for * @param sub the string to look for
* @param with the string to replace with * @param with the string to replace with
@ -232,27 +259,56 @@ public class StringUtil
*/ */
public static String replace(String s, String sub, String with) public static String replace(String s, String sub, String with)
{ {
int c=0; int c = 0;
int i=s.indexOf(sub,c); int i = s.indexOf(sub, c);
if (i == -1) if (i == -1)
{
return s; return s;
}
StringBuilder buf = new StringBuilder(s.length()+with.length()); StringBuilder buf = new StringBuilder(s.length() + with.length());
do do
{ {
buf.append(s.substring(c,i)); buf.append(s, c, i);
buf.append(with); buf.append(with);
c=i+sub.length(); c = i + sub.length();
} while ((i=s.indexOf(sub,c))!=-1); }
while ((i = s.indexOf(sub, c)) != -1);
if (c<s.length()) if (c < s.length())
buf.append(s.substring(c,s.length())); {
buf.append(s.substring(c));
}
return buf.toString(); return buf.toString();
} }
/* ------------------------------------------------------------ */ /**
* Replace first substrings within string.
* <p>
* Fast replacement for {@code java.lang.String#}{@link String#replaceFirst(String, String)}, but without
* Regex support.
* </p>
*
* @param original the original string
* @param target the target string to look for
* @param replacement the replacement string to use
* @return the replaced string
*/
public static String replaceFirst(String original, String target, String replacement)
{
int idx = original.indexOf(target);
if (idx == -1)
return original;
int offset = 0;
int originalLen = original.length();
StringBuilder buf = new StringBuilder(originalLen + replacement.length());
buf.append(original, offset, idx);
offset += idx + target.length();
buf.append(replacement);
buf.append(original, offset, originalLen);
return buf.toString();
}
/** Remove single or double quotes. /** Remove single or double quotes.
* @param s the input string * @param s the input string
* @return the string with quotes removed * @return the string with quotes removed
@ -263,8 +319,6 @@ public class StringUtil
return QuotedStringTokenizer.unquote(s); return QuotedStringTokenizer.unquote(s);
} }
/* ------------------------------------------------------------ */
/** Append substring to StringBuilder /** Append substring to StringBuilder
* @param buf StringBuilder to append to * @param buf StringBuilder to append to
* @param s String to append from * @param s String to append from
@ -288,8 +342,6 @@ public class StringUtil
} }
} }
/* ------------------------------------------------------------ */
/** /**
* append hex digit * append hex digit
* @param buf the buffer to append to * @param buf the buffer to append to
@ -310,7 +362,6 @@ public class StringUtil
buf.append((char)c); buf.append((char)c);
} }
/* ------------------------------------------------------------ */
/** /**
* Append 2 digits (zero padded) to the StringBuffer * Append 2 digits (zero padded) to the StringBuffer
* *
@ -325,8 +376,7 @@ public class StringUtil
buf.append((char)(i%10+'0')); buf.append((char)(i%10+'0'));
} }
} }
/* ------------------------------------------------------------ */
/** /**
* Append 2 digits (zero padded) to the StringBuilder * Append 2 digits (zero padded) to the StringBuilder
* *
@ -341,8 +391,7 @@ public class StringUtil
buf.append((char)(i%10+'0')); buf.append((char)(i%10+'0'));
} }
} }
/* ------------------------------------------------------------ */
/** Return a non null string. /** Return a non null string.
* @param s String * @param s String
* @return The string passed in or empty string if it is null. * @return The string passed in or empty string if it is null.
@ -353,8 +402,7 @@ public class StringUtil
return ""; return "";
return s; return s;
} }
/* ------------------------------------------------------------ */
public static boolean equals(String s,char[] buf, int offset, int length) public static boolean equals(String s,char[] buf, int offset, int length)
{ {
if (s.length()!=length) if (s.length()!=length)
@ -365,13 +413,11 @@ public class StringUtil
return true; return true;
} }
/* ------------------------------------------------------------ */
public static String toUTF8String(byte[] b,int offset,int length) public static String toUTF8String(byte[] b,int offset,int length)
{ {
return new String(b,offset,length,StandardCharsets.UTF_8); return new String(b,offset,length,StandardCharsets.UTF_8);
} }
/* ------------------------------------------------------------ */
public static String toString(byte[] b,int offset,int length,String charset) public static String toString(byte[] b,int offset,int length,String charset)
{ {
try try
@ -380,6 +426,7 @@ public class StringUtil
} }
catch (UnsupportedEncodingException e) catch (UnsupportedEncodingException e)
{ {
LOG.warn(e);
throw new IllegalArgumentException(e); throw new IllegalArgumentException(e);
} }
} }
@ -431,7 +478,6 @@ public class StringUtil
return -1; return -1;
} }
/* ------------------------------------------------------------ */
/** /**
* Test if a string is null or only has whitespace characters in it. * Test if a string is null or only has whitespace characters in it.
* <p> * <p>
@ -494,7 +540,6 @@ public class StringUtil
return str == null || str.isEmpty(); return str == null || str.isEmpty();
} }
/* ------------------------------------------------------------ */
/** /**
* Test if a string is not null and contains at least 1 non-whitespace characters in it. * Test if a string is not null and contains at least 1 non-whitespace characters in it.
* <p> * <p>
@ -534,14 +579,11 @@ public class StringUtil
return false; return false;
} }
/* ------------------------------------------------------------ */
public static boolean isUTF8(String charset) public static boolean isUTF8(String charset)
{ {
return __UTF8.equalsIgnoreCase(charset)||__UTF8.equalsIgnoreCase(normalizeCharset(charset)); return __UTF8.equalsIgnoreCase(charset)||__UTF8.equalsIgnoreCase(normalizeCharset(charset));
} }
/* ------------------------------------------------------------ */
public static String printable(String name) public static String printable(String name)
{ {
if (name==null) if (name==null)
@ -556,7 +598,7 @@ public class StringUtil
return buf.toString(); return buf.toString();
} }
/* ------------------------------------------------------------ */
public static String printable(byte[] b) public static String printable(byte[] b)
{ {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
@ -592,13 +634,10 @@ public class StringUtil
} }
catch(Exception e) catch(Exception e)
{ {
LOG.warn(e);
return s.getBytes(); return s.getBytes();
} }
} }
/** /**
* Converts a binary SID to a string SID * Converts a binary SID to a string SID
* *
@ -631,7 +670,6 @@ public class StringUtil
// the number of subAuthorities we need to attach // the number of subAuthorities we need to attach
int subAuthorityCount = sidBytes[1]; int subAuthorityCount = sidBytes[1];
// attach each of the subAuthorities // attach each of the subAuthorities
for (int i = 0; i < subAuthorityCount; ++i) for (int i = 0; i < subAuthorityCount; ++i)
{ {
@ -670,10 +708,8 @@ public class StringUtil
// the revision byte // the revision byte
sidBytes[byteCount++] = (byte)Integer.parseInt(sidTokens[1]); sidBytes[byteCount++] = (byte)Integer.parseInt(sidTokens[1]);
// the # of sub authorities byte // the # of sub authorities byte
sidBytes[byteCount++] = (byte)subAuthorityCount; sidBytes[byteCount++] = (byte)subAuthorityCount;
// the certAuthority // the certAuthority
String hexStr = Long.toHexString(Long.parseLong(sidTokens[2])); String hexStr = Long.toHexString(Long.parseLong(sidTokens[2]));
@ -681,7 +717,6 @@ public class StringUtil
{ {
hexStr = "0" + hexStr; hexStr = "0" + hexStr;
} }
// place the certAuthority 6 bytes // place the certAuthority 6 bytes
for ( int i = 0 ; i < hexStr.length(); i = i + 2) for ( int i = 0 ; i < hexStr.length(); i = i + 2)
{ {
@ -720,7 +755,6 @@ public class StringUtil
int val = 0; int val = 0;
boolean started = false; boolean started = false;
boolean minus = false; boolean minus = false;
for (int i = from; i < string.length(); i++) for (int i = from; i < string.length(); i++)
{ {
char b = string.charAt(i); char b = string.charAt(i);
@ -741,7 +775,6 @@ public class StringUtil
else else
break; break;
} }
if (started) if (started)
return minus?(-val):val; return minus?(-val):val;
throw new NumberFormatException(string); throw new NumberFormatException(string);
@ -759,7 +792,6 @@ public class StringUtil
long val = 0; long val = 0;
boolean started = false; boolean started = false;
boolean minus = false; boolean minus = false;
for (int i = 0; i < string.length(); i++) for (int i = 0; i < string.length(); i++)
{ {
char b = string.charAt(i); char b = string.charAt(i);
@ -780,7 +812,6 @@ public class StringUtil
else else
break; break;
} }
if (started) if (started)
return minus?(-val):val; return minus?(-val):val;
throw new NumberFormatException(string); throw new NumberFormatException(string);
@ -799,12 +830,10 @@ public class StringUtil
{ {
return null; return null;
} }
if (str.length() <= maxSize) if (str.length() <= maxSize)
{ {
return str; return str;
} }
return str.substring(0,maxSize); return str.substring(0,maxSize);
} }
@ -817,20 +846,18 @@ public class StringUtil
{ {
if (s==null) if (s==null)
return new String[]{}; return new String[]{};
if (!s.startsWith("[") || !s.endsWith("]")) if (!s.startsWith("[") || !s.endsWith("]"))
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (s.length()==2) if (s.length()==2)
return new String[]{}; return new String[]{};
return csvSplit(s,1,s.length()-2); return csvSplit(s,1,s.length()-2);
} }
/** /**
* Parse a CSV string using {@link #csvSplit(List,String, int, int)} * Parse a CSV string using {@link #csvSplit(List,String, int, int)}
* @param s The string to parse * @param s The string to parse
* @return An array of parsed values. * @return An array of parsed values.
*/ */
public static String[] csvSplit(String s) public static String[] csvSplit(String s)
{ {
if (s==null) if (s==null)
@ -851,13 +878,12 @@ public class StringUtil
return null; return null;
if (off<0 || len<0 || off>s.length()) if (off<0 || len<0 || off>s.length())
throw new IllegalArgumentException(); throw new IllegalArgumentException();
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
csvSplit(list,s,off,len); csvSplit(list,s,off,len);
return list.toArray(new String[list.size()]); return list.toArray(new String[list.size()]);
} }
enum CsvSplitState { PRE_DATA, QUOTE, SLOSH, DATA, WHITE, POST_DATA }; enum CsvSplitState { PRE_DATA, QUOTE, SLOSH, DATA, WHITE, POST_DATA }
/** Split a quoted comma separated string to a list /** Split a quoted comma separated string to a list
* <p>Handle <a href="https://www.ietf.org/rfc/rfc4180.txt">rfc4180</a>-like * <p>Handle <a href="https://www.ietf.org/rfc/rfc4180.txt">rfc4180</a>-like
@ -890,7 +916,6 @@ public class StringUtil
case PRE_DATA: case PRE_DATA:
if (Character.isWhitespace(ch)) if (Character.isWhitespace(ch))
continue; continue;
if ('"'==ch) if ('"'==ch)
{ {
state=CsvSplitState.QUOTE; state=CsvSplitState.QUOTE;
@ -902,11 +927,9 @@ public class StringUtil
list.add(""); list.add("");
continue; continue;
} }
state=CsvSplitState.DATA; state=CsvSplitState.DATA;
out.append(ch); out.append(ch);
continue; continue;
case DATA: case DATA:
if (Character.isWhitespace(ch)) if (Character.isWhitespace(ch))
{ {
@ -923,7 +946,6 @@ public class StringUtil
state=CsvSplitState.PRE_DATA; state=CsvSplitState.PRE_DATA;
continue; continue;
} }
out.append(ch); out.append(ch);
continue; continue;
@ -947,7 +969,6 @@ public class StringUtil
out.append(ch); out.append(ch);
last=-1; last=-1;
continue; continue;
case QUOTE: case QUOTE:
if ('\\'==ch) if ('\\'==ch)
{ {
@ -978,13 +999,11 @@ public class StringUtil
continue; continue;
} }
} }
switch(state) switch(state)
{ {
case PRE_DATA: case PRE_DATA:
case POST_DATA: case POST_DATA:
break; break;
case DATA: case DATA:
case QUOTE: case QUOTE:
case SLOSH: case SLOSH:
@ -1011,7 +1030,6 @@ public class StringUtil
loop: for (;i<html.length();i++) loop: for (;i<html.length();i++)
{ {
char c=html.charAt(i); char c=html.charAt(i);
switch(c) switch(c)
{ {
case '&' : case '&' :
@ -1020,13 +1038,11 @@ public class StringUtil
case '\'': case '\'':
case '"': case '"':
break loop; break loop;
default: default:
if (Character.isISOControl(c) && !Character.isWhitespace(c)) if (Character.isISOControl(c) && !Character.isWhitespace(c))
break loop; break loop;
} }
} }
// No characters need sanitizing, so return original string // No characters need sanitizing, so return original string
if (i==html.length()) if (i==html.length())
return html; return html;
@ -1039,7 +1055,6 @@ public class StringUtil
for (;i<html.length();i++) for (;i<html.length();i++)
{ {
char c=html.charAt(i); char c=html.charAt(i);
switch(c) switch(c)
{ {
case '&' : case '&' :
@ -1057,7 +1072,6 @@ public class StringUtil
case '"': case '"':
out.append("&quot;"); out.append("&quot;");
break; break;
default: default:
if (Character.isISOControl(c) && !Character.isWhitespace(c)) if (Character.isISOControl(c) && !Character.isWhitespace(c))
out.append('?'); out.append('?');
@ -1067,8 +1081,7 @@ public class StringUtil
} }
return out.toString(); return out.toString();
} }
/* ------------------------------------------------------------ */
/** The String value of an Object /** The String value of an Object
* <p>This method calls {@link String#valueOf(Object)} unless the object is null, * <p>This method calls {@link String#valueOf(Object)} unless the object is null,
* in which case null is returned</p> * in which case null is returned</p>

View File

@ -268,7 +268,19 @@ public class URIUtil
return buf; return buf;
} }
/**
* Encode a raw URI String and convert any raw spaces to
* their "%20" equivalent.
*
* @param str input raw string
* @return output with spaces converted to "%20"
*/
public static String encodeSpaces(String str)
{
return StringUtil.replace(str, " ", "%20");
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Encode a URI path. /** Encode a URI path.
* @param path The path the encode * @param path The path the encode

View File

@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.ManagedOperation;
@ -99,9 +100,15 @@ public interface Dumpable
else if (o instanceof Map) else if (o instanceof Map)
s = String.format("%s@%x{size=%d}",o.getClass().getName(),o.hashCode(),((Map<?,?>)o).size()); s = String.format("%s@%x{size=%d}",o.getClass().getName(),o.hashCode(),((Map<?,?>)o).size());
else if (o instanceof Dumpable) else if (o instanceof Dumpable)
s = ((Dumpable)o).dumpSelf().replace("\r\n","|").replace("\n","|"); {
s = StringUtil.replace(((Dumpable)o).dumpSelf(), "\r\n", "|")
.replace('\n', '|');
}
else else
s = String.valueOf(o).replace("\r\n","|").replace("\n","|"); {
s = StringUtil.replace(String.valueOf(o), "\r\n", "|")
.replace('\n', '|');
}
if (o instanceof LifeCycle) if (o instanceof LifeCycle)
out.append(s).append(" - ").append((AbstractLifeCycle.getState((LifeCycle)o))).append("\n"); out.append(s).append(" - ").append((AbstractLifeCycle.getState((LifeCycle)o))).append("\n");

View File

@ -18,19 +18,21 @@
package org.eclipse.jetty.util; package org.eclipse.jetty.util;
import java.nio.charset.StandardCharsets; import java.util.ArrayList;
import java.util.concurrent.TimeUnit; import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.emptyArray; import static org.hamcrest.Matchers.emptyArray;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
public class StringUtilTest public class StringUtilTest
@ -98,7 +100,36 @@ public class StringUtilTest
s=" \u0690bc "; s=" \u0690bc ";
assertEquals(StringUtil.replace(s, "\u0690bc", "xyz")," xyz "); assertEquals(StringUtil.replace(s, "\u0690bc", "xyz")," xyz ");
}
public static Stream<String[]> replaceFirstArgs() {
List<String[]> data = new ArrayList<>();
// [original, target, replacement, expected]
// no match
data.add(new String[]{ "abc", "z", "foo", "abc" });
// matches at start of string
data.add(new String[]{ "abc", "a", "foo", "foobc" });
data.add(new String[]{ "abcabcabc", "a", "foo", "foobcabcabc" });
// matches in middle of string
data.add(new String[]{ "abc", "b", "foo", "afooc" });
data.add(new String[]{ "abcabcabc", "b", "foo", "afoocabcabc" });
data.add(new String[]{ "abcabcabc", "cab", "X", "abXcabc" });
// matches at end of string
data.add(new String[]{ "abc", "c", "foo", "abfoo" });
return data.stream();
}
@ParameterizedTest
@MethodSource(value = "replaceFirstArgs")
public void testReplaceFirst(String original, String target, String replacement, String expected)
{
assertThat(StringUtil.replaceFirst(original, target, replacement), is(expected));
} }
@Test @Test
@ -165,50 +196,6 @@ public class StringUtilTest
assertEquals(sid5, StringUtil.sidBytesToString(sid5Bytes)); assertEquals(sid5, StringUtil.sidBytesToString(sid5Bytes));
assertEquals(sid6, StringUtil.sidBytesToString(sid6Bytes)); assertEquals(sid6, StringUtil.sidBytesToString(sid6Bytes));
assertEquals(sid12, StringUtil.sidBytesToString(sid12Bytes)); assertEquals(sid12, StringUtil.sidBytesToString(sid12Bytes));
}
public static void main(String[] arg) throws Exception
{
String string = "Now \u0690xxxxxxxx";
System.err.println(string);
byte[] bytes=string.getBytes(StandardCharsets.UTF_8);
System.err.println(new String(bytes));
System.err.println(bytes.length);
long calc=0;
Utf8StringBuffer strbuf = new Utf8StringBuffer(bytes.length);
for (int i=0;i<10;i++)
{
long s1=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
for (int j=1000000; j-->0;)
{
calc+=new String(bytes,0,bytes.length,StandardCharsets.UTF_8).hashCode();
}
long s2=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
for (int j=1000000; j-->0;)
{
calc+=StringUtil.toUTF8String(bytes,0,bytes.length).hashCode();
}
long s3=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
for (int j=1000000; j-->0;)
{
Utf8StringBuffer buffer = new Utf8StringBuffer(bytes.length);
buffer.append(bytes,0,bytes.length);
calc+=buffer.toString().hashCode();
}
long s4=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
for (int j=1000000; j-->0;)
{
strbuf.reset();
strbuf.append(bytes,0,bytes.length);
calc+=strbuf.toString().hashCode();
}
long s5=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
System.err.println((s2-s1)+", "+(s3-s2)+", "+(s4-s3)+", "+(s5-s4));
}
System.err.println(calc);
} }
@Test @Test

View File

@ -703,7 +703,7 @@ public class ClasspathPattern extends AbstractSet<String>
name=name.substring(0,name.length()-6); name=name.substring(0,name.length()-6);
// Treat path elements as packages for name matching // Treat path elements as packages for name matching
name=name.replace("/","."); name = name.replace('/', '.');
return combine(_packageOrNamePatterns, name, _locations, ()-> return combine(_packageOrNamePatterns, name, _locations, ()->
{ {

View File

@ -38,6 +38,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.JavaVersion;
import org.eclipse.jetty.util.PatternMatcher; import org.eclipse.jetty.util.PatternMatcher;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -210,7 +211,8 @@ public class WebInfConfiguration extends AbstractConfiguration
} }
catch (URISyntaxException e) catch (URISyntaxException e)
{ {
containerUris.add(new URI(u.toString().replaceAll(" ", "%20"))); String fixedUriStr = StringUtil.replace(u.toString(), " ", "%20");
containerUris.add(new URI(fixedUriStr));
} }
} }
} }

View File

@ -21,7 +21,6 @@ package com.acme;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
@ -29,7 +28,6 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
/** /**
* Test Servlet Cookies. * Test Servlet Cookies.
*/ */
@ -117,9 +115,9 @@ public class CookieDump extends HttpServlet
{ {
if (string==null) if (string==null)
return null; return null;
string=string.replace("&", "&amp;"); string = string.replace("&", "&amp;");
string=string.replace( "<", "&lt;"); string = string.replace( "<", "&lt;");
string=string.replace( ">", "&gt;"); string = string.replace( ">", "&gt;");
return string; return string;
} }

View File

@ -36,7 +36,6 @@ import java.util.Enumeration;
import java.util.Locale; import java.util.Locale;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent; import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener; import javax.servlet.AsyncListener;
@ -57,13 +56,14 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.Part; import javax.servlet.http.Part;
/**
/**
* Dump Servlet Request. * Dump Servlet Request.
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class Dump extends HttpServlet public class Dump extends HttpServlet
{ {
/** Zero Width Space, to allow text to be wrapped at designated spots */
private static final String ZWSP = "&#8203;";
boolean fixed; boolean fixed;
Timer _timer; Timer _timer;
@ -647,7 +647,7 @@ public class Dump extends HttpServlet
{ {
name= (String)a.nextElement(); name= (String)a.nextElement();
pout.write("</tr><tr>\n"); pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+":&nbsp;</th>"); pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
Object value=request.getAttribute(name); Object value=request.getAttribute(name);
if (value instanceof File) if (value instanceof File)
{ {
@ -678,7 +678,7 @@ public class Dump extends HttpServlet
{ {
name= (String)a.nextElement(); name= (String)a.nextElement();
pout.write("</tr><tr>\n"); pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+":&nbsp;</th>"); pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
pout.write("<td>"+ toString(getServletContext().getInitParameter(name)) + "</td>"); pout.write("<td>"+ toString(getServletContext().getInitParameter(name)) + "</td>");
} }
@ -689,7 +689,7 @@ public class Dump extends HttpServlet
{ {
name= (String)a.nextElement(); name= (String)a.nextElement();
pout.write("</tr><tr>\n"); pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+":&nbsp;</th>"); pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
pout.write("<td>"+"<pre>" + toString(getServletContext().getAttribute(name)) + "</pre>"+"</td>"); pout.write("<td>"+"<pre>" + toString(getServletContext().getAttribute(name)) + "</pre>"+"</td>");
} }
@ -1055,9 +1055,9 @@ public class Dump extends HttpServlet
{ {
if (s==null) if (s==null)
return "null"; return "null";
s=s.replaceAll("&","&amp;"); s = s.replace("&","&amp;");
s=s.replaceAll("<","&lt;"); s = s.replace("<","&lt;");
s=s.replaceAll(">","&gt;"); s = s.replace(">","&gt;");
return s; return s;
} }
} }