1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.websocket.servlet; 20 21 import java.io.IOException; 22 import java.util.Iterator; 23 import java.util.ServiceLoader; 24 25 import javax.servlet.ServletException; 26 import javax.servlet.http.HttpServlet; 27 import javax.servlet.http.HttpServletRequest; 28 import javax.servlet.http.HttpServletResponse; 29 30 import org.eclipse.jetty.websocket.api.WebSocketBehavior; 31 import org.eclipse.jetty.websocket.api.WebSocketPolicy; 32 import org.eclipse.jetty.websocket.api.annotations.WebSocket; 33 34 /** 35 * Abstract Servlet used to bridge the Servlet API to the WebSocket API. 36 * <p> 37 * To use this servlet, you will be required to register your websockets with the {@link WebSocketServerFactory} so that it can create your websockets under the 38 * appropriate conditions. 39 * <p> 40 * The most basic implementation would be as follows. 41 * 42 * <pre> 43 * package my.example; 44 * 45 * import org.eclipse.jetty.websocket.servlet.WebSocketServlet; 46 * import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; 47 * 48 * public class MyEchoServlet extends WebSocketServlet 49 * { 50 * @Override 51 * public void configure(WebSocketServletFactory factory) 52 * { 53 * // set a 10 second idle timeout 54 * factory.getPolicy().setIdleTimeout(10000); 55 * // register my socket 56 * factory.register(MyEchoSocket.class); 57 * } 58 * } 59 * </pre> 60 * 61 * Note: that only request that conforms to a "WebSocket: Upgrade" handshake request will trigger the {@link WebSocketServerFactory} handling of creating 62 * WebSockets.<br> 63 * All other requests are treated as normal servlet requests. 64 * 65 * <p> 66 * <b>Configuration / Init-Parameters:</b><br> 67 * Note: If you use the {@link WebSocket @WebSocket} annotation, these configuration settings can be specified on a per WebSocket basis, vs a per Servlet 68 * basis. 69 * 70 * <dl> 71 * <dt>maxIdleTime</dt> 72 * <dd>set the time in ms that a websocket may be idle before closing<br> 73 * 74 * <dt>maxMessagesSize</dt> 75 * <dd>set the size in bytes that a websocket may be accept before closing<br> 76 * 77 * <dt>inputBufferSize</dt> 78 * <dd>set the size in bytes of the buffer used to read raw bytes from the network layer<br> 79 * </dl> 80 */ 81 @SuppressWarnings("serial") 82 public abstract class WebSocketServlet extends HttpServlet 83 { 84 private WebSocketServletFactory factory; 85 86 public abstract void configure(WebSocketServletFactory factory); 87 88 @Override 89 public void destroy() 90 { 91 factory.cleanup(); 92 } 93 94 /** 95 * @see javax.servlet.GenericServlet#init() 96 */ 97 @Override 98 public void init() throws ServletException 99 { 100 try 101 { 102 WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER); 103 104 String max = getInitParameter("maxIdleTime"); 105 if (max != null) 106 { 107 policy.setIdleTimeout(Long.parseLong(max)); 108 } 109 110 max = getInitParameter("maxMessageSize"); 111 if (max != null) 112 { 113 policy.setMaxMessageSize(Long.parseLong(max)); 114 } 115 116 max = getInitParameter("inputBufferSize"); 117 if (max != null) 118 { 119 policy.setInputBufferSize(Integer.parseInt(max)); 120 } 121 122 WebSocketServletFactory baseFactory; 123 Iterator<WebSocketServletFactory> factories = ServiceLoader.load(WebSocketServletFactory.class).iterator(); 124 125 if (factories.hasNext()) 126 { 127 baseFactory = factories.next(); 128 } 129 else 130 { 131 // Load the default class if ServiceLoader mechanism isn't valid in this environment. (such as OSGi) 132 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 133 @SuppressWarnings("unchecked") 134 Class<WebSocketServletFactory> wssf = (Class<WebSocketServletFactory>)loader 135 .loadClass("org.eclipse.jetty.websocket.server.WebSocketServerFactory"); 136 baseFactory = wssf.newInstance(); 137 } 138 139 factory = baseFactory.createFactory(policy); 140 141 configure(factory); 142 143 factory.init(); 144 } 145 catch (Exception x) 146 { 147 throw new ServletException(x); 148 } 149 } 150 151 /** 152 * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 153 */ 154 @Override 155 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 156 { 157 if (factory.isUpgradeRequest(request,response)) 158 { 159 // We have an upgrade request 160 if (factory.acceptWebSocket(request,response)) 161 { 162 // We have a socket instance created 163 return; 164 } 165 // If we reach this point, it means we had an incoming request to upgrade 166 // but it was either not a proper websocket upgrade, or it was possibly rejected 167 // due to incoming request constraints (controlled by WebSocketCreator) 168 if (response.isCommitted()) 169 { 170 // not much we can do at this point. 171 return; 172 } 173 } 174 175 // All other processing 176 super.service(request,response); 177 } 178 }