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.events;
20
21 import java.io.IOException;
22 import java.nio.ByteBuffer;
23
24 import org.eclipse.jetty.util.BufferUtil;
25 import org.eclipse.jetty.util.StringUtil;
26 import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
27 import org.eclipse.jetty.util.log.Log;
28 import org.eclipse.jetty.util.log.Logger;
29 import org.eclipse.jetty.websocket.api.CloseException;
30 import org.eclipse.jetty.websocket.api.StatusCode;
31 import org.eclipse.jetty.websocket.api.WebSocketException;
32 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
33 import org.eclipse.jetty.websocket.api.extensions.Frame;
34 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
35 import org.eclipse.jetty.websocket.common.CloseInfo;
36 import org.eclipse.jetty.websocket.common.OpCode;
37 import org.eclipse.jetty.websocket.common.WebSocketFrame;
38 import org.eclipse.jetty.websocket.common.WebSocketSession;
39
40
41
42
43 public abstract class EventDriver implements IncomingFrames
44 {
45 private static final Logger LOG = Log.getLogger(EventDriver.class);
46 protected final WebSocketPolicy policy;
47 protected final Object websocket;
48 protected WebSocketSession session;
49
50 public EventDriver(WebSocketPolicy policy, Object websocket)
51 {
52 this.policy = policy;
53 this.websocket = websocket;
54 }
55
56 public WebSocketPolicy getPolicy()
57 {
58 return policy;
59 }
60
61 public WebSocketSession getSession()
62 {
63 return session;
64 }
65
66 @Override
67 public final void incomingError(WebSocketException e)
68 {
69 if (LOG.isDebugEnabled())
70 {
71 LOG.debug("incoming(WebSocketException)",e);
72 }
73
74 if (e instanceof CloseException)
75 {
76 CloseException close = (CloseException)e;
77 terminateConnection(close.getStatusCode(),close.getMessage());
78 }
79
80 onError(e);
81 }
82
83 @Override
84 public void incomingFrame(Frame frame)
85 {
86 if (LOG.isDebugEnabled())
87 {
88 LOG.debug("{}.onFrame({})",websocket.getClass().getSimpleName(),frame);
89 }
90
91 onFrame(frame);
92
93 try
94 {
95 switch (frame.getType().getOpCode())
96 {
97 case OpCode.CLOSE:
98 {
99 boolean validate = true;
100 CloseInfo close = new CloseInfo(frame,validate);
101
102
103 onClose(close);
104
105
106 if (session.getConnection().getIOState().onCloseHandshake(true))
107 {
108
109 session.getConnection().disconnect();
110 }
111 else
112 {
113
114 session.close(close.getStatusCode(),close.getReason());
115 }
116
117 return;
118 }
119 case OpCode.PING:
120 {
121 byte pongBuf[] = new byte[0];
122 if (frame.hasPayload())
123 {
124 pongBuf = BufferUtil.toArray(frame.getPayload());
125 }
126 session.getRemote().sendPong(ByteBuffer.wrap(pongBuf));
127 break;
128 }
129 case OpCode.BINARY:
130 {
131 onBinaryFrame(frame.getPayload(),frame.isFin());
132 return;
133 }
134 case OpCode.TEXT:
135 {
136 onTextFrame(frame.getPayload(),frame.isFin());
137 return;
138 }
139 }
140 }
141 catch (NotUtf8Exception e)
142 {
143 terminateConnection(StatusCode.BAD_PAYLOAD,e.getMessage());
144 }
145 catch (CloseException e)
146 {
147 terminateConnection(e.getStatusCode(),e.getMessage());
148 }
149 catch (Throwable t)
150 {
151 unhandled(t);
152 }
153 }
154
155 public abstract void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException;
156
157 public abstract void onBinaryMessage(byte[] data);
158
159 public abstract void onClose(CloseInfo close);
160
161 public abstract void onConnect();
162
163 public abstract void onError(Throwable t);
164
165 public abstract void onFrame(Frame frame);
166
167 public abstract void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException;
168
169 public abstract void onTextMessage(String message);
170
171 public void openSession(WebSocketSession session)
172 {
173 LOG.debug("openSession({})",session);
174 this.session = session;
175 this.onConnect();
176 }
177
178 protected void terminateConnection(int statusCode, String rawreason)
179 {
180 String reason = rawreason;
181 reason = StringUtil.truncate(reason,(WebSocketFrame.MAX_CONTROL_PAYLOAD - 2));
182 LOG.debug("terminateConnection({},{})",statusCode,rawreason);
183 session.close(statusCode,reason);
184 }
185
186 private void unhandled(Throwable t)
187 {
188 LOG.warn("Unhandled Error (closing connection)",t);
189
190
191 switch (policy.getBehavior())
192 {
193 case SERVER:
194 terminateConnection(StatusCode.SERVER_ERROR,t.getClass().getSimpleName());
195 break;
196 case CLIENT:
197 terminateConnection(StatusCode.POLICY_VIOLATION,t.getClass().getSimpleName());
198 break;
199 }
200 }
201 }