Merge branch `jetty-9.4.x` into `jetty-9.4.x-3731-cdi-testing`
This commit is contained in:
commit
2f4f42a7df
|
@ -24,7 +24,6 @@ import java.math.RoundingMode;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
@ -67,12 +66,25 @@ public class AbstractRestServlet extends HttpServlet
|
|||
_appid = servletConfig.getInitParameter(APPID_PARAM);
|
||||
}
|
||||
|
||||
|
||||
public static String sanitize(String s)
|
||||
// TODO: consider using StringUtil.sanitizeFileSystemName instead of this?
|
||||
// might introduce jetty-util dependency though
|
||||
public static String sanitize(String str)
|
||||
{
|
||||
if (s==null)
|
||||
if (str == null)
|
||||
return null;
|
||||
return s.replace("<","?").replace("&","?").replace("\n","?");
|
||||
|
||||
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 == '<') || (c == '&'))
|
||||
{
|
||||
chars[i] = '?';
|
||||
}
|
||||
}
|
||||
return String.valueOf(chars);
|
||||
}
|
||||
|
||||
protected String restURL(String item)
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.io.IOException;
|
|||
import java.lang.management.ManagementFactory;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
|
@ -158,7 +157,7 @@ public class Http2Server
|
|||
public void destroy()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Servlet servlet = new HttpServlet()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* A utility test class to locate a Jetty Distribution for testing purposes by searching:
|
||||
* <ul>
|
||||
* <li>The <code>jetty.home</code> system property</li>
|
||||
* <li>The <code>JETTY_HOME</code> environment variable</li>
|
||||
* <li>The working directory hierarchy with subdirectory <code>jetty-distribution/target/home</code></li>
|
||||
* </ul>
|
||||
*/
|
||||
public class JettyDistribution
|
||||
{
|
||||
private final static Logger LOG = Log.getLogger(JettyDistribution.class);
|
||||
public final static Path DISTRIBUTION;
|
||||
|
||||
static
|
||||
{
|
||||
Path distro = asJettyDistribution(System.getProperty("jetty.home"));
|
||||
if (distro==null)
|
||||
distro = asJettyDistribution(System.getenv().get("JETTY_HOME"));
|
||||
|
||||
if (distro==null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Path working = new File(".").getAbsoluteFile().getCanonicalFile().toPath();
|
||||
while(distro == null && working !=null )
|
||||
{
|
||||
distro = asJettyDistribution(working.resolve("jetty-distribution/target/distribution").toString());
|
||||
working = working.getParent();
|
||||
}
|
||||
}
|
||||
catch(Throwable th)
|
||||
{
|
||||
LOG.warn(th);
|
||||
}
|
||||
}
|
||||
DISTRIBUTION = distro;
|
||||
}
|
||||
|
||||
private static Path asJettyDistribution(String test)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (StringUtil.isBlank(test))
|
||||
{
|
||||
LOG.info("asJettyDistribution {} is blank", test);
|
||||
return null;
|
||||
}
|
||||
|
||||
File dir = new File(test);
|
||||
if (!dir.exists() || !dir.isDirectory())
|
||||
{
|
||||
LOG.info("asJettyDistribution {} is not a directory", test);
|
||||
return null;
|
||||
}
|
||||
|
||||
File demoBase = new File(dir,"demo-base");
|
||||
if (!demoBase.exists() || !demoBase.isDirectory())
|
||||
{
|
||||
LOG.info("asJettyDistribution {} has no demo-base", test);
|
||||
return null;
|
||||
}
|
||||
|
||||
LOG.info("asJettyDistribution {}", dir);
|
||||
return dir.getAbsoluteFile().getCanonicalFile().toPath();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Path resolve(String path)
|
||||
{
|
||||
return DISTRIBUTION.resolve(path);
|
||||
}
|
||||
|
||||
public static void main(String... arg)
|
||||
{
|
||||
System.err.println("Jetty Distribution is " + DISTRIBUTION);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@
|
|||
package org.eclipse.jetty.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
|
@ -60,27 +59,14 @@ public class LikeJettyXml
|
|||
public static void main( String[] args ) throws Exception
|
||||
{
|
||||
// Path to as-built jetty-distribution directory
|
||||
String jettyHomeBuild = "jetty-distribution/target/distribution";
|
||||
|
||||
String jettyHomeBuild = JettyDistribution.DISTRIBUTION.toString();
|
||||
|
||||
// Find jetty home and base directories
|
||||
String homePath = System.getProperty("jetty.home", jettyHomeBuild);
|
||||
File start_jar = new File(homePath,"start.jar");
|
||||
if (!start_jar.exists())
|
||||
{
|
||||
homePath = jettyHomeBuild = "jetty-distribution/target/distribution";
|
||||
start_jar = new File(homePath,"start.jar");
|
||||
if (!start_jar.exists())
|
||||
throw new FileNotFoundException(start_jar.toString());
|
||||
}
|
||||
|
||||
File homeDir = new File(homePath);
|
||||
|
||||
String basePath = System.getProperty("jetty.base", homeDir + "/demo-base");
|
||||
File baseDir = new File(basePath);
|
||||
if(!baseDir.exists())
|
||||
{
|
||||
throw new FileNotFoundException(baseDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
// Configure jetty.home and jetty.base system properties
|
||||
String jetty_home = homeDir.getAbsolutePath();
|
||||
|
@ -88,7 +74,6 @@ public class LikeJettyXml
|
|||
System.setProperty("jetty.home", jetty_home);
|
||||
System.setProperty("jetty.base", jetty_base);
|
||||
|
||||
|
||||
// === jetty.xml ===
|
||||
// Setup Threadpool
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
|
@ -219,7 +204,6 @@ public class LikeJettyXml
|
|||
lowResourcesMonitor.setPeriod(1000);
|
||||
lowResourcesMonitor.setLowResourcesIdleTimeout(200);
|
||||
lowResourcesMonitor.setMonitorThreads(true);
|
||||
lowResourcesMonitor.setMaxConnections(0);
|
||||
lowResourcesMonitor.setMaxMemory(0);
|
||||
lowResourcesMonitor.setMaxLowResourcesTime(5000);
|
||||
server.addBean(lowResourcesMonitor);
|
||||
|
|
|
@ -49,8 +49,7 @@ public class OneWebApp
|
|||
// PlusConfiguration) to choosing where the webapp will unpack itself.
|
||||
WebAppContext webapp = new WebAppContext();
|
||||
webapp.setContextPath("/");
|
||||
File warFile = new File(
|
||||
"../../tests/test-jmx/jmx-webapp/target/jmx-webapp");
|
||||
File warFile = JettyDistribution.resolve("demo-base/webapps/async-rest.war").toFile();
|
||||
webapp.setWar(warFile.getAbsolutePath());
|
||||
|
||||
// A WebAppContext is a ContextHandler as well so it needs to be set to
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.embedded;
|
|||
import java.io.File;
|
||||
|
||||
import org.eclipse.jetty.plus.jndi.EnvEntry;
|
||||
import org.eclipse.jetty.plus.jndi.NamingDump;
|
||||
import org.eclipse.jetty.plus.jndi.Resource;
|
||||
import org.eclipse.jetty.plus.jndi.Transaction;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -47,16 +48,14 @@ public class ServerWithAnnotations
|
|||
classlist.addBefore(
|
||||
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
|
||||
"org.eclipse.jetty.annotations.AnnotationConfiguration");
|
||||
|
||||
// Create a WebApp
|
||||
WebAppContext webapp = new WebAppContext();
|
||||
webapp.setContextPath("/");
|
||||
File warFile = new File(
|
||||
"jetty-distribution/target/distribution/demo-base/webapps/test.war");
|
||||
File warFile = JettyDistribution.resolve("demo-base/webapps/test-spec.war").toFile();
|
||||
webapp.setWar(warFile.getAbsolutePath());
|
||||
webapp.setAttribute(
|
||||
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
|
||||
".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$");
|
||||
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
|
||||
".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$");
|
||||
server.setHandler(webapp);
|
||||
|
||||
// Register new transaction manager in JNDI
|
||||
|
@ -64,10 +63,14 @@ public class ServerWithAnnotations
|
|||
new Transaction(new com.acme.MockUserTransaction());
|
||||
|
||||
// Define an env entry with webapp scope.
|
||||
new EnvEntry(webapp, "maxAmount", new Double(100), true);
|
||||
// THIS ENTRY IS OVERRIDEN BY THE ENTRY IN jetty-env.xml
|
||||
new EnvEntry(webapp, "maxAmount", 100d, true);
|
||||
|
||||
// Register a mock DataSource scoped to the webapp
|
||||
new Resource(webapp, "jdbc/mydatasource", new com.acme.MockDataSource());
|
||||
new Resource(server, "jdbc/mydatasource", new com.acme.MockDataSource());
|
||||
|
||||
// Add JNDI context to server for dump
|
||||
server.addBean(new NamingDump());
|
||||
|
||||
// Configure a LoginService
|
||||
HashLoginService loginService = new HashLoginService();
|
||||
|
@ -75,6 +78,7 @@ public class ServerWithAnnotations
|
|||
loginService.setConfig("examples/embedded/src/test/resources/realm.properties");
|
||||
server.addBean(loginService);
|
||||
|
||||
|
||||
server.start();
|
||||
server.dumpStdErr();
|
||||
server.join();
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[depend]
|
||||
alpn-impl/alpn-9
|
|
@ -38,6 +38,8 @@ import org.eclipse.jetty.util.Loader;
|
|||
import org.eclipse.jetty.util.ManifestUtils;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.MultiReleaseJarFile;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -151,7 +153,7 @@ public class AnnotationParser
|
|||
if (name.endsWith(".class"))
|
||||
name = name.substring(0, name.length()-".class".length());
|
||||
|
||||
return name.replace('/', '.');
|
||||
return StringUtil.replace(name,'/', '.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -599,13 +601,12 @@ public class AnnotationParser
|
|||
if (className == null)
|
||||
return;
|
||||
|
||||
String tmp = className;
|
||||
className = className.replace('.', '/')+".class";
|
||||
URL resource = Loader.getResource(className);
|
||||
String classRef = TypeUtil.toClassReference(className);
|
||||
URL resource = Loader.getResource(classRef);
|
||||
if (resource!= null)
|
||||
{
|
||||
Resource r = Resource.newResource(resource);
|
||||
addParsedClass(tmp, r);
|
||||
addParsedClass(className, r);
|
||||
try (InputStream is = r.getInputStream())
|
||||
{
|
||||
scanClass(handlers, null, is);
|
||||
|
@ -626,7 +627,7 @@ public class AnnotationParser
|
|||
Class<?> cz = clazz;
|
||||
while (cz != Object.class)
|
||||
{
|
||||
String nameAsResource = cz.getName().replace('.', '/')+".class";
|
||||
String nameAsResource = TypeUtil.toClassReference(cz);
|
||||
URL resource = Loader.getResource(nameAsResource);
|
||||
if (resource!= null)
|
||||
{
|
||||
|
@ -671,17 +672,16 @@ public class AnnotationParser
|
|||
{
|
||||
MultiException me = new MultiException();
|
||||
|
||||
for (String s:classNames)
|
||||
for (String className : classNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = s;
|
||||
s = s.replace('.', '/')+".class";
|
||||
URL resource = Loader.getResource(s);
|
||||
String classRef = TypeUtil.toClassReference(className);
|
||||
URL resource = Loader.getResource(classRef);
|
||||
if (resource!= null)
|
||||
{
|
||||
Resource r = Resource.newResource(resource);
|
||||
addParsedClass(name, r);
|
||||
addParsedClass(className, r);
|
||||
try (InputStream is = r.getInputStream())
|
||||
{
|
||||
scanClass(handlers, null, is);
|
||||
|
@ -690,7 +690,7 @@ public class AnnotationParser
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
me.add(new RuntimeException("Error scanning class "+s, e));
|
||||
me.add(new RuntimeException("Error scanning class "+className, e));
|
||||
}
|
||||
}
|
||||
me.ifExceptionThrow();
|
||||
|
@ -727,8 +727,9 @@ public class AnnotationParser
|
|||
{
|
||||
Path classpath = rootFile.toPath().relativize(file.toPath());
|
||||
String str = classpath.toString();
|
||||
str = str.substring(0, str.lastIndexOf(".class")).replace('/', '.').replace('\\', '.');
|
||||
|
||||
str = str.substring(0, str.lastIndexOf(".class"));
|
||||
str = StringUtil.replace(str, File.separatorChar, '.');
|
||||
|
||||
try
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -910,7 +911,7 @@ public class AnnotationParser
|
|||
//check file is a valid class file name
|
||||
if (isValidClassFileName(name) && isValidClassFilePath(name))
|
||||
{
|
||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||
String shortName = StringUtil.replace(name, '/', '.').substring(0, name.length() - 6);
|
||||
addParsedClass(shortName, Resource.newResource("jar:"+jar.getURI()+"!/"+entry.getNameInJar()));
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scanning class from jar {}!/{}", jar, entry);
|
||||
|
|
|
@ -19,11 +19,12 @@
|
|||
package org.eclipse.jetty.annotations;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -42,6 +43,7 @@ import org.eclipse.jetty.toolchain.test.IO;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -298,25 +300,17 @@ public class TestAnnotationParser
|
|||
|
||||
private void copyClass(Class<?> clazz, File basedir) throws IOException
|
||||
{
|
||||
String classname = clazz.getName().replace('.',File.separatorChar) + ".class";
|
||||
URL url = this.getClass().getResource('/'+classname);
|
||||
assertThat("URL for: " + classname,url,notNullValue());
|
||||
String classRef = TypeUtil.toClassReference(clazz);
|
||||
URL url = this.getClass().getResource('/' + classRef);
|
||||
assertThat("URL for: " + classRef, url, notNullValue());
|
||||
|
||||
String classpath = classname.substring(0,classname.lastIndexOf(File.separatorChar));
|
||||
FS.ensureDirExists(new File(basedir,classpath));
|
||||
Path outputFile = basedir.toPath().resolve(classRef);
|
||||
FS.ensureDirExists(outputFile.getParent());
|
||||
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try
|
||||
try (InputStream in = url.openStream();
|
||||
OutputStream out = Files.newOutputStream(outputFile))
|
||||
{
|
||||
in = url.openStream();
|
||||
out = new FileOutputStream(new File(basedir,classname));
|
||||
IO.copy(in,out);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.close(out);
|
||||
IO.close(in);
|
||||
IO.copy(in, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.regex.Pattern;
|
|||
|
||||
import org.apache.tools.ant.AntClassLoader;
|
||||
import org.eclipse.jetty.util.PatternMatcher;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppClassLoader;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
@ -88,7 +89,7 @@ public class AntWebInfConfiguration extends WebInfConfiguration
|
|||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
containerUris[i] = new URI(u.toString().replaceAll(" ", "%20"));
|
||||
containerUris[i] = new URI(URIUtil.encodeSpaces(u.toString()));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -22,12 +22,10 @@ import java.nio.ByteBuffer;
|
|||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.jetty.client.api.ContentProvider;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -67,7 +65,6 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
private final AtomicReference<SenderState> senderState = new AtomicReference<>(SenderState.IDLE);
|
||||
private final Callback commitCallback = new CommitCallback();
|
||||
private final IteratingCallback contentCallback = new ContentCallback();
|
||||
private final Callback trailersCallback = new TrailersCallback();
|
||||
private final Callback lastCallback = new LastCallback();
|
||||
private final HttpChannel channel;
|
||||
private HttpContent content;
|
||||
|
@ -444,15 +441,6 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
*/
|
||||
protected abstract void sendContent(HttpExchange exchange, HttpContent content, Callback callback);
|
||||
|
||||
/**
|
||||
* Implementations should send the HTTP trailers and notify the given {@code callback} of the
|
||||
* result of this operation.
|
||||
*
|
||||
* @param exchange the exchange to send
|
||||
* @param callback the callback to notify
|
||||
*/
|
||||
protected abstract void sendTrailers(HttpExchange exchange, Callback callback);
|
||||
|
||||
protected void reset()
|
||||
{
|
||||
HttpContent content = this.content;
|
||||
|
@ -745,24 +733,14 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
if (content == null)
|
||||
return;
|
||||
|
||||
HttpRequest request = exchange.getRequest();
|
||||
Supplier<HttpFields> trailers = request.getTrailers();
|
||||
boolean hasContent = content.hasContent();
|
||||
if (!hasContent)
|
||||
if (!content.hasContent())
|
||||
{
|
||||
if (trailers == null)
|
||||
{
|
||||
// No trailers or content to send, we are done.
|
||||
someToSuccess(exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendTrailers(exchange, lastCallback);
|
||||
}
|
||||
// No content to send, we are done.
|
||||
someToSuccess(exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Was any content sent while committing ?
|
||||
// Was any content sent while committing?
|
||||
ByteBuffer contentBuffer = content.getContent();
|
||||
if (contentBuffer != null)
|
||||
{
|
||||
|
@ -859,9 +837,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
|
||||
if (lastContent)
|
||||
{
|
||||
HttpRequest request = exchange.getRequest();
|
||||
Supplier<HttpFields> trailers = request.getTrailers();
|
||||
sendContent(exchange, content, trailers == null ? lastCallback : trailersCallback);
|
||||
sendContent(exchange, content, lastCallback);
|
||||
return Action.IDLE;
|
||||
}
|
||||
|
||||
|
@ -925,28 +901,6 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
}
|
||||
}
|
||||
|
||||
private class TrailersCallback implements Callback
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
HttpExchange exchange = getHttpExchange();
|
||||
if (exchange == null)
|
||||
return;
|
||||
sendTrailers(exchange, lastCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
HttpContent content = HttpSender.this.content;
|
||||
if (content == null)
|
||||
return;
|
||||
content.failed(x);
|
||||
anyToFailure(x);
|
||||
}
|
||||
}
|
||||
|
||||
private class LastCallback implements Callback
|
||||
{
|
||||
@Override
|
||||
|
|
|
@ -59,7 +59,7 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
{
|
||||
try
|
||||
{
|
||||
new HeadersCallback(exchange, content, callback, getHttpChannel().getHttpConnection()).iterate();
|
||||
new HeadersCallback(exchange, content, callback).iterate();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
|
@ -83,8 +83,8 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
HttpGenerator.Result result = generator.generateRequest(null, null, chunk, contentBuffer, lastContent);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated content ({} bytes) - {}/{}",
|
||||
contentBuffer == null ? -1 : contentBuffer.remaining(),
|
||||
result, generator);
|
||||
contentBuffer == null ? -1 : contentBuffer.remaining(),
|
||||
result, generator);
|
||||
switch (result)
|
||||
{
|
||||
case NEED_CHUNK:
|
||||
|
@ -94,8 +94,8 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
}
|
||||
case NEED_CHUNK_TRAILER:
|
||||
{
|
||||
callback.succeeded();
|
||||
return;
|
||||
chunk = bufferPool.acquire(httpClient.getRequestBufferSize(), false);
|
||||
break;
|
||||
}
|
||||
case FLUSH:
|
||||
{
|
||||
|
@ -138,21 +138,6 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendTrailers(HttpExchange exchange, Callback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
new TrailersCallback(callback).iterate();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(x);
|
||||
callback.failed(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reset()
|
||||
{
|
||||
|
@ -191,19 +176,17 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
private final HttpExchange exchange;
|
||||
private final Callback callback;
|
||||
private final MetaData.Request metaData;
|
||||
private final HttpConnectionOverHTTP httpConnectionOverHTTP;
|
||||
private ByteBuffer headerBuffer;
|
||||
private ByteBuffer chunkBuffer;
|
||||
private ByteBuffer contentBuffer;
|
||||
private boolean lastContent;
|
||||
private boolean generated;
|
||||
|
||||
public HeadersCallback(HttpExchange exchange, HttpContent content, Callback callback, HttpConnectionOverHTTP httpConnectionOverHTTP)
|
||||
public HeadersCallback(HttpExchange exchange, HttpContent content, Callback callback)
|
||||
{
|
||||
super(false);
|
||||
this.exchange = exchange;
|
||||
this.callback = callback;
|
||||
this.httpConnectionOverHTTP = httpConnectionOverHTTP;
|
||||
|
||||
HttpRequest request = exchange.getRequest();
|
||||
ContentProvider requestContent = request.getContent();
|
||||
|
@ -231,10 +214,10 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
HttpGenerator.Result result = generator.generateRequest(metaData, headerBuffer, chunkBuffer, contentBuffer, lastContent);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated headers ({} bytes), chunk ({} bytes), content ({} bytes) - {}/{}",
|
||||
headerBuffer == null ? -1 : headerBuffer.remaining(),
|
||||
chunkBuffer == null ? -1 : chunkBuffer.remaining(),
|
||||
contentBuffer == null ? -1 : contentBuffer.remaining(),
|
||||
result, generator);
|
||||
headerBuffer == null ? -1 : headerBuffer.remaining(),
|
||||
chunkBuffer == null ? -1 : chunkBuffer.remaining(),
|
||||
contentBuffer == null ? -1 : contentBuffer.remaining(),
|
||||
result, generator);
|
||||
switch (result)
|
||||
{
|
||||
case NEED_HEADER:
|
||||
|
@ -249,7 +232,8 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
}
|
||||
case NEED_CHUNK_TRAILER:
|
||||
{
|
||||
return Action.SUCCEEDED;
|
||||
chunkBuffer = httpClient.getByteBufferPool().acquire(httpClient.getRequestBufferSize(), false);
|
||||
break;
|
||||
}
|
||||
case FLUSH:
|
||||
{
|
||||
|
@ -260,11 +244,8 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
chunkBuffer = BufferUtil.EMPTY_BUFFER;
|
||||
if (contentBuffer == null)
|
||||
contentBuffer = BufferUtil.EMPTY_BUFFER;
|
||||
|
||||
httpConnectionOverHTTP.addBytesOut( BufferUtil.length(headerBuffer)
|
||||
+ BufferUtil.length(chunkBuffer)
|
||||
+ BufferUtil.length(contentBuffer));
|
||||
|
||||
long bytes = headerBuffer.remaining() + chunkBuffer.remaining() + contentBuffer.remaining();
|
||||
getHttpChannel().getHttpConnection().addBytesOut(bytes);
|
||||
endPoint.write(this, headerBuffer, chunkBuffer, contentBuffer);
|
||||
generated = true;
|
||||
return Action.SCHEDULED;
|
||||
|
@ -331,83 +312,6 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
}
|
||||
}
|
||||
|
||||
private class TrailersCallback extends IteratingCallback
|
||||
{
|
||||
private final Callback callback;
|
||||
private ByteBuffer chunkBuffer;
|
||||
|
||||
public TrailersCallback(Callback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Action process() throws Throwable
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
HttpGenerator.Result result = generator.generateRequest(null, null, chunkBuffer, null, true);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated trailers {}/{}", result, generator);
|
||||
switch (result)
|
||||
{
|
||||
case NEED_CHUNK_TRAILER:
|
||||
{
|
||||
chunkBuffer = httpClient.getByteBufferPool().acquire(httpClient.getRequestBufferSize(), false);
|
||||
break;
|
||||
}
|
||||
case FLUSH:
|
||||
{
|
||||
EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
|
||||
endPoint.write(this, chunkBuffer);
|
||||
return Action.SCHEDULED;
|
||||
}
|
||||
case SHUTDOWN_OUT:
|
||||
{
|
||||
shutdownOutput();
|
||||
return Action.SUCCEEDED;
|
||||
}
|
||||
case DONE:
|
||||
{
|
||||
return Action.SUCCEEDED;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException(result.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
release();
|
||||
super.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
release();
|
||||
callback.failed(x);
|
||||
super.failed(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCompleteSuccess()
|
||||
{
|
||||
super.onCompleteSuccess();
|
||||
callback.succeeded();
|
||||
}
|
||||
|
||||
private void release()
|
||||
{
|
||||
httpClient.getByteBufferPool().release(chunkBuffer);
|
||||
chunkBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ByteBufferRecyclerCallback extends Callback.Nested
|
||||
{
|
||||
private final ByteBufferPool pool;
|
||||
|
@ -435,7 +339,9 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
public void failed(Throwable x)
|
||||
{
|
||||
for (ByteBuffer buffer : buffers)
|
||||
{
|
||||
pool.release(buffer);
|
||||
}
|
||||
super.failed(x);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
public class HttpSenderOverFCGI extends HttpSender
|
||||
{
|
||||
|
@ -88,7 +89,7 @@ public class HttpSenderOverFCGI extends HttpSender
|
|||
for (HttpField field : headers)
|
||||
{
|
||||
String name = field.getName();
|
||||
String fcgiName = "HTTP_" + name.replaceAll("-", "_").toUpperCase(Locale.ENGLISH);
|
||||
String fcgiName = "HTTP_" + StringUtil.replace(name, '-', '_').toUpperCase(Locale.ENGLISH);
|
||||
fcgiHeaders.add(fcgiName, field.getValue());
|
||||
}
|
||||
|
||||
|
@ -125,10 +126,4 @@ public class HttpSenderOverFCGI extends HttpSender
|
|||
getHttpChannel().flush(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendTrailers(HttpExchange exchange, Callback callback)
|
||||
{
|
||||
callback.succeeded();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.net.URL;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
@ -35,6 +34,8 @@ import javax.servlet.ServletResponse;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Inspired by nginx's try_files functionality.
|
||||
* <p>
|
||||
|
@ -132,7 +133,7 @@ public class TryFilesFilter implements Filter
|
|||
path += info;
|
||||
if (!path.startsWith("/"))
|
||||
path = "/" + path;
|
||||
return value.replaceAll("\\$path", path);
|
||||
return StringUtil.replace(value, "$path", path);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,6 +33,13 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- avoid depending on a range dependency from a transitive dependency -->
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-core</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value</artifactId>
|
||||
|
|
|
@ -196,7 +196,7 @@ public class MimeTypes
|
|||
int charset=type.toString().indexOf(";charset=");
|
||||
if (charset>0)
|
||||
{
|
||||
String alt=type.toString().replace(";charset=","; charset=");
|
||||
String alt = StringUtil.replace(type.toString(), ";charset=", "; charset=");
|
||||
CACHE.put(alt,type);
|
||||
TYPES.put(alt,type.asBuffer());
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class QuotedCSVTest
|
||||
{
|
||||
@Test
|
||||
|
@ -111,13 +111,13 @@ public class QuotedCSVTest
|
|||
{
|
||||
if (buffer.toString().contains("DELETE"))
|
||||
{
|
||||
String s = buffer.toString().replace("DELETE","");
|
||||
String s = StringUtil.strip(buffer.toString(), "DELETE");
|
||||
buffer.setLength(0);
|
||||
buffer.append(s);
|
||||
}
|
||||
if (buffer.toString().contains("APPEND"))
|
||||
{
|
||||
String s = buffer.toString().replace("APPEND","Append")+"!";
|
||||
String s = StringUtil.replace(buffer.toString(), "APPEND", "Append") + "!";
|
||||
buffer.setLength(0);
|
||||
buffer.append(s);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -167,7 +168,7 @@ public class ProxyProtocolTest
|
|||
|
||||
// String is: "MAGIC VER|CMD FAM|PROT LEN SRC_ADDR DST_ADDR SRC_PORT DST_PORT PP2_TYPE_SSL LEN CLIENT VERIFY PP2_SUBTYPE_SSL_VERSION LEN 1.2"
|
||||
String request1 = "0D0A0D0A000D0A515549540A 21 11 001A 0A000004 0A000005 8420 22B8 20 000B 01 00000000 21 0003 312E32";
|
||||
request1 = request1.replace(" ", "");
|
||||
request1 = StringUtil.strip(request1, " ");
|
||||
SocketChannel channel = SocketChannel.open();
|
||||
channel.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
|
||||
channel.write(ByteBuffer.wrap(TypeUtil.fromHexString(request1)));
|
||||
|
|
|
@ -18,16 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.http2.client;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -35,7 +25,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -58,10 +47,14 @@ import org.eclipse.jetty.server.Response;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TrailersTest extends AbstractTest
|
||||
{
|
||||
|
@ -289,7 +282,7 @@ public class TrailersTest extends AbstractTest
|
|||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
assertTrue( frames.size()==3, frames.toString());
|
||||
assertEquals(3, frames.size(), frames.toString());
|
||||
|
||||
HeadersFrame headers = (HeadersFrame)frames.get(0);
|
||||
DataFrame data = (DataFrame)frames.get(1);
|
||||
|
@ -298,7 +291,7 @@ public class TrailersTest extends AbstractTest
|
|||
assertFalse(headers.isEndStream());
|
||||
assertFalse(data.isEndStream());
|
||||
assertTrue(trailers.isEndStream());
|
||||
assertTrue(trailers.getMetaData().getFields().get(trailerName).equals(trailerValue));
|
||||
assertEquals(trailers.getMetaData().getFields().get(trailerName), trailerValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -358,6 +351,5 @@ public class TrailersTest extends AbstractTest
|
|||
|
||||
assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(clientLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,42 +56,57 @@ public class HttpSenderOverHTTP2 extends HttpSender
|
|||
String path = relativize(request.getPath());
|
||||
HttpURI uri = HttpURI.createHttpURI(request.getScheme(), request.getHost(), request.getPort(), path, null, request.getQuery(), null);
|
||||
MetaData.Request metaData = new MetaData.Request(request.getMethod(), uri, HttpVersion.HTTP_2, request.getHeaders());
|
||||
Supplier<HttpFields> trailers = request.getTrailers();
|
||||
metaData.setTrailerSupplier(trailers);
|
||||
HeadersFrame headersFrame = new HeadersFrame(metaData, null, trailers == null && !content.hasContent());
|
||||
HttpChannelOverHTTP2 channel = getHttpChannel();
|
||||
Promise<Stream> promise = new Promise<Stream>()
|
||||
{
|
||||
@Override
|
||||
public void succeeded(Stream stream)
|
||||
{
|
||||
channel.setStream(stream);
|
||||
((IStream)stream).setAttachment(channel);
|
||||
long idleTimeout = request.getIdleTimeout();
|
||||
if (idleTimeout >= 0)
|
||||
stream.setIdleTimeout(idleTimeout);
|
||||
Supplier<HttpFields> trailerSupplier = request.getTrailers();
|
||||
metaData.setTrailerSupplier(trailerSupplier);
|
||||
|
||||
if (content.hasContent() && !expects100Continue(request))
|
||||
HeadersFrame headersFrame;
|
||||
Promise<Stream> promise;
|
||||
if (content.hasContent())
|
||||
{
|
||||
headersFrame = new HeadersFrame(metaData, null, false);
|
||||
promise = new HeadersPromise(request, callback)
|
||||
{
|
||||
@Override
|
||||
public void succeeded(Stream stream)
|
||||
{
|
||||
boolean advanced = content.advance();
|
||||
boolean lastContent = trailers == null && content.isLast();
|
||||
if (advanced || lastContent)
|
||||
super.succeeded(stream);
|
||||
if (expects100Continue(request))
|
||||
{
|
||||
DataFrame dataFrame = new DataFrame(stream.getId(), content.getByteBuffer(), lastContent);
|
||||
stream.data(dataFrame, callback);
|
||||
return;
|
||||
// Don't send the content yet.
|
||||
callback.succeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean advanced = content.advance();
|
||||
boolean lastContent = content.isLast();
|
||||
if (advanced || lastContent)
|
||||
sendContent(stream, content, trailerSupplier, callback);
|
||||
else
|
||||
callback.succeeded();
|
||||
}
|
||||
}
|
||||
callback.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable failure)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpFields trailers = trailerSupplier == null ? null : trailerSupplier.get();
|
||||
boolean endStream = trailers == null || trailers.size() == 0;
|
||||
headersFrame = new HeadersFrame(metaData, null, endStream);
|
||||
promise = new HeadersPromise(request, callback)
|
||||
{
|
||||
callback.failed(failure);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void succeeded(Stream stream)
|
||||
{
|
||||
super.succeeded(stream);
|
||||
if (endStream)
|
||||
callback.succeeded();
|
||||
else
|
||||
sendTrailers(stream, trailers, callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
// TODO optimize the send of HEADERS and DATA frames.
|
||||
HttpChannelOverHTTP2 channel = getHttpChannel();
|
||||
channel.getSession().newStream(headersFrame, promise, channel.getStreamListener());
|
||||
}
|
||||
|
||||
|
@ -118,24 +133,67 @@ public class HttpSenderOverHTTP2 extends HttpSender
|
|||
{
|
||||
if (content.isConsumed())
|
||||
{
|
||||
// The superclass calls sendContent() one more time after the last content.
|
||||
// This is necessary for HTTP/1.1 to generate the terminal chunk (with trailers),
|
||||
// but it's not necessary for HTTP/2 so we just succeed the callback.
|
||||
callback.succeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream stream = getHttpChannel().getStream();
|
||||
Supplier<HttpFields> trailers = exchange.getRequest().getTrailers();
|
||||
DataFrame frame = new DataFrame(stream.getId(), content.getByteBuffer(), trailers == null && content.isLast());
|
||||
stream.data(frame, callback);
|
||||
Supplier<HttpFields> trailerSupplier = exchange.getRequest().getTrailers();
|
||||
sendContent(stream, content, trailerSupplier, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendTrailers(HttpExchange exchange, Callback callback)
|
||||
private void sendContent(Stream stream, HttpContent content, Supplier<HttpFields> trailerSupplier, Callback callback)
|
||||
{
|
||||
Supplier<HttpFields> trailers = exchange.getRequest().getTrailers();
|
||||
MetaData metaData = new MetaData(HttpVersion.HTTP_2, trailers.get());
|
||||
Stream stream = getHttpChannel().getStream();
|
||||
boolean lastContent = content.isLast();
|
||||
HttpFields trailers = null;
|
||||
boolean endStream = false;
|
||||
if (lastContent)
|
||||
{
|
||||
trailers = trailerSupplier == null ? null : trailerSupplier.get();
|
||||
endStream = trailers == null || trailers.size() == 0;
|
||||
}
|
||||
DataFrame dataFrame = new DataFrame(stream.getId(), content.getByteBuffer(), endStream);
|
||||
HttpFields fTrailers = trailers;
|
||||
stream.data(dataFrame, endStream || !lastContent ? callback : Callback.from(() -> sendTrailers(stream, fTrailers, callback), callback::failed));
|
||||
}
|
||||
|
||||
private void sendTrailers(Stream stream, HttpFields trailers, Callback callback)
|
||||
{
|
||||
MetaData metaData = new MetaData(HttpVersion.HTTP_2, trailers);
|
||||
HeadersFrame trailersFrame = new HeadersFrame(stream.getId(), metaData, null, true);
|
||||
stream.headers(trailersFrame, callback);
|
||||
}
|
||||
|
||||
private class HeadersPromise implements Promise<Stream>
|
||||
{
|
||||
private final HttpRequest request;
|
||||
private final Callback callback;
|
||||
|
||||
private HeadersPromise(HttpRequest request, Callback callback)
|
||||
{
|
||||
this.request = request;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded(Stream stream)
|
||||
{
|
||||
HttpChannelOverHTTP2 channel = getHttpChannel();
|
||||
channel.setStream(stream);
|
||||
((IStream)stream).setAttachment(channel);
|
||||
long idleTimeout = request.getIdleTimeout();
|
||||
if (idleTimeout >= 0)
|
||||
stream.setIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
callback.failed(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.http2.client.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.client.HttpRequest;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.util.DeferredContentProvider;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.api.Stream;
|
||||
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
|
||||
import org.eclipse.jetty.http2.frames.DataFrame;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class RequestTrailersTest extends AbstractTest
|
||||
{
|
||||
@Test
|
||||
public void testEmptyTrailersWithoutContent() throws Exception
|
||||
{
|
||||
testEmptyTrailers(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyTrailersWithEagerContent() throws Exception
|
||||
{
|
||||
testEmptyTrailers("eager_content");
|
||||
}
|
||||
|
||||
private void testEmptyTrailers(String content) throws Exception
|
||||
{
|
||||
CountDownLatch trailersLatch = new CountDownLatch(1);
|
||||
start(new ServerSessionListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
|
||||
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
|
||||
stream.headers(responseFrame, Callback.NOOP);
|
||||
return new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onHeaders(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
trailersLatch.countDown();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
|
||||
HttpFields trailers = new HttpFields();
|
||||
request.trailers(() -> trailers);
|
||||
if (content != null)
|
||||
request.content(new StringContentProvider(content));
|
||||
|
||||
ContentResponse response = request.send();
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
|
||||
// The client must not send the trailers.
|
||||
assertFalse(trailersLatch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyTrailersWithDeferredContent() throws Exception
|
||||
{
|
||||
start(new ServerSessionListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
return new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame dataFrame, Callback callback)
|
||||
{
|
||||
callback.succeeded();
|
||||
// We should not receive an empty HEADERS frame for the
|
||||
// trailers, but instead a DATA frame with endStream=true.
|
||||
if (dataFrame.isEndStream())
|
||||
{
|
||||
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
|
||||
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
|
||||
stream.headers(responseFrame, Callback.NOOP);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
|
||||
HttpFields trailers = new HttpFields();
|
||||
request.trailers(() -> trailers);
|
||||
DeferredContentProvider content = new DeferredContentProvider();
|
||||
request.content(content);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
request.send(result ->
|
||||
{
|
||||
assertTrue(result.isSucceeded());
|
||||
assertEquals(HttpStatus.OK_200, result.getResponse().getStatus());
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
// Send deferred content after a while.
|
||||
Thread.sleep(1000);
|
||||
content.offer(ByteBuffer.wrap("deferred_content".getBytes(StandardCharsets.UTF_8)));
|
||||
content.close();
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyTrailersWithEmptyDeferredContent() throws Exception
|
||||
{
|
||||
start(new ServerSessionListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
return new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame dataFrame, Callback callback)
|
||||
{
|
||||
callback.succeeded();
|
||||
// We should not receive an empty HEADERS frame for the
|
||||
// trailers, but instead a DATA frame with endStream=true.
|
||||
if (dataFrame.isEndStream())
|
||||
{
|
||||
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
|
||||
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
|
||||
stream.headers(responseFrame, Callback.NOOP);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
|
||||
HttpFields trailers = new HttpFields();
|
||||
request.trailers(() -> trailers);
|
||||
DeferredContentProvider content = new DeferredContentProvider();
|
||||
request.content(content);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
request.send(result ->
|
||||
{
|
||||
assertTrue(result.isSucceeded());
|
||||
assertEquals(HttpStatus.OK_200, result.getResponse().getStatus());
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
// Send deferred content after a while.
|
||||
Thread.sleep(1000);
|
||||
content.close();
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
|
@ -307,9 +307,36 @@ abstract public class WriteFlusher
|
|||
|
||||
private void fail(Callback callback, Throwable... suppressed)
|
||||
{
|
||||
FailedState failed = (FailedState)_state.get();
|
||||
Throwable cause;
|
||||
loop:
|
||||
while (true)
|
||||
{
|
||||
State state = _state.get();
|
||||
|
||||
switch (state.getType())
|
||||
{
|
||||
case FAILED:
|
||||
{
|
||||
FailedState failed = (FailedState)state;
|
||||
cause = failed.getCause();
|
||||
break loop;
|
||||
}
|
||||
|
||||
case IDLE:
|
||||
for (Throwable t : suppressed)
|
||||
LOG.warn(t);
|
||||
return;
|
||||
|
||||
default:
|
||||
Throwable t = new IllegalStateException();
|
||||
if (!_state.compareAndSet(state, new FailedState(t)))
|
||||
continue;
|
||||
|
||||
cause = t;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
|
||||
Throwable cause = failed.getCause();
|
||||
for (Throwable t : suppressed)
|
||||
{
|
||||
if (t != cause)
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
|
@ -41,6 +40,7 @@ import org.eclipse.jetty.io.EndPoint;
|
|||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Invocable;
|
||||
|
@ -584,7 +584,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("unwrap net_filled={} {} encryptedBuffer={} unwrapBuffer={} appBuffer={}",
|
||||
net_filled,
|
||||
unwrapResult.toString().replace('\n', ' '),
|
||||
StringUtil.replace(unwrapResult.toString(), '\n', ' '),
|
||||
BufferUtil.toSummaryString(_encryptedInput),
|
||||
BufferUtil.toDetailString(app_in),
|
||||
BufferUtil.toDetailString(buffer));
|
||||
|
@ -895,7 +895,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("wrap {} {} ioDone={}/{}",
|
||||
wrapResult.toString().replace('\n', ' '),
|
||||
StringUtil.replace(wrapResult.toString(), '\n', ' '),
|
||||
BufferUtil.toSummaryString(_encryptedOutput),
|
||||
_sslEngine.isInboundDone(),
|
||||
_sslEngine.isOutboundDone());
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -43,10 +35,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class WriteFlusherTest
|
||||
{
|
||||
@Test
|
||||
|
@ -159,6 +159,43 @@ public class WriteFlusherTest
|
|||
assertTrue(flusher.isIdle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallbackThrows() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint(new byte[0], 100);
|
||||
|
||||
AtomicBoolean incompleteFlush = new AtomicBoolean(false);
|
||||
WriteFlusher flusher = new WriteFlusher(endPoint)
|
||||
{
|
||||
@Override
|
||||
protected void onIncompleteFlush()
|
||||
{
|
||||
incompleteFlush.set(true);
|
||||
}
|
||||
};
|
||||
|
||||
FutureCallback callback = new FutureCallback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
super.succeeded();
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
};
|
||||
|
||||
try (StacklessLogging stacklessLogging = new StacklessLogging(WriteFlusher.class))
|
||||
{
|
||||
flusher.write(callback, BufferUtil.toBuffer("How now brown cow!"));
|
||||
callback.get(100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
assertEquals("How now brown cow!", endPoint.takeOutputString());
|
||||
assertTrue(callback.isDone());
|
||||
assertFalse(incompleteFlush.get());
|
||||
assertTrue(flusher.isIdle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseWhileBlocking() throws Exception
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
|
@ -39,6 +38,7 @@ import javax.management.ObjectName;
|
|||
import javax.management.modelmbean.ModelMBean;
|
||||
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.Container;
|
||||
|
@ -394,15 +394,7 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
|
|||
*/
|
||||
public String makeName(String basis)
|
||||
{
|
||||
if (basis == null)
|
||||
return null;
|
||||
return basis
|
||||
.replace(':', '_')
|
||||
.replace('*', '_')
|
||||
.replace('?', '_')
|
||||
.replace('=', '_')
|
||||
.replace(',', '_')
|
||||
.replace(' ', '_');
|
||||
return StringUtil.sanitizeFileSystemName(basis);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,8 +22,10 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import javax.naming.Binding;
|
||||
|
@ -126,7 +128,7 @@ public class NamingContext implements Context, Dumpable
|
|||
this(env, name, parent, parser, null);
|
||||
}
|
||||
|
||||
private NamingContext(Hashtable<String,Object> env,
|
||||
protected NamingContext(Hashtable<String,Object> env,
|
||||
String name,
|
||||
NamingContext parent,
|
||||
NameParser parser,
|
||||
|
@ -143,14 +145,13 @@ public class NamingContext implements Context, Dumpable
|
|||
}
|
||||
|
||||
/**
|
||||
* @return A shallow copy of the Context with the same bindings, but a copy of the Env
|
||||
* @return A shallow copy of the Context with the same bindings, but with the passed environment
|
||||
*/
|
||||
public NamingContext shallowCopy()
|
||||
public Context shallowCopy(Hashtable<String, Object> env)
|
||||
{
|
||||
return new NamingContext(_env, _name, _parent, _parser, _bindings);
|
||||
return new NamingContext(env, _name, _parent, _parser, _bindings);
|
||||
}
|
||||
|
||||
|
||||
public boolean isDeepBindingSupported()
|
||||
{
|
||||
// look for deep binding support in _env
|
||||
|
@ -457,7 +458,7 @@ public class NamingContext implements Context, Dumpable
|
|||
{
|
||||
if(LOG.isDebugEnabled())
|
||||
LOG.debug("Null or empty name, returning shallowCopy of this context");
|
||||
return shallowCopy();
|
||||
return shallowCopy(_env);
|
||||
}
|
||||
|
||||
if (cname.size() == 1)
|
||||
|
@ -541,7 +542,7 @@ public class NamingContext implements Context, Dumpable
|
|||
|
||||
if (cname == null || name.isEmpty())
|
||||
{
|
||||
return shallowCopy();
|
||||
return shallowCopy(_env);
|
||||
}
|
||||
|
||||
if (cname.size() == 0)
|
||||
|
@ -1118,7 +1119,17 @@ public class NamingContext implements Context, Dumpable
|
|||
@Override
|
||||
public void dump(Appendable out,String indent) throws IOException
|
||||
{
|
||||
Dumpable.dumpObjects(out,indent,this, _bindings);
|
||||
Map<String, Object> bindings = new HashMap<>();
|
||||
for (Map.Entry<String,Binding> binding : _bindings.entrySet())
|
||||
bindings.put(binding.getKey(), binding.getValue().getObject());
|
||||
|
||||
Dumpable.dumpObject(out, this);
|
||||
Dumpable.dumpMapEntries(out, indent, bindings, _env.isEmpty());
|
||||
if (!_env.isEmpty())
|
||||
{
|
||||
out.append(indent).append("+> environment\n");
|
||||
Dumpable.dumpMapEntries(out, indent + " ", _env, true);
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<Listener> findListeners()
|
||||
|
|
|
@ -270,7 +270,7 @@ public class localContextRoot implements Context
|
|||
if (cname == null || cname.isEmpty())
|
||||
{
|
||||
//If no name create copy of this context with same bindings, but with copy of the environment so it can be modified
|
||||
return __root.shallowCopy();
|
||||
return __root.shallowCopy(_env);
|
||||
}
|
||||
|
||||
if (cname.size() == 0)
|
||||
|
@ -339,7 +339,7 @@ public class localContextRoot implements Context
|
|||
|
||||
if ((cname == null) || cname.isEmpty())
|
||||
{
|
||||
return __root.shallowCopy();
|
||||
return __root.shallowCopy(_env);
|
||||
}
|
||||
|
||||
if (cname.size() == 1)
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.apache.maven.project.MavenProject;
|
|||
import org.eclipse.jetty.maven.plugin.utils.MavenProjectHelper;
|
||||
import org.eclipse.jetty.util.PathWatcher;
|
||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
@ -661,7 +662,7 @@ public class JettyRunMojo extends AbstractJettyMojo
|
|||
int i = name.lastIndexOf('/');
|
||||
if (i>0)
|
||||
name = name.substring(i+1,name.length());
|
||||
name = name.replace('.', '_');
|
||||
name = StringUtil.replace(name, '.', '_');
|
||||
//name = name+(++COUNTER); //add some digits to ensure uniqueness
|
||||
File overlaysDir = new File (project.getBuild().getDirectory(), "jetty_overlays");
|
||||
File dir = new File(overlaysDir, name);
|
||||
|
|
|
@ -514,7 +514,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
int i=0;
|
||||
while (res == null && (i < _webInfClasses.size()))
|
||||
{
|
||||
String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
|
||||
String newPath = StringUtil.replace(uri, WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
|
||||
res = Resource.newResource(newPath);
|
||||
if (!res.exists())
|
||||
{
|
||||
|
@ -529,7 +529,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
{
|
||||
// Return the real jar file for all accesses to
|
||||
// /WEB-INF/lib/*.jar
|
||||
String jarName = uri.replace(WEB_INF_LIB_PREFIX, "");
|
||||
String jarName = StringUtil.strip(uri, WEB_INF_LIB_PREFIX);
|
||||
if (jarName.startsWith("/") || jarName.startsWith("\\"))
|
||||
jarName = jarName.substring(1);
|
||||
if (jarName.length()==0)
|
||||
|
@ -581,7 +581,7 @@ public class JettyWebAppContext extends WebAppContext
|
|||
|
||||
while (i < _webInfClasses.size())
|
||||
{
|
||||
String newPath = path.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
|
||||
String newPath = StringUtil.replace(path, WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
|
||||
allPaths.addAll(super.getResourcePaths(newPath));
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.jar.Manifest;
|
|||
|
||||
import org.codehaus.plexus.util.SelectorUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -146,7 +147,7 @@ public class SelectiveJarResource extends JarResource
|
|||
String entryName = entry.getName();
|
||||
|
||||
LOG.debug("Looking at "+entryName);
|
||||
String dotCheck = entryName.replace('\\', '/');
|
||||
String dotCheck = StringUtil.replace(entryName, '\\', '/');
|
||||
dotCheck = URIUtil.canonicalPath(dotCheck);
|
||||
if (dotCheck == null)
|
||||
{
|
||||
|
|
|
@ -27,16 +27,6 @@ import java.util.HashSet;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.nosql.NoSqlSessionDataStore;
|
||||
import org.eclipse.jetty.server.session.SessionContext;
|
||||
import org.eclipse.jetty.server.session.SessionData;
|
||||
import org.eclipse.jetty.server.session.UnreadableSessionDataException;
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
|
@ -46,6 +36,16 @@ import com.mongodb.DBObject;
|
|||
import com.mongodb.MongoException;
|
||||
import com.mongodb.WriteConcern;
|
||||
import com.mongodb.WriteResult;
|
||||
import org.eclipse.jetty.nosql.NoSqlSessionDataStore;
|
||||
import org.eclipse.jetty.server.session.SessionContext;
|
||||
import org.eclipse.jetty.server.session.SessionData;
|
||||
import org.eclipse.jetty.server.session.UnreadableSessionDataException;
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* MongoSessionDataStore
|
||||
|
@ -574,8 +574,8 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore
|
|||
{
|
||||
if (vhost == null)
|
||||
return "";
|
||||
|
||||
return vhost.replace('.', '_');
|
||||
|
||||
return StringUtil.replace(vhost, '.', '_');
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,10 +27,10 @@ import java.util.Date;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
||||
/**
|
||||
* MongoUtils
|
||||
|
@ -69,23 +69,17 @@ public class MongoUtils
|
|||
throw new IllegalStateException(valueToDecode.getClass().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static String decodeName(String name)
|
||||
{
|
||||
return name.replace("%2E",".").replace("%25","%");
|
||||
return URIUtil.decodeSpecific(name, ".%");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String encodeName(String name)
|
||||
{
|
||||
return name.replace("%","%25").replace(".","%2E");
|
||||
return URIUtil.encodeSpecific(name, ".%");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Object encodeName(Object value) throws IOException
|
||||
{
|
||||
if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date)
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.TreeSet;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
@ -209,7 +210,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
|
|||
continue;
|
||||
}
|
||||
//transform into a classname to pass to the resolver
|
||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||
String shortName = StringUtil.replace(name, '/', '.').substring(0, name.length() - 6);
|
||||
|
||||
addParsedClass(shortName, getResource(bundle));
|
||||
try (InputStream classInputStream = classUrl.openStream())
|
||||
|
|
|
@ -280,7 +280,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
// the location will often reflect the version.
|
||||
// maybe this is relevant when the file is a war)
|
||||
String location = bundle.getLocation();
|
||||
String toks[] = location.replace('\\', '/').split("/");
|
||||
String toks[] = StringUtil.replace(location, '\\', '/').split("/");
|
||||
contextPath = toks[toks.length - 1];
|
||||
// remove .jar, .war etc:
|
||||
int lastDot = contextPath.lastIndexOf('.');
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.regex.Pattern;
|
|||
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.osgi.boot.utils.Util;
|
||||
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.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -339,7 +340,7 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
|
|||
}
|
||||
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;
|
||||
resourceMap.put(key + ";" + fragment.getSymbolicName(), Resource.newResource(uri));
|
||||
|
|
|
@ -30,10 +30,10 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperFactory;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -61,12 +61,12 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
|
|||
|
||||
public static void addClassThatIdentifiesAJarThatMustBeRejected(Class<?> zclass)
|
||||
{
|
||||
JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(zclass.getName().replace('.', '/') + ".class");
|
||||
JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(TypeUtil.toClassReference(zclass.getName()));
|
||||
}
|
||||
|
||||
public static void addClassThatIdentifiesAJarThatMustBeRejected(String zclassName)
|
||||
{
|
||||
JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(zclassName.replace('.', '/') + ".class");
|
||||
JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(TypeUtil.toClassReference(zclassName));
|
||||
}
|
||||
|
||||
static
|
||||
|
|
|
@ -56,4 +56,10 @@ public class EnvEntry extends NamingEntry
|
|||
{
|
||||
return this.overrideWebXml;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringMetaData()
|
||||
{
|
||||
return "OverrideWebXml=" + overrideWebXml;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,4 +52,10 @@ public class Link extends NamingEntry
|
|||
{
|
||||
return _link;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringMetaData()
|
||||
{
|
||||
return _link;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.plus.jndi;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
|
||||
/**
|
||||
* A utility Dumpable to dump a JNDI naming context tree.
|
||||
*/
|
||||
public class NamingDump implements Dumpable
|
||||
{
|
||||
private final ClassLoader _loader;
|
||||
private final String _name;
|
||||
|
||||
public NamingDump()
|
||||
{
|
||||
this(null,"");
|
||||
}
|
||||
|
||||
public NamingDump(ClassLoader loader, String name)
|
||||
{
|
||||
_loader = loader;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent)
|
||||
{
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
try
|
||||
{
|
||||
if (!StringUtil.isBlank(_name))
|
||||
out.append(_name).append(" ");
|
||||
if (_loader!=null)
|
||||
Thread.currentThread().setContextClassLoader(_loader);
|
||||
Object context = new InitialContext().lookup(_name);
|
||||
if (context instanceof Dumpable)
|
||||
((Dumpable)context).dump(out, indent);
|
||||
else
|
||||
Dumpable.dumpObjects(out, indent, context);
|
||||
}
|
||||
catch(Throwable th)
|
||||
{
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_loader!=null)
|
||||
Thread.currentThread().setContextClassLoader(loader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,14 +49,7 @@ public abstract class NamingEntry
|
|||
protected String _namingEntryNameString; //the name of the NamingEntry relative to the context it is stored in
|
||||
protected String _objectNameString; //the name of the object relative to the context it is stored in
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return _jndiName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a naming entry.
|
||||
*
|
||||
|
@ -173,21 +166,21 @@ public abstract class NamingEntry
|
|||
/**
|
||||
* Save the NamingEntry for later use.
|
||||
* <p>
|
||||
* Saving is done by binding the NamingEntry
|
||||
* Saving is done by binding both the NamingEntry
|
||||
* itself, and the value it represents into
|
||||
* JNDI. In this way, we can link to the
|
||||
* value it represents later, but also
|
||||
* still retrieve the NamingEntry itself too.
|
||||
* <p>
|
||||
* The object is bound at the jndiName passed in.
|
||||
* This NamingEntry is bound at __/jndiName.
|
||||
* The object is bound at scope/jndiName and
|
||||
* the NamingEntry is bound at scope/__/jndiName.
|
||||
* <p>
|
||||
* eg
|
||||
* <pre>
|
||||
* jdbc/foo : DataSource
|
||||
* __/jdbc/foo : NamingEntry
|
||||
* </pre>
|
||||
*
|
||||
* @see NamingEntryUtil#getNameForScope(Object)
|
||||
* @param object the object to save
|
||||
* @throws NamingException if unable to save
|
||||
*/
|
||||
|
@ -212,5 +205,18 @@ public abstract class NamingEntry
|
|||
_objectNameString = objectName.toString();
|
||||
NamingUtil.bind(ic, _objectNameString, object);
|
||||
}
|
||||
|
||||
|
||||
protected String toStringMetaData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String metadata = toStringMetaData();
|
||||
if (metadata == null)
|
||||
return String.format("%s@%x{name=%s}", this.getClass().getName(), hashCode(), getJndiName());
|
||||
return String.format("%s@%x{name=%s,%s}", this.getClass().getName(), hashCode(), getJndiName(), metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import javax.naming.NameParser;
|
|||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -117,7 +118,7 @@ public class NamingEntryUtil
|
|||
* @return all NameEntries of a certain type in the given naming environment scope (server-wide names or context-specific names)
|
||||
* @throws NamingException if unable to lookup the naming entries
|
||||
*/
|
||||
public static List<Object> lookupNamingEntries (Object scope, Class<?> clazz)
|
||||
public static <T> List<? extends T> lookupNamingEntries (Object scope, Class<T> clazz)
|
||||
throws NamingException
|
||||
{
|
||||
try
|
||||
|
@ -126,7 +127,7 @@ public class NamingEntryUtil
|
|||
Context namingEntriesContext = (Context)scopeContext.lookup(NamingEntry.__contextName);
|
||||
ArrayList<Object> list = new ArrayList<Object>();
|
||||
lookupNamingEntries(list, namingEntriesContext, clazz);
|
||||
return list;
|
||||
return (List<T>)list;
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
|
@ -238,8 +239,9 @@ public class NamingEntryUtil
|
|||
if (scope==null)
|
||||
return "";
|
||||
|
||||
String str = scope.getClass().getName()+"@"+Long.toHexString(scope.hashCode());
|
||||
str=str.replace('/', '_').replace(' ', '_');
|
||||
String str = scope.getClass().getName() + "@" + Long.toHexString(scope.hashCode());
|
||||
str = StringUtil.replace(str, '/', '_');
|
||||
str = StringUtil.replace(str, ' ', '_');
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,7 @@ package org.eclipse.jetty.plus.webapp;
|
|||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.Binding;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
|
@ -36,6 +34,7 @@ import org.eclipse.jetty.jndi.NamingContext;
|
|||
import org.eclipse.jetty.jndi.NamingUtil;
|
||||
import org.eclipse.jetty.jndi.local.localContextRoot;
|
||||
import org.eclipse.jetty.plus.jndi.EnvEntry;
|
||||
import org.eclipse.jetty.plus.jndi.NamingDump;
|
||||
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -54,6 +53,7 @@ public class EnvConfiguration extends AbstractConfiguration
|
|||
|
||||
private static final String JETTY_ENV_BINDINGS = "org.eclipse.jetty.jndi.EnvConfiguration";
|
||||
private URL jettyEnvXmlUrl;
|
||||
private NamingDump _dumper;
|
||||
|
||||
public void setJettyEnvXml (URL url)
|
||||
{
|
||||
|
@ -128,6 +128,9 @@ public class EnvConfiguration extends AbstractConfiguration
|
|||
|
||||
//add java:comp/env entries for any EnvEntries that have been defined so far
|
||||
bindEnvEntries(context);
|
||||
|
||||
_dumper = new NamingDump(context.getClassLoader(),"java:comp");
|
||||
context.addBean(_dumper);
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,6 +141,9 @@ public class EnvConfiguration extends AbstractConfiguration
|
|||
@Override
|
||||
public void deconfigure (WebAppContext context) throws Exception
|
||||
{
|
||||
context.removeBean(_dumper);
|
||||
_dumper = null;
|
||||
|
||||
//get rid of any bindings for comp/env for webapp
|
||||
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(context.getClassLoader());
|
||||
|
@ -206,40 +212,23 @@ public class EnvConfiguration extends AbstractConfiguration
|
|||
public void bindEnvEntries (WebAppContext context)
|
||||
throws NamingException
|
||||
{
|
||||
LOG.debug("Binding env entries from the jvm scope");
|
||||
InitialContext ic = new InitialContext();
|
||||
Context envCtx = (Context)ic.lookup("java:comp/env");
|
||||
Object scope = null;
|
||||
List<Object> list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
|
||||
Iterator<Object> itor = list.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
EnvEntry ee = (EnvEntry)itor.next();
|
||||
ee.bindToENC(ee.getJndiName());
|
||||
Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee);
|
||||
NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later
|
||||
}
|
||||
|
||||
LOG.debug("Binding env entries from the jvm scope");
|
||||
doBindings(envCtx, null);
|
||||
|
||||
LOG.debug("Binding env entries from the server scope");
|
||||
|
||||
scope = context.getServer();
|
||||
list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
|
||||
itor = list.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
EnvEntry ee = (EnvEntry)itor.next();
|
||||
ee.bindToENC(ee.getJndiName());
|
||||
Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee);
|
||||
NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later
|
||||
}
|
||||
doBindings(envCtx, context.getServer());
|
||||
|
||||
LOG.debug("Binding env entries from the context scope");
|
||||
scope = context;
|
||||
list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
|
||||
itor = list.iterator();
|
||||
while (itor.hasNext())
|
||||
doBindings(envCtx, context);
|
||||
}
|
||||
|
||||
private void doBindings(Context envCtx, Object scope) throws NamingException
|
||||
{
|
||||
for (EnvEntry ee : NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class))
|
||||
{
|
||||
EnvEntry ee = (EnvEntry)itor.next();
|
||||
ee.bindToENC(ee.getJndiName());
|
||||
Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee);
|
||||
NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later
|
||||
|
|
|
@ -22,5 +22,9 @@
|
|||
</Call>
|
||||
</Call>
|
||||
|
||||
<Call name="addBean">
|
||||
<Arg><New class="org.eclipse.jetty.plus.jndi.NamingDump"/></Arg>
|
||||
</Call>
|
||||
|
||||
</Configure>
|
||||
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
|
||||
package org.eclipse.jetty.plus.jndi;
|
||||
|
||||
import java.util.List;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NameNotFoundException;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
|
@ -27,16 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NameNotFoundException;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TestNamingEntryUtil
|
||||
{
|
||||
public class MyNamingEntry extends NamingEntry
|
||||
|
@ -122,7 +121,7 @@ public class TestNamingEntryUtil
|
|||
public void testLookupNamingEntries() throws Exception
|
||||
{
|
||||
ScopeA scope = new ScopeA();
|
||||
List<?> list = NamingEntryUtil.lookupNamingEntries(scope, MyNamingEntry.class);
|
||||
List<? extends MyNamingEntry> list = NamingEntryUtil.lookupNamingEntries(scope, MyNamingEntry.class);
|
||||
assertThat(list, is(empty()));
|
||||
|
||||
MyNamingEntry mne1 = new MyNamingEntry(scope, "a/b", 1);
|
||||
|
|
|
@ -29,7 +29,6 @@ import java.util.Locale;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
@ -51,6 +50,7 @@ import org.eclipse.jetty.http.HttpHeaderValue;
|
|||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.util.HttpCookieStore;
|
||||
import org.eclipse.jetty.util.ProcessorUtils;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
@ -207,7 +207,7 @@ public abstract class AbstractProxyServlet extends HttpServlet
|
|||
protected Logger createLogger()
|
||||
{
|
||||
String servletName = getServletConfig().getServletName();
|
||||
servletName = servletName.replace('-', '.');
|
||||
servletName = StringUtil.replace(servletName, '-', '.');
|
||||
if ((getClass().getPackage() != null) && !servletName.startsWith(getClass().getPackage().getName()))
|
||||
{
|
||||
servletName = getClass().getName() + "." + servletName;
|
||||
|
|
|
@ -43,7 +43,6 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
|
@ -86,6 +85,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -670,7 +670,7 @@ public class ProxyServletTest
|
|||
|
||||
// Make the request to the proxy, it should transparently forward to the server
|
||||
ContentResponse response = client.newRequest("localhost", proxyConnector.getLocalPort())
|
||||
.path((prefix + target).replaceAll("//", "/"))
|
||||
.path(StringUtil.replace((prefix + target), "//", "/"))
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
assertEquals(200, response.getStatus());
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -454,13 +455,7 @@ public class AttributeNormalizer
|
|||
// leftover
|
||||
expanded.append(str.substring(offset));
|
||||
|
||||
// special case for "$$"
|
||||
if (expanded.indexOf("$$") >= 0)
|
||||
{
|
||||
return expanded.toString().replaceAll("\\$\\$","\\$");
|
||||
}
|
||||
|
||||
return expanded.toString();
|
||||
return StringUtil.replace(expanded.toString(), "$$", "$");
|
||||
}
|
||||
|
||||
private String getString(String property)
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
|
||||
/**
|
||||
|
@ -93,7 +94,7 @@ public class RedirectRegexRule extends RegexRule
|
|||
for (int g = 1; g <= matcher.groupCount(); g++)
|
||||
{
|
||||
String group = matcher.group(g);
|
||||
target = target.replaceAll("\\$" + g, group);
|
||||
target = StringUtil.replace(target, "$" + g, group);
|
||||
}
|
||||
|
||||
target = response.encodeRedirectURL(target);
|
||||
|
@ -110,6 +111,11 @@ public class RedirectRegexRule extends RegexRule
|
|||
@Override
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.rewrite.handler;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
|
|
@ -140,7 +140,8 @@ public class PropertyUserStore extends UserStore implements PathWatcher.Listener
|
|||
int bang_slash = uri.indexOf("!/");
|
||||
if (colon < 0 || bang_slash < 0 || colon > bang_slash)
|
||||
throw new IllegalArgumentException("Not resolved JarFile resource: " + uri);
|
||||
String entry_path = uri.substring(colon + 2).replace("!/", "__").replace('/', '_').replace('.', '_');
|
||||
|
||||
String entry_path = StringUtil.sanitizeFileSystemName(uri.substring(colon + 2));
|
||||
|
||||
Path tmpDirectory = Files.createTempDirectory("users_store");
|
||||
tmpDirectory.toFile().deleteOnExit();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<New class="org.eclipse.jetty.server.ForwardedRequestCustomizer">
|
||||
<Set name="forwardedOnly"><Property name="jetty.httpConfig.forwardedOnly" default="false"/></Set>
|
||||
<Set name="proxyAsAuthority"><Property name="jetty.httpConfig.forwardedProxyAsAuthority" default="false"/></Set>
|
||||
<Set name="forwardedPortAsAuthority"><Property name="jetty.httpConfig.forwardedPortAsAuthority" default="true"/></Set>
|
||||
<Set name="forwardedHeader"><Property name="jetty.httpConfig.forwardedHeader" default="Forwarded"/></Set>
|
||||
<Set name="forwardedHostHeader"><Property name="jetty.httpConfig.forwardedHostHeader" default="X-Forwarded-Host"/></Set>
|
||||
<Set name="forwardedServerHeader"><Property name="jetty.httpConfig.forwardedServerHeader" default="X-Forwarded-Server"/></Set>
|
||||
|
|
|
@ -16,8 +16,15 @@ etc/jetty-http-forwarded.xml
|
|||
[ini-template]
|
||||
### ForwardedRequestCustomizer Configuration
|
||||
|
||||
## If true, only the RFC7239 Forwarded header is accepted
|
||||
# jetty.httpConfig.forwardedOnly=false
|
||||
|
||||
## if true, the proxy address obtained from X-Forwarded-Server or RFC7239 is used as the request authority.
|
||||
# jetty.httpConfig.forwardedProxyAsAuthority=false
|
||||
|
||||
## if true, the X-Forwarded-Port header applies to the authority, else it applies to the remote client address
|
||||
# jetty.httpConfig.forwardedPortAsAuthority=true
|
||||
|
||||
# jetty.httpConfig.forwardedHeader=Forwarded
|
||||
# jetty.httpConfig.forwardedHostHeader=X-Forwarded-Host
|
||||
# jetty.httpConfig.forwardedServerHeader=X-Forwarded-Server
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.lang.invoke.MethodHandle;
|
|||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
|
@ -68,6 +67,8 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
private static final Logger LOG = Log.getLogger(ForwardedRequestCustomizer.class);
|
||||
|
||||
private HostPortHttpField _forcedHost;
|
||||
private boolean _proxyAsAuthority = false;
|
||||
private boolean _forwardedPortAsAuthority = true;
|
||||
private String _forwardedHeader = HttpHeader.FORWARDED.toString();
|
||||
private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
|
||||
private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||
|
@ -77,7 +78,6 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
private String _forwardedHttpsHeader = "X-Proxied-Https";
|
||||
private String _forwardedCipherSuiteHeader = "Proxy-auth-cert";
|
||||
private String _forwardedSslSessionIdHeader = "Proxy-ssl-id";
|
||||
private boolean _proxyAsAuthority = false;
|
||||
private boolean _sslIsSecure = true;
|
||||
private Trie<MethodHandle> _handles;
|
||||
|
||||
|
@ -252,6 +252,25 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if true, the X-Forwarded-Port header applies to the authority,
|
||||
* else it applies to the remote client address
|
||||
*/
|
||||
public boolean getForwardedPortAsAuthority()
|
||||
{
|
||||
return _forwardedPortAsAuthority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the X-Forwarded-Port header will be used for Authority
|
||||
* @param forwardedPortAsAuthority if true, the X-Forwarded-Port header applies to the authority,
|
||||
* else it applies to the remote client address
|
||||
*/
|
||||
public void setForwardedPortAsAuthority(boolean forwardedPortAsAuthority)
|
||||
{
|
||||
_forwardedPortAsAuthority = forwardedPortAsAuthority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the forwardedProtoHeader.
|
||||
*
|
||||
|
@ -483,14 +502,22 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
}
|
||||
}
|
||||
|
||||
private static class XHostPort extends HostPort
|
||||
private static class PossiblyPartialHostPort extends HostPort
|
||||
{
|
||||
XHostPort(String authority)
|
||||
PossiblyPartialHostPort(String authority)
|
||||
{
|
||||
super(authority);
|
||||
}
|
||||
|
||||
XHostPort(String host, int port)
|
||||
protected PossiblyPartialHostPort(String host, int port)
|
||||
{
|
||||
super(host, port);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PortSetHostPort extends PossiblyPartialHostPort
|
||||
{
|
||||
PortSetHostPort(String host, int port)
|
||||
{
|
||||
super(host, port);
|
||||
}
|
||||
|
@ -545,14 +572,24 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
|
||||
public void handleHost(HttpField field)
|
||||
{
|
||||
if (_host==null)
|
||||
_host = new XHostPort(getLeftMost(field.getValue()));
|
||||
if (_forwardedPortAsAuthority && !StringUtil.isEmpty(_forwardedPortHeader))
|
||||
{
|
||||
if (_host == null)
|
||||
_host = new PossiblyPartialHostPort(getLeftMost(field.getValue()));
|
||||
else if (_for instanceof PortSetHostPort)
|
||||
_host = new HostPort(HostPort.normalizeHost(getLeftMost(field.getValue())), _host.getPort());
|
||||
}
|
||||
else if (_host==null)
|
||||
{
|
||||
_host = new HostPort(getLeftMost(field.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleServer(HttpField field)
|
||||
{
|
||||
if (_proxyAsAuthority && _host==null)
|
||||
_host = new XHostPort(getLeftMost(field.getValue()));
|
||||
if (_proxyAsAuthority)
|
||||
return;
|
||||
handleHost(field);
|
||||
}
|
||||
|
||||
public void handleProto(HttpField field)
|
||||
|
@ -563,18 +600,35 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
|
||||
public void handleFor(HttpField field)
|
||||
{
|
||||
if (_for==null)
|
||||
_for = new XHostPort(getLeftMost(field.getValue()));
|
||||
else if (_for instanceof XHostPort && "unknown".equals(_for.getHost()))
|
||||
_for = new XHostPort(HostPort.normalizeHost(getLeftMost(field.getValue())),_for.getPort());
|
||||
if (!_forwardedPortAsAuthority && !StringUtil.isEmpty(_forwardedPortHeader))
|
||||
{
|
||||
if (_for == null)
|
||||
_for = new PossiblyPartialHostPort(getLeftMost(field.getValue()));
|
||||
else if (_for instanceof PortSetHostPort)
|
||||
_for = new HostPort(HostPort.normalizeHost(getLeftMost(field.getValue())), _for.getPort());
|
||||
}
|
||||
else if (_for == null)
|
||||
{
|
||||
_for = new HostPort(getLeftMost(field.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePort(HttpField field)
|
||||
{
|
||||
if (_for == null)
|
||||
_for = new XHostPort("unknown", field.getIntValue());
|
||||
else if (_for instanceof XHostPort && _for.getPort()<=0)
|
||||
_for = new XHostPort(HostPort.normalizeHost(_for.getHost()), field.getIntValue());
|
||||
if (!_forwardedPortAsAuthority)
|
||||
{
|
||||
if (_for == null)
|
||||
_for = new PortSetHostPort(_request.getRemoteHost(), field.getIntValue());
|
||||
else if (_for instanceof PossiblyPartialHostPort && _for.getPort() <= 0)
|
||||
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), field.getIntValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_host == null)
|
||||
_host = new PortSetHostPort(_request.getServerName(), field.getIntValue());
|
||||
else if (_host instanceof PossiblyPartialHostPort && _host.getPort() <= 0)
|
||||
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), field.getIntValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void handleHttps(HttpField field)
|
||||
|
@ -602,19 +656,19 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
break;
|
||||
if (value.startsWith("_") || "unknown".equals(value))
|
||||
break;
|
||||
if (_host == null || _host instanceof XHostPort)
|
||||
if (_proxyAsAuthority && (_host == null || !(_host instanceof Rfc7239HostPort)))
|
||||
_host = new Rfc7239HostPort(value);
|
||||
break;
|
||||
case "for":
|
||||
if (value.startsWith("_") || "unknown".equals(value))
|
||||
break;
|
||||
if (_for == null || _for instanceof XHostPort)
|
||||
if (_for == null || !(_for instanceof Rfc7239HostPort))
|
||||
_for = new Rfc7239HostPort(value);
|
||||
break;
|
||||
case "host":
|
||||
if (value.startsWith("_") || "unknown".equals(value))
|
||||
break;
|
||||
if (_host == null || _host instanceof XHostPort)
|
||||
if (_host == null || !(_host instanceof Rfc7239HostPort))
|
||||
_host = new Rfc7239HostPort(value);
|
||||
break;
|
||||
case "proto":
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
@ -29,15 +38,6 @@ import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
|||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -135,7 +135,7 @@ public class LowResourceMonitor extends ContainerLifeCycle
|
|||
|
||||
/**
|
||||
* @param maxConnections The maximum connections before low resources state is triggered
|
||||
* @deprecated Replaced by ConnectionLimit
|
||||
* @deprecated Replaced by {@link ConnectionLimit}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMaxConnections(int maxConnections)
|
||||
|
|
|
@ -52,12 +52,10 @@ import org.eclipse.jetty.http.HttpVersion;
|
|||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http.Syntax;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -237,7 +235,7 @@ public class Response implements HttpServletResponse
|
|||
if (i >= 0)
|
||||
{
|
||||
httpOnly = true;
|
||||
comment = comment.replace(HTTP_ONLY_COMMENT, "").trim();
|
||||
comment = StringUtil.strip(comment.trim(), HTTP_ONLY_COMMENT);
|
||||
if (comment.length() == 0)
|
||||
comment = null;
|
||||
}
|
||||
|
@ -1146,7 +1144,7 @@ public class Response implements HttpServletResponse
|
|||
return;
|
||||
|
||||
_locale = locale;
|
||||
_fields.put(HttpHeader.CONTENT_LANGUAGE, locale.toString().replace('_', '-'));
|
||||
_fields.put(HttpHeader.CONTENT_LANGUAGE, StringUtil.replace(locale.toString(), '_', '-'));
|
||||
|
||||
if (_outputType != OutputType.NONE)
|
||||
return;
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.Enumeration;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -47,7 +46,6 @@ import org.eclipse.jetty.server.handler.ErrorHandler;
|
|||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -55,6 +53,7 @@ import org.eclipse.jetty.util.Uptime;
|
|||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.component.AttributeContainerMap;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -75,7 +74,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(Server.class);
|
||||
|
||||
private final AttributesMap _attributes = new AttributesMap();
|
||||
private final AttributeContainerMap _attributes = new AttributeContainerMap();
|
||||
private final ThreadPool _threadPool;
|
||||
private final List<Connector> _connectors = new CopyOnWriteArrayList<>();
|
||||
private SessionIdManager _sessionIdManager;
|
||||
|
@ -107,6 +106,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
ServerConnector connector=new ServerConnector(this);
|
||||
connector.setPort(port);
|
||||
setConnectors(new Connector[]{connector});
|
||||
addBean(_attributes);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -584,9 +584,6 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
@Override
|
||||
public void clearAttributes()
|
||||
{
|
||||
Enumeration<String> names = _attributes.getAttributeNames();
|
||||
while (names.hasMoreElements())
|
||||
removeBean(_attributes.getAttribute(names.nextElement()));
|
||||
_attributes.clearAttributes();
|
||||
}
|
||||
|
||||
|
@ -607,7 +604,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
@Override
|
||||
public Enumeration<String> getAttributeNames()
|
||||
{
|
||||
return AttributesMap.getAttributeNamesCopy(_attributes);
|
||||
return _attributes.getAttributeNames();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -617,9 +614,6 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
@Override
|
||||
public void removeAttribute(String name)
|
||||
{
|
||||
Object bean=_attributes.getAttribute(name);
|
||||
if (bean!=null)
|
||||
removeBean(bean);
|
||||
_attributes.removeAttribute(name);
|
||||
}
|
||||
|
||||
|
@ -630,9 +624,6 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
@Override
|
||||
public void setAttribute(String name, Object attribute)
|
||||
{
|
||||
// TODO this is a crude way to get attribute values managed by JMX.
|
||||
Object old=_attributes.getAttribute(name);
|
||||
updateBean(old,attribute);
|
||||
_attributes.setAttribute(name, attribute);
|
||||
}
|
||||
|
||||
|
@ -693,7 +684,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
@Override
|
||||
public void dump(Appendable out,String indent) throws IOException
|
||||
{
|
||||
dumpObjects(out,indent,new ClassLoaderDump(this.getClass().getClassLoader()),_attributes);
|
||||
dumpObjects(out,indent,new ClassLoaderDump(this.getClass().getClassLoader()));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -714,6 +705,5 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
_seconds = seconds;
|
||||
_dateField = dateField;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ public class DefaultHandler extends AbstractHandler
|
|||
{
|
||||
writer.append("<a href=\"").append(href).append("\">");
|
||||
}
|
||||
writer.append(contextPath.replaceAll("%", "%"));
|
||||
writer.append(StringUtil.replace(contextPath, "%", "%"));
|
||||
if (context.isRunning())
|
||||
{
|
||||
writer.append("</a>");
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.server.session;
|
|||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
* SessionContext
|
||||
|
@ -138,7 +139,6 @@ public class SessionContext
|
|||
if (path==null)
|
||||
return "";
|
||||
|
||||
return path.replace('/', '_').replace('.','_').replace('\\','_');
|
||||
return StringUtil.sanitizeFileSystemName(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
|
@ -29,7 +27,6 @@ import java.util.Random;
|
|||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
|
@ -40,6 +37,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
@ -49,6 +47,8 @@ import org.junit.jupiter.api.Disabled;
|
|||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@Disabled
|
||||
@Tag("stress")
|
||||
public class AsyncStressTest
|
||||
|
@ -123,7 +123,7 @@ public class AsyncStressTest
|
|||
int p=path[i][l]=_random.nextInt(__paths.length);
|
||||
|
||||
int period = _random.nextInt(290)+10;
|
||||
String uri=__paths[p][0].replace("<PERIOD>",Integer.toString(period));
|
||||
String uri = StringUtil.replace(__paths[p][0], "<PERIOD>", Integer.toString(period));
|
||||
|
||||
long start=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
|
||||
String request =
|
||||
|
|
|
@ -19,25 +19,20 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
@ -46,11 +41,16 @@ public class ForwardedRequestCustomizerTest
|
|||
private Server _server;
|
||||
private LocalConnector _connector;
|
||||
private RequestHandler _handler;
|
||||
final Deque<String> _results = new ArrayDeque<>();
|
||||
final AtomicBoolean _wasSecure = new AtomicBoolean(false);
|
||||
final AtomicReference<String> _sslSession = new AtomicReference<>();
|
||||
final AtomicReference<String> _sslCertificate = new AtomicReference<>();
|
||||
|
||||
final AtomicReference<String> _scheme = new AtomicReference<>();
|
||||
final AtomicReference<String> _serverName = new AtomicReference<>();
|
||||
final AtomicReference<Integer> _serverPort = new AtomicReference<>();
|
||||
final AtomicReference<String> _remoteAddr = new AtomicReference<>();
|
||||
final AtomicReference<Integer> _remotePort = new AtomicReference<>();
|
||||
final AtomicReference<String> _requestURL = new AtomicReference<>();
|
||||
|
||||
ForwardedRequestCustomizer _customizer;
|
||||
|
||||
@BeforeEach
|
||||
|
@ -62,29 +62,26 @@ public class ForwardedRequestCustomizerTest
|
|||
http.getHttpConfiguration().setRequestHeaderSize(512);
|
||||
http.getHttpConfiguration().setResponseHeaderSize(512);
|
||||
http.getHttpConfiguration().setOutputBufferSize(2048);
|
||||
http.getHttpConfiguration().addCustomizer(_customizer=new ForwardedRequestCustomizer());
|
||||
_connector = new LocalConnector(_server,http);
|
||||
http.getHttpConfiguration().addCustomizer(_customizer = new ForwardedRequestCustomizer());
|
||||
_connector = new LocalConnector(_server, http);
|
||||
_server.addConnector(_connector);
|
||||
_handler = new RequestHandler();
|
||||
_server.setHandler(_handler);
|
||||
|
||||
_handler._checker = new RequestTester()
|
||||
_handler._checker = (request, response) ->
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
_wasSecure.set(request.isSecure());
|
||||
_sslSession.set(String.valueOf(request.getAttribute("javax.servlet.request.ssl_session_id")));
|
||||
_sslCertificate.set(String.valueOf(request.getAttribute("javax.servlet.request.cipher_suite")));
|
||||
_results.add(request.getScheme());
|
||||
_results.add(request.getServerName());
|
||||
_results.add(Integer.toString(request.getServerPort()));
|
||||
_results.add(request.getRemoteAddr());
|
||||
_results.add(Integer.toString(request.getRemotePort()));
|
||||
return true;
|
||||
}
|
||||
_wasSecure.set(request.isSecure());
|
||||
_sslSession.set(String.valueOf(request.getAttribute("javax.servlet.request.ssl_session_id")));
|
||||
_sslCertificate.set(String.valueOf(request.getAttribute("javax.servlet.request.cipher_suite")));
|
||||
_scheme.set(request.getScheme());
|
||||
_serverName.set(request.getServerName());
|
||||
_serverPort.set(request.getServerPort());
|
||||
_remoteAddr.set(request.getRemoteAddr());
|
||||
_remotePort.set(request.getRemotePort());
|
||||
_requestURL.set(request.getRequestURL().toString());
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
_server.start();
|
||||
}
|
||||
|
||||
|
@ -92,391 +89,561 @@ public class ForwardedRequestCustomizerTest
|
|||
public void destroy() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostIpv4() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: 1.2.3.4:2222\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("1.2.3.4",_results.poll());
|
||||
assertEquals("2222",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: 1.2.3.4:2222\n" +
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("1.2.3.4"));
|
||||
assertThat("serverPort", _serverPort.get(), is(2222));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://1.2.3.4:2222/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostIpv6() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: [::1]:2222\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("[::1]",_results.poll());
|
||||
assertEquals("2222",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: [::1]:2222\n" +
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("[::1]"));
|
||||
assertThat("serverPort", _serverPort.get(), is(2222));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://[::1]:2222/"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testURIIpv4() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET http://1.2.3.4:2222/ HTTP/1.1\n"+
|
||||
"Host: wrong\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("1.2.3.4",_results.poll());
|
||||
assertEquals("2222",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET http://1.2.3.4:2222/ HTTP/1.1\n" +
|
||||
"Host: wrong\n" +
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("1.2.3.4"));
|
||||
assertThat("serverPort", _serverPort.get(), is(2222));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://1.2.3.4:2222/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIIpv6() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET http://[::1]:2222/ HTTP/1.1\n"+
|
||||
"Host: wrong\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("[::1]",_results.poll());
|
||||
assertEquals("2222",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET http://[::1]:2222/ HTTP/1.1\n" +
|
||||
"Host: wrong\n" +
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("[::1]"));
|
||||
assertThat("serverPort", _serverPort.get(), is(2222));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://[::1]:2222/"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <a href="https://tools.ietf.org/html/rfc7239#section-4">RFC 7239: Section 4</a>
|
||||
*
|
||||
* Examples of syntax.
|
||||
*/
|
||||
@Test
|
||||
public void testRFC7239_Examples_4() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Forwarded: for=\"_gazonk\"\n"+
|
||||
"Forwarded: For=\"[2001:db8:cafe::17]:4711\"\n"+
|
||||
"Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43\n"+
|
||||
"Forwarded: for=192.0.2.43, for=198.51.100.17\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("[2001:db8:cafe::17]",_results.poll());
|
||||
assertEquals("4711",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Forwarded: for=\"_gazonk\"\n" +
|
||||
"Forwarded: For=\"[2001:db8:cafe::17]:4711\"\n" +
|
||||
"Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43\n" +
|
||||
"Forwarded: for=192.0.2.43, for=198.51.100.17\n" +
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("[2001:db8:cafe::17]"));
|
||||
assertThat("remotePort", _remotePort.get(), is(4711));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <a href="https://tools.ietf.org/html/rfc7239#section-7.1">RFC 7239: Section 7.1</a>
|
||||
*
|
||||
* Examples of syntax with regards to HTTP header fields
|
||||
*/
|
||||
@Test
|
||||
public void testRFC7239_Examples_7_1() throws Exception
|
||||
{
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Forwarded: for=192.0.2.43,for=\"[2001:db8:cafe::17]\",for=unknown\n"+
|
||||
"\n");
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\", for=unknown\n"+
|
||||
"\n");
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Forwarded: for=192.0.2.43\n"+
|
||||
"Forwarded: for=\"[2001:db8:cafe::17]\", for=unknown\n"+
|
||||
"\n");
|
||||
// Without spaces
|
||||
HttpTester.Response response1 = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Forwarded: for=192.0.2.43,for=\"[2001:db8:cafe::17]\",for=unknown\n" +
|
||||
"\n"));
|
||||
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("192.0.2.43",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("192.0.2.43",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("192.0.2.43",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertThat("status", response1.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
|
||||
// With spaces
|
||||
HttpTester.Response response2 = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\", for=unknown\n" +
|
||||
"\n"));
|
||||
assertThat("status", response2.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
|
||||
// As multiple headers
|
||||
HttpTester.Response response3 = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Forwarded: for=192.0.2.43\n" +
|
||||
"Forwarded: for=\"[2001:db8:cafe::17]\", for=unknown\n" +
|
||||
"\n"));
|
||||
|
||||
assertThat("status", response3.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="https://tools.ietf.org/html/rfc7239#section-7.4">RFC 7239: Section 7.4</a>
|
||||
*
|
||||
* Transition
|
||||
*/
|
||||
@Test
|
||||
public void testRFC7239_Examples_7_4() throws Exception
|
||||
{
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\"\n"+
|
||||
"\n");
|
||||
// Old syntax
|
||||
HttpTester.Response response1 = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-For: 192.0.2.43, 2001:db8:cafe::17\n" +
|
||||
"\n"));
|
||||
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("192.0.2.43",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertThat("status", response1.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
|
||||
// New syntax
|
||||
HttpTester.Response response2 = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\"\n" +
|
||||
"\n"));
|
||||
|
||||
assertThat("status", response2.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="https://tools.ietf.org/html/rfc7239#section-7.5">RFC 7239: Section 7.5</a>
|
||||
*
|
||||
* Example Usage
|
||||
*/
|
||||
@Test
|
||||
public void testRFC7239_Examples_7_5() throws Exception
|
||||
{
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com\n"+
|
||||
"\n");
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com\n" +
|
||||
"\n"));
|
||||
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("example.com",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("192.0.2.43",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("example.com"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://example.com/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProto() throws Exception
|
||||
public void testProto_OldSyntax() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"X-Forwarded-Proto: foobar\n"+
|
||||
"Forwarded: proto=https\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("https",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("443",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-Proto: https\n" +
|
||||
"\n"));
|
||||
|
||||
assertTrue(_wasSecure.get(), "wasSecure");
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("https"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(443));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("https://myhost/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRFC7239_Proto() throws Exception
|
||||
{
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Forwarded: proto=https\n" +
|
||||
"\n"));
|
||||
|
||||
assertTrue(_wasSecure.get(), "wasSecure");
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("https"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(443));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("https://myhost/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFor() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"X-Forwarded-For: 10.9.8.7,6.5.4.3\n"+
|
||||
"X-Forwarded-For: 8.9.8.7,7.5.4.3\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("10.9.8.7",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-For: 10.9.8.7,6.5.4.3\n" +
|
||||
"X-Forwarded-For: 8.9.8.7,7.5.4.3\n" +
|
||||
"\n"));
|
||||
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("10.9.8.7"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForIpv4WithPort() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"X-Forwarded-For: 10.9.8.7:1111,6.5.4.3:2222\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("10.9.8.7",_results.poll());
|
||||
assertEquals("1111",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-For: 10.9.8.7:1111,6.5.4.3:2222\n" +
|
||||
"\n"));
|
||||
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("10.9.8.7"));
|
||||
assertThat("remotePort", _remotePort.get(), is(1111));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForIpv6WithPort() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"X-Forwarded-For: [2001:db8:cafe::17]:1111,6.5.4.3:2222\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("[2001:db8:cafe::17]",_results.poll());
|
||||
assertEquals("1111",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-For: [2001:db8:cafe::17]:1111,6.5.4.3:2222\n" +
|
||||
"\n"));
|
||||
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("[2001:db8:cafe::17]"));
|
||||
assertThat("remotePort", _remotePort.get(), is(1111));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForIpv6AndPort() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"X-Forwarded-For: 1:2:3:4:5:6:7:8\n"+
|
||||
"X-Forwarded-Port: 2222\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("[1:2:3:4:5:6:7:8]",_results.poll());
|
||||
assertEquals("2222",_results.poll());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-For: 1:2:3:4:5:6:7:8\n" +
|
||||
"X-Forwarded-Port: 2222\n" +
|
||||
"\n"));
|
||||
|
||||
response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"X-Forwarded-Port: 2222\n"+
|
||||
"X-Forwarded-For: 1:2:3:4:5:6:7:8\n"+
|
||||
"X-Forwarded-For: 7:7:7:7:7:7:7:7\n"+
|
||||
"X-Forwarded-Port: 3333\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("[1:2:3:4:5:6:7:8]",_results.poll());
|
||||
assertEquals("2222",_results.poll());
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(2222));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("[1:2:3:4:5:6:7:8]"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost:2222/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForIpv6AndPort_MultiField() throws Exception
|
||||
{
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-Port: 2222\n" +
|
||||
"X-Forwarded-For: 1:2:3:4:5:6:7:8\n" +
|
||||
"X-Forwarded-For: 7:7:7:7:7:7:7:7\n" +
|
||||
"X-Forwarded-Port: 3333\n" +
|
||||
"\n"));
|
||||
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(2222));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("[1:2:3:4:5:6:7:8]"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost:2222/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLegacyProto() throws Exception
|
||||
{
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"X-Proxied-Https: on\n"+
|
||||
"\n");
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("https",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("443",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertTrue(_wasSecure.get());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Proxied-Https: on\n" +
|
||||
"\n"));
|
||||
assertTrue(_wasSecure.get(), "wasSecure");
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("https"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(443));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("https://myhost/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSslSession() throws Exception
|
||||
{
|
||||
_customizer.setSslIsSecure(false);
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Proxy-Ssl-Id: Wibble\n"+
|
||||
"\n");
|
||||
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertFalse(_wasSecure.get());
|
||||
assertEquals("Wibble",_sslSession.get());
|
||||
|
||||
_customizer.setSslIsSecure(true);
|
||||
response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Proxy-Ssl-Id: 0123456789abcdef\n"+
|
||||
"\n");
|
||||
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("https",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("443",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertTrue(_wasSecure.get());
|
||||
assertEquals("0123456789abcdef",_sslSession.get());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Proxy-Ssl-Id: Wibble\n" +
|
||||
"\n"));
|
||||
|
||||
assertFalse(_wasSecure.get(), "wasSecure");
|
||||
assertThat("sslSession", _sslSession.get(), is("Wibble"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
|
||||
_customizer.setSslIsSecure(true);
|
||||
response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Proxy-Ssl-Id: 0123456789abcdef\n" +
|
||||
"\n"));
|
||||
|
||||
assertTrue(_wasSecure.get(), "wasSecure");
|
||||
assertThat("sslSession", _sslSession.get(), is("0123456789abcdef"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("https"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(443));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("https://myhost/"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSslCertificate() throws Exception
|
||||
{
|
||||
_customizer.setSslIsSecure(false);
|
||||
String response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Proxy-auth-cert: Wibble\n"+
|
||||
"\n");
|
||||
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertFalse(_wasSecure.get());
|
||||
assertEquals("Wibble",_sslCertificate.get());
|
||||
|
||||
|
||||
_customizer.setSslIsSecure(true);
|
||||
response=_connector.getResponse(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: myhost\n"+
|
||||
"Proxy-auth-cert: 0123456789abcdef\n"+
|
||||
"\n");
|
||||
|
||||
assertThat(response, Matchers.containsString("200 OK"));
|
||||
assertEquals("https",_results.poll());
|
||||
assertEquals("myhost",_results.poll());
|
||||
assertEquals("443",_results.poll());
|
||||
assertEquals("0.0.0.0",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertTrue(_wasSecure.get());
|
||||
assertEquals("0123456789abcdef",_sslCertificate.get());
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Proxy-auth-cert: Wibble\n" +
|
||||
"\n"));
|
||||
|
||||
assertFalse(_wasSecure.get(), "wasSecure");
|
||||
assertThat("sslCertificate", _sslCertificate.get(), is("Wibble"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
|
||||
_customizer.setSslIsSecure(true);
|
||||
response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"Proxy-auth-cert: 0123456789abcdef\n" +
|
||||
"\n"));
|
||||
|
||||
assertTrue(_wasSecure.get(), "wasSecure");
|
||||
assertThat("sslCertificate", _sslCertificate.get(), is("0123456789abcdef"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("https"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(443));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("https://myhost/"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resetting the server port via a forwarding header
|
||||
*/
|
||||
@Test
|
||||
public void testPort_For() throws Exception
|
||||
{
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-Port: 4444\n" +
|
||||
"X-Forwarded-For: 192.168.1.200\n" +
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(4444));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.168.1.200"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost:4444/"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resetting the server port via a forwarding header
|
||||
*/
|
||||
@Test
|
||||
public void testMixed() throws Exception
|
||||
public void testRemote_Port_For() throws Exception
|
||||
{
|
||||
String response = _connector.getResponse(
|
||||
_customizer.setForwardedPortAsAuthority(false);
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-Port: 4444\n" +
|
||||
"X-Forwarded-For: 192.168.1.200\n" +
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.168.1.200"));
|
||||
assertThat("remotePort", _remotePort.get(), is(4444));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost/"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting the server Port before the "Host" header has been seen.
|
||||
*/
|
||||
@Test
|
||||
public void testPort_For_LateHost() throws Exception
|
||||
{
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"X-Forwarded-Port: 4444\n" + // this order is intentional
|
||||
"X-Forwarded-For: 192.168.1.200\n" +
|
||||
"Host: myhost\n" + // leave this as the last header
|
||||
"\n"));
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("myhost"));
|
||||
assertThat("serverPort", _serverPort.get(), is(4444));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.168.1.200"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://myhost:4444/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMixed_For_Port_RFC_For() throws Exception
|
||||
{
|
||||
HttpTester.Response response = HttpTester.parseResponse(
|
||||
_connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
"Host: myhost\n" +
|
||||
"X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222\n" +
|
||||
"X-Forwarded-Port: 3333\n" +
|
||||
"Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com\n"+
|
||||
"Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com\n" +
|
||||
"X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222\n" +
|
||||
"\n");
|
||||
"\n"));
|
||||
|
||||
assertEquals("http",_results.poll());
|
||||
assertEquals("example.com",_results.poll());
|
||||
assertEquals("80",_results.poll());
|
||||
assertEquals("192.0.2.43",_results.poll());
|
||||
assertEquals("0",_results.poll());
|
||||
assertThat("status", response.getStatus(), is(200));
|
||||
assertThat("scheme", _scheme.get(), is("http"));
|
||||
assertThat("serverName", _serverName.get(), is("example.com"));
|
||||
assertThat("serverPort", _serverPort.get(), is(80));
|
||||
assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43"));
|
||||
assertThat("remotePort", _remotePort.get(), is(0));
|
||||
assertThat("requestURL", _requestURL.get(), is("http://example.com/"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
interface RequestTester
|
||||
{
|
||||
boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException;
|
||||
boolean check(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||
}
|
||||
|
||||
private class RequestHandler extends AbstractHandler
|
||||
{
|
||||
private RequestTester _checker;
|
||||
@SuppressWarnings("unused")
|
||||
private String _content;
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
((Request)request).setHandled(true);
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
if (request.getContentLength()>0
|
||||
&& !MimeTypes.Type.FORM_ENCODED.asString().equals(request.getContentType())
|
||||
&& !request.getContentType().startsWith("multipart/form-data"))
|
||||
_content=IO.toString(request.getInputStream());
|
||||
|
||||
if (_checker!=null && _checker.check(request,response))
|
||||
if (_checker != null && _checker.check(request, response))
|
||||
response.setStatus(200);
|
||||
else
|
||||
response.sendError(500);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=WARN
|
||||
#org.eclipse.jetty.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.ConnectionLimit.LEVEL=DEBUG
|
||||
|
|
|
@ -963,7 +963,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String tmp = jsp.replace('.','_');
|
||||
String tmp = StringUtil.replace(jsp, '.', '_');
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.warn("JspUtil.makeJavaIdentifier failed for jsp "+jsp +" using "+tmp+" instead");
|
||||
|
@ -1000,9 +1000,9 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
s = 1;
|
||||
|
||||
//remove the element after last slash, which should be name of jsp
|
||||
tmp = tmp.substring(s,i);
|
||||
tmp = tmp.substring(s,i).trim();
|
||||
|
||||
tmp = tmp.replace('/','.').trim();
|
||||
tmp = StringUtil.replace(tmp, '/', '.');
|
||||
tmp = (".".equals(tmp)? "": tmp);
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
|
|
|
@ -18,13 +18,9 @@
|
|||
|
||||
package org.eclipse.jetty.servlet;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -34,10 +30,14 @@ import org.eclipse.jetty.http.HttpTester;
|
|||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class ResponseHeadersTest
|
||||
{
|
||||
public static class SimulateUpgradeServlet extends HttpServlet
|
||||
|
@ -144,7 +144,7 @@ public class ResponseHeadersTest
|
|||
assertThat("Response Code",response.getStatus(),is(200));
|
||||
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 = StringUtil.replace(actualPathInfo, "%0A", " "); // replace OBS fold with space
|
||||
expected = URLDecoder.decode(expected, "utf-8"); // decode the rest
|
||||
expected = expected.trim(); // trim whitespace at start/end
|
||||
assertThat("Response Header X-example", response.get("X-Example"), is(expected));
|
||||
|
|
|
@ -29,7 +29,6 @@ import java.util.Enumeration;
|
|||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
@ -324,7 +323,7 @@ public class CGI extends HttpServlet
|
|||
if (name.equalsIgnoreCase("Proxy"))
|
||||
continue;
|
||||
String value = req.getHeader(name);
|
||||
env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-', '_'), value);
|
||||
env.set("HTTP_" + StringUtil.replace(name.toUpperCase(Locale.ENGLISH), '-', '_'), value);
|
||||
}
|
||||
|
||||
// these extra ones were from printenv on www.dev.nomura.co.uk
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.Enumeration;
|
|||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
@ -368,8 +367,8 @@ public class CrossOriginFilter implements Filter
|
|||
|
||||
private String parseAllowedWildcardOriginToRegex(String allowedOrigin)
|
||||
{
|
||||
String regex = allowedOrigin.replace(".", "\\.");
|
||||
return regex.replace("*", ".*"); // we want to be greedy here to match multiple subdomains, thus we use .*
|
||||
String regex = StringUtil.replace(allowedOrigin, ".", "\\.");
|
||||
return StringUtil.replace(regex, "*", ".*"); // we want to be greedy here to match multiple subdomains, thus we use .*
|
||||
}
|
||||
|
||||
private boolean isSimpleRequest(HttpServletRequest request)
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.eclipse.jetty.http.HttpTester;
|
|||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlet.ServletTester;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -94,7 +95,7 @@ public class CrossOriginFilterTest
|
|||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String otherOrigin = origin.replace("localhost", "127.0.0.1");
|
||||
String otherOrigin = StringUtil.replace(origin, "localhost", "127.0.0.1");
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
|
@ -284,7 +285,7 @@ public class CrossOriginFilterTest
|
|||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
String origin = "http://localhost";
|
||||
String otherOrigin = origin.replace("localhost", "127.0.0.1");
|
||||
String otherOrigin = StringUtil.replace(origin, "localhost", "127.0.0.1");
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin + "," + otherOrigin);
|
||||
tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
|
|
|
@ -26,14 +26,13 @@ import java.util.List;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/** Fast String Utilities.
|
||||
/**
|
||||
* Fast String Utilities.
|
||||
*
|
||||
* These string utilities provide both convenience methods and
|
||||
* performance improvements over most standard library versions. The
|
||||
* main aim of the optimizations is to avoid object creation unless
|
||||
* absolutely required.
|
||||
*
|
||||
*
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/** Convert alternate charset names (eg utf8) to normalized
|
||||
* name (eg UTF-8).
|
||||
* @param s the charset to normalize
|
||||
|
@ -74,8 +72,7 @@ public class StringUtil
|
|||
String n=CHARSETS.get(s);
|
||||
return (n==null)?s:n;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/** Convert alternate charset names (eg utf8) to normalized
|
||||
* name (eg UTF-8).
|
||||
* @param s the charset to normalize
|
||||
|
@ -88,9 +85,7 @@ public class StringUtil
|
|||
String n=CHARSETS.get(s,offset,length);
|
||||
return (n==null)?s.substring(offset,offset+length):n;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static final char[] lowercases = {
|
||||
'\000','\001','\002','\003','\004','\005','\006','\007',
|
||||
'\010','\011','\012','\013','\014','\015','\016','\017',
|
||||
|
@ -109,7 +104,6 @@ public class StringUtil
|
|||
'\160','\161','\162','\163','\164','\165','\166','\167',
|
||||
'\170','\171','\172','\173','\174','\175','\176','\177' };
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* fast lower case conversion. Only works on ascii (not unicode)
|
||||
* @param s the string to convert
|
||||
|
@ -122,7 +116,6 @@ public class StringUtil
|
|||
|
||||
char[] c = null;
|
||||
int i=s.length();
|
||||
|
||||
// look for first conversion
|
||||
while (i-->0)
|
||||
{
|
||||
|
@ -138,7 +131,6 @@ public class StringUtil
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (i-->0)
|
||||
{
|
||||
if(c[i]<=127)
|
||||
|
@ -148,8 +140,55 @@ public class StringUtil
|
|||
return c==null?s:new String(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all characters from input string that are known to have
|
||||
* special meaning in various filesystems.
|
||||
*
|
||||
* <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: pipe, redirect, combine, slash, equivalence, bang, glob, selection, etc...</li>
|
||||
* <li>Space</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param str the raw input string
|
||||
* @return the sanitized output string. or null if {@code str} is null.
|
||||
*/
|
||||
public static String sanitizeFileSystemName(String str)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
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
|
||||
// piping : special meaning on unix / osx / windows
|
||||
(c == '|') || (c == '>') || (c == '<') || (c == '/') || (c == '&') ||
|
||||
// special characters on windows
|
||||
(c == '\\') || (c == '.') || (c == ':') ||
|
||||
// special characters on osx
|
||||
(c == '=') || (c == '"') || (c == ',') ||
|
||||
// glob / selection characters on most OS's
|
||||
(c == '*') || (c == '?') ||
|
||||
// bang execution on unix / osx
|
||||
(c == '!') ||
|
||||
// spaces are just generally difficult to work with
|
||||
(c == ' '))
|
||||
{
|
||||
chars[i] = '_';
|
||||
}
|
||||
}
|
||||
return String.valueOf(chars);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static boolean startsWithIgnoreCase(String s,String w)
|
||||
{
|
||||
if (w==null)
|
||||
|
@ -174,13 +213,11 @@ public class StringUtil
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public static boolean endsWithIgnoreCase(String s,String w)
|
||||
{
|
||||
if (w==null)
|
||||
return true;
|
||||
|
||||
if (s==null)
|
||||
return false;
|
||||
|
||||
|
@ -206,8 +243,7 @@ public class StringUtil
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* returns the next index of a character from the chars string
|
||||
* @param s the input string to search
|
||||
|
@ -221,10 +257,48 @@ public class StringUtil
|
|||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* replace substrings within string.
|
||||
* Replace chars within string.
|
||||
* <p>
|
||||
* Fast replacement for {@code java.lang.String#}{@link String#replace(char, char)}
|
||||
* </p>
|
||||
*
|
||||
* @param str the input string
|
||||
* @param find the char to look for
|
||||
* @param with the char to replace with
|
||||
* @return the now replaced string
|
||||
*/
|
||||
public static String replace(String str, char find, char with)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
if (find == with)
|
||||
return str;
|
||||
|
||||
int c = 0;
|
||||
int idx = str.indexOf(find, c);
|
||||
if (idx == -1)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
char[] chars = str.toCharArray();
|
||||
int len = chars.length;
|
||||
for (int i = idx; i < len; i++)
|
||||
{
|
||||
if (chars[i] == find)
|
||||
chars[i] = with;
|
||||
}
|
||||
return String.valueOf(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace substrings within string.
|
||||
* <p>
|
||||
* Fast replacement for {@code java.lang.String#}{@link String#replace(CharSequence, CharSequence)}
|
||||
* </p>
|
||||
*
|
||||
* @param s the input string
|
||||
* @param sub the string to look for
|
||||
* @param with the string to replace with
|
||||
|
@ -232,27 +306,59 @@ public class StringUtil
|
|||
*/
|
||||
public static String replace(String s, String sub, String with)
|
||||
{
|
||||
int c=0;
|
||||
int i=s.indexOf(sub,c);
|
||||
if (i == -1)
|
||||
return s;
|
||||
|
||||
StringBuilder buf = new StringBuilder(s.length()+with.length());
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
int c = 0;
|
||||
int i = s.indexOf(sub, c);
|
||||
if (i == -1)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder(s.length() + with.length());
|
||||
do
|
||||
{
|
||||
buf.append(s.substring(c,i));
|
||||
buf.append(s, c, i);
|
||||
buf.append(with);
|
||||
c=i+sub.length();
|
||||
} while ((i=s.indexOf(sub,c))!=-1);
|
||||
|
||||
if (c<s.length())
|
||||
buf.append(s.substring(c,s.length()));
|
||||
|
||||
return buf.toString();
|
||||
c = i + sub.length();
|
||||
}
|
||||
while ((i = s.indexOf(sub, c)) != -1);
|
||||
if (c < s.length())
|
||||
{
|
||||
buf.append(s.substring(c));
|
||||
}
|
||||
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.
|
||||
* @param s the input string
|
||||
* @return the string with quotes removed
|
||||
|
@ -263,8 +369,6 @@ public class StringUtil
|
|||
return QuotedStringTokenizer.unquote(s);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Append substring to StringBuilder
|
||||
* @param buf StringBuilder to append to
|
||||
* @param s String to append from
|
||||
|
@ -288,8 +392,6 @@ public class StringUtil
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* append hex digit
|
||||
* @param buf the buffer to append to
|
||||
|
@ -310,7 +412,6 @@ public class StringUtil
|
|||
buf.append((char)c);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Append 2 digits (zero padded) to the StringBuffer
|
||||
*
|
||||
|
@ -325,8 +426,7 @@ public class StringUtil
|
|||
buf.append((char)(i%10+'0'));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* Append 2 digits (zero padded) to the StringBuilder
|
||||
*
|
||||
|
@ -341,8 +441,7 @@ public class StringUtil
|
|||
buf.append((char)(i%10+'0'));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/** Return a non null string.
|
||||
* @param s String
|
||||
* @return The string passed in or empty string if it is null.
|
||||
|
@ -353,8 +452,7 @@ public class StringUtil
|
|||
return "";
|
||||
return s;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public static boolean equals(String s,char[] buf, int offset, int length)
|
||||
{
|
||||
if (s.length()!=length)
|
||||
|
@ -365,13 +463,11 @@ public class StringUtil
|
|||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String toUTF8String(byte[] b,int offset,int length)
|
||||
{
|
||||
return new String(b,offset,length,StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String toString(byte[] b,int offset,int length,String charset)
|
||||
{
|
||||
try
|
||||
|
@ -380,6 +476,7 @@ public class StringUtil
|
|||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +528,6 @@ public class StringUtil
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Test if a string is null or only has whitespace characters in it.
|
||||
* <p>
|
||||
|
@ -494,7 +590,6 @@ public class StringUtil
|
|||
return str == null || str.isEmpty();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Test if a string is not null and contains at least 1 non-whitespace characters in it.
|
||||
* <p>
|
||||
|
@ -534,14 +629,11 @@ public class StringUtil
|
|||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static boolean isUTF8(String charset)
|
||||
{
|
||||
return __UTF8.equalsIgnoreCase(charset)||__UTF8.equalsIgnoreCase(normalizeCharset(charset));
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String printable(String name)
|
||||
{
|
||||
if (name==null)
|
||||
|
@ -556,7 +648,7 @@ public class StringUtil
|
|||
return buf.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public static String printable(byte[] b)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
@ -592,13 +684,10 @@ public class StringUtil
|
|||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return s.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Converts a binary SID to a string SID
|
||||
*
|
||||
|
@ -631,7 +720,6 @@ public class StringUtil
|
|||
|
||||
// the number of subAuthorities we need to attach
|
||||
int subAuthorityCount = sidBytes[1];
|
||||
|
||||
// attach each of the subAuthorities
|
||||
for (int i = 0; i < subAuthorityCount; ++i)
|
||||
{
|
||||
|
@ -670,10 +758,8 @@ public class StringUtil
|
|||
|
||||
// the revision byte
|
||||
sidBytes[byteCount++] = (byte)Integer.parseInt(sidTokens[1]);
|
||||
|
||||
// the # of sub authorities byte
|
||||
sidBytes[byteCount++] = (byte)subAuthorityCount;
|
||||
|
||||
// the certAuthority
|
||||
String hexStr = Long.toHexString(Long.parseLong(sidTokens[2]));
|
||||
|
||||
|
@ -681,7 +767,6 @@ public class StringUtil
|
|||
{
|
||||
hexStr = "0" + hexStr;
|
||||
}
|
||||
|
||||
// place the certAuthority 6 bytes
|
||||
for ( int i = 0 ; i < hexStr.length(); i = i + 2)
|
||||
{
|
||||
|
@ -720,7 +805,6 @@ public class StringUtil
|
|||
int val = 0;
|
||||
boolean started = false;
|
||||
boolean minus = false;
|
||||
|
||||
for (int i = from; i < string.length(); i++)
|
||||
{
|
||||
char b = string.charAt(i);
|
||||
|
@ -741,7 +825,6 @@ public class StringUtil
|
|||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (started)
|
||||
return minus?(-val):val;
|
||||
throw new NumberFormatException(string);
|
||||
|
@ -759,7 +842,6 @@ public class StringUtil
|
|||
long val = 0;
|
||||
boolean started = false;
|
||||
boolean minus = false;
|
||||
|
||||
for (int i = 0; i < string.length(); i++)
|
||||
{
|
||||
char b = string.charAt(i);
|
||||
|
@ -780,7 +862,6 @@ public class StringUtil
|
|||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (started)
|
||||
return minus?(-val):val;
|
||||
throw new NumberFormatException(string);
|
||||
|
@ -799,12 +880,10 @@ public class StringUtil
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str.length() <= maxSize)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
return str.substring(0,maxSize);
|
||||
}
|
||||
|
||||
|
@ -817,20 +896,18 @@ public class StringUtil
|
|||
{
|
||||
if (s==null)
|
||||
return new String[]{};
|
||||
|
||||
if (!s.startsWith("[") || !s.endsWith("]"))
|
||||
throw new IllegalArgumentException();
|
||||
if (s.length()==2)
|
||||
return new String[]{};
|
||||
|
||||
return csvSplit(s,1,s.length()-2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a CSV string using {@link #csvSplit(List,String, int, int)}
|
||||
* @param s The string to parse
|
||||
* @return An array of parsed values.
|
||||
*/
|
||||
* Parse a CSV string using {@link #csvSplit(List,String, int, int)}
|
||||
* @param s The string to parse
|
||||
* @return An array of parsed values.
|
||||
*/
|
||||
public static String[] csvSplit(String s)
|
||||
{
|
||||
if (s==null)
|
||||
|
@ -851,13 +928,12 @@ public class StringUtil
|
|||
return null;
|
||||
if (off<0 || len<0 || off>s.length())
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
csvSplit(list,s,off,len);
|
||||
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
|
||||
* <p>Handle <a href="https://www.ietf.org/rfc/rfc4180.txt">rfc4180</a>-like
|
||||
|
@ -890,7 +966,6 @@ public class StringUtil
|
|||
case PRE_DATA:
|
||||
if (Character.isWhitespace(ch))
|
||||
continue;
|
||||
|
||||
if ('"'==ch)
|
||||
{
|
||||
state=CsvSplitState.QUOTE;
|
||||
|
@ -902,11 +977,9 @@ public class StringUtil
|
|||
list.add("");
|
||||
continue;
|
||||
}
|
||||
|
||||
state=CsvSplitState.DATA;
|
||||
out.append(ch);
|
||||
continue;
|
||||
|
||||
case DATA:
|
||||
if (Character.isWhitespace(ch))
|
||||
{
|
||||
|
@ -923,7 +996,6 @@ public class StringUtil
|
|||
state=CsvSplitState.PRE_DATA;
|
||||
continue;
|
||||
}
|
||||
|
||||
out.append(ch);
|
||||
continue;
|
||||
|
||||
|
@ -947,7 +1019,6 @@ public class StringUtil
|
|||
out.append(ch);
|
||||
last=-1;
|
||||
continue;
|
||||
|
||||
case QUOTE:
|
||||
if ('\\'==ch)
|
||||
{
|
||||
|
@ -978,13 +1049,11 @@ public class StringUtil
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case PRE_DATA:
|
||||
case POST_DATA:
|
||||
break;
|
||||
|
||||
case DATA:
|
||||
case QUOTE:
|
||||
case SLOSH:
|
||||
|
@ -1011,7 +1080,6 @@ public class StringUtil
|
|||
loop: for (;i<html.length();i++)
|
||||
{
|
||||
char c=html.charAt(i);
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case '&' :
|
||||
|
@ -1020,13 +1088,11 @@ public class StringUtil
|
|||
case '\'':
|
||||
case '"':
|
||||
break loop;
|
||||
|
||||
default:
|
||||
if (Character.isISOControl(c) && !Character.isWhitespace(c))
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
|
||||
// No characters need sanitizing, so return original string
|
||||
if (i==html.length())
|
||||
return html;
|
||||
|
@ -1039,7 +1105,6 @@ public class StringUtil
|
|||
for (;i<html.length();i++)
|
||||
{
|
||||
char c=html.charAt(i);
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case '&' :
|
||||
|
@ -1057,7 +1122,6 @@ public class StringUtil
|
|||
case '"':
|
||||
out.append(""");
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Character.isISOControl(c) && !Character.isWhitespace(c))
|
||||
out.append('?');
|
||||
|
@ -1067,8 +1131,12 @@ public class StringUtil
|
|||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public static String strip(String str, String find)
|
||||
{
|
||||
return StringUtil.replace(str, find, "");
|
||||
}
|
||||
|
||||
/** The String value of an Object
|
||||
* <p>This method calls {@link String#valueOf(Object)} unless the object is null,
|
||||
* in which case null is returned</p>
|
||||
|
|
|
@ -206,6 +206,46 @@ public class TypeUtil
|
|||
return class2Name.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Classpath / Classloader reference for the
|
||||
* provided class file.
|
||||
*
|
||||
* <p>
|
||||
* Convenience method for the code
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* String ref = myObject.getClass().getName().replace('.','/') + ".class";
|
||||
* </pre>
|
||||
*
|
||||
* @param clazz the class to reference
|
||||
* @return the classpath reference syntax for the class file
|
||||
*/
|
||||
public static String toClassReference(Class<?> clazz)
|
||||
{
|
||||
return TypeUtil.toClassReference(clazz.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Classpath / Classloader reference for the
|
||||
* provided class file.
|
||||
*
|
||||
* <p>
|
||||
* Convenience method for the code
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* String ref = myClassName.replace('.','/') + ".class";
|
||||
* </pre>
|
||||
*
|
||||
* @param className the class to reference
|
||||
* @return the classpath reference syntax for the class file
|
||||
*/
|
||||
public static String toClassReference(String className)
|
||||
{
|
||||
return StringUtil.replace(className, '.', '/').concat(".class");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Convert String value to instance.
|
||||
* @param type The class of the instance, which may be a primitive TYPE field.
|
||||
|
@ -560,7 +600,7 @@ public class TypeUtil
|
|||
}
|
||||
}
|
||||
|
||||
String resourceName = clazz.getName().replace('.', '/') + ".class";
|
||||
String resourceName = TypeUtil.toClassReference(clazz);
|
||||
ClassLoader loader = clazz.getClassLoader();
|
||||
URL url = (loader == null ? ClassLoader.getSystemClassLoader() : loader).getResource(resourceName);
|
||||
if (url != null)
|
||||
|
|
|
@ -268,7 +268,134 @@ public class URIUtil
|
|||
|
||||
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 raw String and convert any specific characters to their URI encoded equivalent.
|
||||
*
|
||||
* @param str input raw string
|
||||
* @param charsToEncode the list of raw characters that need to be encoded (if encountered)
|
||||
* @return output with specified characters encoded.
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
public static String encodeSpecific(String str, String charsToEncode)
|
||||
{
|
||||
if ((str == null) || (str.length() == 0))
|
||||
return null;
|
||||
|
||||
if ((charsToEncode == null) || (charsToEncode.length() == 0))
|
||||
return str;
|
||||
|
||||
char[] find = charsToEncode.toCharArray();
|
||||
int len = str.length();
|
||||
StringBuilder ret = new StringBuilder((int)(len * 0.20d));
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char c = str.charAt(i);
|
||||
boolean escaped = false;
|
||||
for (char f : find)
|
||||
{
|
||||
if (c == f)
|
||||
{
|
||||
escaped = true;
|
||||
ret.append('%');
|
||||
int d = 0xf & ((0xF0 & c) >> 4);
|
||||
ret.append((char)((d > 9 ? ('A' - 10) : '0') + d));
|
||||
d = 0xf & c;
|
||||
ret.append((char)((d > 9 ? ('A' - 10) : '0') + d));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!escaped)
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a raw String and convert any specific URI encoded sequences into characters.
|
||||
*
|
||||
* @param str input raw string
|
||||
* @param charsToDecode the list of raw characters that need to be decoded (if encountered), leaving all other encoded sequences alone.
|
||||
* @return output with specified characters decoded.
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
public static String decodeSpecific(String str, String charsToDecode)
|
||||
{
|
||||
if ((str == null) || (str.length() == 0))
|
||||
return null;
|
||||
|
||||
if ((charsToDecode == null) || (charsToDecode.length() == 0))
|
||||
return str;
|
||||
|
||||
int idx = str.indexOf('%');
|
||||
if (idx == -1)
|
||||
{
|
||||
// no hits
|
||||
return str;
|
||||
}
|
||||
|
||||
char[] find = charsToDecode.toCharArray();
|
||||
int len = str.length();
|
||||
Utf8StringBuilder ret = new Utf8StringBuilder(len);
|
||||
ret.append(str, 0, idx);
|
||||
|
||||
for (int i = idx; i < len; i++)
|
||||
{
|
||||
char c = str.charAt(i);
|
||||
switch (c)
|
||||
{
|
||||
case '%':
|
||||
if ((i + 2) < len)
|
||||
{
|
||||
char u = str.charAt(i + 1);
|
||||
char l = str.charAt(i + 2);
|
||||
char result = (char)(0xff & (TypeUtil.convertHexDigit(u) * 16 + TypeUtil.convertHexDigit(l)));
|
||||
boolean decoded = false;
|
||||
for (char f : find)
|
||||
{
|
||||
if (f == result)
|
||||
{
|
||||
ret.append(result);
|
||||
decoded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (decoded)
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Bad URI % encoding");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Encode a URI path.
|
||||
* @param path The path the encode
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
|
||||
/**
|
||||
* An Attributes implementation that holds it's values in an immutable {@link ContainerLifeCycle}
|
||||
*/
|
||||
public class AttributeContainerMap extends ContainerLifeCycle implements Attributes
|
||||
{
|
||||
private final Map<String, Object> _map = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public synchronized void setAttribute(String name, Object attribute)
|
||||
{
|
||||
Object old = _map.put(name, attribute);
|
||||
updateBean(old, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeAttribute(String name)
|
||||
{
|
||||
Object removed = _map.remove(name);
|
||||
if (removed != null)
|
||||
removeBean(removed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object getAttribute(String name)
|
||||
{
|
||||
return _map.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Enumeration<String> getAttributeNames()
|
||||
{
|
||||
return Collections.enumeration(_map.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clearAttributes()
|
||||
{
|
||||
_map.clear();
|
||||
this.removeBeans();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
Dumpable.dumpObject(out, this);
|
||||
Dumpable.dumpMapEntries(out, indent, _map, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{size=%d}",this.getClass().getSimpleName(),hashCode(),_map.size());
|
||||
}
|
||||
}
|
|
@ -132,7 +132,7 @@ public interface Container
|
|||
|
||||
/**
|
||||
* @param clazz the class of the beans
|
||||
* @return the list of beans of the given class from the entire managed hierarchy
|
||||
* @return the list of beans of the given class from the entire Container hierarchy
|
||||
* @param <T> the Bean type
|
||||
*/
|
||||
public <T> Collection<T> getContainedBeans(Class<T> clazz);
|
||||
|
|
|
@ -550,13 +550,17 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
|
|||
@Override
|
||||
public <T> Collection<T> getBeans(Class<T> clazz)
|
||||
{
|
||||
ArrayList<T> beans = new ArrayList<>();
|
||||
ArrayList<T> beans = null;
|
||||
for (Bean b : _beans)
|
||||
{
|
||||
if (clazz.isInstance(b._bean))
|
||||
{
|
||||
if (beans == null)
|
||||
beans = new ArrayList<>();
|
||||
beans.add(clazz.cast(b._bean));
|
||||
}
|
||||
}
|
||||
return beans;
|
||||
return beans == null ? Collections.emptyList() : beans;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -879,7 +883,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
|
|||
|
||||
/**
|
||||
* @param clazz the class of the beans
|
||||
* @return the list of beans of the given class from the entire managed hierarchy
|
||||
* @return the list of beans of the given class from the entire Container hierarchy
|
||||
* @param <T> the Bean type
|
||||
*/
|
||||
@Override
|
||||
|
@ -893,7 +897,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
|
|||
/**
|
||||
* @param clazz the class of the beans
|
||||
* @param <T> the Bean type
|
||||
* @param beans the collection to add beans of the given class from the entire managed hierarchy
|
||||
* @param beans the collection to add beans of the given class from the entire Container hierarchy
|
||||
*/
|
||||
protected <T> void getContainedBeans(Class<T> clazz, Collection<T> beans)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Iterator;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.ManagedOperation;
|
||||
|
||||
|
@ -92,16 +93,24 @@ public interface Dumpable
|
|||
String s;
|
||||
if (o==null)
|
||||
s = "null";
|
||||
else if (o instanceof Dumpable)
|
||||
{
|
||||
s = ((Dumpable)o).dumpSelf();
|
||||
s = StringUtil.replace(s, "\r\n", "|");
|
||||
s = StringUtil.replace(s, '\n', '|');
|
||||
}
|
||||
else if (o instanceof Collection)
|
||||
s = String.format("%s@%x(size=%d)",o.getClass().getName(),o.hashCode(),((Collection)o).size());
|
||||
else if (o.getClass().isArray())
|
||||
s = String.format("%s@%x[size=%d]",o.getClass().getComponentType(),o.hashCode(), Array.getLength(o));
|
||||
else if (o instanceof Map)
|
||||
s = String.format("%s@%x{size=%d}",o.getClass().getName(),o.hashCode(),((Map<?,?>)o).size());
|
||||
else if (o instanceof Dumpable)
|
||||
s = ((Dumpable)o).dumpSelf().replace("\r\n","|").replace("\n","|");
|
||||
else
|
||||
s = String.valueOf(o).replace("\r\n","|").replace("\n","|");
|
||||
{
|
||||
s = String.valueOf(o);
|
||||
s = StringUtil.replace(s, "\r\n", "|");
|
||||
s = StringUtil.replace(s, '\n', '|');
|
||||
}
|
||||
|
||||
if (o instanceof LifeCycle)
|
||||
out.append(s).append(" - ").append((AbstractLifeCycle.getState((LifeCycle)o))).append("\n");
|
||||
|
@ -130,7 +139,7 @@ public interface Dumpable
|
|||
{
|
||||
dumpObject(out,object);
|
||||
|
||||
int size = extraChildren==null?0:extraChildren.length;
|
||||
int extras = extraChildren==null?0:extraChildren.length;
|
||||
|
||||
if (object instanceof Stream)
|
||||
object = ((Stream)object).toArray();
|
||||
|
@ -139,87 +148,25 @@ public interface Dumpable
|
|||
|
||||
if (object instanceof Container)
|
||||
{
|
||||
Container container = (Container)object;
|
||||
ContainerLifeCycle containerLifeCycle = container instanceof ContainerLifeCycle ? (ContainerLifeCycle)container : null;
|
||||
for (Iterator<Object> i = container.getBeans().iterator(); i.hasNext();)
|
||||
{
|
||||
Object bean = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
if (bean instanceof LifeCycle)
|
||||
{
|
||||
if (container.isManaged(bean))
|
||||
{
|
||||
out.append(indent).append("+= ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out, nextIndent, bean);
|
||||
}
|
||||
else if (containerLifeCycle != null && containerLifeCycle.isAuto(bean))
|
||||
{
|
||||
out.append(indent).append("+? ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out, nextIndent, bean);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(indent).append("+~ ");
|
||||
dumpObject(out, bean);
|
||||
}
|
||||
}
|
||||
else if (containerLifeCycle != null && containerLifeCycle.isUnmanaged(bean))
|
||||
{
|
||||
out.append(indent).append("+~ ");
|
||||
dumpObject(out, bean);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(indent).append("+- ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out, nextIndent, bean);
|
||||
}
|
||||
}
|
||||
dumpContainer(out, indent, (Container)object, extras==0);
|
||||
}
|
||||
if (object instanceof Iterable)
|
||||
{
|
||||
for (Iterator i = ((Iterable<?>)object).iterator(); i.hasNext();)
|
||||
{
|
||||
Object item = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
out.append(indent).append("+: ");
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out,nextIndent, item);
|
||||
}
|
||||
dumpIterable(out, indent, (Iterable<?>)object, extras==0);
|
||||
}
|
||||
else if (object instanceof Map)
|
||||
{
|
||||
for (Iterator<? extends Map.Entry<?, ?>> i = ((Map<?,?>)object).entrySet().iterator(); i.hasNext();)
|
||||
{
|
||||
Map.Entry entry = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
out.append(indent).append("+@ ").append(String.valueOf(entry.getKey())).append('=');
|
||||
Object item = entry.getValue();
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out,nextIndent, item);
|
||||
}
|
||||
dumpMapEntries(out, indent, (Map<?,?>)object, extras==0);
|
||||
}
|
||||
|
||||
if (size==0)
|
||||
if (extras==0)
|
||||
return;
|
||||
|
||||
int i = 0;
|
||||
for (Object item : extraChildren)
|
||||
{
|
||||
i++;
|
||||
String nextIndent = indent + (i<size ? "| " : " ");
|
||||
String nextIndent = indent + (i<extras ? "| " : " ");
|
||||
out.append(indent).append("+> ");
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
|
@ -227,4 +174,91 @@ public interface Dumpable
|
|||
dumpObjects(out, nextIndent, item);
|
||||
}
|
||||
}
|
||||
|
||||
static void dumpContainer(Appendable out, String indent, Container object, boolean last) throws IOException
|
||||
{
|
||||
Container container = object;
|
||||
ContainerLifeCycle containerLifeCycle = container instanceof ContainerLifeCycle ? (ContainerLifeCycle)container : null;
|
||||
for (Iterator<Object> i = container.getBeans().iterator(); i.hasNext();)
|
||||
{
|
||||
Object bean = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || !last) ? "| " : " ");
|
||||
if (bean instanceof LifeCycle)
|
||||
{
|
||||
if (container.isManaged(bean))
|
||||
{
|
||||
out.append(indent).append("+= ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out, nextIndent, bean);
|
||||
}
|
||||
else if (containerLifeCycle != null && containerLifeCycle.isAuto(bean))
|
||||
{
|
||||
out.append(indent).append("+? ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out, nextIndent, bean);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(indent).append("+~ ");
|
||||
dumpObject(out, bean);
|
||||
}
|
||||
}
|
||||
else if (containerLifeCycle != null && containerLifeCycle.isUnmanaged(bean))
|
||||
{
|
||||
out.append(indent).append("+~ ");
|
||||
dumpObject(out, bean);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(indent).append("+- ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out, nextIndent, bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dumpIterable(Appendable out, String indent, Iterable<?> iterable, boolean last) throws IOException
|
||||
{
|
||||
for (Iterator i = iterable.iterator(); i.hasNext();)
|
||||
{
|
||||
Object item = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || !last) ? "| " : " ");
|
||||
out.append(indent).append("+: ");
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out,nextIndent, item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void dumpMapEntries(Appendable out, String indent, Map<?,?> map, boolean last) throws IOException
|
||||
{
|
||||
for (Iterator<? extends Map.Entry<?, ?>> i = map.entrySet().iterator(); i.hasNext();)
|
||||
{
|
||||
Map.Entry entry = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || !last) ? "| " : " ");
|
||||
out.append(indent).append("+@ ").append(String.valueOf(entry.getKey())).append(" = ");
|
||||
Object item = entry.getValue();
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out,nextIndent, item);
|
||||
}
|
||||
}
|
||||
|
||||
static Dumpable named(String name, Object object)
|
||||
{
|
||||
return (out, indent) ->
|
||||
{
|
||||
out.append(name).append(": ");
|
||||
Dumpable.dumpObjects(out, indent, object);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Uptime;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
|
||||
|
@ -102,7 +103,7 @@ public class Log
|
|||
// NOTE: cannot use jetty-util's StringUtil as that initializes logging itself.
|
||||
if (osName != null && osName.length() > 0)
|
||||
{
|
||||
osName = osName.toLowerCase(Locale.ENGLISH).replace(' ','-');
|
||||
osName = StringUtil.replace(osName.toLowerCase(Locale.ENGLISH), ' ', '-');
|
||||
loadProperties("jetty-logging-" + osName + ".properties",__props);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.List;
|
|||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -326,8 +327,8 @@ public class JarFileResource extends JarResource
|
|||
String dir=_urlString.substring(_urlString.lastIndexOf("!/")+2);
|
||||
while(e.hasMoreElements())
|
||||
{
|
||||
JarEntry entry = e.nextElement();
|
||||
String name=entry.getName().replace('\\','/');
|
||||
JarEntry entry = e.nextElement();
|
||||
String name = StringUtil.replace(entry.getName(), '\\', '/');
|
||||
if(!name.startsWith(dir) || name.length()==dir.length())
|
||||
{
|
||||
continue;
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.jar.JarInputStream;
|
|||
import java.util.jar.Manifest;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -212,7 +213,7 @@ public class JarResource extends URLResource
|
|||
continue;
|
||||
}
|
||||
|
||||
String dotCheck = entryName.replace('\\', '/');
|
||||
String dotCheck = StringUtil.replace(entryName, '\\', '/');
|
||||
dotCheck = URIUtil.canonicalPath(dotCheck);
|
||||
if (dotCheck == null)
|
||||
{
|
||||
|
|
|
@ -18,15 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import static org.eclipse.jetty.util.PathWatcher.PathWatchEventType.ADDED;
|
||||
import static org.eclipse.jetty.util.PathWatcher.PathWatchEventType.DELETED;
|
||||
import static org.eclipse.jetty.util.PathWatcher.PathWatchEventType.MODIFIED;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -52,6 +43,15 @@ import org.junit.jupiter.api.Disabled;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import static org.eclipse.jetty.util.PathWatcher.PathWatchEventType.ADDED;
|
||||
import static org.eclipse.jetty.util.PathWatcher.PathWatchEventType.DELETED;
|
||||
import static org.eclipse.jetty.util.PathWatcher.PathWatchEventType.MODIFIED;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Disabled
|
||||
@ExtendWith(WorkDirExtension.class)
|
||||
public class PathWatcherTest
|
||||
|
@ -111,7 +111,7 @@ public class PathWatcherTest
|
|||
synchronized (events)
|
||||
{
|
||||
Path relativePath = this.baseDir.relativize(event.getPath());
|
||||
String key = relativePath.toString().replace(File.separatorChar,'/');
|
||||
String key = StringUtil.replace(relativePath.toString(), File.separatorChar, '/');
|
||||
|
||||
List<PathWatchEventType> types = this.events.get(key);
|
||||
if (types == null)
|
||||
|
|
|
@ -18,19 +18,21 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.emptyArray;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class StringUtilTest
|
||||
|
@ -98,7 +100,36 @@ public class StringUtilTest
|
|||
|
||||
s=" \u0690bc ";
|
||||
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
|
||||
|
@ -165,50 +196,6 @@ public class StringUtilTest
|
|||
assertEquals(sid5, StringUtil.sidBytesToString(sid5Bytes));
|
||||
assertEquals(sid6, StringUtil.sidBytesToString(sid6Bytes));
|
||||
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
|
||||
|
|
|
@ -18,18 +18,22 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/**
|
||||
* URIUtil Tests.
|
||||
*/
|
||||
|
@ -314,4 +318,109 @@ public class URIUtilTest
|
|||
assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar")),is(new URI("file:///tmp/foo.jar")));
|
||||
assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar!/some/path")),is(new URI("file:///tmp/foo.jar")));
|
||||
}
|
||||
|
||||
public static Stream<String[]> encodeSpaces()
|
||||
{
|
||||
List<String[]> data = new ArrayList<>();
|
||||
|
||||
// [raw, expected]
|
||||
|
||||
// null
|
||||
data.add(new String[]{null, null});
|
||||
|
||||
// no spaces
|
||||
data.add(new String[]{"abc", "abc"});
|
||||
|
||||
// match
|
||||
data.add(new String[]{"a c", "a%20c"});
|
||||
data.add(new String[]{" ", "%20%20%20"});
|
||||
data.add(new String[]{"a%20space", "a%20space"});
|
||||
|
||||
return data.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource(value = "encodeSpaces")
|
||||
public void testEncodeSpaces(String raw, String expected)
|
||||
{
|
||||
assertThat(URIUtil.encodeSpaces(raw), is(expected));
|
||||
}
|
||||
|
||||
public static Stream<String[]> encodeSpecific()
|
||||
{
|
||||
List<String[]> data = new ArrayList<>();
|
||||
|
||||
// [raw, chars, expected]
|
||||
|
||||
// null input
|
||||
data.add(new String[]{null, null, null});
|
||||
|
||||
// null chars
|
||||
data.add(new String[]{"abc", null, "abc"});
|
||||
|
||||
// empty chars
|
||||
data.add(new String[]{"abc", "", "abc"});
|
||||
|
||||
// no matches
|
||||
data.add(new String[]{"abc", ".;", "abc"});
|
||||
data.add(new String[]{"xyz", ".;", "xyz"});
|
||||
data.add(new String[]{":::", ".;", ":::"});
|
||||
|
||||
// matches
|
||||
data.add(new String[]{"a c", " ", "a%20c"});
|
||||
data.add(new String[]{"name=value", "=", "name%3Dvalue"});
|
||||
data.add(new String[]{"This has fewer then 10% hits.", ".%", "This has fewer then 10%25 hits%2E"});
|
||||
|
||||
// partially encoded already
|
||||
data.add(new String[]{"a%20name=value%20pair", "=", "a%20name%3Dvalue%20pair"});
|
||||
data.add(new String[]{"a%20name=value%20pair", "=%", "a%2520name%3Dvalue%2520pair"});
|
||||
|
||||
return data.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource(value = "encodeSpecific")
|
||||
public void testEncodeSpecific(String raw, String chars, String expected)
|
||||
{
|
||||
assertThat(URIUtil.encodeSpecific(raw, chars), is(expected));
|
||||
}
|
||||
|
||||
public static Stream<String[]> decodeSpecific()
|
||||
{
|
||||
List<String[]> data = new ArrayList<>();
|
||||
|
||||
// [raw, chars, expected]
|
||||
|
||||
// null input
|
||||
data.add(new String[]{null, null, null});
|
||||
|
||||
// null chars
|
||||
data.add(new String[]{"abc", null, "abc"});
|
||||
|
||||
// empty chars
|
||||
data.add(new String[]{"abc", "", "abc"});
|
||||
|
||||
// no matches
|
||||
data.add(new String[]{"abc", ".;", "abc"});
|
||||
data.add(new String[]{"xyz", ".;", "xyz"});
|
||||
data.add(new String[]{":::", ".;", ":::"});
|
||||
|
||||
// matches
|
||||
data.add(new String[]{"a%20c", " ", "a c"});
|
||||
data.add(new String[]{"name%3Dvalue", "=", "name=value"});
|
||||
data.add(new String[]{"This has fewer then 10%25 hits%2E", ".%", "This has fewer then 10% hits."});
|
||||
|
||||
// partially decode
|
||||
data.add(new String[]{"a%20name%3Dvalue%20pair", "=", "a%20name=value%20pair"});
|
||||
data.add(new String[]{"a%2520name%3Dvalue%2520pair", "=%", "a%20name=value%20pair"});
|
||||
|
||||
return data.stream();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource(value = "decodeSpecific")
|
||||
public void testDecodeSpecific(String raw, String chars, String expected)
|
||||
{
|
||||
assertThat(URIUtil.decodeSpecific(raw, chars), is(expected));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,11 +48,12 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
|||
|
||||
private class RunningJob implements Runnable
|
||||
{
|
||||
private final CountDownLatch _run = new CountDownLatch(1);
|
||||
private final CountDownLatch _stopping = new CountDownLatch(1);
|
||||
private final CountDownLatch _stopped = new CountDownLatch(1);
|
||||
private final String _name;
|
||||
private final boolean _fail;
|
||||
final CountDownLatch _run = new CountDownLatch(1);
|
||||
final CountDownLatch _stopping = new CountDownLatch(1);
|
||||
final CountDownLatch _stopped = new CountDownLatch(1);
|
||||
final String _name;
|
||||
final boolean _fail;
|
||||
|
||||
RunningJob()
|
||||
{
|
||||
this(null, false);
|
||||
|
@ -118,7 +119,7 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
|||
|
||||
private class CloseableJob extends RunningJob implements Closeable
|
||||
{
|
||||
private final CountDownLatch _closed = new CountDownLatch(1);
|
||||
final CountDownLatch _closed = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
|
@ -382,24 +383,24 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
|||
// Wait until the first 2 start running
|
||||
waitForThreads(tp,2);
|
||||
waitForIdle(tp,0);
|
||||
assertTrue(job0._run.await(200, TimeUnit.MILLISECONDS));
|
||||
assertTrue(job1._run.await(200, TimeUnit.MILLISECONDS));
|
||||
|
||||
// Queue should be empty after thread pool is stopped
|
||||
tp.stop();
|
||||
assertThat(tp.getQueue().size(), is(0));
|
||||
|
||||
// First 2 jobs closed by InterruptedException
|
||||
assertThat(job0._stopped.await(200, TimeUnit.MILLISECONDS), is(true));
|
||||
assertThat(job1._stopped.await(200, TimeUnit.MILLISECONDS), is(true));
|
||||
assertTrue(job0._stopped.await(200, TimeUnit.MILLISECONDS));
|
||||
assertTrue(job1._stopped.await(200, TimeUnit.MILLISECONDS));
|
||||
|
||||
// Verify RunningJobs in the queue have not been run
|
||||
assertThat(job2._run.await(200, TimeUnit.MILLISECONDS), is(false));
|
||||
assertThat(job4._run.await(200, TimeUnit.MILLISECONDS), is(false));
|
||||
assertFalse(job2._run.await(200, TimeUnit.MILLISECONDS));
|
||||
assertFalse(job4._run.await(200, TimeUnit.MILLISECONDS));
|
||||
|
||||
// Verify ClosableJobs have not been run but have been closed
|
||||
assertThat(job4._run.await(200, TimeUnit.MILLISECONDS), is(false));
|
||||
assertThat(job3._closed.await(200, TimeUnit.MILLISECONDS), is(true));
|
||||
|
||||
tp.stop();
|
||||
assertFalse(job3._run.await(200, TimeUnit.MILLISECONDS));
|
||||
assertTrue(job3._closed.await(200, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.util.function.Supplier;
|
|||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.util.ArrayTernaryTrie;
|
||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -703,7 +704,7 @@ public class ClasspathPattern extends AbstractSet<String>
|
|||
name=name.substring(0,name.length()-6);
|
||||
|
||||
// Treat path elements as packages for name matching
|
||||
name=name.replace("/",".");
|
||||
name = StringUtil.replace(name, '/', '.');
|
||||
|
||||
return combine(_packageOrNamePatterns, name, _locations, ()->
|
||||
{
|
||||
|
|
|
@ -41,7 +41,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
|
||||
import org.eclipse.jetty.util.ClassVisibilityChecker;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -338,12 +339,10 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
if(LOG.isDebugEnabled())
|
||||
LOG.debug("addJar - {}", fn);
|
||||
String fnlc=fn.getName().toLowerCase(Locale.ENGLISH);
|
||||
// don't check if this is a directory, see Bug 353165
|
||||
// don't check if this is a directory (prevents use of symlinks), see Bug 353165
|
||||
if (isFileSupported(fnlc))
|
||||
{
|
||||
String jar=fn.toString();
|
||||
jar=StringUtil.replace(jar, ",", "%2C");
|
||||
jar=StringUtil.replace(jar, ";", "%3B");
|
||||
String jar = URIUtil.encodeSpecific(fn.toString(), ",;");
|
||||
addClassPath(jar);
|
||||
}
|
||||
}
|
||||
|
@ -498,7 +497,9 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
// Try the parent loader
|
||||
try
|
||||
{
|
||||
parent_class = _parent.loadClass(name);
|
||||
parent_class = _parent.loadClass(name);
|
||||
if (parent_class == null)
|
||||
throw new ClassNotFoundException("Bad ClassLoader: returned null for loadClass(" + name + ")");
|
||||
|
||||
// If the webapp is allowed to see this class
|
||||
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parent_class))
|
||||
|
@ -630,7 +631,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
// Look in the webapp classloader as a resource, to avoid
|
||||
// loading a system class.
|
||||
Class<?> webapp_class = null;
|
||||
String path = name.replace('.', '/').concat(".class");
|
||||
String path = TypeUtil.toClassReference(name);
|
||||
URL webapp_url = findResource(path);
|
||||
|
||||
if (webapp_url!=null && (!checkSystemResource || !_context.isSystemResource(name,webapp_url)))
|
||||
|
@ -656,7 +657,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
return super.findClass(name);
|
||||
}
|
||||
|
||||
String path = name.replace('.', '/').concat(".class");
|
||||
String path = TypeUtil.toClassReference(name);
|
||||
URL url = findResource(path);
|
||||
if (url==null)
|
||||
throw new ClassNotFoundException(name);
|
||||
|
@ -723,7 +724,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode());
|
||||
return String.format("%s{%s}@%x", this.getClass().getSimpleName(), _name, hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -34,7 +34,6 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRegistration.Dynamic;
|
||||
import javax.servlet.ServletSecurityElement;
|
||||
|
@ -1040,15 +1039,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
public String toString()
|
||||
{
|
||||
if (_war!=null)
|
||||
{
|
||||
String war=_war;
|
||||
if (war.indexOf("/webapps/")>=0)
|
||||
war=war.substring(war.indexOf("/webapps/")+8);
|
||||
return super.toString()+"{"+war+"}";
|
||||
}
|
||||
return super.toString()+"{"+_war+"}";
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
|
@ -1066,15 +1060,39 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
server_classes=new ArrayList<>(_serverClasses);
|
||||
Collections.sort(server_classes);
|
||||
}
|
||||
|
||||
|
||||
String name = getDisplayName();
|
||||
if (name == null)
|
||||
{
|
||||
if (_war != null)
|
||||
{
|
||||
if (_war.indexOf("/webapps/") >= 0)
|
||||
name = _war.substring(_war.indexOf("/webapps/") + 8);
|
||||
else
|
||||
name = _war;
|
||||
}
|
||||
else if (getResourceBase() != null)
|
||||
{
|
||||
name = getResourceBase();
|
||||
if (name.indexOf("/webapps/") >= 0)
|
||||
name = name.substring(name.indexOf("/webapps/") + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = this.getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
name = String.format("%s@%x", name, hashCode());
|
||||
|
||||
dumpObjects(out,indent,
|
||||
new ClassLoaderDump(getClassLoader()),
|
||||
new DumpableCollection("Systemclasses "+this,system_classes),
|
||||
new DumpableCollection("Serverclasses "+this,server_classes),
|
||||
new DumpableCollection("Configurations "+this,_configurations),
|
||||
new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet()),
|
||||
new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet()),
|
||||
new DumpableCollection("Initparams "+this,getInitParams().entrySet())
|
||||
new DumpableCollection("Systemclasses " + name, system_classes),
|
||||
new DumpableCollection("Serverclasses " + name, server_classes),
|
||||
new DumpableCollection("Configurations " + name, _configurations),
|
||||
new DumpableCollection("Handler attributes " + name, ((AttributesMap)getAttributes()).getAttributeEntrySet()),
|
||||
new DumpableCollection("Context attributes " + name, ((Context)getServletContext()).getAttributeEntrySet()),
|
||||
new DumpableCollection("Initparams " + name, getInitParams().entrySet())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.JavaVersion;
|
||||
import org.eclipse.jetty.util.PatternMatcher;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -210,7 +211,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
containerUris.add(new URI(u.toString().replaceAll(" ", "%20")));
|
||||
containerUris.add(new URI(URIUtil.encodeSpaces(u.toString())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -811,10 +812,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
|
||||
//Context name
|
||||
String contextPath = context.getContextPath();
|
||||
contextPath=contextPath.replace('/','_');
|
||||
contextPath=contextPath.replace('\\','_');
|
||||
canonicalName.append(contextPath);
|
||||
canonicalName.append(context.getContextPath());
|
||||
|
||||
//Virtual host (if there is one)
|
||||
canonicalName.append("-");
|
||||
|
@ -824,17 +822,9 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
else
|
||||
canonicalName.append(vhosts[0]);
|
||||
|
||||
// sanitize
|
||||
for (int i=0;i<canonicalName.length();i++)
|
||||
{
|
||||
char c=canonicalName.charAt(i);
|
||||
if (!Character.isJavaIdentifierPart(c) && "-.".indexOf(c)<0)
|
||||
canonicalName.setCharAt(i,'.');
|
||||
}
|
||||
|
||||
canonicalName.append("-");
|
||||
|
||||
return canonicalName.toString();
|
||||
return StringUtil.sanitizeFileSystemName(canonicalName.toString());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
@ -38,9 +35,8 @@ import org.eclipse.jetty.server.handler.HandlerCollection;
|
|||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.IO;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
|
@ -51,6 +47,9 @@ import org.eclipse.jetty.webapp.WebAppContext;
|
|||
import org.eclipse.jetty.webapp.WebInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebXmlConfiguration;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
|
||||
/**
|
||||
* Utility to build out exploded directory WebApps, in the /target/tests/ directory, for testing out servers that use javax.websocket endpoints.
|
||||
|
@ -88,7 +87,7 @@ public class WSServer
|
|||
public void copyClass(Class<?> clazz) throws Exception
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
String endpointPath = clazz.getName().replace('.','/') + ".class";
|
||||
String endpointPath = TypeUtil.toClassReference(clazz);
|
||||
URL classUrl = cl.getResource(endpointPath);
|
||||
assertThat("Class URL for: " + clazz,classUrl,notNullValue());
|
||||
File destFile = Paths.get( classesDir.toString(), FS.separators( endpointPath)).toFile();
|
||||
|
|
|
@ -34,12 +34,8 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
|
@ -58,52 +54,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
|
||||
public class WebSocketConnectionStatsTest
|
||||
{
|
||||
|
||||
@WebSocket
|
||||
public static class ClientSocket
|
||||
{
|
||||
CountDownLatch closed = new CountDownLatch(1);
|
||||
int closeStatus;
|
||||
String closeReason;
|
||||
String behavior;
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(Session session)
|
||||
{
|
||||
behavior = session.getPolicy().getBehavior().name();
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
closeStatus = statusCode;
|
||||
closeReason = reason;
|
||||
closed.countDown();
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable cause)
|
||||
{
|
||||
cause.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("[%s@%s]", behavior, Integer.toHexString(hashCode()));
|
||||
}
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class EchoSocket extends ClientSocket
|
||||
{
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(Session session, String message)
|
||||
{
|
||||
session.getRemote().sendString(message, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyWebSocketServlet extends WebSocketServlet
|
||||
{
|
||||
@Override
|
||||
|
@ -113,11 +63,12 @@ public class WebSocketConnectionStatsTest
|
|||
}
|
||||
}
|
||||
|
||||
Server server;
|
||||
WebSocketClient client;
|
||||
ConnectionStatistics statistics;
|
||||
CountDownLatch wsUpgradeComplete = new CountDownLatch(1);
|
||||
CountDownLatch wsConnectionClosed = new CountDownLatch(1);
|
||||
private Server server;
|
||||
private ServerConnector connector;
|
||||
private WebSocketClient client;
|
||||
private ConnectionStatistics statistics;
|
||||
private CountDownLatch wsUpgradeComplete = new CountDownLatch(1);
|
||||
private CountDownLatch wsConnectionClosed = new CountDownLatch(1);
|
||||
|
||||
@BeforeEach
|
||||
public void start() throws Exception
|
||||
|
@ -137,8 +88,7 @@ public class WebSocketConnectionStatsTest
|
|||
};
|
||||
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(8080);
|
||||
connector = new ServerConnector(server);
|
||||
connector.addBean(statistics);
|
||||
server.addConnector(connector);
|
||||
|
||||
|
@ -173,8 +123,8 @@ public class WebSocketConnectionStatsTest
|
|||
@Test
|
||||
public void echoStatsTest() throws Exception
|
||||
{
|
||||
URI uri = URI.create("ws://localhost:8080/testPath");
|
||||
ClientSocket socket = new ClientSocket();
|
||||
URI uri = URI.create("ws://localhost:"+connector.getLocalPort()+"/testPath");
|
||||
EventSocket socket = new EventSocket();
|
||||
Future<Session> connect = client.connect(socket, uri);
|
||||
|
||||
final long numMessages = 10000;
|
||||
|
@ -193,9 +143,11 @@ public class WebSocketConnectionStatsTest
|
|||
{
|
||||
session.getRemote().sendString(msgText);
|
||||
}
|
||||
session.close(StatusCode.NORMAL, null);
|
||||
|
||||
assertTrue(socket.closed.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(wsConnectionClosed.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
assertTrue(socket.closed.await(5, TimeUnit.SECONDS));
|
||||
assertTrue(wsConnectionClosed.await(5, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(statistics.getConnectionsMax(), is(1L));
|
||||
assertThat(statistics.getConnections(), is(0L));
|
||||
|
@ -204,7 +156,7 @@ public class WebSocketConnectionStatsTest
|
|||
assertThat(statistics.getReceivedMessages(), is(numMessages + 2L));
|
||||
|
||||
WebSocketFrame textFrame = new TextFrame().setPayload(msgText);
|
||||
WebSocketFrame closeFrame = new CloseInfo(socket.closeStatus, socket.closeReason).asFrame();
|
||||
WebSocketFrame closeFrame = new CloseInfo(socket.closeCode, socket.closeReason).asFrame();
|
||||
|
||||
final long textFrameSize = getFrameByteSize(textFrame);
|
||||
final long closeFrameSize = getFrameByteSize(closeFrame);
|
||||
|
|
|
@ -80,7 +80,6 @@ public class BadNetworkTest
|
|||
server = new Server();
|
||||
|
||||
connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
context = new ServletContextHandler();
|
||||
|
|
|
@ -119,7 +119,6 @@ public class ClientCloseTest
|
|||
server = new Server();
|
||||
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
|
|
|
@ -63,7 +63,6 @@ public class ClientSessionsTest
|
|||
server = new Server();
|
||||
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
|
|
|
@ -65,7 +65,6 @@ public class SlowClientTest
|
|||
server = new Server();
|
||||
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
|
|
|
@ -65,7 +65,6 @@ public class ServerCloseTest
|
|||
server = new Server();
|
||||
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
|
|
|
@ -64,7 +64,6 @@ public class SlowServerTest
|
|||
server = new Server();
|
||||
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
|
|
|
@ -84,7 +84,10 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke
|
|||
|
||||
if (ssl == null)
|
||||
{
|
||||
this.sslContextFactory = new SslContextFactory.Server();
|
||||
if (policy.getBehavior() == WebSocketBehavior.CLIENT)
|
||||
this.sslContextFactory = new SslContextFactory.Client();
|
||||
else if (policy.getBehavior() == WebSocketBehavior.SERVER)
|
||||
this.sslContextFactory = new SslContextFactory.Server();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.eclipse.jetty.toolchain.test.IO;
|
|||
import org.eclipse.jetty.toolchain.test.JAR;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -82,7 +83,7 @@ public class WSServer
|
|||
public void copyClass(Class<?> clazz) throws Exception
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
String endpointPath = clazz.getName().replace('.','/') + ".class";
|
||||
String endpointPath = TypeUtil.toClassReference(clazz);
|
||||
URL classUrl = cl.getResource(endpointPath);
|
||||
assertThat("Class URL for: " + clazz,classUrl,notNullValue());
|
||||
File destFile = new File(classesDir,FS.separators(endpointPath));
|
||||
|
|
29
pom.xml
29
pom.xml
|
@ -283,7 +283,7 @@
|
|||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
<useReleaseProfile>false</useReleaseProfile>
|
||||
<goals>javadoc:aggregate-jar deploy</goals>
|
||||
<arguments>-Peclipse-release -Paggregate-javadoc-jar</arguments>
|
||||
<arguments>-Peclipse-release</arguments>
|
||||
<preparationGoals>clean install</preparationGoals>
|
||||
<mavenExecutorId>forked-path</mavenExecutorId>
|
||||
</configuration>
|
||||
|
@ -534,20 +534,18 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<charset>UTF-8</charset>
|
||||
<docencoding>UTF-8</docencoding>
|
||||
<encoding>UTF-8</encoding>
|
||||
<additionalparam>-html5</additionalparam>
|
||||
<docfilessubdirs>true</docfilessubdirs>
|
||||
<detectLinks>false</detectLinks>
|
||||
<detectJavaApiLink>false</detectJavaApiLink>
|
||||
<show>protected</show>
|
||||
<attach>true</attach>
|
||||
<excludePackageNames>com.acme,org.slf4j*,org.mortbay*,*.jmh*,org.eclipse.jetty.embedded*,org.eclipse.jetty.example.asyncrest*,org.eclipse.jetty.test*</excludePackageNames>
|
||||
<excludePackageNames>com.*:org.slf4j*:org.mortbay*:*.jmh*:org.eclipse.jetty.embedded*:org.eclipse.jetty.example.asyncrest*:org.eclipse.jetty.test*</excludePackageNames>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -1128,6 +1126,27 @@
|
|||
</pluginManagement>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>jdk11</id>
|
||||
<activation>
|
||||
<jdk>[11,)</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<additionalJOption>--no-module-directories</additionalJOption>
|
||||
<additionalOptions>-html5</additionalOptions>
|
||||
<excludePackageNames>com.*:org.slf4j*:org.mortbay*:*.jmh*:org.eclipse.jetty.embedded*:org.eclipse.jetty.example.asyncrest*:org.eclipse.jetty.test*</excludePackageNames>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>config</id>
|
||||
<activation>
|
||||
|
|
|
@ -18,18 +18,16 @@
|
|||
|
||||
package org.eclipse.jetty.test.support;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -39,9 +37,14 @@ import java.util.Properties;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.server.NetworkConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Allows for setting up a Jetty server for testing based on XML configuration files.
|
||||
*/
|
||||
|
@ -55,8 +58,8 @@ public class TestableJettyServer
|
|||
private String _scheme = HttpScheme.HTTP.asString();
|
||||
|
||||
/* Popular Directories */
|
||||
private File baseDir;
|
||||
private File testResourcesDir;
|
||||
private Path baseDir;
|
||||
private Path testResourcesDir;
|
||||
|
||||
public TestableJettyServer() throws IOException
|
||||
{
|
||||
|
@ -64,31 +67,28 @@ public class TestableJettyServer
|
|||
Properties properties = new Properties();
|
||||
|
||||
/* Establish Popular Directories */
|
||||
String baseDirPath = System.getProperty("basedir");
|
||||
if (baseDirPath == null)
|
||||
{
|
||||
baseDirPath = System.getProperty("user.dir",".");
|
||||
}
|
||||
baseDir = new File(baseDirPath);
|
||||
properties.setProperty("test.basedir",baseDir.getAbsolutePath());
|
||||
baseDir = MavenTestingUtils.getBasePath();
|
||||
properties.setProperty("test.basedir",baseDir.toString());
|
||||
|
||||
testResourcesDir = new File(baseDirPath,"src/test/resources".replace('/',File.separatorChar));
|
||||
properties.setProperty("test.resourcesdir",testResourcesDir.getAbsolutePath());
|
||||
testResourcesDir = MavenTestingUtils.getTestResourcesPath();
|
||||
properties.setProperty("test.resourcesdir",testResourcesDir.toString());
|
||||
|
||||
File testDocRoot = new File(testResourcesDir,"docroots");
|
||||
properties.setProperty("test.docroot.base",testDocRoot.getAbsolutePath());
|
||||
Path testDocRoot = MavenTestingUtils.getTestResourcePathDir("docroots");
|
||||
properties.setProperty("test.docroot.base",testDocRoot.toString());
|
||||
|
||||
File targetDir = new File(baseDir,"target");
|
||||
properties.setProperty("test.targetdir",targetDir.getAbsolutePath());
|
||||
Path targetDir = MavenTestingUtils.getTargetPath();
|
||||
properties.setProperty("test.targetdir",targetDir.toString());
|
||||
|
||||
File webappsDir = new File(targetDir,"webapps");
|
||||
properties.setProperty("test.webapps",webappsDir.getAbsolutePath());
|
||||
Path webappsDir = MavenTestingUtils.getTargetPath("webapps");
|
||||
properties.setProperty("test.webapps",webappsDir.toString());
|
||||
|
||||
// Write out configuration for use by ConfigurationManager.
|
||||
File testConfig = new File(targetDir,"testable-jetty-server-config.properties");
|
||||
FileOutputStream out = new FileOutputStream(testConfig);
|
||||
properties.store(out,"Generated by " + TestableJettyServer.class.getName());
|
||||
|
||||
Path testConfig = targetDir.resolve("testable-jetty-server-config.properties");
|
||||
try(OutputStream out = Files.newOutputStream(testConfig))
|
||||
{
|
||||
properties.store(out,"Generated by " + TestableJettyServer.class.getName());
|
||||
}
|
||||
|
||||
for (Object key:properties.keySet())
|
||||
_properties.put(String.valueOf(key),String.valueOf(properties.get(key)));
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ public class TestableJettyServer
|
|||
|
||||
public void addConfiguration(String testConfigName) throws MalformedURLException
|
||||
{
|
||||
addConfiguration(new File(testResourcesDir,testConfigName));
|
||||
addConfiguration(MavenTestingUtils.getTestResourceFile(testConfigName));
|
||||
}
|
||||
|
||||
public void setProperty(String key, String value)
|
||||
|
|
|
@ -21,7 +21,6 @@ package com.acme;
|
|||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
|
@ -29,7 +28,6 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Test Servlet Cookies.
|
||||
*/
|
||||
|
@ -117,9 +115,9 @@ public class CookieDump extends HttpServlet
|
|||
{
|
||||
if (string==null)
|
||||
return null;
|
||||
string=string.replace("&", "&");
|
||||
string=string.replace( "<", "<");
|
||||
string=string.replace( ">", ">");
|
||||
string = string.replace("&", "&");
|
||||
string = string.replace( "<", "<");
|
||||
string = string.replace( ">", ">");
|
||||
return string;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import java.util.Enumeration;
|
|||
import java.util.Locale;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
|
@ -57,13 +56,14 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Dump Servlet Request.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class Dump extends HttpServlet
|
||||
{
|
||||
/** Zero Width Space, to allow text to be wrapped at designated spots */
|
||||
private static final String ZWSP = "​";
|
||||
boolean fixed;
|
||||
Timer _timer;
|
||||
|
||||
|
@ -647,7 +647,7 @@ public class Dump extends HttpServlet
|
|||
{
|
||||
name= (String)a.nextElement();
|
||||
pout.write("</tr><tr>\n");
|
||||
pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+": </th>");
|
||||
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ": </th>");
|
||||
Object value=request.getAttribute(name);
|
||||
if (value instanceof File)
|
||||
{
|
||||
|
@ -678,7 +678,7 @@ public class Dump extends HttpServlet
|
|||
{
|
||||
name= (String)a.nextElement();
|
||||
pout.write("</tr><tr>\n");
|
||||
pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+": </th>");
|
||||
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ": </th>");
|
||||
pout.write("<td>"+ toString(getServletContext().getInitParameter(name)) + "</td>");
|
||||
}
|
||||
|
||||
|
@ -689,7 +689,7 @@ public class Dump extends HttpServlet
|
|||
{
|
||||
name= (String)a.nextElement();
|
||||
pout.write("</tr><tr>\n");
|
||||
pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+": </th>");
|
||||
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ": </th>");
|
||||
pout.write("<td>"+"<pre>" + toString(getServletContext().getAttribute(name)) + "</pre>"+"</td>");
|
||||
}
|
||||
|
||||
|
@ -1055,9 +1055,9 @@ public class Dump extends HttpServlet
|
|||
{
|
||||
if (s==null)
|
||||
return "null";
|
||||
s=s.replaceAll("&","&");
|
||||
s=s.replaceAll("<","<");
|
||||
s=s.replaceAll(">",">");
|
||||
s = s.replace("&","&");
|
||||
s = s.replace("<","<");
|
||||
s = s.replace(">",">");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.net.URISyntaxException;
|
|||
import java.net.URL;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
|
Loading…
Reference in New Issue