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