Merge remote-tracking branch 'origin/jetty-9.4.x'
This commit is contained in:
commit
bf3ea9ae44
11
KEYS.txt
11
KEYS.txt
|
@ -1,6 +1,7 @@
|
|||
# GPG Release Key Fingerprints
|
||||
Jan Bartel AED5 EE6C 45D0 FE8D 5D1B 164F 27DE D4BF 6216 DB
|
||||
Simone Bordet 8B09 6546 B1A8 F026 56B1 5D3B 1677 D141 BCF3 58
|
||||
Joakim Erdfelt <joakim@erdfelt.com> BFBB 21C2 46D7 7768 3628 7A48 A04E 0C74 ABB3 5FEA
|
||||
Joakim Erdfelt <joakim@apache.org> B59B 67FD 7904 9843 67F9 3180 0818 D9D6 8FB6 7BAC
|
||||
Jesse McConnell 2A68 4B57 436A 81FA 8706 B53C 61C3 351A 438A 3B7D
|
||||
Jan Bartel <janb@mortbay.com> AED5 EE6C 45D0 FE8D 5D1B 164F 27DE D4BF 6216 DB8F
|
||||
Jesse McConnell <jesse.mcconnell@gmail.com> 2A68 4B57 436A 81FA 8706 B53C 61C3 351A 438A 3B7D
|
||||
Joakim Erdfelt <joakim.erdfelt@gmail.com> 5989 BAF7 6217 B843 D66B E55B 2D0E 1FB8 FE4B 68B4
|
||||
Joakim Erdfelt <joakim@apache.org> B59B 67FD 7904 9843 67F9 3180 0818 D9D6 8FB6 7BAC
|
||||
Joakim Erdfelt <joakim@erdfelt.com> BFBB 21C2 46D7 7768 3628 7A48 A04E 0C74 ABB3 5FEA
|
||||
Simone Bordet <simone.bordet@gmail.com> 8B09 6546 B1A8 F026 56B1 5D3B 1677 D141 BCF3 584D
|
||||
|
|
|
@ -42,6 +42,7 @@ public class DumpServlet extends HttpServlet
|
|||
out.println("<h1>DumpServlet</h1>");
|
||||
out.println("<pre>");
|
||||
out.println("requestURI=" + request.getRequestURI());
|
||||
out.println("requestURL=" + request.getRequestURL().toString());
|
||||
out.println("contextPath=" + request.getContextPath());
|
||||
out.println("servletPath=" + request.getServletPath());
|
||||
out.println("pathInfo=" + request.getPathInfo());
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.embedded;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class HelloSessionServlet extends HttpServlet
|
||||
{
|
||||
public HelloSessionServlet() {}
|
||||
|
||||
@Override
|
||||
protected void doGet( HttpServletRequest request,
|
||||
HttpServletResponse response ) throws ServletException,
|
||||
IOException
|
||||
{
|
||||
response.setContentType("text/html");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.addHeader("Cache-Control","no-cache");
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
String message;
|
||||
String link;
|
||||
|
||||
String greeting = request.getParameter("greeting");
|
||||
if (greeting != null)
|
||||
{
|
||||
session.setAttribute("greeting", greeting);
|
||||
message = "New greeting '" + greeting + "' set in session.";
|
||||
link = "Click <a href=\"/\">here</a> to use the new greeting from the session.";
|
||||
}
|
||||
else
|
||||
{
|
||||
greeting = (String)session.getAttribute("greeting");
|
||||
|
||||
if (greeting != null)
|
||||
{
|
||||
message = "Greeting '" + greeting + "' set from session.";
|
||||
}
|
||||
else
|
||||
{
|
||||
greeting = "Hello";
|
||||
message = "Greeting '" + greeting + "' is default.";
|
||||
}
|
||||
|
||||
link = "Click <a href=\"/?greeting=Hola\">here</a> to set a new greeting.";
|
||||
}
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<h1>" + greeting + " from HelloSessionServlet</h1>");
|
||||
out.println("<p>" + message + "</p>");
|
||||
out.println("<pre>");
|
||||
out.println("session.getId() = " +session.getId());
|
||||
out.println("session.isNew() = " +session.isNew());
|
||||
out.println("</pre>");
|
||||
out.println("<p>" + link + "</p>");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.embedded;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.session.DefaultSessionCache;
|
||||
import org.eclipse.jetty.server.session.NullSessionDataStore;
|
||||
import org.eclipse.jetty.server.session.SessionCache;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
||||
|
||||
public class OneServletContextWithSession
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Server server = new Server(8080);
|
||||
|
||||
// Create a ServletContext, with a session handler enabled.
|
||||
ServletContextHandler context = new ServletContextHandler(
|
||||
ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/");
|
||||
context.setResourceBase(System.getProperty("java.io.tmpdir"));
|
||||
server.setHandler(context);
|
||||
|
||||
// Access the SessionHandler from the context.
|
||||
SessionHandler sessions = context.getSessionHandler();
|
||||
|
||||
// Explicitly set Session Cache and null Datastore.
|
||||
// This is normally done by default,
|
||||
// but is done explicitly here for demonstration.
|
||||
// If more than one context is to be deployed, it is
|
||||
// simpler to use SessionCacheFactory and/or
|
||||
// SessionDataStoreFactory instances set as beans on
|
||||
// the server.
|
||||
SessionCache cache = new DefaultSessionCache(sessions);
|
||||
cache.setSessionDataStore(new NullSessionDataStore());
|
||||
sessions.setSessionCache(cache);
|
||||
|
||||
// Servlet to read/set the greeting stored in the session.
|
||||
// Can be accessed using http://localhost:8080/hello
|
||||
context.addServlet(HelloSessionServlet.class, "/");
|
||||
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
}
|
|
@ -39,10 +39,6 @@
|
|||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<!--
|
||||
<groupId>org.eclipse.jetty.orbit</groupId>
|
||||
<artifactId>javax.servlet</artifactId>
|
||||
-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -83,5 +79,6 @@
|
|||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -222,13 +222,14 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
|||
}
|
||||
|
||||
/**
|
||||
* @param request request object
|
||||
* @param b StringBuilder to write to
|
||||
* @throws IOException if unable to append extended log
|
||||
* @deprecated override {@link #logExtended(StringBuilder, Request, Response)} instead
|
||||
* Writes extended request and response information to the output stream.
|
||||
*
|
||||
* @param b StringBuilder to write to
|
||||
* @param request request object
|
||||
* @param response response object
|
||||
* @throws IOException if unable to log the extended information
|
||||
*/
|
||||
@Deprecated
|
||||
protected void logExtended(Request request, StringBuilder b) throws IOException
|
||||
protected void logExtended(StringBuilder b, Request request, Response response) throws IOException
|
||||
{
|
||||
String referer = request.getHeader(HttpHeader.REFERER.toString());
|
||||
if (referer == null)
|
||||
|
@ -251,19 +252,6 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes extended request and response information to the output stream.
|
||||
*
|
||||
* @param b StringBuilder to write to
|
||||
* @param request request object
|
||||
* @param response response object
|
||||
* @throws IOException if unable to log the extended information
|
||||
*/
|
||||
protected void logExtended(StringBuilder b, Request request, Response response) throws IOException
|
||||
{
|
||||
logExtended(request, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request paths that will not be logged.
|
||||
*
|
||||
|
|
|
@ -1681,7 +1681,9 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
_metaData=request;
|
||||
HttpURI uri = request.getURI();
|
||||
_originalUri = uri.toString();
|
||||
_originalUri = uri.isAbsolute() && request.getHttpVersion()!=HttpVersion.HTTP_2
|
||||
? uri.toString()
|
||||
: uri.getPathQuery();
|
||||
|
||||
if (uri.getScheme()==null)
|
||||
uri.setScheme("http");
|
||||
|
@ -1817,7 +1819,6 @@ public class Request implements HttpServletRequest
|
|||
_requestAttributeListeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setAsyncSupported(boolean supported,String source)
|
||||
{
|
||||
|
|
|
@ -91,6 +91,51 @@ public class RequestLogTest
|
|||
assertThat(log,containsString("GET http://host:80/foo?data=1 HTTP/1.0\" 200 "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHTTP10Host() throws Exception
|
||||
{
|
||||
_connector.getResponse(
|
||||
"GET /foo?name=value HTTP/1.0\n"+
|
||||
"Host: servername\n"+
|
||||
"\n");
|
||||
String log = _log.exchange(null,5,TimeUnit.SECONDS);
|
||||
assertThat(log,containsString("GET /foo?name=value"));
|
||||
assertThat(log,containsString(" 200 "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHTTP11() throws Exception
|
||||
{
|
||||
_connector.getResponse(
|
||||
"GET /foo?name=value HTTP/1.1\n"+
|
||||
"Host: servername\n"+
|
||||
"\n");
|
||||
String log = _log.exchange(null,5,TimeUnit.SECONDS);
|
||||
assertThat(log,containsString("GET /foo?name=value"));
|
||||
assertThat(log,containsString(" 200 "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbsolute() throws Exception
|
||||
{
|
||||
_connector.getResponse(
|
||||
"GET http://hostname:8888/foo?name=value HTTP/1.1\n"+
|
||||
"Host: servername\n"+
|
||||
"\n");
|
||||
String log = _log.exchange(null,5,TimeUnit.SECONDS);
|
||||
assertThat(log,containsString("GET http://hostname:8888/foo?name=value"));
|
||||
assertThat(log,containsString(" 200 "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuery() throws Exception
|
||||
{
|
||||
_connector.getResponse("GET /foo?name=value HTTP/1.0\n\n");
|
||||
String log = _log.exchange(null,5,TimeUnit.SECONDS);
|
||||
assertThat(log,containsString("GET /foo?name=value"));
|
||||
assertThat(log,containsString(" 200 "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmallData() throws Exception
|
||||
{
|
||||
|
|
|
@ -24,22 +24,25 @@ import java.io.FilterOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* RolloverFileOutputStream
|
||||
*
|
||||
* RolloverFileOutputStream.
|
||||
*
|
||||
* <p>
|
||||
* This output stream puts content in a file that is rolled over every 24 hours.
|
||||
* The filename must include the string "yyyy_mm_dd", which is replaced with the
|
||||
* actual date when creating and rolling over the file.
|
||||
*
|
||||
* </p>
|
||||
* <p>
|
||||
* Old files are retained for a number of days before being deleted.
|
||||
* </p>
|
||||
*/
|
||||
public class RolloverFileOutputStream extends FilterOutputStream
|
||||
{
|
||||
|
@ -51,6 +54,7 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
final static int ROLLOVER_FILE_RETAIN_DAYS = 31;
|
||||
|
||||
private RollTask _rollTask;
|
||||
private ZonedDateTime midnight;
|
||||
private SimpleDateFormat _fileBackupFormat;
|
||||
private SimpleDateFormat _fileDateFormat;
|
||||
|
||||
|
@ -172,19 +176,21 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
|
||||
_rollTask=new RollTask();
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
now.setTimeZone(zone);
|
||||
|
||||
GregorianCalendar midnight =
|
||||
new GregorianCalendar(now.get(Calendar.YEAR),
|
||||
now.get(Calendar.MONTH),
|
||||
now.get(Calendar.DAY_OF_MONTH),
|
||||
23,0);
|
||||
midnight.setTimeZone(zone);
|
||||
midnight.add(Calendar.HOUR,1);
|
||||
__rollover.scheduleAtFixedRate(_rollTask,midnight.getTime(),1000L*60*60*24);
|
||||
midnight = ZonedDateTime.now().toLocalDate().atStartOfDay(zone.toZoneId());
|
||||
|
||||
scheduleNextRollover();
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleNextRollover()
|
||||
{
|
||||
// Increment to next day.
|
||||
// Using Calendar.add(DAY, 1) takes in account Daylights Savings
|
||||
// differences, and still maintains the "midnight" settings for
|
||||
// Hour, Minute, Second, Milliseconds
|
||||
midnight = midnight.toLocalDate().plus(1, ChronoUnit.DAYS).atStartOfDay(midnight.getZone());
|
||||
__rollover.schedule(_rollTask,midnight.toInstant().toEpochMilli());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getFilename()
|
||||
|
@ -254,7 +260,9 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
{
|
||||
if (_retainDays>0)
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
ZonedDateTime now = ZonedDateTime.now(this.midnight.getZone());
|
||||
now.minus(_retainDays, ChronoUnit.DAYS);
|
||||
long expired = now.toInstant().toEpochMilli();
|
||||
|
||||
File file= new File(_filename);
|
||||
File dir = new File(file.getParent());
|
||||
|
@ -272,9 +280,10 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
if(fn.startsWith(prefix)&&fn.indexOf(suffix,prefix.length())>=0)
|
||||
{
|
||||
File f = new File(dir,fn);
|
||||
long date = f.lastModified();
|
||||
if ( ((now-date)/(1000*60*60*24))>_retainDays)
|
||||
f.delete();
|
||||
if(f.lastModified() < expired)
|
||||
{
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,8 +306,6 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
throws IOException
|
||||
|
@ -316,8 +323,6 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
private class RollTask extends TimerTask
|
||||
{
|
||||
|
@ -327,13 +332,13 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
try
|
||||
{
|
||||
RolloverFileOutputStream.this.setFile();
|
||||
RolloverFileOutputStream.this.scheduleNextRollover();
|
||||
RolloverFileOutputStream.this.removeOldFiles();
|
||||
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
// Cannot log this exception to a LOG, as RolloverFOS can be used by logging
|
||||
e.printStackTrace();
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,13 +33,18 @@ import javax.websocket.server.ServerApplicationConfig;
|
|||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
|
||||
import org.eclipse.jetty.websocket.server.DefaultMappedWebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.server.MappedWebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
|
||||
@HandlesTypes(
|
||||
|
@ -47,13 +52,11 @@ import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
|||
public class WebSocketServerContainerInitializer implements ServletContainerInitializer
|
||||
{
|
||||
public static final String ENABLE_KEY = "org.eclipse.jetty.websocket.jsr356";
|
||||
public static final String ADD_DYNAMIC_FILTER_KEY = "org.eclipse.jetty.websocket.jsr356.addDynamicFilter";
|
||||
private static final Logger LOG = Log.getLogger(WebSocketServerContainerInitializer.class);
|
||||
|
||||
|
||||
/**
|
||||
* DestroyListener
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static class ContextDestroyListener implements ServletContextListener
|
||||
{
|
||||
|
@ -80,107 +83,97 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a ServletContext for {@code init-param} or {@code attribute} at {@code keyName} for
|
||||
* true or false setting that determines if the specified feature is enabled (or not).
|
||||
*
|
||||
* @param context the context to search
|
||||
* @param keyName the key name
|
||||
* @param defValue the default value, if the value is not specified in the context
|
||||
* @return the value for the feature key
|
||||
*/
|
||||
public static boolean isEnabledViaContext(ServletContext context, String keyName, boolean defValue)
|
||||
{
|
||||
// Try context parameters first
|
||||
String cp = context.getInitParameter(keyName);
|
||||
|
||||
if(cp != null)
|
||||
{
|
||||
if (TypeUtil.isTrue(cp))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TypeUtil.isFalse(cp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
// Next, try attribute on context
|
||||
Object enable = context.getAttribute(ENABLE_KEY);
|
||||
|
||||
if(enable != null)
|
||||
{
|
||||
if (TypeUtil.isTrue(enable))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TypeUtil.isFalse(enable))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Jetty Native approach.
|
||||
* <p>
|
||||
* Note: this will add the Upgrade filter to the existing list, with no regard for order. It will just be tacked onto the end of the list.
|
||||
*
|
||||
* @param context the servlet context handler
|
||||
* @return the created websocket server container
|
||||
* @throws ServletException if unable to create the websocket server container
|
||||
* Embedded Jetty approach for non-bytecode scanning.
|
||||
*/
|
||||
public static ServerContainer configureContext(ServletContextHandler context) throws ServletException
|
||||
{
|
||||
// Create Filter
|
||||
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
|
||||
// Create Basic components
|
||||
WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
|
||||
ByteBufferPool bufferPool = new MappedByteBufferPool();
|
||||
MappedWebSocketCreator creator = new DefaultMappedWebSocketCreator();
|
||||
WebSocketServerFactory factory = new WebSocketServerFactory(policy, bufferPool);
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),context.getServer().getThreadPool());
|
||||
context.addBean(jettyContainer, true);
|
||||
ServerContainer jettyContainer = new ServerContainer(creator,factory,context.getServer().getThreadPool());
|
||||
context.addBean(jettyContainer);
|
||||
|
||||
context.setAttribute(WebSocketUpgradeFilter.CREATOR_KEY, creator);
|
||||
context.setAttribute(WebSocketUpgradeFilter.FACTORY_KEY, factory);
|
||||
|
||||
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
|
||||
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
|
||||
|
||||
return jettyContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet 3.1 approach.
|
||||
* <p>
|
||||
* This will use Servlet 3.1 techniques on the {@link ServletContext} to add a filter at the start of the filter chain.
|
||||
*
|
||||
* @param context the servlet context
|
||||
* @param jettyContext the jetty servlet context handler
|
||||
* @return the created websocket server container
|
||||
* @throws ServletException if unable to create the websocket server container
|
||||
*/
|
||||
public static ServerContainer configureContext(ServletContext context, ServletContextHandler jettyContext) throws ServletException
|
||||
{
|
||||
|
||||
// Create Filter
|
||||
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),jettyContext.getServer().getThreadPool());
|
||||
jettyContext.addBean(jettyContainer, true);
|
||||
|
||||
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
|
||||
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
|
||||
|
||||
if(isEnabledViaContext(context.getServletContext(), ADD_DYNAMIC_FILTER_KEY, true))
|
||||
{
|
||||
WebSocketUpgradeFilter.configureContext(context);
|
||||
}
|
||||
|
||||
return jettyContainer;
|
||||
}
|
||||
|
||||
private boolean isEnabled(Set<Class<?>> c, ServletContext context)
|
||||
/**
|
||||
* @deprecated use {@link #configureContext(ServletContextHandler)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static ServerContainer configureContext(ServletContext context, ServletContextHandler jettyContext) throws ServletException
|
||||
{
|
||||
// Try context parameters first
|
||||
String cp = context.getInitParameter(ENABLE_KEY);
|
||||
if(TypeUtil.isTrue(cp))
|
||||
{
|
||||
// forced on
|
||||
return true;
|
||||
}
|
||||
|
||||
if(TypeUtil.isFalse(cp))
|
||||
{
|
||||
// forced off
|
||||
LOG.warn("JSR-356 support disabled via parameter on context {} - {}",context.getContextPath(),context);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next, try attribute on context
|
||||
Object enable = context.getAttribute(ENABLE_KEY);
|
||||
|
||||
if(TypeUtil.isTrue(enable))
|
||||
{
|
||||
// forced on
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TypeUtil.isFalse(enable))
|
||||
{
|
||||
// forced off
|
||||
LOG.warn("JSR-356 support disabled via attribute on context {} - {}",context.getContextPath(),context);
|
||||
return false;
|
||||
}
|
||||
|
||||
// if not forced on or off, determine behavior based on annotations.
|
||||
if (c.isEmpty())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("No JSR-356 annotations or interfaces discovered. JSR-356 support disabled",context.getContextPath(),context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return configureContext(jettyContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
|
||||
{
|
||||
if(!isEnabled(c,context))
|
||||
if(!isEnabledViaContext(context, ENABLE_KEY, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -203,26 +196,26 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
|
|||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(context.getClassLoader());
|
||||
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
ServerContainer jettyContainer = configureContext(context,jettyContext);
|
||||
|
||||
context.addListener(new ContextDestroyListener()); //make sure context is cleaned up when the context stops
|
||||
|
||||
// Establish the DecoratedObjectFactory thread local
|
||||
// for various ServiceLoader initiated components to use.
|
||||
DecoratedObjectFactory instantiator = (DecoratedObjectFactory)context.getAttribute(DecoratedObjectFactory.ATTR);
|
||||
if (instantiator == null)
|
||||
ServerContainer jettyContainer = configureContext(jettyContext);
|
||||
|
||||
context.addListener(new ContextDestroyListener()); // make sure context is cleaned up when the context stops
|
||||
|
||||
if (c.isEmpty())
|
||||
{
|
||||
LOG.info("Using WebSocket local DecoratedObjectFactory - none found in ServletContext");
|
||||
instantiator = new DecoratedObjectFactory();
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("No JSR-356 annotations or interfaces discovered");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Found {} classes",c.size());
|
||||
}
|
||||
|
||||
|
||||
// Now process the incoming classes
|
||||
Set<Class<? extends Endpoint>> discoveredExtendedEndpoints = new HashSet<>();
|
||||
Set<Class<?>> discoveredAnnotatedEndpoints = new HashSet<>();
|
||||
|
@ -312,9 +305,7 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
|
|||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoSocket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Testing the use of an alternate {@link org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter}
|
||||
* defined in the WEB-INF/web.xml
|
||||
*/
|
||||
public class AltFilterTest
|
||||
{
|
||||
@Rule
|
||||
public TestingDir testdir = new TestingDir();
|
||||
|
||||
@Rule
|
||||
public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test");
|
||||
|
||||
@Test
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
WSServer wsb = new WSServer(testdir,"app");
|
||||
wsb.copyWebInf("alt-filter-web.xml");
|
||||
// the endpoint (extends javax.websocket.Endpoint)
|
||||
wsb.copyClass(BasicEchoSocket.class);
|
||||
|
||||
try
|
||||
{
|
||||
wsb.start();
|
||||
URI uri = wsb.getServerBaseURI();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
wsb.deployWebapp(webapp);
|
||||
|
||||
FilterHolder filterWebXml = webapp.getServletHandler().getFilter("wsuf-test");
|
||||
assertThat("Filter[wsuf-test]", filterWebXml, notNullValue());
|
||||
|
||||
FilterHolder filterSCI = webapp.getServletHandler().getFilter("Jetty_WebSocketUpgradeFilter");
|
||||
assertThat("Filter[Jetty_WebSocketUpgradeFilter]", filterSCI, nullValue());
|
||||
|
||||
WebSocketClient client = new WebSocketClient(bufferPool);
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
JettyEchoSocket clientEcho = new JettyEchoSocket();
|
||||
Future<Session> future = client.connect(clientEcho,uri.resolve("echo"));
|
||||
// wait for connect
|
||||
future.get(1,TimeUnit.SECONDS);
|
||||
clientEcho.sendMessage("Hello Echo");
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
Assert.assertEquals("Expected message","Hello Echo",msgs.poll());
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
wsb.stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,21 +58,18 @@ public class ExtensionStackProcessingTest
|
|||
{
|
||||
private Server server;
|
||||
private ServerConnector connector;
|
||||
private ExtensionFactory serverExtensionFactory;
|
||||
private WebSocketContainer client;
|
||||
|
||||
private ServletContextHandler servletContextHandler;
|
||||
|
||||
@Before
|
||||
public void prepare() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(server, "/", true, false);
|
||||
ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
|
||||
|
||||
WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter)context.getAttribute(WebSocketUpgradeFilter.class.getName());
|
||||
serverExtensionFactory = filter.getFactory().getExtensionFactory();
|
||||
|
||||
servletContextHandler = new ServletContextHandler(server, "/", true, false);
|
||||
ServerContainer container = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
|
||||
|
||||
ServerEndpointConfig config = ServerEndpointConfig.Builder.create(BasicEchoEndpoint.class, "/").build();
|
||||
container.addEndpoint(config);
|
||||
|
@ -88,11 +85,18 @@ public class ExtensionStackProcessingTest
|
|||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
private void assumeDeflateFrameAvailable()
|
||||
{
|
||||
WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter)servletContextHandler.getAttribute(WebSocketUpgradeFilter.class.getName());
|
||||
ExtensionFactory serverExtensionFactory = filter.getFactory().getExtensionFactory();
|
||||
Assume.assumeTrue("Server has permessage-deflate extension registered",serverExtensionFactory.isAvailable("permessage-deflate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeflateFrameExtension() throws Exception
|
||||
{
|
||||
Assume.assumeTrue("Server has deflate-frame extension registered",serverExtensionFactory.isAvailable("deflate-frame"));
|
||||
assumeDeflateFrameAvailable();
|
||||
|
||||
ClientEndpointConfig config = ClientEndpointConfig.Builder.create()
|
||||
.extensions(Arrays.<Extension>asList(new JsrExtension("deflate-frame")))
|
||||
|
@ -140,7 +144,7 @@ public class ExtensionStackProcessingTest
|
|||
@Test
|
||||
public void testPerMessageDeflateExtension() throws Exception
|
||||
{
|
||||
Assume.assumeTrue("Server has permessage-deflate extension registered",serverExtensionFactory.isAvailable("permessage-deflate"));
|
||||
assumeDeflateFrameAvailable();
|
||||
|
||||
ClientEndpointConfig config = ClientEndpointConfig.Builder.create()
|
||||
.extensions(Arrays.<Extension>asList(new JsrExtension("permessage-deflate")))
|
||||
|
|
|
@ -142,6 +142,11 @@ public class WSServer
|
|||
{
|
||||
return serverUri;
|
||||
}
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
public File getWebAppDir()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1">
|
||||
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.websocket.jsr356.addDynamicFilter</param-name>
|
||||
<param-value>false</param-value>
|
||||
</context-param>
|
||||
|
||||
<filter>
|
||||
<filter-name>wsuf-test</filter-name>
|
||||
<filter-class>org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>wsuf-test</filter-name>
|
||||
<url-pattern>/echo/*</url-pattern>
|
||||
</filter-mapping>
|
||||
</web-app>
|
|
@ -221,9 +221,13 @@ public abstract class AbstractEventDriver extends AbstractLifeCycle implements I
|
|||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("openSession({})",session);
|
||||
{
|
||||
LOG.debug("openSession({})", session);
|
||||
LOG.debug("objectFactory={}", session.getContainerScope().getObjectFactory());
|
||||
}
|
||||
this.session = session;
|
||||
this.session.getContainerScope().getObjectFactory().decorate(this.websocket);
|
||||
|
||||
try
|
||||
{
|
||||
this.onConnect();
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathMappings;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
|
||||
public class DefaultMappedWebSocketCreator implements MappedWebSocketCreator
|
||||
{
|
||||
private final PathMappings<WebSocketCreator> mappings = new PathMappings<>();
|
||||
|
||||
@Override
|
||||
public void addMapping(PathSpec spec, WebSocketCreator creator)
|
||||
{
|
||||
this.mappings.put(spec, creator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathMappings<WebSocketCreator> getMappings()
|
||||
{
|
||||
return this.mappings;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@ import javax.servlet.DispatcherType;
|
|||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
@ -40,6 +39,7 @@ import org.eclipse.jetty.http.pathmap.RegexPathSpec;
|
|||
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
|
@ -59,11 +59,11 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
{
|
||||
public static final String CONTEXT_ATTRIBUTE_KEY = "contextAttributeKey";
|
||||
private static final Logger LOG = Log.getLogger(WebSocketUpgradeFilter.class);
|
||||
|
||||
|
||||
public static WebSocketUpgradeFilter configureContext(ServletContextHandler context) throws ServletException
|
||||
{
|
||||
// Prevent double configure
|
||||
WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter)context.getAttribute(WebSocketUpgradeFilter.class.getName());
|
||||
WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter) context.getAttribute(WebSocketUpgradeFilter.class.getName());
|
||||
if (filter != null)
|
||||
{
|
||||
return filter;
|
||||
|
@ -72,77 +72,71 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
// Dynamically add filter
|
||||
filter = new WebSocketUpgradeFilter();
|
||||
filter.setToAttribute(context, WebSocketUpgradeFilter.class.getName());
|
||||
|
||||
|
||||
String name = "Jetty_WebSocketUpgradeFilter";
|
||||
String pathSpec = "/*";
|
||||
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);
|
||||
|
||||
|
||||
FilterHolder fholder = new FilterHolder(filter);
|
||||
fholder.setName(name);
|
||||
fholder.setAsyncSupported(true);
|
||||
fholder.setInitParameter(CONTEXT_ATTRIBUTE_KEY,WebSocketUpgradeFilter.class.getName());
|
||||
context.addFilter(fholder,pathSpec,dispatcherTypes);
|
||||
|
||||
fholder.setInitParameter(CONTEXT_ATTRIBUTE_KEY, WebSocketUpgradeFilter.class.getName());
|
||||
context.addFilter(fholder, pathSpec, dispatcherTypes);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Adding [{}] {} mapped to {} to {}",name,filter,pathSpec,context);
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
public static WebSocketUpgradeFilter configureContext(ServletContext context) throws ServletException
|
||||
{
|
||||
// Prevent double configure
|
||||
WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter)context.getAttribute(WebSocketUpgradeFilter.class.getName());
|
||||
if (filter != null)
|
||||
{
|
||||
return filter;
|
||||
LOG.debug("Adding [{}] {} mapped to {} to {}", name, filter, pathSpec, context);
|
||||
}
|
||||
|
||||
// Dynamically add filter
|
||||
filter = new WebSocketUpgradeFilter();
|
||||
filter.setToAttribute(context, WebSocketUpgradeFilter.class.getName());
|
||||
|
||||
String name = "Jetty_Dynamic_WebSocketUpgradeFilter";
|
||||
String pathSpec = "/*";
|
||||
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);
|
||||
boolean isMatchAfter = false;
|
||||
String urlPatterns[] = { pathSpec };
|
||||
|
||||
FilterRegistration.Dynamic dyn = context.addFilter(name,filter);
|
||||
dyn.setAsyncSupported(true);
|
||||
dyn.setInitParameter(CONTEXT_ATTRIBUTE_KEY,WebSocketUpgradeFilter.class.getName());
|
||||
dyn.addMappingForUrlPatterns(dispatcherTypes,isMatchAfter,urlPatterns);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Adding [{}] {} mapped to {} to {}",name,filter,pathSpec,context);
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
private final WebSocketServerFactory factory;
|
||||
private final PathMappings<WebSocketCreator> pathmap = new PathMappings<>();
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #configureContext(ServletContextHandler)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static WebSocketUpgradeFilter configureContext(ServletContext context) throws ServletException
|
||||
{
|
||||
ContextHandler handler = ContextHandler.getContextHandler(context);
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
throw new ServletException("Not running on Jetty, WebSocket support unavailable");
|
||||
}
|
||||
|
||||
if (!(handler instanceof ServletContextHandler))
|
||||
{
|
||||
throw new ServletException("Not running in Jetty ServletContextHandler, WebSocket support via " + WebSocketUpgradeFilter.class.getName() + " unavailable");
|
||||
}
|
||||
|
||||
return configureContext((ServletContextHandler) handler);
|
||||
}
|
||||
|
||||
public static final String CREATOR_KEY = "org.eclipse.jetty.websocket.server.creator";
|
||||
public static final String FACTORY_KEY = "org.eclipse.jetty.websocket.server.factory";
|
||||
|
||||
private final WebSocketPolicy policy;
|
||||
private final ByteBufferPool bufferPool;
|
||||
private WebSocketServerFactory factory;
|
||||
private MappedWebSocketCreator mappedWebSocketCreator;
|
||||
private String fname;
|
||||
private boolean alreadySetToAttribute = false;
|
||||
|
||||
|
||||
public WebSocketUpgradeFilter()
|
||||
{
|
||||
this(WebSocketPolicy.newServerPolicy(),new MappedByteBufferPool());
|
||||
this(WebSocketPolicy.newServerPolicy(), new MappedByteBufferPool());
|
||||
}
|
||||
|
||||
|
||||
public WebSocketUpgradeFilter(WebSocketPolicy policy, ByteBufferPool bufferPool)
|
||||
{
|
||||
factory = new WebSocketServerFactory(policy,bufferPool);
|
||||
addBean(factory,true);
|
||||
this.policy = policy;
|
||||
this.bufferPool = bufferPool;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addMapping(PathSpec spec, WebSocketCreator creator)
|
||||
{
|
||||
pathmap.put(spec,creator);
|
||||
mappedWebSocketCreator.addMapping(spec, creator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,10 +163,9 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
public void destroy()
|
||||
{
|
||||
factory.cleanup();
|
||||
pathmap.reset();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
|
||||
{
|
||||
|
@ -180,10 +173,10 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
{
|
||||
// no factory, cannot operate
|
||||
LOG.debug("WebSocketUpgradeFilter is not operational - no WebSocketServletFactory configured");
|
||||
chain.doFilter(request,response);
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
HttpServletRequest httpreq = (HttpServletRequest) request;
|
||||
|
@ -195,7 +188,7 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Since this is a filter, we need to be smart about determining the target path
|
||||
String contextPath = httpreq.getContextPath();
|
||||
String target = httpreq.getRequestURI();
|
||||
|
@ -203,37 +196,37 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
{
|
||||
target = target.substring(contextPath.length());
|
||||
}
|
||||
|
||||
MappedResource<WebSocketCreator> resource = pathmap.getMatch(target);
|
||||
|
||||
MappedResource<WebSocketCreator> resource = mappedWebSocketCreator.getMappings().getMatch(target);
|
||||
if (resource == null)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("WebSocket Upgrade on {} has no associated endpoint", target);
|
||||
LOG.debug("PathMappings: {}", pathmap.dump());
|
||||
LOG.debug("PathMappings: {}", mappedWebSocketCreator.getMappings().dump());
|
||||
}
|
||||
// no match.
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if(LOG.isDebugEnabled())
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("WebSocket Upgrade detected on {} for endpoint {}", target, resource);
|
||||
}
|
||||
|
||||
|
||||
WebSocketCreator creator = resource.getResource();
|
||||
|
||||
|
||||
// Store PathSpec resource mapping as request attribute
|
||||
httpreq.setAttribute(PathSpec.class.getName(), resource.getPathSpec());
|
||||
|
||||
|
||||
// We have an upgrade request
|
||||
if (factory.acceptWebSocket(creator, httpreq, httpresp))
|
||||
{
|
||||
// We have a socket instance created
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If we reach this point, it means we had an incoming request to upgrade
|
||||
// but it was either not a proper websocket upgrade, or it was possibly rejected
|
||||
// due to incoming request constraints (controlled by WebSocketCreator)
|
||||
|
@ -251,71 +244,83 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
LOG.debug("Not a HttpServletRequest, skipping WebSocketUpgradeFilter");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// not an Upgrade request
|
||||
chain.doFilter(request,response);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
{
|
||||
return ContainerLifeCycle.dump(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
out.append(indent).append(" +- pathmap=").append(pathmap.toString()).append("\n");
|
||||
pathmap.dump(out,indent + " ");
|
||||
out.append(indent).append(" +- pathmap=").append(mappedWebSocketCreator.toString()).append("\n");
|
||||
mappedWebSocketCreator.getMappings().dump(out, indent + " ");
|
||||
}
|
||||
|
||||
|
||||
public WebSocketServerFactory getFactory()
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
||||
@ManagedAttribute(value = "mappings", readonly = true)
|
||||
@Override
|
||||
public PathMappings<WebSocketCreator> getMappings()
|
||||
{
|
||||
return pathmap;
|
||||
return mappedWebSocketCreator.getMappings();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException
|
||||
{
|
||||
fname = config.getFilterName();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
ServletContext ctx = config.getServletContext();
|
||||
factory.init(ctx);
|
||||
WebSocketPolicy policy = factory.getPolicy();
|
||||
|
||||
mappedWebSocketCreator = (MappedWebSocketCreator) config.getServletContext().getAttribute(CREATOR_KEY);
|
||||
if (mappedWebSocketCreator == null)
|
||||
{
|
||||
mappedWebSocketCreator = new DefaultMappedWebSocketCreator();
|
||||
}
|
||||
|
||||
factory = (WebSocketServerFactory) config.getServletContext().getAttribute(FACTORY_KEY);
|
||||
if (factory == null)
|
||||
{
|
||||
factory = new WebSocketServerFactory(policy, bufferPool);
|
||||
}
|
||||
factory.init(config.getServletContext());
|
||||
addBean(factory, true);
|
||||
|
||||
// TODO: Policy isn't from attributes
|
||||
|
||||
String max = config.getInitParameter("maxIdleTime");
|
||||
if (max != null)
|
||||
{
|
||||
policy.setIdleTimeout(Long.parseLong(max));
|
||||
factory.getPolicy().setIdleTimeout(Long.parseLong(max));
|
||||
}
|
||||
|
||||
|
||||
max = config.getInitParameter("maxTextMessageSize");
|
||||
if (max != null)
|
||||
{
|
||||
policy.setMaxTextMessageSize(Integer.parseInt(max));
|
||||
factory.getPolicy().setMaxTextMessageSize(Integer.parseInt(max));
|
||||
}
|
||||
|
||||
|
||||
max = config.getInitParameter("maxBinaryMessageSize");
|
||||
if (max != null)
|
||||
{
|
||||
policy.setMaxBinaryMessageSize(Integer.parseInt(max));
|
||||
factory.getPolicy().setMaxBinaryMessageSize(Integer.parseInt(max));
|
||||
}
|
||||
|
||||
|
||||
max = config.getInitParameter("inputBufferSize");
|
||||
if (max != null)
|
||||
{
|
||||
policy.setInputBufferSize(Integer.parseInt(max));
|
||||
factory.getPolicy().setInputBufferSize(Integer.parseInt(max));
|
||||
}
|
||||
|
||||
|
||||
String key = config.getInitParameter(CONTEXT_ATTRIBUTE_KEY);
|
||||
if (key == null)
|
||||
{
|
||||
|
@ -323,7 +328,7 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
key = WebSocketUpgradeFilter.class.getName();
|
||||
}
|
||||
|
||||
setToAttribute(ctx, key);
|
||||
setToAttribute(config.getServletContext(), key);
|
||||
|
||||
factory.start();
|
||||
}
|
||||
|
@ -335,45 +340,45 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
|
|||
|
||||
private void setToAttribute(ServletContextHandler context, String key) throws ServletException
|
||||
{
|
||||
if(alreadySetToAttribute)
|
||||
if (alreadySetToAttribute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getAttribute(key) != null)
|
||||
{
|
||||
throw new ServletException(WebSocketUpgradeFilter.class.getName() +
|
||||
throw new ServletException(WebSocketUpgradeFilter.class.getName() +
|
||||
" is defined twice for the same context attribute key '" + key
|
||||
+ "'. Make sure you have different init-param '" +
|
||||
+ "'. Make sure you have different init-param '" +
|
||||
CONTEXT_ATTRIBUTE_KEY + "' values set");
|
||||
}
|
||||
context.setAttribute(key,this);
|
||||
|
||||
context.setAttribute(key, this);
|
||||
|
||||
alreadySetToAttribute = true;
|
||||
}
|
||||
|
||||
|
||||
public void setToAttribute(ServletContext context, String key) throws ServletException
|
||||
{
|
||||
if(alreadySetToAttribute)
|
||||
if (alreadySetToAttribute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getAttribute(key) != null)
|
||||
{
|
||||
throw new ServletException(WebSocketUpgradeFilter.class.getName() +
|
||||
throw new ServletException(WebSocketUpgradeFilter.class.getName() +
|
||||
" is defined twice for the same context attribute key '" + key
|
||||
+ "'. Make sure you have different init-param '" +
|
||||
+ "'. Make sure you have different init-param '" +
|
||||
CONTEXT_ATTRIBUTE_KEY + "' values set");
|
||||
}
|
||||
context.setAttribute(key,this);
|
||||
|
||||
context.setAttribute(key, this);
|
||||
|
||||
alreadySetToAttribute = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[factory=%s,pathmap=%s]",this.getClass().getSimpleName(),factory,pathmap);
|
||||
return String.format("%s[factory=%s,creator=%s]", this.getClass().getSimpleName(), factory, mappedWebSocketCreator);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.net.URL;
|
|||
import java.net.UnknownHostException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -1429,13 +1430,12 @@ public class XmlConfiguration
|
|||
*/
|
||||
public static void main(final String... args) throws Exception
|
||||
{
|
||||
final AtomicReference<Throwable> exception = new AtomicReference<>();
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>()
|
||||
try
|
||||
{
|
||||
public Object run()
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>()
|
||||
{
|
||||
try
|
||||
@Override
|
||||
public Void run() throws Exception
|
||||
{
|
||||
Properties properties = null;
|
||||
|
||||
|
@ -1509,26 +1509,15 @@ public class XmlConfiguration
|
|||
lc.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.debug(Log.EXCEPTION,e);
|
||||
exception.set(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
Throwable th = exception.get();
|
||||
if (th != null)
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Error|Exception e)
|
||||
{
|
||||
if (th instanceof RuntimeException)
|
||||
throw (RuntimeException)th;
|
||||
else if (th instanceof Exception)
|
||||
throw (Exception)th;
|
||||
else if (th instanceof Error)
|
||||
throw (Error)th;
|
||||
throw new Error(th);
|
||||
LOG.warn(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue