1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.server;
20
21 import java.io.IOException;
22 import java.util.EnumSet;
23
24 import javax.servlet.DispatcherType;
25 import javax.servlet.Filter;
26 import javax.servlet.FilterChain;
27 import javax.servlet.FilterConfig;
28 import javax.servlet.ServletException;
29 import javax.servlet.ServletRequest;
30 import javax.servlet.ServletResponse;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33
34 import org.eclipse.jetty.io.ByteBufferPool;
35 import org.eclipse.jetty.io.MappedByteBufferPool;
36 import org.eclipse.jetty.servlet.FilterHolder;
37 import org.eclipse.jetty.servlet.ServletContextHandler;
38 import org.eclipse.jetty.util.annotation.ManagedAttribute;
39 import org.eclipse.jetty.util.annotation.ManagedObject;
40 import org.eclipse.jetty.util.component.ContainerLifeCycle;
41 import org.eclipse.jetty.util.component.Dumpable;
42 import org.eclipse.jetty.util.log.Log;
43 import org.eclipse.jetty.util.log.Logger;
44 import org.eclipse.jetty.websocket.api.WebSocketBehavior;
45 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
46 import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
47 import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
48 import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
49 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
50
51
52
53
54 @ManagedObject("WebSocket Upgrade Filter")
55 public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter, MappedWebSocketCreator, Dumpable
56 {
57 private static final Logger LOG = Log.getLogger(WebSocketUpgradeFilter.class);
58
59 public static WebSocketUpgradeFilter configureContext(ServletContextHandler context)
60 {
61 WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
62
63 WebSocketUpgradeFilter filter = new WebSocketUpgradeFilter(policy);
64 FilterHolder fholder = new FilterHolder(filter);
65 fholder.setName("Jetty_WebSocketUpgradeFilter");
66 fholder.setDisplayName("WebSocket Upgrade Filter");
67 String pathSpec = "/*";
68 context.addFilter(fholder,pathSpec,EnumSet.of(DispatcherType.REQUEST));
69 LOG.debug("Adding {} mapped to {} to {}",filter,pathSpec,context);
70
71
72 context.setAttribute(WebSocketUpgradeFilter.class.getName(),filter);
73
74 return filter;
75 }
76
77 private final WebSocketServerFactory factory;
78 private final PathMappings<WebSocketCreator> pathmap = new PathMappings<>();
79
80 public WebSocketUpgradeFilter(WebSocketPolicy policy)
81 {
82 this(policy, new MappedByteBufferPool());
83 }
84
85 public WebSocketUpgradeFilter(WebSocketPolicy policy, ByteBufferPool bufferPool)
86 {
87 factory = new WebSocketServerFactory(policy,bufferPool);
88 addBean(factory,true);
89 }
90
91 @Override
92 public void addMapping(PathSpec spec, WebSocketCreator creator)
93 {
94 pathmap.put(spec,creator);
95 }
96
97 @Override
98 public void destroy()
99 {
100 factory.cleanup();
101 pathmap.reset();
102 super.destroy();
103 }
104
105 @Override
106 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
107 {
108 if (factory == null)
109 {
110
111 LOG.debug("WebSocketUpgradeFilter is not operational - no WebSocketServletFactory configured");
112 chain.doFilter(request,response);
113 return;
114 }
115
116 if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse))
117 {
118 HttpServletRequest httpreq = (HttpServletRequest)request;
119 HttpServletResponse httpresp = (HttpServletResponse)response;
120
121
122 String contextPath = httpreq.getContextPath();
123 String target = httpreq.getRequestURI();
124 if (target.startsWith(contextPath))
125 {
126 target = target.substring(contextPath.length());
127 }
128
129 if (factory.isUpgradeRequest(httpreq,httpresp))
130 {
131 LOG.debug("target = [{}]",target);
132
133 MappedResource<WebSocketCreator> resource = pathmap.getMatch(target);
134 if (resource == null)
135 {
136 if (LOG.isDebugEnabled())
137 {
138 LOG.debug("WebSocket Upgrade on {} has no associated endpoint",target);
139 LOG.debug("PathMappings: {}",pathmap.dump());
140 }
141
142 chain.doFilter(request,response);
143 return;
144 }
145 LOG.debug("WebSocket Upgrade detected on {} for endpoint {}",target,resource);
146
147 WebSocketCreator creator = resource.getResource();
148
149
150 httpreq.setAttribute(PathSpec.class.getName(),resource.getPathSpec());
151
152
153 if (factory.acceptWebSocket(creator,httpreq,httpresp))
154 {
155
156 return;
157 }
158
159
160
161
162 if (response.isCommitted())
163 {
164
165 return;
166 }
167 }
168 }
169
170
171 chain.doFilter(request,response);
172 }
173
174 @Override
175 public String dump()
176 {
177 return ContainerLifeCycle.dump(this);
178 }
179
180 @Override
181 public void dump(Appendable out, String indent) throws IOException
182 {
183 out.append(indent).append(" +- pathmap=").append(pathmap.toString()).append("\n");
184 pathmap.dump(out,indent + " ");
185 }
186
187 public WebSocketServerFactory getFactory()
188 {
189 return factory;
190 }
191
192 @ManagedAttribute(value = "mappings", readonly = true)
193 @Override
194 public PathMappings<WebSocketCreator> getMappings()
195 {
196 return pathmap;
197 }
198
199 @Override
200 public void init(FilterConfig config) throws ServletException
201 {
202 try
203 {
204 WebSocketPolicy policy = factory.getPolicy();
205
206 String max = config.getInitParameter("maxIdleTime");
207 if (max != null)
208 {
209 policy.setIdleTimeout(Long.parseLong(max));
210 }
211
212 max = config.getInitParameter("maxTextMessageSize");
213 if (max != null)
214 {
215 policy.setMaxTextMessageSize(Integer.parseInt(max));
216 }
217
218 max = config.getInitParameter("maxBinaryMessageSize");
219 if (max != null)
220 {
221 policy.setMaxBinaryMessageSize(Integer.parseInt(max));
222 }
223
224 max = config.getInitParameter("inputBufferSize");
225 if (max != null)
226 {
227 policy.setInputBufferSize(Integer.parseInt(max));
228 }
229
230 factory.start();
231 }
232 catch (Exception x)
233 {
234 throw new ServletException(x);
235 }
236 }
237
238 @Override
239 public String toString()
240 {
241 return String.format("%s[factory=%s,pathmap=%s]",this.getClass().getSimpleName(),factory,pathmap);
242 }
243 }