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 javax.servlet.http.HttpServletRequest; 46 * import org.eclipse.jetty.websocket.WebSocket; 47 * import org.eclipse.jetty.websocket.server.WebSocketServlet; 48 * 49 * public class MyEchoServlet extends WebSocketServlet 50 * { 51 * @Override 52 * public void registerWebSockets(WebSocketServerFactory factory) 53 * { 54 * factory.register(MyEchoSocket.class); 55 * } 56 * } 57 * </pre> 58 * 59 * Note: that only request that conforms to a "WebSocket: Upgrade" handshake request will trigger the {@link WebSocketServerFactory} handling of creating 60 * WebSockets.<br> 61 * All other requests are treated as normal servlet requests. 62 * 63 * <p> 64 * <b>Configuration / Init-Parameters:</b><br> 65 * Note: If you use the {@link WebSocket @WebSocket} annotation, these configuration settings can be specified on a per WebSocket basis, vs a per Servlet 66 * basis. 67 * 68 * <dl> 69 * <dt>maxIdleTime</dt> 70 * <dd>set the time in ms that a websocket may be idle before closing<br> 71 * 72 * <dt>maxMessagesSize</dt> 73 * <dd>set the size in bytes that a websocket may be accept before closing<br> 74 * 75 * <dt>inputBufferSize</dt> 76 * <dd>set the size in bytes of the buffer used to read raw bytes from the network layer<br> 77 * </dl> 78 */ 79 @SuppressWarnings("serial") 80 public abstract class WebSocketServlet extends HttpServlet 81 { 82 private WebSocketServletFactory factory; 83 84 public abstract void configure(WebSocketServletFactory factory); 85 86 @Override 87 public void destroy() 88 { 89 factory.cleanup(); 90 } 91 92 /** 93 * @see javax.servlet.GenericServlet#init() 94 */ 95 @Override 96 public void init() throws ServletException 97 { 98 try 99 { 100 WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER); 101 102 String max = getInitParameter("maxIdleTime"); 103 if (max != null) 104 { 105 policy.setIdleTimeout(Long.parseLong(max)); 106 } 107 108 max = getInitParameter("maxMessageSize"); 109 if (max != null) 110 { 111 policy.setMaxMessageSize(Long.parseLong(max)); 112 } 113 114 max = getInitParameter("inputBufferSize"); 115 if (max != null) 116 { 117 policy.setInputBufferSize(Integer.parseInt(max)); 118 } 119 120 WebSocketServletFactory baseFactory; 121 Iterator<WebSocketServletFactory> factories = ServiceLoader.load(WebSocketServletFactory.class).iterator(); 122 123 if (factories.hasNext()) 124 { 125 baseFactory = factories.next(); 126 } 127 else 128 { 129 // Load the default class if ServiceLoader mechanism isn't valid in this environment. (such as OSGi) 130 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 131 @SuppressWarnings("unchecked") 132 Class<WebSocketServletFactory> wssf = (Class<WebSocketServletFactory>)loader 133 .loadClass("org.eclipse.jetty.websocket.server.WebSocketServerFactory"); 134 baseFactory = wssf.newInstance(); 135 } 136 137 factory = baseFactory.createFactory(policy); 138 139 configure(factory); 140 141 factory.init(); 142 } 143 catch (Exception x) 144 { 145 throw new ServletException(x); 146 } 147 } 148 149 /** 150 * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 151 */ 152 @Override 153 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 154 { 155 if (factory.isUpgradeRequest(request,response)) 156 { 157 // We have an upgrade request 158 if (factory.acceptWebSocket(request,response)) 159 { 160 // We have a socket instance created 161 return; 162 } 163 // If we reach this point, it means we had an incoming request to upgrade 164 // but it was either not a proper websocket upgrade, or it was possibly rejected 165 // due to incoming request constraints (controlled by WebSocketCreator) 166 if (response.isCommitted()) 167 { 168 // not much we can do at this point. 169 return; 170 } 171 } 172 173 // All other processing 174 super.service(request,response); 175 } 176 }