1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.common;
20
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.net.URI;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.eclipse.jetty.util.MultiMap;
29 import org.eclipse.jetty.util.StringUtil;
30 import org.eclipse.jetty.util.UrlEncoded;
31 import org.eclipse.jetty.util.annotation.ManagedAttribute;
32 import org.eclipse.jetty.util.annotation.ManagedObject;
33 import org.eclipse.jetty.util.component.ContainerLifeCycle;
34 import org.eclipse.jetty.util.component.Dumpable;
35 import org.eclipse.jetty.util.log.Log;
36 import org.eclipse.jetty.util.log.Logger;
37 import org.eclipse.jetty.websocket.api.CloseStatus;
38 import org.eclipse.jetty.websocket.api.RemoteEndpoint;
39 import org.eclipse.jetty.websocket.api.Session;
40 import org.eclipse.jetty.websocket.api.StatusCode;
41 import org.eclipse.jetty.websocket.api.SuspendToken;
42 import org.eclipse.jetty.websocket.api.UpgradeRequest;
43 import org.eclipse.jetty.websocket.api.UpgradeResponse;
44 import org.eclipse.jetty.websocket.api.WebSocketException;
45 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
46 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
47 import org.eclipse.jetty.websocket.api.extensions.Frame;
48 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
49 import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
50 import org.eclipse.jetty.websocket.common.events.EventDriver;
51
52 @ManagedObject
53 public class WebSocketSession extends ContainerLifeCycle implements Session, IncomingFrames
54 {
55 private static final Logger LOG = Log.getLogger(WebSocketSession.class);
56 private final URI requestURI;
57 private final EventDriver websocket;
58 private final LogicalConnection connection;
59 private ExtensionFactory extensionFactory;
60 private long maximumMessageSize;
61 private String protocolVersion;
62 private long timeout;
63 private Map<String, String[]> parameterMap = new HashMap<>();
64 private WebSocketRemoteEndpoint remote;
65 private IncomingFrames incomingHandler;
66 private OutgoingFrames outgoingHandler;
67 private WebSocketPolicy policy;
68 private UpgradeRequest upgradeRequest;
69 private UpgradeResponse upgradeResponse;
70
71 public WebSocketSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
72 {
73 if (requestURI == null)
74 {
75 throw new RuntimeException("Request URI cannot be null");
76 }
77
78 this.requestURI = requestURI;
79 this.websocket = websocket;
80 this.connection = connection;
81 this.outgoingHandler = connection;
82 this.incomingHandler = websocket;
83
84
85 MultiMap<String> params = new MultiMap<>();
86 String query = requestURI.getQuery();
87 if (StringUtil.isNotBlank(query))
88 {
89 UrlEncoded.decodeTo(query,params,StringUtil.__UTF8_CHARSET,-1);
90 }
91
92 for (String name : params.keySet())
93 {
94 List<String> valueList = params.getValues(name);
95 String valueArr[] = new String[valueList.size()];
96 valueArr = valueList.toArray(valueArr);
97 parameterMap.put(name,valueArr);
98 }
99 }
100
101 @Override
102 public void close() throws IOException
103 {
104 connection.close();
105 }
106
107 @Override
108 public void close(CloseStatus closeStatus)
109 {
110 this.close(closeStatus.getCode(),closeStatus.getPhrase());
111 }
112
113 @Override
114 public void close(int statusCode, String reason)
115 {
116 connection.close(statusCode,reason);
117 websocket.onClose(new CloseInfo(statusCode,reason));
118 }
119
120
121
122
123 @Override
124 public void disconnect()
125 {
126 connection.disconnect();
127
128
129 websocket.onClose(new CloseInfo(StatusCode.NO_CLOSE,"Harsh disconnect"));
130 }
131
132 @Override
133 public void dump(Appendable out, String indent) throws IOException
134 {
135 super.dump(out,indent);
136 out.append(indent).append(" +- incomingHandler : ");
137 if (incomingHandler instanceof Dumpable)
138 {
139 ((Dumpable)incomingHandler).dump(out,indent + " ");
140 }
141 else
142 {
143 out.append(incomingHandler.toString()).append('\n');
144 }
145
146 out.append(indent).append(" +- outgoingHandler : ");
147 if (outgoingHandler instanceof Dumpable)
148 {
149 ((Dumpable)outgoingHandler).dump(out,indent + " ");
150 }
151 else
152 {
153 out.append(outgoingHandler.toString()).append('\n');
154 }
155 }
156
157 public LogicalConnection getConnection()
158 {
159 return connection;
160 }
161
162 public ExtensionFactory getExtensionFactory()
163 {
164 return extensionFactory;
165 }
166
167
168
169
170 @Override
171 public long getIdleTimeout()
172 {
173 return timeout;
174 }
175
176 @ManagedAttribute(readonly = true)
177 public IncomingFrames getIncomingHandler()
178 {
179 return incomingHandler;
180 }
181
182 @Override
183 public InetSocketAddress getLocalAddress()
184 {
185 return connection.getLocalAddress();
186 }
187
188 @Override
189 public long getMaximumMessageSize()
190 {
191 return maximumMessageSize;
192 }
193
194 @ManagedAttribute(readonly = true)
195 public OutgoingFrames getOutgoingHandler()
196 {
197 return outgoingHandler;
198 }
199
200 @Override
201 public WebSocketPolicy getPolicy()
202 {
203 return policy;
204 }
205
206 @Override
207 public String getProtocolVersion()
208 {
209 return protocolVersion;
210 }
211
212 @Override
213 public RemoteEndpoint getRemote()
214 {
215 if (!isOpen())
216 {
217 throw new WebSocketException("Session has not been opened yet");
218 }
219 return remote;
220 }
221
222 @Override
223 public InetSocketAddress getRemoteAddress()
224 {
225 return remote.getInetSocketAddress();
226 }
227
228 @Override
229 public UpgradeRequest getUpgradeRequest()
230 {
231 return this.upgradeRequest;
232 }
233
234 @Override
235 public UpgradeResponse getUpgradeResponse()
236 {
237 return this.upgradeResponse;
238 }
239
240
241
242
243 @Override
244 public void incomingError(WebSocketException e)
245 {
246 if (connection.getIOState().isInputClosed())
247 {
248 return;
249 }
250
251 websocket.incomingError(e);
252 }
253
254
255
256
257 @Override
258 public void incomingFrame(Frame frame)
259 {
260 if (connection.getIOState().isInputClosed())
261 {
262 return;
263 }
264
265
266 incomingHandler.incomingFrame(frame);
267 }
268
269 @Override
270 public boolean isOpen()
271 {
272 if (this.connection == null)
273 {
274 return false;
275 }
276 return this.connection.isOpen();
277 }
278
279 @Override
280 public boolean isSecure()
281 {
282 if (upgradeRequest == null)
283 {
284 throw new IllegalStateException("No valid UpgradeRequest yet");
285 }
286
287 URI requestURI = upgradeRequest.getRequestURI();
288
289 return "wss".equalsIgnoreCase(requestURI.getScheme());
290 }
291
292
293
294
295
296
297 public void open()
298 {
299 if (remote != null)
300 {
301
302 return;
303 }
304
305
306 remote = new WebSocketRemoteEndpoint(connection,outgoingHandler);
307
308
309 websocket.openSession(this);
310
311 if (LOG.isDebugEnabled())
312 {
313 LOG.debug("open -> {}",dump());
314 }
315 }
316
317 public void setExtensionFactory(ExtensionFactory extensionFactory)
318 {
319 this.extensionFactory = extensionFactory;
320 }
321
322
323
324
325 @Override
326 public void setIdleTimeout(long seconds)
327 {
328 this.timeout = seconds;
329 }
330
331 @Override
332 public void setMaximumMessageSize(long length)
333 {
334 this.maximumMessageSize = length;
335 }
336
337 public void setOutgoingHandler(OutgoingFrames outgoing)
338 {
339 this.outgoingHandler = outgoing;
340 }
341
342 public void setPolicy(WebSocketPolicy policy)
343 {
344 this.policy = policy;
345 }
346
347 public void setUpgradeRequest(UpgradeRequest request)
348 {
349 this.upgradeRequest = request;
350 }
351
352 public void setUpgradeResponse(UpgradeResponse response)
353 {
354 this.upgradeResponse = response;
355 }
356
357 @Override
358 public SuspendToken suspend()
359 {
360
361 return null;
362 }
363
364 @Override
365 public String toString()
366 {
367 StringBuilder builder = new StringBuilder();
368 builder.append("WebSocketSession[");
369 builder.append("websocket=").append(websocket);
370 builder.append(",behavior=").append(policy.getBehavior());
371 builder.append(",connection=").append(connection);
372 builder.append(",remote=").append(remote);
373 builder.append(",incoming=").append(incomingHandler);
374 builder.append(",outgoing=").append(outgoingHandler);
375 builder.append("]");
376 return builder.toString();
377 }
378 }