Merge remote-tracking branch 'origin/jetty-9.4.x'
This commit is contained in:
commit
c02dec5654
27
VERSION.txt
27
VERSION.txt
|
@ -1,5 +1,32 @@
|
|||
jetty-10.0.0-SNAPSHOT
|
||||
|
||||
jetty-9.4.0.RC3 - 05 December 2016
|
||||
+ 1051 NCSARequestLog/RolloverFileOutputStream does not roll day after DST
|
||||
ends
|
||||
+ 1062 Jetty allows requests to hang under PUT load
|
||||
+ 1090 Allow WebSocketUpgradeFilter to be used by WEB-INF/web.xml
|
||||
+ 1092 jetty-runner jstl support
|
||||
+ 1108 Please improve logging in SslContextFactory when there are no approved
|
||||
cipher suites
|
||||
+ 1117 quickstart generator of quickstart-web.xml should keep ids
|
||||
+ 1118 Filter.destroy() conflicts with ContainerLifeCycle.destroy() in
|
||||
WebSocketUpgradeFilter
|
||||
+ 1123 Broken lifecycle for WebSocket's mappings
|
||||
+ 1124 Allow configuration of WebSocket mappings from Spring
|
||||
+ 1127 AsyncMiddleManServletTest Test failure
|
||||
+ 1128 Stats Servlet hidden from classpath
|
||||
+ 1130 PROXY protocol support reports incorrect remote address
|
||||
+ 1134 Jetty HTTP/2 client problems
|
||||
+ 1135 Avoid allocations from Method.getParameterTypes() if possible
|
||||
+ 1138 Ensure xml validation works on web descriptors
|
||||
+ 1139 Support configuration of properties during --add-to-start
|
||||
+ 1142 Do not warn for default settings in sessions
|
||||
+ 1143 Upgrade google cloud APIs to 0.7.0
|
||||
+ 117 Support proxies with WebSocketClient
|
||||
+ 572 Don't reject HTTP/2 requests without body in low threads mode
|
||||
+ 877 Programmatic servlet mappings cannot override mappings from
|
||||
webdefault.xml using quickstart
|
||||
|
||||
jetty-9.4.0.RC2 - 16 November 2016
|
||||
+ 240 Missing content for multipart request after upgrade to Jetty > 9.2.7
|
||||
+ 586 Thread pools and connectors
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.eclipse.jetty.server.Handler;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.SessionIdManager;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -209,33 +208,32 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
|
|||
@Override
|
||||
public String newSessionId(HttpServletRequest request, long created)
|
||||
{
|
||||
synchronized (this)
|
||||
if (request==null)
|
||||
return newSessionId(created);
|
||||
|
||||
// A requested session ID can only be used if it is in use already.
|
||||
String requested_id=request.getRequestedSessionId();
|
||||
if (requested_id!=null)
|
||||
{
|
||||
if (request==null)
|
||||
return newSessionId(created);
|
||||
|
||||
// A requested session ID can only be used if it is in use already.
|
||||
String requested_id=request.getRequestedSessionId();
|
||||
if (requested_id!=null)
|
||||
{
|
||||
String cluster_id=getId(requested_id);
|
||||
if (isIdInUse(cluster_id))
|
||||
return cluster_id;
|
||||
}
|
||||
|
||||
|
||||
// Else reuse any new session ID already defined for this request.
|
||||
String new_id=(String)request.getAttribute(__NEW_SESSION_ID);
|
||||
if (new_id!=null&&isIdInUse(new_id))
|
||||
return new_id;
|
||||
|
||||
// pick a new unique ID!
|
||||
String id = newSessionId(request.hashCode());
|
||||
|
||||
request.setAttribute(__NEW_SESSION_ID,id);
|
||||
return id;
|
||||
String cluster_id=getId(requested_id);
|
||||
if (isIdInUse(cluster_id))
|
||||
return cluster_id;
|
||||
}
|
||||
|
||||
|
||||
// Else reuse any new session ID already defined for this request.
|
||||
String new_id=(String)request.getAttribute(__NEW_SESSION_ID);
|
||||
if (new_id!=null&&isIdInUse(new_id))
|
||||
return new_id;
|
||||
|
||||
// pick a new unique ID!
|
||||
String id = newSessionId(request.hashCode());
|
||||
|
||||
request.setAttribute(__NEW_SESSION_ID,id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -246,45 +244,49 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
|
|||
{
|
||||
// pick a new unique ID!
|
||||
String id=null;
|
||||
while (id==null||id.length()==0)
|
||||
{
|
||||
long r0=_weakRandom
|
||||
?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^((seedTerm)<<32))
|
||||
:_random.nextLong();
|
||||
if (r0<0)
|
||||
r0=-r0;
|
||||
|
||||
// random chance to reseed
|
||||
if (_reseed>0 && (r0%_reseed)== 1L)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Reseeding {}",this);
|
||||
if (_random instanceof SecureRandom)
|
||||
{
|
||||
SecureRandom secure = (SecureRandom)_random;
|
||||
secure.setSeed(secure.generateSeed(8));
|
||||
}
|
||||
else
|
||||
{
|
||||
_random.setSeed(_random.nextLong()^System.currentTimeMillis()^seedTerm^Runtime.getRuntime().freeMemory());
|
||||
}
|
||||
}
|
||||
|
||||
long r1=_weakRandom
|
||||
?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^((seedTerm)<<32))
|
||||
:_random.nextLong();
|
||||
if (r1<0)
|
||||
r1=-r1;
|
||||
|
||||
id=Long.toString(r0,36)+Long.toString(r1,36);
|
||||
|
||||
//add in the id of the node to ensure unique id across cluster
|
||||
//NOTE this is different to the node suffix which denotes which node the request was received on
|
||||
if (_workerName!=null)
|
||||
id=_workerName + id;
|
||||
|
||||
id = id+Long.toString(COUNTER.getAndIncrement());
|
||||
|
||||
synchronized (_random)
|
||||
{
|
||||
while (id==null||id.length()==0)
|
||||
{
|
||||
long r0=_weakRandom
|
||||
?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^((seedTerm)<<32))
|
||||
:_random.nextLong();
|
||||
if (r0<0)
|
||||
r0=-r0;
|
||||
|
||||
// random chance to reseed
|
||||
if (_reseed>0 && (r0%_reseed)== 1L)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Reseeding {}",this);
|
||||
if (_random instanceof SecureRandom)
|
||||
{
|
||||
SecureRandom secure = (SecureRandom)_random;
|
||||
secure.setSeed(secure.generateSeed(8));
|
||||
}
|
||||
else
|
||||
{
|
||||
_random.setSeed(_random.nextLong()^System.currentTimeMillis()^seedTerm^Runtime.getRuntime().freeMemory());
|
||||
}
|
||||
}
|
||||
|
||||
long r1=_weakRandom
|
||||
?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^((seedTerm)<<32))
|
||||
:_random.nextLong();
|
||||
if (r1<0)
|
||||
r1=-r1;
|
||||
|
||||
id=Long.toString(r0,36)+Long.toString(r1,36);
|
||||
|
||||
//add in the id of the node to ensure unique id across cluster
|
||||
//NOTE this is different to the node suffix which denotes which node the request was received on
|
||||
if (_workerName!=null)
|
||||
id=_workerName + id;
|
||||
|
||||
id = id+Long.toString(COUNTER.getAndIncrement());
|
||||
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -38,8 +38,11 @@ import java.net.SocketTimeoutException;
|
|||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.eclipse.jetty.start.Props.Prop;
|
||||
import org.eclipse.jetty.start.config.CommandLineConfigSource;
|
||||
import org.eclipse.jetty.start.config.ConfigSource;
|
||||
|
||||
/**
|
||||
* Main start class.
|
||||
|
@ -399,6 +402,32 @@ public class Main
|
|||
doStop(args);
|
||||
}
|
||||
|
||||
if (args.isUpdateIni())
|
||||
{
|
||||
for (ConfigSource config : baseHome.getConfigSources())
|
||||
{
|
||||
System.out.printf("ConfigSource %s%n",config.getId());
|
||||
for (StartIni ini : config.getStartInis())
|
||||
{
|
||||
for (String line : ini.getAllLines())
|
||||
{
|
||||
Matcher m = Module.SET_PROPERTY.matcher(line);
|
||||
if (m.matches() && m.groupCount()==3)
|
||||
{
|
||||
String name = m.group(2);
|
||||
String value = m.group(3);
|
||||
Prop p = args.getProperties().getProp(name);
|
||||
if (p!=null && ("#".equals(m.group(1)) || !value.equals(p.value)))
|
||||
{
|
||||
ini.update(baseHome,args.getProperties());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check base directory
|
||||
BaseBuilder baseBuilder = new BaseBuilder(baseHome,args);
|
||||
if(baseBuilder.build())
|
||||
|
|
|
@ -61,9 +61,8 @@ import org.eclipse.jetty.start.config.CommandLineConfigSource;
|
|||
public class Module implements Comparable<Module>
|
||||
{
|
||||
private static final String VERSION_UNSPECIFIED = "9.2";
|
||||
private static Pattern MOD_NAME = Pattern.compile("^(.*)\\.mod",Pattern.CASE_INSENSITIVE);
|
||||
private static Pattern SET_PROPERTY = Pattern.compile("^(#?)\\s*([^=\\s]+)=(.*)$");
|
||||
|
||||
static Pattern MOD_NAME = Pattern.compile("^(.*)\\.mod",Pattern.CASE_INSENSITIVE);
|
||||
static Pattern SET_PROPERTY = Pattern.compile("^(#?)\\s*([^=\\s]+)=(.*)$");
|
||||
|
||||
/** The file of the module */
|
||||
private final Path _path;
|
||||
|
|
|
@ -178,6 +178,8 @@ public class StartArgs
|
|||
private boolean version = false;
|
||||
private boolean dryRun = false;
|
||||
private boolean createStartd = false;
|
||||
private boolean updateIni = false;
|
||||
|
||||
|
||||
private boolean exec = false;
|
||||
private String exec_properties;
|
||||
|
@ -786,6 +788,11 @@ public class StartArgs
|
|||
return createStartd;
|
||||
}
|
||||
|
||||
public boolean isUpdateIni()
|
||||
{
|
||||
return updateIni;
|
||||
}
|
||||
|
||||
public void parse(ConfigSources sources)
|
||||
{
|
||||
ListIterator<ConfigSource> iter = sources.reverseListIterator();
|
||||
|
@ -899,6 +906,13 @@ public class StartArgs
|
|||
return;
|
||||
}
|
||||
|
||||
if (arg.equals("--update-ini") || arg.equals("--update-inis"))
|
||||
{
|
||||
run = false;
|
||||
updateIni = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if ("--list-classpath".equals(arg) || "--version".equals(arg) || "-v".equals(arg) || "--info".equals(arg))
|
||||
{
|
||||
listClasspath = true;
|
||||
|
|
|
@ -18,8 +18,16 @@
|
|||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.eclipse.jetty.start.Props.Prop;
|
||||
|
||||
/**
|
||||
* Simple Start .INI handler
|
||||
|
@ -78,4 +86,40 @@ public class StartIni extends TextFile
|
|||
{
|
||||
return basedir;
|
||||
}
|
||||
|
||||
public void update(BaseHome baseHome,Props props) throws IOException
|
||||
{
|
||||
String update = getFile().getFileName().toString();
|
||||
update = update.substring(0,update.lastIndexOf("."));
|
||||
String source = baseHome.toShortForm(getFile());
|
||||
|
||||
try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(getFile(),StandardCharsets.UTF_8,StandardOpenOption.TRUNCATE_EXISTING,StandardOpenOption.CREATE)))
|
||||
{
|
||||
for (String line : getAllLines())
|
||||
{
|
||||
Matcher m = Module.SET_PROPERTY.matcher(line);
|
||||
if (m.matches() && m.groupCount()==3)
|
||||
{
|
||||
String name = m.group(2);
|
||||
String value = m.group(3);
|
||||
Prop p = props.getProp(name);
|
||||
if (p!=null && ("#".equals(m.group(1)) || !value.equals(p.value)))
|
||||
{
|
||||
StartLog.info("%-15s property updated %s=%s",update,name,p.value);
|
||||
writer.printf("%s=%s%n",name,p.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.println(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.println(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StartLog.info("%-15s updated %s",update,source);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ public class TextFile implements Iterable<String>
|
|||
{
|
||||
private final Path file;
|
||||
private final List<String> lines = new ArrayList<>();
|
||||
private final List<String> allLines = new ArrayList<>();
|
||||
|
||||
public TextFile(Path file) throws FileNotFoundException, IOException
|
||||
{
|
||||
|
@ -62,6 +63,8 @@ public class TextFile implements Iterable<String>
|
|||
continue;
|
||||
}
|
||||
|
||||
allLines.add(line);
|
||||
|
||||
if (line.charAt(0) == '#')
|
||||
{
|
||||
continue;
|
||||
|
@ -106,6 +109,11 @@ public class TextFile implements Iterable<String>
|
|||
return lines;
|
||||
}
|
||||
|
||||
public List<String> getAllLines()
|
||||
{
|
||||
return allLines;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
}
|
||||
|
@ -130,4 +138,10 @@ public class TextFile implements Iterable<String>
|
|||
{
|
||||
addUniqueLine(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return file.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,12 @@
|
|||
|
||||
package org.eclipse.jetty.start.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.start.Props;
|
||||
import org.eclipse.jetty.start.RawArgs;
|
||||
import org.eclipse.jetty.start.StartIni;
|
||||
|
||||
/**
|
||||
* A Configuration Source
|
||||
|
@ -72,4 +76,9 @@ public interface ConfigSource
|
|||
* @return the value of the property, or null if not found
|
||||
*/
|
||||
public String getProperty(String key);
|
||||
|
||||
public default Set<StartIni> getStartInis()
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ import java.nio.file.Path;
|
|||
import java.nio.file.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.start.FS;
|
||||
import org.eclipse.jetty.start.NaturalSort;
|
||||
|
@ -75,6 +77,7 @@ public class DirConfigSource implements ConfigSource
|
|||
private final int weight;
|
||||
private final RawArgs args;
|
||||
private final Props props;
|
||||
private final Set<StartIni> startInis = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Create DirConfigSource with specified identifier and directory.
|
||||
|
@ -109,6 +112,7 @@ public class DirConfigSource implements ConfigSource
|
|||
if (FS.canReadFile(iniFile))
|
||||
{
|
||||
StartIni ini = new StartIni(iniFile);
|
||||
startInis.add(ini);
|
||||
args.addAll(ini.getLines(),iniFile);
|
||||
parseAllArgs(ini.getLines(),iniFile.toString());
|
||||
}
|
||||
|
@ -149,6 +153,7 @@ public class DirConfigSource implements ConfigSource
|
|||
{
|
||||
StartLog.debug("Reading %s/start.d/%s - %s",id,diniFile.getFileName(),diniFile);
|
||||
StartIni ini = new StartIni(diniFile);
|
||||
startInis.add(ini);
|
||||
args.addAll(ini.getLines(),diniFile);
|
||||
parseAllArgs(ini.getLines(),diniFile.toString());
|
||||
}
|
||||
|
@ -156,6 +161,12 @@ public class DirConfigSource implements ConfigSource
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<StartIni> getStartInis()
|
||||
{
|
||||
return startInis;
|
||||
}
|
||||
|
||||
private void parseAllArgs(List<String> lines, String origin)
|
||||
{
|
||||
for (String line : lines)
|
||||
|
|
|
@ -114,6 +114,10 @@ Module Management:
|
|||
Note: not all modules have ini templates and thus may
|
||||
be transitively enabled and not explicitly enabled in
|
||||
a ini file.
|
||||
|
||||
--update-ini Scan all start.ini and start.d/*.ini files and update
|
||||
any properties with values specified on the command
|
||||
line. e.g. --update-ini jetty.http.port=8888
|
||||
|
||||
--create-startd Ensure that a start.d directory exists for use by
|
||||
subsequent --add-to-start=*. If a start.ini file exists
|
||||
|
|
|
@ -12,6 +12,8 @@ PROP|main.prop=value0
|
|||
PROP|name=value
|
||||
PROP|name0=changed0
|
||||
PROP|name1=changed1
|
||||
PROP|property=value
|
||||
PROP|property0=value0
|
||||
|
||||
# Files / Directories to create
|
||||
EXISTS|start.d/parameterized.ini
|
||||
|
|
|
@ -12,6 +12,8 @@ PROP|main.prop=value0
|
|||
PROP|name=value
|
||||
PROP|name0=changed0
|
||||
PROP|name1=changed1
|
||||
PROP|property=value
|
||||
PROP|property0=value0
|
||||
|
||||
# Files / Directories to create
|
||||
EXISTS|start.d/parameterized.ini
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
## The XMLs we expect (order is important)
|
||||
XML|${jetty.home}/etc/base.xml
|
||||
XML|${jetty.home}/etc/main.xml
|
||||
|
||||
# The LIBs we expect (order is irrelevant)
|
||||
LIB|${jetty.home}/lib/base.jar
|
||||
LIB|${jetty.home}/lib/main.jar
|
||||
LIB|${jetty.home}/lib/other.jar
|
||||
|
||||
# The Properties we expect (order is irrelevant)
|
||||
PROP|main.prop=value0
|
||||
PROP|name=value
|
||||
PROP|name0=changed0
|
||||
PROP|name1=changed1
|
||||
PROP|property=value
|
||||
PROP|property0=changed0
|
||||
PROP|property1=changed1
|
||||
|
||||
# Files / Directories to create
|
||||
EXISTS|start.d/parameterized.ini
|
|
@ -0,0 +1,10 @@
|
|||
--create-startd
|
||||
other=value
|
||||
name=changed
|
||||
name0=changed0
|
||||
name1=changed1
|
||||
--add-to-start=parameterized
|
||||
|
||||
--update-ini
|
||||
property0=changed0
|
||||
property1=changed1
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
#p=v
|
||||
property=value
|
||||
#comment
|
||||
property0=value0
|
||||
#comment
|
||||
#property1=value1
|
|
@ -22,7 +22,6 @@ import java.io.IOException;
|
|||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.common.AcceptHash;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
|
@ -50,18 +49,9 @@ public class HandshakeRFC6455 implements WebSocketHandshake
|
|||
response.addHeader("Connection","Upgrade");
|
||||
response.addHeader("Sec-WebSocket-Accept",AcceptHash.hashKey(key));
|
||||
|
||||
if (response.getExtensions() != null)
|
||||
{
|
||||
String value = ExtensionConfig.toHeaderValue(response.getExtensions());
|
||||
if (value != null)
|
||||
{
|
||||
response.addHeader("Sec-WebSocket-Extensions",value);
|
||||
}
|
||||
}
|
||||
|
||||
request.complete();
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
|
||||
response.setStatusCode(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
|
||||
response.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.eclipse.jetty.websocket.servlet;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -42,25 +44,59 @@ public class ServletUpgradeResponse implements UpgradeResponse
|
|||
private Map<String, List<String>> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
private List<ExtensionConfig> extensions = new ArrayList<>();
|
||||
private boolean success = false;
|
||||
private int status;
|
||||
|
||||
public ServletUpgradeResponse(HttpServletResponse response)
|
||||
{
|
||||
this.response = response;
|
||||
|
||||
for (String name : response.getHeaderNames())
|
||||
{
|
||||
headers.put(name, new ArrayList<String>(response.getHeaders(name)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
this.response.addHeader(name, value);
|
||||
if (value!=null)
|
||||
{
|
||||
List<String> values = headers.get(name);
|
||||
if (values==null)
|
||||
{
|
||||
values = new ArrayList<>();
|
||||
headers.put(name,values);
|
||||
}
|
||||
values.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
// remove from the real response
|
||||
if (response!=null)
|
||||
response.setHeader(name,null);
|
||||
|
||||
|
||||
List<String> values = headers.get(name);
|
||||
if (values==null)
|
||||
{
|
||||
values = new ArrayList<>();
|
||||
headers.put(name,values);
|
||||
}
|
||||
else
|
||||
values.clear();
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
private void commitHeaders()
|
||||
public void complete()
|
||||
{
|
||||
if (response==null)
|
||||
return;
|
||||
|
||||
// Take a copy of all the real response headers
|
||||
Map<String, Collection<String>> real = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
for (String name : response.getHeaderNames())
|
||||
{
|
||||
real.put(name,response.getHeaders(name));
|
||||
}
|
||||
|
||||
// Transfer all headers to the real HTTP response
|
||||
for (Map.Entry<String, List<String>> entry : getHeaders().entrySet())
|
||||
{
|
||||
|
@ -69,11 +105,17 @@ public class ServletUpgradeResponse implements UpgradeResponse
|
|||
response.addHeader(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void complete()
|
||||
{
|
||||
commitHeaders();
|
||||
|
||||
// Prepend the real headers to the copy headers
|
||||
for (Map.Entry<String, Collection<String>> entry : real.entrySet())
|
||||
{
|
||||
String name = entry.getKey();
|
||||
Collection<String> prepend = entry.getValue();
|
||||
List<String> values = headers.getOrDefault(name,headers.containsKey(name)?null:new ArrayList<>());
|
||||
values.addAll(0,prepend);
|
||||
}
|
||||
|
||||
status = response.getStatus();
|
||||
response = null;
|
||||
}
|
||||
|
||||
|
@ -92,13 +134,27 @@ public class ServletUpgradeResponse implements UpgradeResponse
|
|||
@Override
|
||||
public String getHeader(String name)
|
||||
{
|
||||
return response.getHeader(name);
|
||||
if (response!=null)
|
||||
{
|
||||
String value = response.getHeader(name);
|
||||
if (value!=null)
|
||||
return value;
|
||||
}
|
||||
List<String> values = headers.get(name);
|
||||
if (values!=null && !values.isEmpty())
|
||||
return values.get(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getHeaderNames()
|
||||
{
|
||||
return getHeaders().keySet();
|
||||
if (response==null)
|
||||
return headers.keySet();
|
||||
|
||||
Set<String> h = new HashSet<>(response.getHeaderNames());
|
||||
h.addAll(headers.keySet());
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,13 +166,20 @@ public class ServletUpgradeResponse implements UpgradeResponse
|
|||
@Override
|
||||
public List<String> getHeaders(String name)
|
||||
{
|
||||
return getHeaders().get(name);
|
||||
if (response==null)
|
||||
return headers.get(name);
|
||||
|
||||
List<String> values = new ArrayList<>(response.getHeaders(name));
|
||||
values.addAll(headers.get(name));
|
||||
return values.isEmpty()?null:values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatusCode()
|
||||
{
|
||||
return response.getStatus();
|
||||
if (response!=null)
|
||||
return response.getStatus();
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -154,20 +217,20 @@ public class ServletUpgradeResponse implements UpgradeResponse
|
|||
public void sendError(int statusCode, String message) throws IOException
|
||||
{
|
||||
setSuccess(false);
|
||||
applyHeaders();
|
||||
response.sendError(statusCode, message);
|
||||
response.flushBuffer(); // commit response
|
||||
response = null;
|
||||
HttpServletResponse r = response;
|
||||
complete();
|
||||
r.sendError(statusCode, message);
|
||||
r.flushBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendForbidden(String message) throws IOException
|
||||
{
|
||||
setSuccess(false);
|
||||
applyHeaders();
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, message);
|
||||
response.flushBuffer(); // commit response
|
||||
response = null;
|
||||
HttpServletResponse r = response;
|
||||
complete();
|
||||
r.sendError(HttpServletResponse.SC_FORBIDDEN, message);
|
||||
r.flushBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -187,33 +250,11 @@ public class ServletUpgradeResponse implements UpgradeResponse
|
|||
extensionsNegotiated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
response.setHeader(name, value);
|
||||
}
|
||||
|
||||
private void applyHeaders()
|
||||
{
|
||||
// Transfer all headers to the real HTTP response
|
||||
for (Map.Entry<String, List<String>> entry : getHeaders().entrySet())
|
||||
{
|
||||
for (String value : entry.getValue())
|
||||
{
|
||||
response.addHeader(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setStatus(int status)
|
||||
{
|
||||
response.setStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatusCode(int statusCode)
|
||||
{
|
||||
response.setStatus(statusCode);
|
||||
if (response!=null)
|
||||
response.setStatus(statusCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -227,4 +268,10 @@ public class ServletUpgradeResponse implements UpgradeResponse
|
|||
{
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("r=%s s=%d h=%s",response,status,headers);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public interface WebSocketServletFactory
|
|||
try
|
||||
{
|
||||
Class<? extends WebSocketServletFactory> wsClazz =
|
||||
(Class<? extends WebSocketServletFactory>) Class.forName(DEFAULT_IMPL);
|
||||
(Class<? extends WebSocketServletFactory>) Class.forName(DEFAULT_IMPL,true,Thread.currentThread().getContextClassLoader());
|
||||
Constructor<? extends WebSocketServletFactory> ctor = wsClazz.getDeclaredConstructor(new Class<?>[]{ServletContext.class, WebSocketPolicy.class});
|
||||
return ctor.newInstance(ctx, policy);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue