1 //
2 // ========================================================================
3 // Copyright (c) 1995-2016 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
23 import javax.servlet.ServletContext;
24 import javax.servlet.ServletException;
25 import javax.servlet.http.HttpServlet;
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28
29 import org.eclipse.jetty.websocket.api.WebSocketBehavior;
30 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
31 import org.eclipse.jetty.websocket.api.annotations.WebSocket;
32
33 /**
34 * Abstract Servlet used to bridge the Servlet API to the WebSocket API.
35 * <p>
36 * To use this servlet, you will be required to register your websockets with the {@link WebSocketServletFactory} so that it can create your websockets under the
37 * appropriate conditions.
38 * <p>
39 * The most basic implementation would be as follows.
40 *
41 * <pre>
42 * package my.example;
43 *
44 * import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
45 * import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
46 *
47 * public class MyEchoServlet extends WebSocketServlet
48 * {
49 * @Override
50 * public void configure(WebSocketServletFactory factory)
51 * {
52 * // set a 10 second idle timeout
53 * factory.getPolicy().setIdleTimeout(10000);
54 * // register my socket
55 * factory.register(MyEchoSocket.class);
56 * }
57 * }
58 * </pre>
59 *
60 * Note: that only request that conforms to a "WebSocket: Upgrade" handshake request will trigger the {@link WebSocketServletFactory} handling of creating
61 * WebSockets.<br>
62 * All other requests are treated as normal servlet requests.
63 *
64 * <p>
65 * <b>Configuration / Init-Parameters:</b><br>
66 * Note: If you use the {@link WebSocket @WebSocket} annotation, these configuration settings can be specified on a per WebSocket basis, vs a per Servlet
67 * basis.
68 *
69 * <dl>
70 * <dt>maxIdleTime</dt>
71 * <dd>set the time in ms that a websocket may be idle before closing<br>
72 *
73 * <dt>maxTextMessageSize</dt>
74 * <dd>set the size in UTF-8 bytes that a websocket may be accept as a Text Message before closing<br>
75 *
76 * <dt>maxBinaryMessageSize</dt>
77 * <dd>set the size in bytes that a websocket may be accept as a Binary Message before closing<br>
78 *
79 * <dt>inputBufferSize</dt>
80 * <dd>set the size in bytes of the buffer used to read raw bytes from the network layer<br>
81 * </dl>
82 */
83 @SuppressWarnings("serial")
84 public abstract class WebSocketServlet extends HttpServlet
85 {
86 private WebSocketServletFactory factory;
87
88 public abstract void configure(WebSocketServletFactory factory);
89
90 @Override
91 public void destroy()
92 {
93 try
94 {
95 factory.stop();
96 }
97 catch (Exception ignore)
98 {
99 // ignore;
100 }
101 }
102
103 /**
104 * @see javax.servlet.GenericServlet#init()
105 */
106 @Override
107 public void init() throws ServletException
108 {
109 try
110 {
111 WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
112
113 String max = getInitParameter("maxIdleTime");
114 if (max != null)
115 {
116 policy.setIdleTimeout(Long.parseLong(max));
117 }
118
119 max = getInitParameter("maxTextMessageSize");
120 if (max != null)
121 {
122 policy.setMaxTextMessageSize(Integer.parseInt(max));
123 }
124
125 max = getInitParameter("maxBinaryMessageSize");
126 if (max != null)
127 {
128 policy.setMaxBinaryMessageSize(Integer.parseInt(max));
129 }
130
131 max = getInitParameter("inputBufferSize");
132 if (max != null)
133 {
134 policy.setInputBufferSize(Integer.parseInt(max));
135 }
136
137 ServletContext ctx = getServletContext();
138 factory = WebSocketServletFactory.Loader.load(ctx, policy);
139
140 configure(factory);
141
142 factory.start();
143
144 ctx.setAttribute(WebSocketServletFactory.class.getName(),factory);
145 }
146 catch (Exception x)
147 {
148 throw new ServletException(x);
149 }
150 }
151
152 /**
153 * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
154 */
155 @Override
156 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
157 {
158 if (factory.isUpgradeRequest(request,response))
159 {
160 // We have an upgrade request
161 if (factory.acceptWebSocket(request,response))
162 {
163 // We have a socket instance created
164 return;
165 }
166 // If we reach this point, it means we had an incoming request to upgrade
167 // but it was either not a proper websocket upgrade, or it was possibly rejected
168 // due to incoming request constraints (controlled by WebSocketCreator)
169 if (response.isCommitted())
170 {
171 // not much we can do at this point.
172 return;
173 }
174 }
175
176 // All other processing
177 super.service(request,response);
178 }
179 }