Merge branch 'master' into session-refactor
This commit is contained in:
commit
599696bfc5
72
VERSION.txt
72
VERSION.txt
|
@ -1,5 +1,77 @@
|
|||
jetty-9.4.0-SNAPSHOT
|
||||
|
||||
jetty-9.3.7.v20160115 - 15 January 2016
|
||||
+ 471171 Support SYNC_FLUSH in GzipHandler
|
||||
+ 485469 permessage-deflate extension causes protocol error in Firefox/Chrome
|
||||
+ 485714 Update SSL configuration to mitigate SLOTH vulnerability
|
||||
+ 485884 WebAppContext defaults should be same for xml or war deployment
|
||||
+ 485969 WebSocket upgrade response should honor HttpConfiguration server
|
||||
version settings
|
||||
|
||||
jetty-9.3.7.RC1 - 13 January 2016
|
||||
+ 481986 Dead JSR 356 Server Session still being tracked after
|
||||
Session/Connection closure
|
||||
+ 484616 Outdated version of javaee_web_services_client_1_2.xsd
|
||||
+ 485031 two PathWatcher threads running after automatically restarting webapp
|
||||
+ 485063 After stopping JettyWebAppContext, it still contains reference to old
|
||||
WebAppClassLoader via ServerContainer bean
|
||||
+ 485064 HashSessionManager leaks ScheduledExecutorScheduler with reference to
|
||||
un-deployed webapp
|
||||
+ 485376 Multiple charset attributes in Content-Type
|
||||
+ 485535 jetty.sh results in FAILED when running service restart
|
||||
+ 485663 NullPointerException in WebSocketSession during upgrade with DEBUG
|
||||
logging
|
||||
+ 485712 Quickstart web.xml is absolute
|
||||
|
||||
jetty-9.3.7.RC0 - 05 January 2016
|
||||
+ 458745 Async ISE in async Echo
|
||||
+ 481567 permessage-deflate causing data-dependent ju.zip.DataFormatException:
|
||||
invalid stored block lengths
|
||||
+ 482173 Track original Query string in Rewrite RuleContainer too
|
||||
+ 482243 Fixed GzipHandler for Include.
|
||||
+ 482270 Expose upgrade request locales.
|
||||
+ 482272 Fixed relative symlink checking
|
||||
+ 482506 HTTP/2 load test with h2load fails.
|
||||
+ 482670 HttpURI wrongly parser URI paths starting with /@
|
||||
+ 482855 Content-Length omitted for POST requests with empty body
|
||||
+ 482959 Local stream count never decrements when closing a stream causing
|
||||
IllegalStateException.
|
||||
+ 483009 MultiPartContentProvider may send wrong Content-Length.
|
||||
+ 483039 HTTP2 Upgrade case sensitivity on Connection header
|
||||
+ 483344 text/csv Mime Type For CSV in mime properties File
|
||||
+ 483413 Warn on @Deprecated servlet/filter use
|
||||
+ 483422 Empty chunked body in 304 Response
|
||||
+ 483620 Servlet annotation mapping to "/" should override webdefault.xml
|
||||
mapping
|
||||
+ 483857 jetty-client onComplete isn't called in case of exception in
|
||||
GZIPContentDecoder.
|
||||
+ 483878 Parallel requests stuck via the http client transport over HTTP/2.
|
||||
+ 484167 GOAWAY frames aren't handling disconnects appropriately on Client.
|
||||
+ 484210 HttpClient over HTTP/2 should honor maxConcurrentStreams.
|
||||
+ 484262 Race condition between GOAWAY disconnect and ability to make new
|
||||
request.
|
||||
+ 484349 Promote WebSocket PathMappings / PathSpec to Jetty Http
|
||||
+ 484350 Allow GzipHandler path include/exclude to use regex
|
||||
+ 484397 Unavoidable NullPointerException in onMessage-Handler for
|
||||
PongMessages
|
||||
+ 484440 Swap WebSocket PathMappings for new jetty-http PathMappings
|
||||
+ 484585 Avoid sending request using a connection that is idle timing out.
|
||||
+ 484603 HashLoginService does not stop its PropertyUserStore
|
||||
+ 484612 Restore WebSocket Session.close() sending 1000/Normal status code
|
||||
+ 484621 Client hangs till timeout when Authentication.authenticate() throws
|
||||
exception.
|
||||
+ 484622 Improve handling of Direct and Mapped buffers for static content
|
||||
+ 484624 Disable CachingWebAppClassLoader
|
||||
+ 484657 Support HSTS rfc6797
|
||||
+ 484683 FastCGI request idle timeout is handled incorrectly.
|
||||
+ 484718 Review idle timeout handling.
|
||||
+ 484801 Avoid non-cached memory mapped files
|
||||
+ 484818 Expose interesting HTTP/2 attributes and operations via JMX.
|
||||
+ 484822 Jetty ThreadMonitor memory leak
|
||||
+ 484861 Improve FlowControlStrategy stall handling.
|
||||
+ 484876 Make simpler to customize the FlowControlStrategy.
|
||||
+ 484878 Make BufferingFlowControlStrategy.bufferRatio configurable via JMX.
|
||||
|
||||
jetty-9.3.6.v20151106 - 06 November 2015
|
||||
+ 419966 Add ContentProvider that submits multipart/form-data.
|
||||
+ 472675 No main manifest attribute, in jetty-runner regression
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
|
@ -244,6 +244,28 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
return _tempDirectory;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void initializeWebAppContextDefaults(WebAppContext webapp)
|
||||
{
|
||||
if (_defaultsDescriptor != null)
|
||||
webapp.setDefaultsDescriptor(_defaultsDescriptor);
|
||||
webapp.setExtractWAR(_extractWars);
|
||||
webapp.setParentLoaderPriority(_parentLoaderPriority);
|
||||
if (_configurationClasses != null)
|
||||
webapp.setConfigurationClasses(_configurationClasses);
|
||||
|
||||
if (_tempDirectory != null)
|
||||
{
|
||||
/* Since the Temp Dir is really a context base temp directory,
|
||||
* Lets set the Temp Directory in a way similar to how WebInfConfiguration does it,
|
||||
* instead of setting the WebAppContext.setTempDirectory(File).
|
||||
* If we used .setTempDirectory(File) all webapps will wind up in the
|
||||
* same temp / work directory, overwriting each others work.
|
||||
*/
|
||||
webapp.setAttribute(WebAppContext.BASETEMPDIR, _tempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ContextHandler createContextHandler(final App app) throws Exception
|
||||
|
@ -267,9 +289,7 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
if (context instanceof WebAppContext)
|
||||
{
|
||||
WebAppContext webapp = (WebAppContext)context;
|
||||
webapp.setParentLoaderPriority(_parentLoaderPriority);
|
||||
if (_defaultsDescriptor != null)
|
||||
webapp.setDefaultsDescriptor(_defaultsDescriptor);
|
||||
initializeWebAppContextDefaults(webapp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -327,31 +347,10 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
context = "/" + context;
|
||||
}
|
||||
|
||||
|
||||
webAppContext.setContextPath(context);
|
||||
webAppContext.setWar(file.getAbsolutePath());
|
||||
if (_defaultsDescriptor != null)
|
||||
{
|
||||
webAppContext.setDefaultsDescriptor(_defaultsDescriptor);
|
||||
}
|
||||
webAppContext.setExtractWAR(_extractWars);
|
||||
webAppContext.setParentLoaderPriority(_parentLoaderPriority);
|
||||
if (_configurationClasses != null)
|
||||
{
|
||||
webAppContext.setConfigurationClasses(_configurationClasses);
|
||||
}
|
||||
initializeWebAppContextDefaults(webAppContext);
|
||||
|
||||
if (_tempDirectory != null)
|
||||
{
|
||||
/* Since the Temp Dir is really a context base temp directory,
|
||||
* Lets set the Temp Directory in a way similar to how WebInfConfiguration does it,
|
||||
* instead of setting the
|
||||
* WebAppContext.setTempDirectory(File).
|
||||
* If we used .setTempDirectory(File) all webapps will wind up in the
|
||||
* same temp / work directory, overwriting each others work.
|
||||
*/
|
||||
webAppContext.setAttribute(WebAppContext.BASETEMPDIR, _tempDirectory);
|
||||
}
|
||||
return webAppContext;
|
||||
}
|
||||
|
||||
|
|
|
@ -785,7 +785,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.gcloud</groupId>
|
||||
<artifactId>gcloud-session-manager</artifactId>
|
||||
<artifactId>jetty-gcloud-session-manager</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -527,6 +527,7 @@ case "$ACTION" in
|
|||
|
||||
restart)
|
||||
JETTY_SH=$0
|
||||
> "$JETTY_STATE"
|
||||
if [ ! -f $JETTY_SH ]; then
|
||||
if [ ! -f $JETTY_HOME/bin/jetty.sh ]; then
|
||||
echo "$JETTY_HOME/bin/jetty.sh does not exist."
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>gcloud-session-manager</artifactId>
|
||||
<artifactId>jetty-gcloud-session-manager</artifactId>
|
||||
<name>Jetty :: GCloud :: Session Manager</name>
|
||||
|
||||
<dependencies>
|
|
@ -40,7 +40,7 @@ maven://com.google.api-client/google-api-client/1.15.0-rc|lib/gcloud/google-api-
|
|||
maven://com.google.apis/google-api-services-datastore/v1beta2-rev23-1.19.0|lib/gcloud/google-api-services-datastore-v1beta2-rev23-1.19.0.jar
|
||||
|
||||
[lib]
|
||||
lib/gcloud-session-manager-${jetty.version}.jar
|
||||
lib/jetty-gcloud-session-manager-${jetty.version}.jar
|
||||
lib/gcloud/*.jar
|
||||
|
||||
[xml]
|
|
@ -17,7 +17,7 @@
|
|||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>gcloud-session-manager</module>
|
||||
<module>jetty-gcloud-session-manager</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -20,10 +20,13 @@ package org.eclipse.jetty.http.pathmap;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.jetty.util.ArrayTernaryTrie;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -42,10 +45,12 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(PathMappings.class);
|
||||
private List<MappedResource<E>> mappings = new ArrayList<MappedResource<E>>();
|
||||
private MappedResource<E> defaultResource = null;
|
||||
private MappedResource<E> rootResource = null;
|
||||
|
||||
private final Set<MappedResource<E>> _mappings = new TreeSet<>();
|
||||
|
||||
private Trie<MappedResource<E>> _exactMap=new ArrayTernaryTrie<>(false);
|
||||
private Trie<MappedResource<E>> _prefixMap=new ArrayTernaryTrie<>(false);
|
||||
private Trie<MappedResource<E>> _suffixMap=new ArrayTernaryTrie<>(false);
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
{
|
||||
|
@ -55,18 +60,25 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
|
|||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
ContainerLifeCycle.dump(out,indent,mappings);
|
||||
ContainerLifeCycle.dump(out,indent,_mappings);
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "mappings", readonly = true)
|
||||
public List<MappedResource<E>> getMappings()
|
||||
{
|
||||
return mappings;
|
||||
return new ArrayList<>(_mappings);
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return _mappings.size();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
mappings.clear();
|
||||
_mappings.clear();
|
||||
_prefixMap.clear();
|
||||
_suffixMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,22 +89,19 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
|
|||
*/
|
||||
public List<MappedResource<E>> getMatches(String path)
|
||||
{
|
||||
boolean matchRoot = "/".equals(path);
|
||||
boolean isRootPath = "/".equals(path);
|
||||
|
||||
List<MappedResource<E>> ret = new ArrayList<>();
|
||||
int len = mappings.size();
|
||||
for (int i = 0; i < len; i++)
|
||||
for (MappedResource<E> mr :_mappings)
|
||||
{
|
||||
MappedResource<E> mr = mappings.get(i);
|
||||
|
||||
switch (mr.getPathSpec().group)
|
||||
{
|
||||
case ROOT:
|
||||
if (matchRoot)
|
||||
if (isRootPath)
|
||||
ret.add(mr);
|
||||
break;
|
||||
case DEFAULT:
|
||||
if (matchRoot || mr.getPathSpec().matches(path))
|
||||
if (isRootPath || mr.getPathSpec().matches(path))
|
||||
ret.add(mr);
|
||||
break;
|
||||
default:
|
||||
|
@ -106,54 +115,160 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
|
|||
|
||||
public MappedResource<E> getMatch(String path)
|
||||
{
|
||||
if (path.equals("/") && rootResource != null)
|
||||
PathSpecGroup last_group=null;
|
||||
|
||||
// Search all the mappings
|
||||
for (MappedResource<E> mr : _mappings)
|
||||
{
|
||||
return rootResource;
|
||||
PathSpecGroup group=mr.getPathSpec().getGroup();
|
||||
if (group!=last_group)
|
||||
{
|
||||
// New group in list, so let's look for an optimization
|
||||
switch(group)
|
||||
{
|
||||
case EXACT:
|
||||
{
|
||||
int i= path.length();
|
||||
final Trie<MappedResource<E>> exact_map=_exactMap;
|
||||
while(i>=0)
|
||||
{
|
||||
MappedResource<E> candidate=exact_map.getBest(path,0,i);
|
||||
if (candidate==null)
|
||||
break;
|
||||
if (candidate.getPathSpec().matches(path))
|
||||
return candidate;
|
||||
i=candidate.getPathSpec().getPrefix().length()-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PREFIX_GLOB:
|
||||
{
|
||||
int i= path.length();
|
||||
final Trie<MappedResource<E>> prefix_map=_prefixMap;
|
||||
while(i>=0)
|
||||
{
|
||||
MappedResource<E> candidate=prefix_map.getBest(path,0,i);
|
||||
if (candidate==null)
|
||||
break;
|
||||
if (candidate.getPathSpec().matches(path))
|
||||
return candidate;
|
||||
i=candidate.getPathSpec().getPrefix().length()-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SUFFIX_GLOB:
|
||||
{
|
||||
int i=0;
|
||||
final Trie<MappedResource<E>> suffix_map=_suffixMap;
|
||||
while ((i=path.indexOf('.',i+1))>0)
|
||||
{
|
||||
MappedResource<E> candidate=suffix_map.get(path,i+1,path.length()-i-1);
|
||||
if (candidate!=null && candidate.getPathSpec().matches(path))
|
||||
return candidate;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if (mr.getPathSpec().matches(path))
|
||||
return mr;
|
||||
|
||||
last_group=group;
|
||||
}
|
||||
|
||||
int len = mappings.size();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
MappedResource<E> mr = mappings.get(i);
|
||||
if (mr.getPathSpec().matches(path))
|
||||
{
|
||||
return mr;
|
||||
}
|
||||
}
|
||||
return defaultResource;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<MappedResource<E>> iterator()
|
||||
{
|
||||
return mappings.iterator();
|
||||
return _mappings.iterator();
|
||||
}
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public void put(PathSpec pathSpec, E resource)
|
||||
public static PathSpec asPathSpec(String pathSpecString)
|
||||
{
|
||||
if ((pathSpecString == null) || (pathSpecString.length() < 1))
|
||||
{
|
||||
throw new RuntimeException("Path Spec String must start with '^', '/', or '*.': got [" + pathSpecString + "]");
|
||||
}
|
||||
return pathSpecString.charAt(0) == '^' ? new RegexPathSpec(pathSpecString):new ServletPathSpec(pathSpecString);
|
||||
}
|
||||
|
||||
public boolean put(String pathSpecString, E resource)
|
||||
{
|
||||
return put(asPathSpec(pathSpecString),resource);
|
||||
}
|
||||
|
||||
public boolean put(PathSpec pathSpec, E resource)
|
||||
{
|
||||
MappedResource<E> entry = new MappedResource<>(pathSpec,resource);
|
||||
switch (pathSpec.group)
|
||||
{
|
||||
case DEFAULT:
|
||||
defaultResource = entry;
|
||||
case EXACT:
|
||||
String exact = pathSpec.getPrefix();
|
||||
while (exact!=null && !_exactMap.put(exact,entry))
|
||||
_exactMap=new ArrayTernaryTrie<>((ArrayTernaryTrie<MappedResource<E>>)_exactMap,1.5);
|
||||
break;
|
||||
case ROOT:
|
||||
rootResource = entry;
|
||||
case PREFIX_GLOB:
|
||||
String prefix = pathSpec.getPrefix();
|
||||
while (prefix!=null && !_prefixMap.put(prefix,entry))
|
||||
_prefixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie<MappedResource<E>>)_prefixMap,1.5);
|
||||
break;
|
||||
case SUFFIX_GLOB:
|
||||
String suffix = pathSpec.getSuffix();
|
||||
while (suffix!=null && !_suffixMap.put(suffix,entry))
|
||||
_suffixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie<MappedResource<E>>)_prefixMap,1.5);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
boolean added =_mappings.add(entry);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} {} to {}",added?"Added":"Ignored",entry,this);
|
||||
return added;
|
||||
}
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public boolean remove(PathSpec pathSpec)
|
||||
{
|
||||
switch (pathSpec.group)
|
||||
{
|
||||
case EXACT:
|
||||
_exactMap.remove(pathSpec.getPrefix());
|
||||
break;
|
||||
case PREFIX_GLOB:
|
||||
_prefixMap.remove(pathSpec.getPrefix());
|
||||
break;
|
||||
case SUFFIX_GLOB:
|
||||
_suffixMap.remove(pathSpec.getSuffix());
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: add warning when replacing an existing pathspec?
|
||||
|
||||
mappings.add(entry);
|
||||
Iterator<MappedResource<E>> iter = _mappings.iterator();
|
||||
boolean removed=false;
|
||||
while (iter.hasNext())
|
||||
{
|
||||
if (iter.next().getPathSpec().equals(pathSpec))
|
||||
{
|
||||
removed=true;
|
||||
iter.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Added {} to {}",entry,this);
|
||||
Collections.sort(mappings);
|
||||
LOG.debug("{} {} to {}",removed?"Removed":"Ignored",pathSpec,this);
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[size=%d]",this.getClass().getSimpleName(),mappings.size());
|
||||
return String.format("%s[size=%d]",this.getClass().getSimpleName(),_mappings.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ public abstract class PathSpec implements Comparable<PathSpec>
|
|||
protected PathSpecGroup group;
|
||||
protected int pathDepth;
|
||||
protected int specLength;
|
||||
protected String prefix;
|
||||
protected String suffix;
|
||||
|
||||
@Override
|
||||
public int compareTo(PathSpec other)
|
||||
|
@ -124,6 +126,24 @@ public abstract class PathSpec implements Comparable<PathSpec>
|
|||
return pathSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple prefix match for the pathspec or null
|
||||
* @return A simple prefix match for the pathspec or null
|
||||
*/
|
||||
public String getPrefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple suffix match for the pathspec or null
|
||||
* @return A simple suffix match for the pathspec or null
|
||||
*/
|
||||
public String getSuffix()
|
||||
{
|
||||
return suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relative path.
|
||||
*
|
||||
|
|
|
@ -34,6 +34,17 @@ public enum PathSpecGroup
|
|||
{
|
||||
// NOTE: Order of enums determines order of Groups.
|
||||
|
||||
/**
|
||||
* The root spec for accessing the Root behavior.
|
||||
*
|
||||
* <pre>
|
||||
* "" - servlet spec (Root Servlet)
|
||||
* null - servlet spec (Root Servlet)
|
||||
* </pre>
|
||||
*
|
||||
* Note: there is no known uri-template spec variant of this kind of path spec
|
||||
*/
|
||||
ROOT,
|
||||
/**
|
||||
* For exactly defined path specs, no glob.
|
||||
*/
|
||||
|
@ -74,17 +85,6 @@ public enum PathSpecGroup
|
|||
* Note: there is no known uri-template spec variant of this kind of path spec
|
||||
*/
|
||||
SUFFIX_GLOB,
|
||||
/**
|
||||
* The root spec for accessing the Root behavior.
|
||||
*
|
||||
* <pre>
|
||||
* "" - servlet spec (Root Servlet)
|
||||
* null - servlet spec (Root Servlet)
|
||||
* </pre>
|
||||
*
|
||||
* Note: there is no known uri-template spec variant of this kind of path spec
|
||||
*/
|
||||
ROOT,
|
||||
/**
|
||||
* The default spec for accessing the Default path behavior.
|
||||
*
|
||||
|
|
|
@ -18,12 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.http.pathmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
|
@ -31,54 +27,16 @@ import java.util.function.Predicate;
|
|||
* <p>
|
||||
* Used by {@link org.eclipse.jetty.util.IncludeExclude} logic
|
||||
*/
|
||||
public class PathSpecSet implements Set<String>, Predicate<String>
|
||||
public class PathSpecSet extends AbstractSet<String> implements Predicate<String>
|
||||
{
|
||||
private final Set<PathSpec> specs = new TreeSet<>();
|
||||
private final PathMappings<Boolean> specs = new PathMappings<>();
|
||||
|
||||
@Override
|
||||
public boolean test(String s)
|
||||
{
|
||||
for (PathSpec spec : specs)
|
||||
{
|
||||
if (spec.matches(s))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return specs.getMatch(s)!=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return specs.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator()
|
||||
{
|
||||
return new Iterator<String>()
|
||||
{
|
||||
private Iterator<PathSpec> iter = specs.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return iter.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next()
|
||||
{
|
||||
PathSpec spec = iter.next();
|
||||
if (spec == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return spec.getDeclaration();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
|
@ -86,20 +44,6 @@ public class PathSpecSet implements Set<String>, Predicate<String>
|
|||
return specs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
if (o instanceof PathSpec)
|
||||
{
|
||||
return specs.contains(o);
|
||||
}
|
||||
if (o instanceof String)
|
||||
{
|
||||
return specs.contains(toPathSpec((String)o));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private PathSpec asPathSpec(Object o)
|
||||
{
|
||||
if (o == null)
|
||||
|
@ -112,48 +56,15 @@ public class PathSpecSet implements Set<String>, Predicate<String>
|
|||
}
|
||||
if (o instanceof String)
|
||||
{
|
||||
return toPathSpec((String)o);
|
||||
}
|
||||
return toPathSpec(o.toString());
|
||||
}
|
||||
|
||||
private PathSpec toPathSpec(String rawSpec)
|
||||
{
|
||||
if ((rawSpec == null) || (rawSpec.length() < 1))
|
||||
{
|
||||
throw new RuntimeException("Path Spec String must start with '^', '/', or '*.': got [" + rawSpec + "]");
|
||||
}
|
||||
if (rawSpec.charAt(0) == '^')
|
||||
{
|
||||
return new RegexPathSpec(rawSpec);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ServletPathSpec(rawSpec);
|
||||
return PathMappings.asPathSpec((String)o);
|
||||
}
|
||||
return PathMappings.asPathSpec(o.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray()
|
||||
public boolean add(String s)
|
||||
{
|
||||
return toArray(new String[specs.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a)
|
||||
{
|
||||
int i = 0;
|
||||
for (PathSpec spec : specs)
|
||||
{
|
||||
a[i++] = (T)spec.getDeclaration();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(String e)
|
||||
{
|
||||
return specs.add(toPathSpec(e));
|
||||
return specs.put(PathMappings.asPathSpec(s),Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -162,55 +73,30 @@ public class PathSpecSet implements Set<String>, Predicate<String>
|
|||
return specs.remove(asPathSpec(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> coll)
|
||||
{
|
||||
for (Object o : coll)
|
||||
{
|
||||
if (!specs.contains(asPathSpec(o)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends String> coll)
|
||||
{
|
||||
boolean ret = false;
|
||||
|
||||
for (String s : coll)
|
||||
{
|
||||
ret |= add(s);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> coll)
|
||||
{
|
||||
List<PathSpec> collSpecs = new ArrayList<>();
|
||||
for (Object o : coll)
|
||||
{
|
||||
collSpecs.add(asPathSpec(o));
|
||||
}
|
||||
return specs.retainAll(collSpecs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> coll)
|
||||
{
|
||||
List<PathSpec> collSpecs = new ArrayList<>();
|
||||
for (Object o : coll)
|
||||
{
|
||||
collSpecs.add(asPathSpec(o));
|
||||
}
|
||||
return specs.removeAll(collSpecs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
specs.clear();
|
||||
specs.reset();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator()
|
||||
{
|
||||
final Iterator<MappedResource<Boolean>> iterator = specs.iterator();
|
||||
return new Iterator<String>()
|
||||
{
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next()
|
||||
{
|
||||
return iterator.next().getPathSpec().getDeclaration();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,15 +54,18 @@ public class ServletPathSpec extends PathSpec
|
|||
if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*'))
|
||||
{
|
||||
this.group = PathSpecGroup.PREFIX_GLOB;
|
||||
this.prefix = servletPathSpec.substring(0,specLength-2);
|
||||
}
|
||||
// suffix based
|
||||
else if (servletPathSpec.charAt(0) == '*')
|
||||
{
|
||||
this.group = PathSpecGroup.SUFFIX_GLOB;
|
||||
this.suffix = servletPathSpec.substring(2,specLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.group = PathSpecGroup.EXACT;
|
||||
this.prefix = servletPathSpec;
|
||||
}
|
||||
|
||||
for (int i = 0; i < specLength; i++)
|
||||
|
@ -109,6 +112,11 @@ public class ServletPathSpec extends PathSpec
|
|||
{
|
||||
throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec \""+ servletPathSpec +"\"");
|
||||
}
|
||||
|
||||
if (idx<1 || servletPathSpec.charAt(idx-1)!='/')
|
||||
{
|
||||
throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix glob '*' can only exist after '/': bad spec \""+ servletPathSpec +"\"");
|
||||
}
|
||||
}
|
||||
else if (servletPathSpec.startsWith("*."))
|
||||
{
|
||||
|
|
|
@ -278,4 +278,14 @@ public class PathMappingsTest
|
|||
assertEquals("suffix",p.getMatch("/foo/something.txt").getResource());
|
||||
assertEquals("prefix",p.getMatch("/dump/gzip/something.txt").getResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadPathSpecs()
|
||||
{
|
||||
try{new ServletPathSpec("*");Assert.fail();}catch(IllegalArgumentException e){}
|
||||
try{new ServletPathSpec("/foo/*/bar");Assert.fail();}catch(IllegalArgumentException e){}
|
||||
try{new ServletPathSpec("/foo*");Assert.fail();}catch(IllegalArgumentException e){}
|
||||
try{new ServletPathSpec("*/foo");Assert.fail();}catch(IllegalArgumentException e){}
|
||||
try{new ServletPathSpec("*.foo/*");Assert.fail();}catch(IllegalArgumentException e){}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -316,12 +316,6 @@
|
|||
<artifactId>http2-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty.alpn</groupId>
|
||||
<artifactId>alpn-boot</artifactId>
|
||||
<version>${alpn.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-alpn</artifactId>
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 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.quickstart;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Normalize Attribute to String.
|
||||
* <p>Replaces and expands:
|
||||
* <ul>
|
||||
* <li>${WAR}</li>
|
||||
* <li>${jetty.base}</li>
|
||||
* <li>${jetty.home}</li>
|
||||
* <li>${user.home}</li>
|
||||
* <li>${user.dir}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class AttributeNormalizer
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AttributeNormalizer.class);
|
||||
private final Path _warPath;
|
||||
private final Path _jettyBasePath;
|
||||
private final Path _jettyHomePath;
|
||||
private final Path _userHomePath;
|
||||
private final Path _userDirPath;
|
||||
|
||||
|
||||
public AttributeNormalizer(Resource baseResource)
|
||||
{
|
||||
try
|
||||
{
|
||||
_warPath=baseResource==null?null:baseResource.getFile().toPath();
|
||||
_jettyBasePath=systemPath("jetty.base");
|
||||
_jettyHomePath=systemPath("jetty.home");
|
||||
_userHomePath=systemPath("user.home");
|
||||
_userDirPath=systemPath("user.dir");
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Path systemPath(String property) throws Exception
|
||||
{
|
||||
String p=System.getProperty(property);
|
||||
if (p!=null)
|
||||
return new File(p).getAbsoluteFile().getCanonicalFile().toPath();
|
||||
return null;
|
||||
}
|
||||
|
||||
public String normalize(Object o)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Find a URI
|
||||
URI uri=null;
|
||||
if (o instanceof URI)
|
||||
uri=(URI)o;
|
||||
else if (o instanceof URL)
|
||||
uri = ((URL)o).toURI();
|
||||
else if (o instanceof File)
|
||||
uri = ((File)o).toURI();
|
||||
else
|
||||
{
|
||||
String s=o.toString();
|
||||
uri=new URI(s);
|
||||
if (uri.getScheme()==null)
|
||||
return s;
|
||||
}
|
||||
|
||||
if ("jar".equalsIgnoreCase(uri.getScheme()))
|
||||
{
|
||||
String raw = uri.getRawSchemeSpecificPart();
|
||||
int bang=raw.indexOf("!/");
|
||||
String normal=normalize(raw.substring(0,bang));
|
||||
String suffix=raw.substring(bang);
|
||||
return "jar:"+normal+suffix;
|
||||
}
|
||||
else if ("file".equalsIgnoreCase(uri.getScheme()))
|
||||
{
|
||||
return "file:"+normalizePath(new File(uri).toPath());
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
return String.valueOf(o);
|
||||
}
|
||||
|
||||
public String normalizePath(Path path)
|
||||
{
|
||||
if (_warPath!=null && path.startsWith(_warPath))
|
||||
return URIUtil.addPaths("${WAR}",_warPath.relativize(path).toString());
|
||||
if (_jettyBasePath!=null && path.startsWith(_jettyBasePath))
|
||||
return URIUtil.addPaths("${jetty.base}",_jettyBasePath.relativize(path).toString());
|
||||
if (_jettyHomePath!=null && path.startsWith(_jettyHomePath))
|
||||
return URIUtil.addPaths("${jetty.home}",_jettyHomePath.relativize(path).toString());
|
||||
if (_userHomePath!=null && path.startsWith(_userHomePath))
|
||||
return URIUtil.addPaths("${user.home}",_userHomePath.relativize(path).toString());
|
||||
if (_userDirPath!=null && path.startsWith(_userDirPath))
|
||||
return URIUtil.addPaths("${user.dir}",_userDirPath.relativize(path).toString());
|
||||
|
||||
return path.toString();
|
||||
}
|
||||
|
||||
|
||||
public String expand(String s)
|
||||
{
|
||||
int i=s.indexOf("${");
|
||||
if (i<0)
|
||||
return s;
|
||||
int e=s.indexOf('}',i+3);
|
||||
String prop=s.substring(i+2,e);
|
||||
switch(prop)
|
||||
{
|
||||
case "WAR":
|
||||
return s.substring(0,i)+_warPath+expand(s.substring(e+1));
|
||||
case "jetty.base":
|
||||
return s.substring(0,i)+_jettyBasePath+expand(s.substring(e+1));
|
||||
case "jetty.home":
|
||||
return s.substring(0,i)+_jettyHomePath+expand(s.substring(e+1));
|
||||
case "user.home":
|
||||
return s.substring(0,i)+_userHomePath+expand(s.substring(e+1));
|
||||
case "user.dir":
|
||||
return s.substring(0,i)+_userDirPath+expand(s.substring(e+1));
|
||||
default:
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,9 @@ package org.eclipse.jetty.quickstart;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EventListener;
|
||||
|
@ -55,6 +58,7 @@ import org.eclipse.jetty.servlet.ServletMapping;
|
|||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.webapp.MetaData;
|
||||
import org.eclipse.jetty.webapp.MetaData.OriginInfo;
|
||||
|
@ -128,16 +132,16 @@ public class QuickStartDescriptorGenerator
|
|||
// Set some special context parameters
|
||||
|
||||
// The location of the war file on disk
|
||||
String resourceBase = _webApp.getBaseResource().getFile().getCanonicalFile().getAbsoluteFile().toURI().toString();
|
||||
AttributeNormalizer normalizer = new AttributeNormalizer(_webApp.getBaseResource());
|
||||
|
||||
// The library order
|
||||
addContextParamFromAttribute(out,ServletContext.ORDERED_LIBS);
|
||||
//the servlet container initializers
|
||||
addContextParamFromAttribute(out,AnnotationConfiguration.CONTAINER_INITIALIZERS);
|
||||
//the tlds discovered
|
||||
addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,resourceBase);
|
||||
addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,normalizer);
|
||||
//the META-INF/resources discovered
|
||||
addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,resourceBase);
|
||||
addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,normalizer);
|
||||
|
||||
|
||||
// init params
|
||||
|
@ -515,7 +519,27 @@ public class QuickStartDescriptorGenerator
|
|||
*/
|
||||
private void addContextParamFromAttribute(XmlAppendable out, String attribute) throws IOException
|
||||
{
|
||||
addContextParamFromAttribute(out,attribute,null);
|
||||
Object o = _webApp.getAttribute(attribute);
|
||||
if (o == null)
|
||||
return;
|
||||
|
||||
Collection<?> c = (o instanceof Collection)? (Collection<?>)o:Collections.singletonList(o);
|
||||
StringBuilder v=new StringBuilder();
|
||||
for (Object i:c)
|
||||
{
|
||||
if (i!=null)
|
||||
{
|
||||
if (v.length()>0)
|
||||
v.append(",\n ");
|
||||
else
|
||||
v.append("\n ");
|
||||
QuotedStringTokenizer.quote(v,i.toString());
|
||||
}
|
||||
}
|
||||
out.openTag("context-param")
|
||||
.tag("param-name",attribute)
|
||||
.tagCDATA("param-value",v.toString())
|
||||
.closeTag();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -526,7 +550,7 @@ public class QuickStartDescriptorGenerator
|
|||
* @param resourceBase
|
||||
* @throws IOException
|
||||
*/
|
||||
private void addContextParamFromAttribute(XmlAppendable out, String attribute, String resourceBase) throws IOException
|
||||
private void addContextParamFromAttribute(XmlAppendable out, String attribute, AttributeNormalizer normalizer) throws IOException
|
||||
{
|
||||
Object o = _webApp.getAttribute(attribute);
|
||||
if (o == null)
|
||||
|
@ -542,16 +566,14 @@ public class QuickStartDescriptorGenerator
|
|||
v.append(",\n ");
|
||||
else
|
||||
v.append("\n ");
|
||||
if (resourceBase==null)
|
||||
QuotedStringTokenizer.quote(v,i.toString());
|
||||
else
|
||||
QuotedStringTokenizer.quote(v,i.toString().replace(resourceBase,"${WAR}/"));
|
||||
QuotedStringTokenizer.quote(v,normalizer.normalize(i));
|
||||
}
|
||||
}
|
||||
out.openTag("context-param")
|
||||
.tag("param-name",attribute)
|
||||
.tagCDATA("param-value",v.toString())
|
||||
.closeTag();
|
||||
.closeTag();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -99,6 +99,7 @@ public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
values.add(value);
|
||||
}
|
||||
|
||||
AttributeNormalizer normalizer = new AttributeNormalizer(context.getBaseResource());
|
||||
// handle values
|
||||
switch(name)
|
||||
{
|
||||
|
@ -125,15 +126,14 @@ public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
case MetaInfConfiguration.METAINF_TLDS:
|
||||
{
|
||||
List<Object> tlds = new ArrayList<>();
|
||||
String war=context.getBaseResource().getURI().toString();
|
||||
Object o=context.getAttribute(MetaInfConfiguration.METAINF_TLDS);
|
||||
if (o instanceof Collection<?>)
|
||||
tlds.addAll((Collection<?>)o);
|
||||
for (String i : values)
|
||||
{
|
||||
Resource r = Resource.newResource(i.replace("${WAR}/",war));
|
||||
Resource r = Resource.newResource(normalizer.expand(i));
|
||||
if (r.exists())
|
||||
tlds.add(r.getURL());
|
||||
tlds.add(r.getURI().toURL());
|
||||
else
|
||||
throw new IllegalArgumentException("TLD not found: "+r);
|
||||
}
|
||||
|
@ -145,10 +145,9 @@ public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
|
||||
case MetaInfConfiguration.METAINF_RESOURCES:
|
||||
{
|
||||
String war=context.getBaseResource().getURI().toString();
|
||||
for (String i : values)
|
||||
{
|
||||
Resource r = Resource.newResource(i.replace("${WAR}/",war));
|
||||
Resource r = Resource.newResource(normalizer.expand(i));
|
||||
if (r.exists())
|
||||
visitMetaInfResource(context,r);
|
||||
else
|
||||
|
|
|
@ -184,12 +184,11 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
|||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Customizes the request attributes for general secure settings.
|
||||
* The default impl calls {@link Request#setSecure(boolean)} with true
|
||||
* and sets a response header if the Strict-Transport-Security options
|
||||
* are set.
|
||||
* </p>
|
||||
* @param request the request being customized
|
||||
*/
|
||||
protected void customizeSecure(Request request)
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/** ContextHandlerCollection.
|
||||
*
|
||||
* This {@link org.eclipse.jetty.server.handler.HandlerCollection} is creates a
|
||||
* {@link org.eclipse.jetty.http.PathMap} to it's contained handlers based
|
||||
* Map of contexts to it's contained handlers based
|
||||
* on the context path and virtual hosts of any contained {@link org.eclipse.jetty.server.handler.ContextHandler}s.
|
||||
* The contexts do not need to be directly contained, only children of the contained handlers.
|
||||
* Multiple contexts may have the same context path and they are called in order until one
|
||||
|
|
|
@ -68,6 +68,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
|||
private int _minGzipSize=DEFAULT_MIN_GZIP_SIZE;
|
||||
private int _compressionLevel=Deflater.DEFAULT_COMPRESSION;
|
||||
private boolean _checkGzExists = true;
|
||||
private boolean _syncFlush = false;
|
||||
|
||||
// non-static, as other GzipHandler instances may have different configurations
|
||||
private final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>();
|
||||
|
@ -193,6 +194,27 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
|||
_methods.include(m);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if {@link Deflater#SYNC_FLUSH} is used, else {@link Deflater#NO_FLUSH}
|
||||
*/
|
||||
public boolean isSyncFlush()
|
||||
{
|
||||
return _syncFlush;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* <p>Set the {@link Deflater} flush mode to use. {@link Deflater#SYNC_FLUSH}
|
||||
* should be used if the application wishes to stream the data, but this may
|
||||
* hurt compression performance.
|
||||
* @param syncFlush True if {@link Deflater#SYNC_FLUSH} is used, else {@link Deflater#NO_FLUSH}
|
||||
*/
|
||||
public void setSyncFlush(boolean syncFlush)
|
||||
{
|
||||
_syncFlush = syncFlush;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Add included mime types. Inclusion takes precedence over
|
||||
|
@ -465,7 +487,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
|
|||
}
|
||||
|
||||
// install interceptor and handle
|
||||
out.setInterceptor(new GzipHttpOutputInterceptor(this,_vary,baseRequest.getHttpChannel(),out.getInterceptor()));
|
||||
out.setInterceptor(new GzipHttpOutputInterceptor(this,_vary,baseRequest.getHttpChannel(),out.getInterceptor(),_syncFlush));
|
||||
if (_handler!=null)
|
||||
_handler.handle(target,baseRequest, request, response);
|
||||
}
|
||||
|
|
|
@ -56,27 +56,29 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
private final HttpChannel _channel;
|
||||
private final HttpField _vary;
|
||||
private final int _bufferSize;
|
||||
private final boolean _syncFlush;
|
||||
|
||||
private Deflater _deflater;
|
||||
private ByteBuffer _buffer;
|
||||
|
||||
public GzipHttpOutputInterceptor(GzipFactory factory, HttpChannel channel, HttpOutput.Interceptor next)
|
||||
public GzipHttpOutputInterceptor(GzipFactory factory, HttpChannel channel, HttpOutput.Interceptor next,boolean syncFlush)
|
||||
{
|
||||
this(factory,VARY_ACCEPT_ENCODING_USER_AGENT,channel.getHttpConfiguration().getOutputBufferSize(),channel,next);
|
||||
this(factory,VARY_ACCEPT_ENCODING_USER_AGENT,channel.getHttpConfiguration().getOutputBufferSize(),channel,next,syncFlush);
|
||||
}
|
||||
|
||||
public GzipHttpOutputInterceptor(GzipFactory factory, HttpField vary, HttpChannel channel, HttpOutput.Interceptor next)
|
||||
public GzipHttpOutputInterceptor(GzipFactory factory, HttpField vary, HttpChannel channel, HttpOutput.Interceptor next,boolean syncFlush)
|
||||
{
|
||||
this(factory,vary,channel.getHttpConfiguration().getOutputBufferSize(),channel,next);
|
||||
this(factory,vary,channel.getHttpConfiguration().getOutputBufferSize(),channel,next,syncFlush);
|
||||
}
|
||||
|
||||
public GzipHttpOutputInterceptor(GzipFactory factory, HttpField vary, int bufferSize, HttpChannel channel, HttpOutput.Interceptor next)
|
||||
public GzipHttpOutputInterceptor(GzipFactory factory, HttpField vary, int bufferSize, HttpChannel channel, HttpOutput.Interceptor next,boolean syncFlush)
|
||||
{
|
||||
_factory=factory;
|
||||
_channel=channel;
|
||||
_interceptor=next;
|
||||
_vary=vary;
|
||||
_bufferSize=bufferSize;
|
||||
_syncFlush=syncFlush;
|
||||
}
|
||||
|
||||
public HttpOutput.Interceptor getNextInterceptor()
|
||||
|
@ -353,7 +355,7 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
|
|||
int len=_buffer.capacity()-_buffer.limit() - (_last?8:0);
|
||||
if (len>0)
|
||||
{
|
||||
int produced=_deflater.deflate(_buffer.array(),off,len,Deflater.NO_FLUSH);
|
||||
int produced=_deflater.deflate(_buffer.array(),off,len,_syncFlush?Deflater.SYNC_FLUSH:Deflater.NO_FLUSH);
|
||||
_buffer.limit(_buffer.limit()+produced);
|
||||
}
|
||||
boolean finished=_deflater.finished();
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.net.Socket;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -36,6 +37,7 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Test;
|
||||
|
@ -58,8 +60,8 @@ public class SSLCloseTest
|
|||
server.addConnector(connector);
|
||||
server.setHandler(new WriteHandler());
|
||||
server.start();
|
||||
|
||||
SSLContext ctx=SSLContext.getInstance("SSLv3");
|
||||
|
||||
SSLContext ctx=SSLContext.getInstance("TLSv1.2");
|
||||
ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
|
||||
|
||||
int port=connector.getLocalPort();
|
||||
|
|
|
@ -189,7 +189,7 @@ public class SSLEngineTest
|
|||
|
||||
Socket[] client=new Socket[numConns];
|
||||
|
||||
SSLContext ctx=SSLContext.getInstance("SSLv3");
|
||||
SSLContext ctx=SSLContext.getInstance("TLSv1.2");
|
||||
ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
|
||||
|
||||
int port=connector.getLocalPort();
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
|
@ -0,0 +1,8 @@
|
|||
[name]
|
||||
protonego-boot
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
|
@ -250,14 +250,10 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
setTrustAll(trustAll);
|
||||
addExcludeProtocols("SSL", "SSLv2", "SSLv2Hello", "SSLv3");
|
||||
setExcludeCipherSuites(
|
||||
"SSL_RSA_WITH_DES_CBC_SHA",
|
||||
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
|
||||
"^.*_RSA_.*_(MD5|SHA|SHA1)$",
|
||||
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
|
||||
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
|
||||
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
|
||||
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
|
||||
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of SslContextFactory
|
||||
|
|
|
@ -222,7 +222,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testAddPath() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
|
||||
Path subdir = dir.resolve("sub");
|
||||
FS.ensureDirExists(subdir.toFile());
|
||||
|
@ -240,7 +240,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testAddRootPath() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Path subdir = dir.resolve("sub");
|
||||
Files.createDirectories(subdir);
|
||||
|
||||
|
@ -288,7 +288,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testIsContainedIn() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
Files.createFile(foo);
|
||||
|
@ -303,7 +303,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testIsDirectory() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
Path foo = dir.resolve("foo");
|
||||
Files.createFile(foo);
|
||||
|
@ -324,7 +324,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testLastModified() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
File file = testdir.getFile("foo");
|
||||
file.createNewFile();
|
||||
|
||||
|
@ -340,7 +340,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testLastModified_NotExists() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
|
||||
try (Resource base = newResource(dir.toFile()))
|
||||
{
|
||||
|
@ -352,7 +352,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testLength() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path file = dir.resolve("foo");
|
||||
|
@ -375,7 +375,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testLength_NotExists() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try (Resource base = newResource(dir.toFile()))
|
||||
|
@ -388,7 +388,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testDelete() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
Path file = dir.resolve("foo");
|
||||
Files.createFile(file);
|
||||
|
@ -408,7 +408,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testDelete_NotExists() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try (Resource base = newResource(dir.toFile()))
|
||||
|
@ -426,7 +426,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testName() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
String expected = dir.toAbsolutePath().toString();
|
||||
|
@ -440,7 +440,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testInputStream() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path file = dir.resolve("foo");
|
||||
|
@ -466,7 +466,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testReadableByteChannel() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path file = dir.resolve("foo");
|
||||
|
@ -495,7 +495,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testGetURI() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path file = dir.resolve("foo");
|
||||
|
@ -514,7 +514,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testGetURL() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path file = dir.resolve("foo");
|
||||
|
@ -532,7 +532,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testList() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Files.createFile(dir.resolve("foo"));
|
||||
|
@ -561,7 +561,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testSymlink() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
|
||||
Path foo = dir.resolve("foo");
|
||||
Path bar = dir.resolve("bar");
|
||||
|
@ -601,7 +601,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testNonExistantSymlink() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path foo = dir.resolve("foo");
|
||||
|
@ -644,7 +644,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testCaseInsensitiveAlias() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
Path path = dir.resolve("file");
|
||||
Files.createFile(path);
|
||||
|
@ -681,7 +681,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testCase8dot3Alias() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path path = dir.resolve("TextFile.Long.txt");
|
||||
|
@ -718,7 +718,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testNTFSFileStreamAlias() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path path = dir.resolve("testfile");
|
||||
|
@ -761,7 +761,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testNTFSFileDataStreamAlias() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path path = dir.resolve("testfile");
|
||||
|
@ -806,7 +806,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testNTFSFileEncodedDataStreamAlias() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path path = dir.resolve("testfile");
|
||||
|
@ -843,7 +843,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testSemicolon() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -868,7 +868,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testSingleQuote() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try
|
||||
|
@ -894,7 +894,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testSingleBackTick() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try
|
||||
|
@ -923,7 +923,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testBrackets() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try
|
||||
|
@ -949,7 +949,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testBraces() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try
|
||||
|
@ -978,7 +978,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testCaret() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try
|
||||
|
@ -1007,7 +1007,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testPipe() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
try
|
||||
|
@ -1040,13 +1040,13 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testExist_Normal() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path path = dir.resolve("a.jsp");
|
||||
Files.createFile(path);
|
||||
|
||||
URI ref = testdir.getDir().toURI().resolve("a.jsp");
|
||||
URI ref = testdir.getPath().toUri().resolve("a.jsp");
|
||||
try (Resource fileres = newResource(ref))
|
||||
{
|
||||
assertThat("Resource: " + fileres,fileres.exists(),is(true));
|
||||
|
@ -1056,7 +1056,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testSingleQuoteInFileName() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path fooA = dir.resolve("foo's.txt");
|
||||
|
@ -1121,7 +1121,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testExist_BadURINull() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path path = dir.resolve("a.jsp");
|
||||
|
@ -1130,7 +1130,7 @@ public class FileSystemResourceTest
|
|||
try
|
||||
{
|
||||
// request with null at end
|
||||
URI uri = testdir.getDir().toURI().resolve("a.jsp%00");
|
||||
URI uri = testdir.getPath().toUri().resolve("a.jsp%00");
|
||||
assertThat("Null URI",uri,notNullValue());
|
||||
|
||||
Resource r = newResource(uri);
|
||||
|
@ -1147,7 +1147,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testExist_BadURINullX() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path path = dir.resolve("a.jsp");
|
||||
|
@ -1156,7 +1156,7 @@ public class FileSystemResourceTest
|
|||
try
|
||||
{
|
||||
// request with null and x at end
|
||||
URI uri = testdir.getDir().toURI().resolve("a.jsp%00x");
|
||||
URI uri = testdir.getPath().toUri().resolve("a.jsp%00x");
|
||||
assertThat("NullX URI",uri,notNullValue());
|
||||
|
||||
Resource r = newResource(uri);
|
||||
|
@ -1173,7 +1173,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testEncoding() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Files.createDirectories(dir);
|
||||
|
||||
Path specials = dir.resolve("a file with,spe#ials");
|
||||
|
@ -1192,7 +1192,7 @@ public class FileSystemResourceTest
|
|||
@Test
|
||||
public void testUtf8Dir() throws Exception
|
||||
{
|
||||
Path dir = testdir.getDir().toPath().normalize().toRealPath();
|
||||
Path dir = testdir.getPath().normalize().toRealPath();
|
||||
Path utf8Dir = dir.resolve("bãm");
|
||||
Files.createDirectories(utf8Dir);
|
||||
|
||||
|
@ -1209,4 +1209,6 @@ public class FileSystemResourceTest
|
|||
assertThat("Alias: " + r,r,hasNoAlias());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
|
@ -56,6 +57,20 @@ public class SslContextFactoryTest
|
|||
cf = new SslContextFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSLOTH() throws Exception
|
||||
{
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
||||
cf.start();
|
||||
|
||||
System.err.println(Arrays.asList(cf.getSelectedProtocols()));
|
||||
for (String cipher : cf.getSelectedCipherSuites())
|
||||
System.err.println(cipher);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoTsFileKs() throws Exception
|
||||
{
|
||||
|
|
|
@ -53,8 +53,6 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
|
|||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.client.io.UpgradeListener;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.SessionListener;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
|
@ -73,7 +71,7 @@ import org.eclipse.jetty.websocket.jsr356.metadata.EndpointMetadata;
|
|||
* <p>
|
||||
* This should be specific to a JVM if run in a standalone mode. or specific to a WebAppContext if running on the Jetty server.
|
||||
*/
|
||||
public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketContainerScope, SessionListener
|
||||
public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketContainerScope
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ClientContainer.class);
|
||||
|
||||
|
@ -105,8 +103,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
|
|||
this.scopeDelegate = scope;
|
||||
client = new WebSocketClient(scope, new SslContextFactory(trustAll));
|
||||
client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy()));
|
||||
SessionFactory sessionFactory = new JsrSessionFactory(this,this,client);
|
||||
client.setSessionFactory(sessionFactory);
|
||||
client.setSessionFactory(new JsrSessionFactory(this));
|
||||
addBean(client);
|
||||
|
||||
this.endpointClientMetadataCache = new ConcurrentHashMap<>();
|
||||
|
|
|
@ -44,7 +44,6 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.SessionListener;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver;
|
||||
|
@ -74,9 +73,9 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
private JsrAsyncRemote asyncRemote;
|
||||
private JsrBasicRemote basicRemote;
|
||||
|
||||
public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners)
|
||||
public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection)
|
||||
{
|
||||
super(container, requestURI, websocket, connection, sessionListeners);
|
||||
super(container, requestURI, websocket, connection);
|
||||
if (!(websocket instanceof AbstractJsrEventDriver))
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot use, not a JSR WebSocket: " + websocket);
|
||||
|
|
|
@ -19,36 +19,32 @@
|
|||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.SessionListener;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver;
|
||||
|
||||
public class JsrSessionFactory implements SessionFactory
|
||||
{
|
||||
private AtomicLong idgen = new AtomicLong(0);
|
||||
private static final Logger LOG = Log.getLogger(JsrSessionFactory.class);
|
||||
private final ClientContainer container;
|
||||
private final SessionListener[] listeners;
|
||||
|
||||
public JsrSessionFactory(ClientContainer container, SessionListener... sessionListeners)
|
||||
public JsrSessionFactory(ClientContainer container)
|
||||
{
|
||||
if(LOG.isDebugEnabled()) {
|
||||
LOG.debug("Container: {}", container);
|
||||
}
|
||||
this.container = container;
|
||||
this.listeners = sessionListeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
|
||||
{
|
||||
return new JsrSession(container,getNextId(),requestURI,websocket,connection,listeners);
|
||||
}
|
||||
|
||||
public String getNextId()
|
||||
{
|
||||
return String.format("websocket-%d",idgen.incrementAndGet());
|
||||
return new JsrSession(container,connection.getId(),requestURI,websocket,connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,6 +30,7 @@ import javax.websocket.server.ServerEndpointConfig;
|
|||
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSessionFactory;
|
||||
|
@ -56,7 +57,7 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
EventDriverFactory eventDriverFactory = this.webSocketServerFactory.getEventDriverFactory();
|
||||
eventDriverFactory.addImplementation(new JsrServerEndpointImpl());
|
||||
eventDriverFactory.addImplementation(new JsrServerExtendsEndpointImpl());
|
||||
this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this,this));
|
||||
this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this));
|
||||
addBean(webSocketServerFactory);
|
||||
}
|
||||
|
||||
|
@ -240,4 +241,16 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
// incoming streaming buffer size
|
||||
webSocketServerFactory.getPolicy().setMaxTextMessageBufferSize(max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionClosed(WebSocketSession session)
|
||||
{
|
||||
webSocketServerFactory.onSessionClosed(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionOpened(WebSocketSession session)
|
||||
{
|
||||
webSocketServerFactory.onSessionOpened(session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 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.websocket.jsr356.server;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SessionTrackingTest
|
||||
{
|
||||
public static class ClientSocket extends Endpoint
|
||||
{
|
||||
public Session session;
|
||||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config)
|
||||
{
|
||||
this.session = session;
|
||||
openLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Session session, CloseReason closeReason)
|
||||
{
|
||||
closeLatch.countDown();
|
||||
}
|
||||
|
||||
public void waitForOpen(long timeout, TimeUnit unit) throws InterruptedException
|
||||
{
|
||||
assertThat("ClientSocket opened",openLatch.await(timeout,unit),is(true));
|
||||
}
|
||||
|
||||
public void waitForClose(long timeout, TimeUnit unit) throws InterruptedException
|
||||
{
|
||||
assertThat("ClientSocket opened",closeLatch.await(timeout,unit),is(true));
|
||||
}
|
||||
}
|
||||
|
||||
@ServerEndpoint("/test")
|
||||
public static class EchoSocket
|
||||
{
|
||||
@OnMessage
|
||||
public String echo(String msg)
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
private static Server server;
|
||||
private static WebSocketServerFactory wsServerFactory;
|
||||
private static URI serverURI;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
ServerConnector serverConnector = new ServerConnector(server);
|
||||
serverConnector.setPort(0);
|
||||
server.addConnector(serverConnector);
|
||||
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
|
||||
servletContextHandler.setContextPath("/");
|
||||
server.setHandler(servletContextHandler);
|
||||
|
||||
ServerContainer serverContainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
|
||||
serverContainer.addEndpoint(EchoSocket.class);
|
||||
|
||||
wsServerFactory = serverContainer.getBean(WebSocketServerFactory.class);
|
||||
|
||||
server.start();
|
||||
|
||||
String host = serverConnector.getHost();
|
||||
if (StringUtil.isBlank(host))
|
||||
{
|
||||
host = "localhost";
|
||||
}
|
||||
serverURI = new URI("ws://" + host + ":" + serverConnector.getLocalPort());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
if (server == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveSessions() throws Exception
|
||||
{
|
||||
// Create Client
|
||||
ClientContainer clientContainer = new ClientContainer();
|
||||
try
|
||||
{
|
||||
clientContainer.start();
|
||||
|
||||
// Establish connections
|
||||
ClientSocket cli1 = new ClientSocket();
|
||||
clientContainer.connectToServer(cli1,serverURI.resolve("/test"));
|
||||
cli1.waitForOpen(1,TimeUnit.SECONDS);
|
||||
|
||||
// Assert open connections
|
||||
assertServerOpenConnectionCount(1);
|
||||
|
||||
// Establish new connection
|
||||
ClientSocket cli2 = new ClientSocket();
|
||||
clientContainer.connectToServer(cli2,serverURI.resolve("/test"));
|
||||
cli2.waitForOpen(1,TimeUnit.SECONDS);
|
||||
|
||||
// Assert open connections
|
||||
assertServerOpenConnectionCount(2);
|
||||
|
||||
// Establish close both connections
|
||||
cli1.session.close();
|
||||
cli2.session.close();
|
||||
|
||||
cli1.waitForClose(1,TimeUnit.SECONDS);
|
||||
cli2.waitForClose(1,TimeUnit.SECONDS);
|
||||
|
||||
// Assert open connections
|
||||
assertServerOpenConnectionCount(0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
clientContainer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertServerOpenConnectionCount(int expectedCount)
|
||||
{
|
||||
Collection<WebSocketSession> sessions = wsServerFactory.getBeans(WebSocketSession.class);
|
||||
int openCount = 0;
|
||||
for (WebSocketSession session : sessions)
|
||||
{
|
||||
assertThat("Session.isopen: " + session,session.isOpen(),is(true));
|
||||
openCount++;
|
||||
}
|
||||
assertThat("Open Session Count",openCount,is(expectedCount));
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@ package org.eclipse.jetty.websocket.jsr356.server.browser;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.websocket.DeploymentException;
|
||||
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
|
@ -79,7 +81,11 @@ public class JsrBrowserDebugTool
|
|||
private void setupServer(int port) throws DeploymentException, ServletException
|
||||
{
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
|
||||
HttpConfiguration httpConf = new HttpConfiguration();
|
||||
httpConf.setSendServerVersion(true);
|
||||
|
||||
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConf));
|
||||
connector.setPort(port);
|
||||
server.addConnector(connector);
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ org.eclipse.jetty.LEVEL=WARN
|
|||
# org.eclipse.jetty.websocket.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
|
||||
|
||||
org.eclipse.jetty.websocket.common.WebSocketSession.LEVEL=DEBUG
|
||||
org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG
|
||||
|
||||
### Show state changes on BrowserDebugTool
|
||||
# -- LEAVE THIS AT DEBUG LEVEL --
|
||||
org.eclipse.jetty.websocket.jsr356.server.browser.LEVEL=DEBUG
|
||||
|
|
|
@ -53,7 +53,6 @@ import org.eclipse.jetty.websocket.client.io.UpgradeListener;
|
|||
import org.eclipse.jetty.websocket.client.masks.Masker;
|
||||
import org.eclipse.jetty.websocket.client.masks.RandomMasker;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.SessionListener;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
@ -64,7 +63,7 @@ import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
|||
/**
|
||||
* WebSocketClient provides a means of establishing connections to remote websocket endpoints.
|
||||
*/
|
||||
public class WebSocketClient extends ContainerLifeCycle implements SessionListener, WebSocketContainerScope
|
||||
public class WebSocketClient extends ContainerLifeCycle implements WebSocketContainerScope
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketClient.class);
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.net.InetSocketAddress;
|
|||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.SuspendToken;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
|
@ -36,7 +35,7 @@ public interface LogicalConnection extends OutgoingFrames, SuspendToken
|
|||
* <p>
|
||||
* Basic usage: results in an non-blocking async write, then connection close.
|
||||
*
|
||||
* @see StatusCode
|
||||
* @see org.eclipse.jetty.websocket.api.StatusCode
|
||||
* @see #close(int, String)
|
||||
*/
|
||||
public void close();
|
||||
|
@ -50,7 +49,7 @@ public interface LogicalConnection extends OutgoingFrames, SuspendToken
|
|||
* the status code
|
||||
* @param reason
|
||||
* the (optional) reason. (can be null for no reason)
|
||||
* @see StatusCode
|
||||
* @see org.eclipse.jetty.websocket.api.StatusCode
|
||||
*/
|
||||
public void close(int statusCode, String reason);
|
||||
|
||||
|
@ -155,4 +154,10 @@ public interface LogicalConnection extends OutgoingFrames, SuspendToken
|
|||
* @return the suspend token
|
||||
*/
|
||||
SuspendToken suspend();
|
||||
|
||||
/**
|
||||
* Get Unique ID for the Connection
|
||||
* @return the unique ID for the connection
|
||||
*/
|
||||
public String getId();
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 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.websocket.common;
|
||||
|
||||
/**
|
||||
* Basic listener interface for Session open/close.
|
||||
* <p>
|
||||
* Used primarily for tracking open sessions.
|
||||
*/
|
||||
public interface SessionListener
|
||||
{
|
||||
public void onSessionOpened(WebSocketSession session);
|
||||
|
||||
public void onSessionClosed(WebSocketSession session);
|
||||
}
|
|
@ -67,7 +67,6 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
|
|||
private final URI requestURI;
|
||||
private final LogicalConnection connection;
|
||||
private final EventDriver websocket;
|
||||
private final SessionListener[] sessionListeners;
|
||||
private final Executor executor;
|
||||
private ClassLoader classLoader;
|
||||
private ExtensionFactory extensionFactory;
|
||||
|
@ -80,7 +79,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
|
|||
private UpgradeRequest upgradeRequest;
|
||||
private UpgradeResponse upgradeResponse;
|
||||
|
||||
public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners)
|
||||
public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, EventDriver websocket, LogicalConnection connection)
|
||||
{
|
||||
Objects.requireNonNull(containerScope,"Container Scope cannot be null");
|
||||
Objects.requireNonNull(requestURI,"Request URI cannot be null");
|
||||
|
@ -90,11 +89,11 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
|
|||
this.requestURI = requestURI;
|
||||
this.websocket = websocket;
|
||||
this.connection = connection;
|
||||
this.sessionListeners = sessionListeners;
|
||||
this.executor = connection.getExecutor();
|
||||
this.outgoingHandler = connection;
|
||||
this.incomingHandler = websocket;
|
||||
this.connection.getIOState().addListener(this);
|
||||
this.policy = containerScope.getPolicy();
|
||||
|
||||
addBean(this.connection);
|
||||
addBean(this.websocket);
|
||||
|
@ -435,36 +434,28 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
|
|||
CloseInfo close = ioState.getCloseInfo();
|
||||
// confirmed close of local endpoint
|
||||
notifyClose(close.getStatusCode(),close.getReason());
|
||||
|
||||
// notify session listeners
|
||||
for (SessionListener listener : sessionListeners)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{}.onSessionClosed()",listener.getClass().getSimpleName());
|
||||
listener.onSessionClosed(this);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.ignore(t);
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{}.onSessionClosed()",containerScope.getClass().getSimpleName());
|
||||
containerScope.onSessionClosed(this);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.ignore(t);
|
||||
}
|
||||
break;
|
||||
case CONNECTED:
|
||||
// notify session listeners
|
||||
for (SessionListener listener : sessionListeners)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{}.onSessionOpen()", listener.getClass().getSimpleName());
|
||||
listener.onSessionOpened(this);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.ignore(t);
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{}.onSessionOpened()",containerScope.getClass().getSimpleName());
|
||||
containerScope.onSessionOpened(this);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.ignore(t);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -31,26 +31,10 @@ import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
|||
public class WebSocketSessionFactory implements SessionFactory
|
||||
{
|
||||
private final WebSocketContainerScope containerScope;
|
||||
private final SessionListener[] listeners;
|
||||
|
||||
public WebSocketSessionFactory(WebSocketContainerScope containerScope, SessionListener... sessionListeners)
|
||||
public WebSocketSessionFactory(WebSocketContainerScope containerScope)
|
||||
{
|
||||
this.containerScope = containerScope;
|
||||
if ((sessionListeners != null) && (sessionListeners.length > 0))
|
||||
{
|
||||
this.listeners = sessionListeners;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.containerScope instanceof SessionListener)
|
||||
{
|
||||
this.listeners = new SessionListener[] { (SessionListener)containerScope };
|
||||
}
|
||||
else
|
||||
{
|
||||
this.listeners = new SessionListener[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,6 +46,6 @@ public class WebSocketSessionFactory implements SessionFactory
|
|||
@Override
|
||||
public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
|
||||
{
|
||||
return new WebSocketSession(containerScope, requestURI,websocket,connection,listeners);
|
||||
return new WebSocketSession(containerScope, requestURI,websocket,connection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -407,12 +407,13 @@ public abstract class CompressExtension extends AbstractExtension
|
|||
{
|
||||
Frame frame = entry.frame;
|
||||
BatchMode batchMode = entry.batchMode;
|
||||
if (OpCode.isControlFrame(frame.getOpCode()) || !frame.hasPayload())
|
||||
if (OpCode.isControlFrame(frame.getOpCode()))
|
||||
{
|
||||
// Do not deflate control frames
|
||||
nextOutgoingFrame(frame,this,batchMode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
compress(entry,true);
|
||||
}
|
||||
|
||||
|
@ -434,7 +435,7 @@ public abstract class CompressExtension extends AbstractExtension
|
|||
// no input supplied
|
||||
needsCompress = false;
|
||||
}
|
||||
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
byte[] output = new byte[outputLength];
|
||||
|
@ -486,7 +487,8 @@ public abstract class CompressExtension extends AbstractExtension
|
|||
}
|
||||
else if (fin)
|
||||
{
|
||||
// Special case: 8.2.3.6. Generating an Empty Fragment Manually
|
||||
// Special case: 7.2.3.6. Generating an Empty Fragment Manually
|
||||
// https://tools.ietf.org/html/rfc7692#section-7.2.3.6
|
||||
payload = ByteBuffer.wrap(new byte[] { 0x00 });
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.eclipse.jetty.websocket.common.OpCode;
|
|||
/**
|
||||
* Per Message Deflate Compression extension for WebSocket.
|
||||
* <p>
|
||||
* Attempts to follow <a href="https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-12">draft-ietf-hybi-permessage-compression-12</a>
|
||||
* Attempts to follow <a href="https://tools.ietf.org/html/rfc7692">Compression Extensions for WebSocket</a>
|
||||
*/
|
||||
public class PerMessageDeflateExtension extends CompressExtension
|
||||
{
|
||||
|
|
|
@ -214,6 +214,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
private final WebSocketPolicy policy;
|
||||
private final AtomicBoolean suspendToken;
|
||||
private final FrameFlusher flusher;
|
||||
private final String id;
|
||||
private List<ExtensionConfig> extensions;
|
||||
private boolean isFilling;
|
||||
private ByteBuffer prefillBuffer;
|
||||
|
@ -224,6 +225,11 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
public AbstractWebSocketConnection(EndPoint endp, Executor executor, Scheduler scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool)
|
||||
{
|
||||
super(endp,executor);
|
||||
this.id = String.format("%s:%d->%s:%d",
|
||||
endp.getLocalAddress().getAddress().getHostAddress(),
|
||||
endp.getLocalAddress().getPort(),
|
||||
endp.getRemoteAddress().getAddress().getHostAddress(),
|
||||
endp.getRemoteAddress().getPort());
|
||||
this.policy = policy;
|
||||
this.bufferPool = bufferPool;
|
||||
this.generator = new Generator(policy,bufferPool);
|
||||
|
@ -347,6 +353,12 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
{
|
||||
return generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdleTimeout()
|
||||
|
@ -747,6 +759,43 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
return String.format("%s@%X{endp=%s,ios=%s,f=%s,g=%s,p=%s}",getClass().getSimpleName(),hashCode(),getEndPoint(),ioState,flusher,generator,parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
|
||||
EndPoint endp = getEndPoint();
|
||||
if(endp != null)
|
||||
{
|
||||
result = prime * result + endp.getLocalAddress().hashCode();
|
||||
result = prime * result + endp.getRemoteAddress().hashCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AbstractWebSocketConnection other = (AbstractWebSocketConnection)obj;
|
||||
EndPoint endp = getEndPoint();
|
||||
EndPoint otherEndp = other.getEndPoint();
|
||||
if (endp == null)
|
||||
{
|
||||
if (otherEndp != null)
|
||||
return false;
|
||||
}
|
||||
else if (!endp.equals(otherEndp))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra bytes from the initial HTTP upgrade that need to
|
||||
* be processed by the websocket parser before starting
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
|||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
|
||||
public class SimpleContainerScope extends ContainerLifeCycle implements WebSocketContainerScope
|
||||
{
|
||||
|
@ -105,4 +106,14 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke
|
|||
{
|
||||
this.sslContextFactory = sslContextFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionOpened(WebSocketSession session)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionClosed(WebSocketSession session)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.eclipse.jetty.io.ByteBufferPool;
|
|||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
|
||||
/**
|
||||
* Defined Scope for a WebSocketContainer.
|
||||
|
@ -64,4 +65,19 @@ public interface WebSocketContainerScope
|
|||
* @return the SslContextFactory in use by the container (can be null if no SSL context is defined)
|
||||
*/
|
||||
public SslContextFactory getSslContextFactory();
|
||||
|
||||
/**
|
||||
* A Session has been opened
|
||||
*
|
||||
* @param session the session that was opened
|
||||
*/
|
||||
public void onSessionOpened(WebSocketSession session);
|
||||
|
||||
/**
|
||||
* A Session has been closed
|
||||
*
|
||||
* @param session the session that was closed
|
||||
*/
|
||||
public void onSessionClosed(WebSocketSession session);
|
||||
|
||||
}
|
||||
|
|
|
@ -107,6 +107,12 @@ public class LocalWebSocketConnection implements LogicalConnection, IncomingFram
|
|||
return this.bufferPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
|
|
|
@ -70,6 +70,12 @@ public class DummyConnection implements LogicalConnection
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId()
|
||||
{
|
||||
return "dummy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ public class WebSocketServerConnection extends AbstractWebSocketConnection imple
|
|||
endp.setIdleTimeout(policy.getIdleTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
|
|
|
@ -36,11 +36,15 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
|
@ -58,7 +62,6 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
|
|||
import org.eclipse.jetty.websocket.api.util.QuoteUtil;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.SessionListener;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
@ -75,7 +78,7 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
|||
/**
|
||||
* Factory to create WebSocket connections
|
||||
*/
|
||||
public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory, SessionListener
|
||||
public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
|
||||
|
||||
|
@ -619,6 +622,9 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Handshake Response: {}", handshaker);
|
||||
|
||||
if (getSendServerVersion(connector))
|
||||
response.setHeader("Server",HttpConfiguration.SERVER_VERSION);
|
||||
|
||||
// Process (version specific) handshake response
|
||||
handshaker.doHandshakeResponse(request, response);
|
||||
|
||||
|
@ -627,4 +633,19 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean getSendServerVersion(Connector connector)
|
||||
{
|
||||
ConnectionFactory connFactory = connector.getConnectionFactory(HttpVersion.HTTP_1_1.asString());
|
||||
if (connFactory == null)
|
||||
return false;
|
||||
|
||||
if (connFactory instanceof HttpConnectionFactory)
|
||||
{
|
||||
HttpConfiguration httpConf = ((HttpConnectionFactory)connFactory).getHttpConfiguration();
|
||||
if (httpConf != null)
|
||||
return httpConf.getSendServerVersion();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
24
pom.xml
24
pom.xml
|
@ -1001,5 +1001,29 @@
|
|||
<alpn.version>8.1.6.v20151105</alpn.version>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>8u71</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>java.version</name>
|
||||
<value>1.8.0_71</value>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<alpn.version>8.1.7.v20160121</alpn.version>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>8u72</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>java.version</name>
|
||||
<value>1.8.0_72</value>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<alpn.version>8.1.7.v20160121</alpn.version>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2016 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.quickstart;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class AttributeNormalizerTest
|
||||
{
|
||||
@Parameters(name="{0} = {1}")
|
||||
public static List<String[]> data()
|
||||
{
|
||||
String[][] tests = {
|
||||
{ "WAR", "/opt/jetty-distro/demo.base/webapps/root" },
|
||||
{ "jetty.home", "/opt/jetty-distro" },
|
||||
{ "jetty.base", "/opt/jetty-distro/demo.base" },
|
||||
{ "user.home", "/home/user" },
|
||||
{ "user.dir", "/etc/init.d" },
|
||||
};
|
||||
|
||||
return Arrays.asList(tests);
|
||||
}
|
||||
|
||||
private static String origJettyBase;
|
||||
private static String origJettyHome;
|
||||
private static String origUserHome;
|
||||
private static String origUserDir;
|
||||
|
||||
@BeforeClass
|
||||
public static void initProperties()
|
||||
{
|
||||
origJettyBase = System.getProperty("jetty.base");
|
||||
origJettyHome = System.getProperty("jetty.home");
|
||||
origUserHome = System.getProperty("user.home");
|
||||
origUserDir = System.getProperty("user.dir");
|
||||
|
||||
System.setProperty("jetty.home","/opt/jetty-distro");
|
||||
System.setProperty("jetty.base","/opt/jetty-distro/demo.base");
|
||||
System.setProperty("user.home","/home/user");
|
||||
System.setProperty("user.dir","/etc/init.d");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void restoreProperties()
|
||||
{
|
||||
if(origJettyBase != null) System.setProperty("jetty.base",origJettyBase);
|
||||
if(origJettyHome != null) System.setProperty("jetty.home",origJettyHome);
|
||||
if(origUserHome != null) System.setProperty("user.home",origUserHome);
|
||||
if(origUserDir != null) System.setProperty("user.dir",origUserDir);
|
||||
}
|
||||
|
||||
@Parameter(0)
|
||||
public String key;
|
||||
|
||||
@Parameter(1)
|
||||
public String path;
|
||||
|
||||
private AttributeNormalizer normalizer;
|
||||
|
||||
public AttributeNormalizerTest() throws MalformedURLException
|
||||
{
|
||||
normalizer = new AttributeNormalizer(Resource.newResource("/opt/jetty-distro/demo.base/webapps/root"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqual()
|
||||
{
|
||||
assertEquals("file:${" + key + "}",normalizer.normalize("file:" + path));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsSlash()
|
||||
{
|
||||
assertEquals("file:${" + key + "}",normalizer.normalize("file:" + path + "/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsSlashFile()
|
||||
{
|
||||
assertEquals("file:${" + key + "}/file",normalizer.normalize("file:" + path + "/file"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIEquals() throws URISyntaxException
|
||||
{
|
||||
assertEquals("file:${" + key + "}",normalizer.normalize(new URI("file:" + path)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIEqualsSlash() throws URISyntaxException
|
||||
{
|
||||
assertEquals("file:${" + key + "}",normalizer.normalize(new URI("file:" + path + "/")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIEqualsSlashFile() throws URISyntaxException
|
||||
{
|
||||
assertEquals("file:${" + key + "}/file",normalizer.normalize(new URI("file:" + path + "/file")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURLEquals() throws MalformedURLException
|
||||
{
|
||||
assertEquals("file:${" + key + "}",normalizer.normalize(new URL("file:" + path)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURLEqualsSlash() throws MalformedURLException
|
||||
{
|
||||
assertEquals("file:${" + key + "}",normalizer.normalize(new URL("file:" + path + "/")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURLEqualsSlashFile() throws MalformedURLException
|
||||
{
|
||||
assertEquals("file:${" + key + "}/file",normalizer.normalize(new URL("file:" + path + "/file")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_BangFile()
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize("jar:file:" + path + "!/file"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_SlashBangFile()
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize("jar:file:" + path + "/!/file"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_FileBangFile()
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}/file!/file",normalizer.normalize("jar:file:" + path + "/file!/file"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_URIBangFile() throws URISyntaxException
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URI("jar:file:" + path + "!/file")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_URISlashBangFile() throws URISyntaxException
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URI("jar:file:" + path + "/!/file")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_URIFileBangFile() throws URISyntaxException
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}/file!/file",normalizer.normalize(new URI("jar:file:" + path + "/file!/file")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_URLBangFile() throws MalformedURLException
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URL("jar:file:" + path + "!/file")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_URLSlashBangFile() throws MalformedURLException
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URL("jar:file:" + path + "/!/file")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJarFileEquals_URLFileBangFile() throws MalformedURLException
|
||||
{
|
||||
assertEquals("jar:file:${" + key + "}/file!/file",normalizer.normalize(new URL("jar:file:" + path + "/file!/file")));
|
||||
}
|
||||
}
|
|
@ -160,7 +160,7 @@ public class QuickStartTest
|
|||
if (contextXml != null)
|
||||
{
|
||||
// System.err.println("Applying "+contextXml);
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml.getURL());
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml.getURI().toURL());
|
||||
xmlConfiguration.configure(webapp);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.gcloud</groupId>
|
||||
<artifactId>gcloud-session-manager</artifactId>
|
||||
<artifactId>jetty-gcloud-session-manager</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
Loading…
Reference in New Issue