You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2012/03/16 00:11:48 UTC
svn commit: r1301263 - in /tomcat/tc7.0.x/trunk: ./
java/org/apache/catalina/util/ java/org/apache/catalina/websocket/
java/org/apache/coyote/ java/org/apache/coyote/http11/upgrade/
test/org/apache/catalina/util/ test/org/apache/catalina/websocket/ web...
Author: markt
Date: Thu Mar 15 23:11:47 2012
New Revision: 1301263
URL: http://svn.apache.org/viewvc?rev=1301263&view=rev
Log:
More WebSocket changes including some code based on ideas in a larger patch by Petr Praus, Jonathan Drake & Slávka
Added:
tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java
- copied, changed from r1245848, tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/util/TestConversions.java
- copied unchanged from r1245848, tomcat/trunk/test/org/apache/catalina/util/TestConversions.java
Modified:
tomcat/tc7.0.x/trunk/ (props changed)
tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Conversions.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/Constants.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/MessageInbound.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/StreamInbound.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsInputStream.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsOutbound.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/Constants.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeAprProcessor.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeBioProcessor.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeOutbound.java
tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/websocket/TestWebSocket.java (contents, props changed)
tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java (contents, props changed)
tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java (contents, props changed)
tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.html
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Mar 15 23:11:47 2012
@@ -1 +1 @@
-/tomcat/trunk:1156115-1157160,1157162-1157859,1157862-1157942,1157945-1160347,1160349-1163716,1163718-1166689,1166691-1174340,1174342-1175596,1175598-1175611,1175613-1175932,1175934-1177783,1177785-1177980,1178006-1180720,1180722-1183094,1183096-1187753,1187755,1187775,1187801,1187806,1187809,1187826-1188312,1188314-1188401,1188646-1188840,1188842-1190176,1190178-1195223,1195225-1195953,1195955,1195957-1201238,1201240-1203345,1203347-1206623,1206625-1208046,1208073,1208096,1208114,1208145,1208772,1209194-1212125,1212127-1220291,1220293,1220295-1221321,1221323-1222328,1222332-1222401,1222405-1222795,1222850-1222950,1222969-1225326,1225328-1225463,1225465,1225627,1225629-1226534,1226536-1228908,1228911-1228923,1228927-1229532,1229534-1230766,1230768-1231625,1231627-1233414,1233419-1235207,1235209-1237425,1237427,1237429-1237977,1237981,1237985,1237995,1238070,1238073,1239024-1239048,1239050-1239062,1239135,1239256,1239258-1239485,1239785-1240046,1240101,1240106,1240109,1240112
,1240114,1240116,1240118,1240121,1240329,1240474-1240850,1240857,1241087,1241160,1241408-1241822,1241908-1241909,1241982,1242099,1242110,1242371,1242434,1242495,1242947,1243034,1243038,1244302,1244511,1244567,1244718-1244719,1244935-1244938,1245274,1245449,1245849,1290875,1292334,1292338,1292345-1292347,1293155,1293831-1293832,1295998,1296284,1297014-1297015,1297017,1297158,1297177,1297202,1297209,1297213,1297717,1297722,1297729,1297768,1297778,1297818,1297828,1297979,1297987,1298121,1298140,1298590,1298592,1298628-1298629,1298794,1298983-1298984,1299020,1299034,1299819,1300154-1300155,1300569,1300948
+/tomcat/trunk:1156115-1157160,1157162-1157859,1157862-1157942,1157945-1160347,1160349-1163716,1163718-1166689,1166691-1174340,1174342-1175596,1175598-1175611,1175613-1175932,1175934-1177783,1177785-1177980,1178006-1180720,1180722-1183094,1183096-1187753,1187755,1187775,1187801,1187806,1187809,1187826-1188312,1188314-1188401,1188646-1188840,1188842-1190176,1190178-1195223,1195225-1195953,1195955,1195957-1201238,1201240-1203345,1203347-1206623,1206625-1208046,1208073,1208096,1208114,1208145,1208772,1209194-1212125,1212127-1220291,1220293,1220295-1221321,1221323-1222328,1222332-1222401,1222405-1222795,1222850-1222950,1222969-1225326,1225328-1225463,1225465,1225627,1225629-1226534,1226536-1228908,1228911-1228923,1228927-1229532,1229534-1230766,1230768-1231625,1231627-1233414,1233419-1235207,1235209-1237425,1237427,1237429-1237977,1237981,1237985,1237995,1238070,1238073,1239024-1239048,1239050-1239062,1239135,1239256,1239258-1239485,1239785-1240046,1240101,1240106,1240109,1240112
,1240114,1240116,1240118,1240121,1240329,1240474-1240850,1240857,1241087,1241160,1241408-1241822,1241908-1241909,1241912-1242110,1242371-1292130,1292334,1292338,1292345-1292347,1293155,1293831-1293832,1295998,1296284,1297014-1297015,1297017,1297158,1297177,1297202,1297209,1297213,1297717,1297722,1297729,1297768,1297778,1297818,1297828,1297979,1297987,1298121,1298140,1298590,1298592,1298628-1298629,1298794,1298983-1298984,1299020,1299034,1299819,1300154-1300155,1300569,1300948
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Conversions.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Conversions.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Conversions.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Conversions.java Thu Mar 15 23:11:47 2012
@@ -32,7 +32,7 @@ public class Conversions {
int shift = 0;
long result = 0;
- for (int i = input.length; i < 0; i--) {
+ for (int i = input.length - 1; i >= 0; i--) {
result = result + ((input[i] & 0xFF) << shift);
shift += 8;
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/Constants.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/Constants.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/Constants.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/Constants.java Thu Mar 15 23:11:47 2012
@@ -21,4 +21,12 @@ package org.apache.catalina.websocket;
*/
public class Constants {
public static final String Package = "org.apache.catalina.websocket";
+
+ // OP Codes
+ public static final byte OPCODE_CONTINUATION = 0x00;
+ public static final byte OPCODE_TEXT = 0x01;
+ public static final byte OPCODE_BINARY = 0x02;
+ public static final byte OPCODE_CLOSE = 0x08;
+ public static final byte OPCODE_PING = 0x09;
+ public static final byte OPCODE_PONG = 0x0A;
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/MessageInbound.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/MessageInbound.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/MessageInbound.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/MessageInbound.java Thu Mar 15 23:11:47 2012
@@ -24,8 +24,10 @@ import java.nio.CharBuffer;
public abstract class MessageInbound extends StreamInbound {
- // TODO: Make buffer sizes configurable
- // TODO: Allow buffers to expand
+ // 2MB - like maxPostSize
+ private int byteBufferMaxSize = 2097152;
+ private int charBufferMaxSize = 2097152;
+
ByteBuffer bb = ByteBuffer.allocate(8192);
CharBuffer cb = CharBuffer.allocate(8192);
@@ -34,6 +36,9 @@ public abstract class MessageInbound ext
int read = 0;
while (read > -1) {
bb.position(bb.position() + read);
+ if (bb.remaining() == 0) {
+ resizeByteBuffer();
+ }
read = is.read(bb.array(), bb.position(), bb.remaining());
}
bb.flip();
@@ -46,14 +51,70 @@ public abstract class MessageInbound ext
int read = 0;
while (read > -1) {
cb.position(cb.position() + read);
+ if (cb.remaining() == 0) {
+ resizeCharBuffer();
+ }
read = r.read(cb.array(), cb.position(), cb.remaining());
}
- cb.limit(cb.position());
- cb.position(0);
+ cb.flip();
onTextMessage(cb);
cb.clear();
}
+ private void resizeByteBuffer() throws IOException {
+ int maxSize = getByteBufferMaxSize();
+ if (bb.limit() >= maxSize) {
+ // TODO i18n
+ throw new IOException("Buffer not big enough for message");
+ }
+
+ long newSize = bb.limit() * 2;
+ if (newSize > maxSize) {
+ newSize = maxSize;
+ }
+
+ // Cast is safe. newSize < maxSize and maxSize is an int
+ ByteBuffer newBuffer = ByteBuffer.allocate((int) newSize);
+ bb.rewind();
+ newBuffer.put(bb);
+ bb = newBuffer;
+ }
+
+ private void resizeCharBuffer() throws IOException {
+ int maxSize = getCharBufferMaxSize();
+ if (cb.limit() >= maxSize) {
+ // TODO i18n
+ throw new IOException("Buffer not big enough for message");
+ }
+
+ long newSize = cb.limit() * 2;
+ if (newSize > maxSize) {
+ newSize = maxSize;
+ }
+
+ // Cast is safe. newSize < maxSize and maxSize is an int
+ CharBuffer newBuffer = CharBuffer.allocate((int) newSize);
+ cb.rewind();
+ newBuffer.put(cb);
+ cb = newBuffer;
+ }
+
+ public int getByteBufferMaxSize() {
+ return byteBufferMaxSize;
+ }
+
+ public void setByteBufferMaxSize(int byteBufferMaxSize) {
+ this.byteBufferMaxSize = byteBufferMaxSize;
+ }
+
+ public int getCharBufferMaxSize() {
+ return charBufferMaxSize;
+ }
+
+ public void setCharBufferMaxSize(int charBufferMaxSize) {
+ this.charBufferMaxSize = charBufferMaxSize;
+ }
+
protected abstract void onBinaryMessage(ByteBuffer message)
throws IOException;
protected abstract void onTextMessage(CharBuffer message)
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/StreamInbound.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/StreamInbound.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/StreamInbound.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/StreamInbound.java Thu Mar 15 23:11:47 2012
@@ -20,8 +20,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.nio.ByteBuffer;
-import org.apache.catalina.util.Conversions;
import org.apache.coyote.http11.upgrade.UpgradeInbound;
import org.apache.coyote.http11.upgrade.UpgradeOutbound;
import org.apache.coyote.http11.upgrade.UpgradeProcessor;
@@ -30,18 +30,6 @@ import org.apache.tomcat.util.net.Abstra
public abstract class StreamInbound implements UpgradeInbound {
- // These attributes apply to the current frame being processed
- private boolean fin = true;
- private boolean rsv1 = false;
- private boolean rsv2 = false;
- private boolean rsv3 = false;
- private int opCode = -1;
- private long payloadLength = -1;
-
- // These attributes apply to the message that may be spread over multiple
- // frames
- // TODO
-
private UpgradeProcessor<?> processor = null;
private WsOutbound outbound;
@@ -56,93 +44,102 @@ public abstract class StreamInbound impl
this.processor = processor;
}
- public WsOutbound getStreamOutbound() {
+ public WsOutbound getOutbound() {
return outbound;
}
@Override
public SocketState onData() throws IOException {
- // Must be start the start of a frame
-
- // Read the first byte
- int i = processor.read();
+ // Must be start the start of a frame or series of frames
+ WsInputStream wsIs = new WsInputStream(processor);
- fin = (i & 0x80) > 0;
+ WsFrameHeader header = wsIs.getFrameHeader();
- rsv1 = (i & 0x40) > 0;
- rsv2 = (i & 0x20) > 0;
- rsv3 = (i & 0x10) > 0;
-
- if (rsv1 || rsv2 || rsv3) {
- // TODO: Not supported.
+ // TODO User defined extensions may define values for rsv
+ if (header.getRsv() > 0) {
+ getOutbound().close(1002, null);
+ return SocketState.CLOSED;
}
- opCode = (i & 0x0F);
- validateOpCode(opCode);
+ byte opCode = header.getOpCode();
- // Read the next byte
- i = processor.read();
+ if (opCode == Constants.OPCODE_BINARY) {
+ onBinaryData(wsIs);
+ return SocketState.UPGRADED;
+ } else if (opCode == Constants.OPCODE_TEXT) {
+ InputStreamReader r =
+ new InputStreamReader(wsIs, B2CConverter.UTF_8);
+ onTextData(r);
+ return SocketState.UPGRADED;
+ }
- // Client data must be masked and this isn't
- if ((i & 0x80) == 0) {
- // TODO: Better message
- throw new IOException();
+ // Must be a control frame and control frames:
+ // - have a limited payload length
+ // - must not be fragmented
+ if (wsIs.getPayloadLength() > 125 || !wsIs.getFrameHeader().getFin()) {
+ getOutbound().close(1002, null);
+ return SocketState.CLOSED;
}
- payloadLength = i & 0x7F;
- if (payloadLength == 126) {
- byte[] extended = new byte[2];
- processor.read(extended);
- payloadLength = Conversions.byteArrayToLong(extended);
- } else if (payloadLength == 127) {
- byte[] extended = new byte[8];
- processor.read(extended);
- payloadLength = Conversions.byteArrayToLong(extended);
+ if (opCode == Constants.OPCODE_CLOSE){
+ doClose(wsIs);
+ return SocketState.CLOSED;
+ } else if (opCode == Constants.OPCODE_PING) {
+ doPing(wsIs);
+ return SocketState.UPGRADED;
+ } else if (opCode == Constants.OPCODE_PONG) {
+ doPong(wsIs);
+ return SocketState.UPGRADED;
}
- byte[] mask = new byte[4];
- processor.read(mask);
+ getOutbound().close(1002, null);
+ return SocketState.CLOSED;
+ }
- if (opCode == 1 || opCode == 2) {
- WsInputStream wsIs = new WsInputStream(processor, mask,
- payloadLength);
- if (opCode == 2) {
- onBinaryData(wsIs);
- } else {
- InputStreamReader r =
- new InputStreamReader(wsIs, B2CConverter.UTF_8);
- onTextData(r);
+ private void doClose(InputStream is) throws IOException {
+ // Control messages have a max size of 125 bytes. Need to try and read
+ // one more so we reach end of stream (less 2 for the status)
+ ByteBuffer data = ByteBuffer.allocate(124);
+
+ int status = is.read();
+ if (status != -1) {
+ status = status << 8;
+ status = status + is.read();
+ int read = 0;
+ while (read > -1) {
+ data.position(data.position() + read);
+ read = is.read(data.array(), data.position(), data.remaining());
}
+ } else {
+ status = 0;
}
+ data.flip();
+ getOutbound().close(status, data);
+ }
- // TODO: Doesn't currently handle multi-frame messages. That will need
- // some refactoring.
-
- // TODO: Per frame extension handling is not currently supported.
-
- // TODO: Handle other control frames.
+ private void doPing(InputStream is) throws IOException {
+ // Control messages have a max size of 125 bytes. Need to try and read
+ // one more so we reach end of stream
+ ByteBuffer data = ByteBuffer.allocate(126);
+
+ int read = 0;
+ while (read > -1) {
+ data.position(data.position() + read);
+ read = is.read(data.array(), data.position(), data.remaining());
+ }
- // TODO: Handle control frames appearing in the middle of a multi-frame
- // message
+ data.flip();
+ getOutbound().pong(data);
+ }
- return SocketState.UPGRADED;
+ private void doPong(InputStream is) throws IOException {
+ // Unsolicited pong - swallow it
+ int read = 0;
+ while (read > -1) {
+ read = is.read();
+ }
}
protected abstract void onBinaryData(InputStream is) throws IOException;
protected abstract void onTextData(Reader r) throws IOException;
-
- private void validateOpCode(int opCode) throws IOException {
- switch (opCode) {
- case 0:
- case 1:
- case 2:
- case 8:
- case 9:
- case 10:
- break;
- default:
- // TODO: Message
- throw new IOException();
- }
- }
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java Thu Mar 15 23:11:47 2012
@@ -19,6 +19,7 @@ package org.apache.catalina.websocket;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
@@ -68,17 +69,17 @@ public abstract class WebSocketServlet e
String subProtocol = null;
List<String> extensions = Collections.emptyList();
- if (!headerContains(req, "upgrade", "websocket")) {
+ if (!headerContainsToken(req, "upgrade", "websocket")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
- if (!headerContains(req, "connection", "upgrade")) {
+ if (!headerContainsToken(req, "connection", "upgrade")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
- if (!headerContains(req, "sec-websocket-version", "13")) {
+ if (!headerContainsToken(req, "sec-websocket-version", "13")) {
resp.setStatus(426);
resp.setHeader("Sec-WebSocket-Version", "13");
return;
@@ -96,8 +97,14 @@ public abstract class WebSocketServlet e
return;
}
- // TODO Read client handshake - Sec-WebSocket-Protocol
- // Sec-WebSocket-Extensions
+ List<String> subProtocols = getTokensFromHeader(req,
+ "Sec-WebSocket-Protocol-Client");
+ if (!subProtocols.isEmpty()) {
+ subProtocol = selectSubProtocol(subProtocols);
+
+ }
+
+ // TODO Read client handshake - Sec-WebSocket-Extensions
// TODO Extensions require the ability to specify something (API TBD)
// that can be passed to the Tomcat internals and process extension
@@ -108,27 +115,27 @@ public abstract class WebSocketServlet e
resp.setHeader("connection", "upgrade");
resp.setHeader("Sec-WebSocket-Accept", getWebSocketAccept(key));
if (subProtocol != null) {
- // TODO
+ resp.setHeader("Sec-WebSocket-Protocol", subProtocol);
}
if (!extensions.isEmpty()) {
// TODO
}
// Small hack until the Servlet API provides a way to do this.
- StreamInbound inbound = createWebSocketInbound();
+ StreamInbound inbound = createWebSocketInbound(subProtocol);
((RequestFacade) req).doUpgrade(inbound);
}
- private boolean headerContains(HttpServletRequest req, String headerName,
- String target) {
+ /*
+ * This only works for tokens. Quoted strings need more sophisticated
+ * parsing.
+ */
+ private boolean headerContainsToken(HttpServletRequest req,
+ String headerName, String target) {
Enumeration<String> headers = req.getHeaders(headerName);
while (headers.hasMoreElements()) {
String header = headers.nextElement();
- // TODO Splitting headers into tokens isn't quite this simple but
- // this should be OK in this case. It is tempting to change the
- // header parsing code so there is a one to one mapping between
- // token and enumeration entry.
String[] tokens = header.split(",");
for (String token : tokens) {
if (target.equalsIgnoreCase(token.trim())) {
@@ -140,6 +147,26 @@ public abstract class WebSocketServlet e
}
+ /*
+ * This only works for tokens. Quoted strings need more sophisticated
+ * parsing.
+ */
+ private List<String> getTokensFromHeader(HttpServletRequest req,
+ String headerName) {
+ List<String> result = new ArrayList<String>();
+
+ Enumeration<String> headers = req.getHeaders(headerName);
+ while (headers.hasMoreElements()) {
+ String header = headers.nextElement();
+ String[] tokens = header.split(",");
+ for (String token : tokens) {
+ result.add(token.trim());
+ }
+ }
+ return result;
+ }
+
+
private String getWebSocketAccept(String key) {
synchronized (sha1Helper) {
sha1Helper.reset();
@@ -163,5 +190,27 @@ public abstract class WebSocketServlet e
return true;
}
- protected abstract StreamInbound createWebSocketInbound();
+ /**
+ * Intended to be overridden by sub-classes that wish to select a
+ * sub-protocol if the client provides a list of supported protocols.
+ *
+ * @param subProtocols The list of sub-protocols supported by the client
+ * in client preference order. The server is under no
+ * obligation to respect the declared preference
+ * @return <code>null</code> if no sub-protocol is selected or the name of
+ * the protocol which <b>must</b> be one of the protocols listed by
+ * the client.
+ */
+ protected String selectSubProtocol(List<String> subProtocols) {
+ return null;
+ }
+
+ /**
+ * Create the instance that will process this inbound connection.
+ *
+ * @param subProtocol The sub-protocol agreed between the client and
+ * server or <code>null</code> if none was agreed
+ * @return
+ */
+ protected abstract StreamInbound createWebSocketInbound(String subProtocol);
}
Copied: tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java (from r1245848, tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java)
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java?p2=tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java&p1=tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java&r1=1245848&r2=1301263&rev=1301263&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java Thu Mar 15 23:11:47 2012
@@ -23,17 +23,13 @@ package org.apache.catalina.websocket;
public class WsFrameHeader {
private final boolean fin;
- private final boolean rsv1;
- private final boolean rsv2;
- private final boolean rsv3;
+ private final int rsv;
private final byte opCode;
public WsFrameHeader(int b) {
fin = (b & 0x80) > 0;
- rsv1 = (b & 0x40) > 0;
- rsv2 = (b & 0x20) > 0;
- rsv3 = (b & 0x10) > 0;
+ rsv = (b & 0x70) >>> 4;
opCode = (byte) (b & 0x0F);
}
@@ -42,21 +38,11 @@ public class WsFrameHeader {
return fin;
}
- public boolean getRsv1() {
- return rsv1;
- }
-
- public boolean getRsv2() {
- return rsv2;
- }
-
- public boolean getRsv3() {
- return rsv3;
+ public int getRsv() {
+ return rsv;
}
public byte getOpCode() {
return opCode;
}
-
-
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsInputStream.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsInputStream.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsInputStream.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsInputStream.java Thu Mar 15 23:11:47 2012
@@ -18,34 +18,96 @@ package org.apache.catalina.websocket;
import java.io.IOException;
+import org.apache.catalina.util.Conversions;
import org.apache.coyote.http11.upgrade.UpgradeProcessor;
public class WsInputStream extends java.io.InputStream {
private UpgradeProcessor<?> processor;
- private byte[] mask;
+ private WsFrameHeader wsFrameHeader;
+ private long payloadLength = -1;
+ private int[] mask = new int[4];
+
+
private long remaining;
- private long read;
+ private long readThisFragment;
- public WsInputStream(UpgradeProcessor<?> processor, byte[] mask,
- long remaining) {
+ public WsInputStream(UpgradeProcessor<?> processor) throws IOException {
this.processor = processor;
- this.mask = mask;
- this.remaining = remaining;
- this.read = 0;
+
+ processFrameHeader();
}
+
+ private void processFrameHeader() throws IOException {
+
+ // TODO: Per frame extension handling is not currently supported.
+
+ // TODO: Handle control frames between fragments
+
+ int i = processor.read();
+ this.wsFrameHeader = new WsFrameHeader(i);
+
+ // Client data must be masked
+ i = processor.read();
+ if ((i & 0x80) == 0) {
+ // TODO: StringManager / i18n
+ throw new IOException("Client frame not masked");
+ }
+
+ payloadLength = i & 0x7F;
+ if (payloadLength == 126) {
+ byte[] extended = new byte[2];
+ processor.read(extended);
+ payloadLength = Conversions.byteArrayToLong(extended);
+ } else if (payloadLength == 127) {
+ byte[] extended = new byte[8];
+ processor.read(extended);
+ payloadLength = Conversions.byteArrayToLong(extended);
+ }
+ remaining = payloadLength;
+
+ for (int j = 0; j < mask.length; j++) {
+ mask[j] = processor.read() & 0xFF;
+ }
+
+ readThisFragment = 0;
+ }
+
+ public WsFrameHeader getFrameHeader() {
+ return wsFrameHeader;
+ }
+
+ public long getPayloadLength() {
+ return payloadLength;
+ }
+
+
+ // ----------------------------------------------------- InputStream methods
+
@Override
public int read() throws IOException {
+ while (remaining == 0 && !getFrameHeader().getFin()) {
+ // Need more data - process next frame
+ processFrameHeader();
+
+ if (getFrameHeader().getOpCode() != Constants.OPCODE_CONTINUATION) {
+ // TODO i18n
+ throw new IOException("Not a continuation frame");
+ }
+ }
+
if (remaining == 0) {
return -1;
}
remaining--;
- read++;
+ readThisFragment++;
int masked = processor.read();
- return masked ^ mask[(int) ((read - 1) % 4)];
+ if(masked == -1) {
+ return -1;
+ }
+ return masked ^ mask[(int) ((readThisFragment - 1) % 4)];
}
-
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsOutbound.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsOutbound.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsOutbound.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/websocket/WsOutbound.java Thu Mar 15 23:11:47 2012
@@ -25,11 +25,12 @@ import org.apache.tomcat.util.buf.B2CCon
public class WsOutbound {
- private static final int DEFAULT_BUFFER_SIZE = 2048;
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
private UpgradeOutbound upgradeOutbound;
private ByteBuffer bb;
private CharBuffer cb;
+ private boolean closed = false;
protected Boolean text = null;
protected boolean firstFrame = true;
@@ -37,9 +38,7 @@ public class WsOutbound {
public WsOutbound(UpgradeOutbound upgradeOutbound) {
this.upgradeOutbound = upgradeOutbound;
// TODO: Make buffer size configurable
- // Byte buffer needs to be 4* char buffer to be sure that char buffer
- // can always we written into Byte buffer
- this.bb = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE * 4);
+ this.bb = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
this.cb = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
}
@@ -81,7 +80,7 @@ public class WsOutbound {
flush();
}
text = Boolean.FALSE;
- doWriteBinary(msgBb, true);
+ doWriteBytes(msgBb, true);
}
@@ -105,28 +104,71 @@ public class WsOutbound {
return;
}
if (text.booleanValue()) {
+ cb.flip();
doWriteText(cb, finalFragment);
} else {
- doWriteBinary(bb, finalFragment);
+ bb.flip();
+ doWriteBytes(bb, finalFragment);
}
}
- public void close() throws IOException {
+ public void close(int status, ByteBuffer data) throws IOException {
+ // TODO Think about threading requirements for writing. This is not
+ // currently thread safe and writing almost certainly needs to be.
+ if (closed) {
+ return;
+ }
+ closed = true;
+
doFlush(true);
- // TODO: Send a close message
+ upgradeOutbound.write(0x88);
+ if (status == 0) {
+ upgradeOutbound.write(0);
+ } else if (data == null) {
+ upgradeOutbound.write(2);
+ upgradeOutbound.write(status >>> 8);
+ upgradeOutbound.write(status);
+ } else {
+ upgradeOutbound.write(2 + data.limit());
+ upgradeOutbound.write(status >>> 8);
+ upgradeOutbound.write(status);
+ upgradeOutbound.write(data.array(), 0, data.limit());
+ }
+ upgradeOutbound.flush();
+
bb = null;
cb = null;
upgradeOutbound = null;
}
+ public void pong(ByteBuffer data) throws IOException {
+ // TODO Think about threading requirements for writing. This is not
+ // currently thread safe and writing almost certainly needs to be.
+ if (closed) {
+ // TODO - handle this - ISE?
+ }
- protected void doWriteBinary(ByteBuffer buffer, boolean finalFragment)
- throws IOException {
+ doFlush(true);
+
+ upgradeOutbound.write(0x8A);
+ upgradeOutbound.write(data.limit());
+ upgradeOutbound.write(data.array(), 0, data.limit());
+
+ upgradeOutbound.flush();
+ }
- // Prepare to write
- buffer.flip();
+ /**
+ * Writes the provided bytes as the payload in a new WebSocket frame.
+ *
+ * @param buffer The bytes to include in the payload.
+ * @param finalFragment Do these bytes represent the final fragment of a
+ * WebSocket message?
+ * @throws IOException
+ */
+ private void doWriteBytes(ByteBuffer buffer, boolean finalFragment)
+ throws IOException {
// Work out the first byte
int first = 0x00;
@@ -143,13 +185,24 @@ public class WsOutbound {
// Continuation frame is OpCode 0
upgradeOutbound.write(first);
- // Note: buffer will never be more than 2^16 in length
if (buffer.limit() < 126) {
upgradeOutbound.write(buffer.limit());
- } else {
+ } else if (buffer.limit() < 65536) {
upgradeOutbound.write(126);
upgradeOutbound.write(buffer.limit() >>> 8);
upgradeOutbound.write(buffer.limit() & 0xFF);
+ } else {
+ // Will never be more than 2^31-1
+ upgradeOutbound.write(127);
+ upgradeOutbound.write(0);
+ upgradeOutbound.write(0);
+ upgradeOutbound.write(0);
+ upgradeOutbound.write(0);
+ upgradeOutbound.write(buffer.limit() >>> 24);
+ upgradeOutbound.write(buffer.limit() >>> 16);
+ upgradeOutbound.write(buffer.limit() >>> 8);
+ upgradeOutbound.write(buffer.limit() & 0xFF);
+
}
// Write the content
@@ -167,12 +220,19 @@ public class WsOutbound {
}
- protected void doWriteText(CharBuffer buffer, boolean finalFragment)
+ private void doWriteText(CharBuffer buffer, boolean finalFragment)
throws IOException {
- buffer.flip();
- B2CConverter.UTF_8.newEncoder().encode(buffer, bb, true);
- doWriteBinary(bb, finalFragment);
- // Reset
+ do {
+ B2CConverter.UTF_8.newEncoder().encode(buffer, bb, true);
+ bb.flip();
+ if (buffer.hasRemaining()) {
+ doWriteBytes(bb, false);
+ } else {
+ doWriteBytes(bb, finalFragment);
+ }
+ } while (buffer.hasRemaining());
+
+ // Reset - bb will be cleared in doWriteBytes()
cb.clear();
}
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProtocol.java Thu Mar 15 23:11:47 2012
@@ -30,6 +30,7 @@ import javax.management.MalformedObjectN
import javax.management.ObjectName;
import org.apache.coyote.http11.upgrade.UpgradeInbound;
+import org.apache.coyote.http11.upgrade.UpgradeProcessor;
import org.apache.juli.logging.Log;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.modeler.Registry;
@@ -592,7 +593,9 @@ public abstract class AbstractProtocol i
upgradePoll(socket, processor);
} else {
// Connection closed. OK to recycle the processor.
- release(socket, processor, true, false);
+ if (!(processor instanceof UpgradeProcessor)) {
+ release(socket, processor, true, false);
+ }
}
return state;
} catch(java.net.SocketException e) {
@@ -614,7 +617,10 @@ public abstract class AbstractProtocol i
// less-than-verbose logs.
getLog().error(sm.getString("ajpprotocol.proto.error"), e);
}
- release(socket, processor, true, false);
+ // Don't try to add upgrade processors back into the pool
+ if (!(processor instanceof UpgradeProcessor)) {
+ release(socket, processor, true, false);
+ }
return SocketState.CLOSED;
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/Constants.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/Constants.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/Constants.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/Constants.java Thu Mar 15 23:11:47 2012
@@ -1,22 +1,22 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.coyote.http11.upgrade;
-
-public class Constants {
-
- public static final String Package = "org.apache.coyote.http11.upgrade";
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.http11.upgrade;
+
+public class Constants {
+
+ public static final String Package = "org.apache.coyote.http11.upgrade";
+}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeAprProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeAprProcessor.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeAprProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeAprProcessor.java Thu Mar 15 23:11:47 2012
@@ -1,73 +1,73 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.coyote.http11.upgrade;
-
-import java.io.IOException;
-
-import org.apache.tomcat.jni.Socket;
-import org.apache.tomcat.util.net.SocketWrapper;
-
-/**
- * Implementation note: The need to extend Http11Processor could probably be
- * removed if the Processor interface was expanded to cover all of the methods
- * required by the AbstractProtocol. That would simplify the code and further
- * reduce the size of instances of this class.
- */
-public class UpgradeAprProcessor extends UpgradeProcessor<Long> {
-
- long socket;
-
-
- public UpgradeAprProcessor(SocketWrapper<Long> wrapper,
- UpgradeInbound upgradeInbound) {
- super(upgradeInbound);
-
- this.socket = wrapper.getSocket().longValue();
- }
-
-
- /*
- * Output methods
- */
- @Override
- public void flush() throws IOException {
- // NOOP
- }
-
-
- @Override
- public void write(int b) throws IOException {
- Socket.send(socket, new byte[] {(byte) b}, 0, 1);
- }
-
-
- /*
- * Input methods
- */
- @Override
- public int read() throws IOException {
- byte[] bytes = new byte[1];
- Socket.recv(socket, bytes, 0, 1);
- return bytes[0];
- }
-
-
- @Override
- public int read(byte[] bytes) throws IOException {
- return Socket.recv(socket, bytes, 0, bytes.length);
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.http11.upgrade;
+
+import java.io.IOException;
+
+import org.apache.tomcat.jni.Socket;
+import org.apache.tomcat.util.net.SocketWrapper;
+
+/**
+ * Implementation note: The need to extend Http11Processor could probably be
+ * removed if the Processor interface was expanded to cover all of the methods
+ * required by the AbstractProtocol. That would simplify the code and further
+ * reduce the size of instances of this class.
+ */
+public class UpgradeAprProcessor extends UpgradeProcessor<Long> {
+
+ private final long socket;
+
+
+ public UpgradeAprProcessor(SocketWrapper<Long> wrapper,
+ UpgradeInbound upgradeInbound) {
+ super(upgradeInbound);
+
+ this.socket = wrapper.getSocket().longValue();
+ }
+
+
+ /*
+ * Output methods
+ */
+ @Override
+ public void flush() throws IOException {
+ // NOOP
+ }
+
+
+ @Override
+ public void write(int b) throws IOException {
+ Socket.send(socket, new byte[] {(byte) b}, 0, 1);
+ }
+
+
+ /*
+ * Input methods
+ */
+ @Override
+ public int read() throws IOException {
+ byte[] bytes = new byte[1];
+ Socket.recv(socket, bytes, 0, 1);
+ return bytes[0];
+ }
+
+
+ @Override
+ public int read(byte[] bytes) throws IOException {
+ return Socket.recv(socket, bytes, 0, bytes.length);
+ }
+}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeBioProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeBioProcessor.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeBioProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeBioProcessor.java Thu Mar 15 23:11:47 2012
@@ -1,74 +1,74 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.coyote.http11.upgrade;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-
-import org.apache.tomcat.util.net.SocketWrapper;
-
-/**
- * Implementation note: The need to extend Http11Processor could probably be
- * removed if the Processor interface was expanded to cover all of the methods
- * required by the AbstractProtocol. That would simplify the code and further
- * reduce the size of instances of this class.
- */
-public class UpgradeBioProcessor extends UpgradeProcessor<Socket> {
-
- private InputStream inputStream;
- private OutputStream outputStream;
-
- public UpgradeBioProcessor(SocketWrapper<Socket> wrapper,
- UpgradeInbound upgradeInbound) throws IOException {
- super(upgradeInbound);
-
- this.inputStream = wrapper.getSocket().getInputStream();
- this.outputStream = wrapper.getSocket().getOutputStream();
- }
-
-
- /*
- * Output methods
- */
- @Override
- public void flush() throws IOException {
- outputStream.flush();
- }
-
-
- @Override
- public void write(int b) throws IOException {
- outputStream.write(b);
- }
-
-
- /*
- * Input methods
- */
- @Override
- public int read() throws IOException {
- return inputStream.read();
- }
-
-
- @Override
- public int read(byte[] bytes) throws IOException {
- return inputStream.read(bytes);
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.http11.upgrade;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+import org.apache.tomcat.util.net.SocketWrapper;
+
+/**
+ * Implementation note: The need to extend Http11Processor could probably be
+ * removed if the Processor interface was expanded to cover all of the methods
+ * required by the AbstractProtocol. That would simplify the code and further
+ * reduce the size of instances of this class.
+ */
+public class UpgradeBioProcessor extends UpgradeProcessor<Socket> {
+
+ private final InputStream inputStream;
+ private final OutputStream outputStream;
+
+ public UpgradeBioProcessor(SocketWrapper<Socket> wrapper,
+ UpgradeInbound upgradeInbound) throws IOException {
+ super(upgradeInbound);
+
+ this.inputStream = wrapper.getSocket().getInputStream();
+ this.outputStream = wrapper.getSocket().getOutputStream();
+ }
+
+
+ /*
+ * Output methods
+ */
+ @Override
+ public void flush() throws IOException {
+ outputStream.flush();
+ }
+
+
+ @Override
+ public void write(int b) throws IOException {
+ outputStream.write(b);
+ }
+
+
+ /*
+ * Input methods
+ */
+ @Override
+ public int read() throws IOException {
+ return inputStream.read();
+ }
+
+
+ @Override
+ public int read(byte[] bytes) throws IOException {
+ return inputStream.read(bytes);
+ }
+}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java Thu Mar 15 23:11:47 2012
@@ -33,8 +33,8 @@ import org.apache.tomcat.util.net.Socket
*/
public class UpgradeNioProcessor extends UpgradeProcessor<NioChannel> {
- private NioChannel nioChannel;
- private NioSelectorPool pool;
+ private final NioChannel nioChannel;
+ private final NioSelectorPool pool;
public UpgradeNioProcessor(SocketWrapper<NioChannel> wrapper,
UpgradeInbound upgradeInbound, NioSelectorPool pool) {
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeOutbound.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeOutbound.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeOutbound.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeOutbound.java Thu Mar 15 23:11:47 2012
@@ -32,7 +32,7 @@ public class UpgradeOutbound extends Out
processor.flush();
}
- private UpgradeProcessor<?> processor;
+ private final UpgradeProcessor<?> processor;
public UpgradeOutbound(UpgradeProcessor<?> processor) {
this.processor = processor;
Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java Thu Mar 15 23:11:47 2012
@@ -1,118 +1,117 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.coyote.http11.upgrade;
-
-import java.io.IOException;
-import java.util.concurrent.Executor;
-
-import org.apache.coyote.Processor;
-import org.apache.coyote.Request;
-import org.apache.coyote.http11.Constants;
-import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
-import org.apache.tomcat.util.net.SSLSupport;
-import org.apache.tomcat.util.net.SocketStatus;
-import org.apache.tomcat.util.net.SocketWrapper;
-import org.apache.tomcat.util.res.StringManager;
-
-public abstract class UpgradeProcessor<S> implements Processor<S> {
-
- protected static final StringManager sm =
- StringManager.getManager(Constants.Package);
-
- private final UpgradeInbound upgradeInbound;
-
- protected UpgradeProcessor (UpgradeInbound upgradeInbound) {
- this.upgradeInbound = upgradeInbound;
- upgradeInbound.setUpgradeProcessor(this);
- upgradeInbound.setUpgradeOutbound(new UpgradeOutbound(this));
- }
-
- // Output methods
- public abstract void flush() throws IOException;
- public abstract void write(int b) throws IOException;
-
- // Input methods
- public abstract int read() throws IOException;
- public abstract int read(byte[] bytes) throws IOException;
-
- @Override
- public final UpgradeInbound getUpgradeInbound() {
- return upgradeInbound;
- }
-
- @Override
- public final SocketState upgradeDispatch() throws IOException {
- return upgradeInbound.onData();
- }
-
- @Override
- public final boolean isUpgrade() {
- return true;
- }
-
- @Override
- public final void recycle(boolean socketClosing) {
- // Currently a NO-OP as upgrade processors are not recycled.
- }
-
- // NO-OP methods for upgrade
- @Override
- public final Executor getExecutor() {
- return null;
- }
-
- @Override
- public final SocketState process(SocketWrapper<S> socketWrapper)
- throws IOException {
- return null;
- }
-
- @Override
- public final SocketState event(SocketStatus status) throws IOException {
- return null;
- }
-
- @Override
- public final SocketState asyncDispatch(SocketStatus status) {
- return null;
- }
-
- @Override
- public final SocketState asyncPostProcess() {
- return null;
- }
-
- @Override
- public final boolean isComet() {
- return false;
- }
-
- @Override
- public final boolean isAsync() {
- return false;
- }
-
- @Override
- public final Request getRequest() {
- return null;
- }
-
- @Override
- public final void setSslSupport(SSLSupport sslSupport) {
- // NOOP
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.http11.upgrade;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+
+import org.apache.coyote.Processor;
+import org.apache.coyote.Request;
+import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.SocketWrapper;
+import org.apache.tomcat.util.res.StringManager;
+
+public abstract class UpgradeProcessor<S> implements Processor<S> {
+
+ protected static final StringManager sm =
+ StringManager.getManager(Constants.Package);
+
+ private final UpgradeInbound upgradeInbound;
+
+ protected UpgradeProcessor (UpgradeInbound upgradeInbound) {
+ this.upgradeInbound = upgradeInbound;
+ upgradeInbound.setUpgradeProcessor(this);
+ upgradeInbound.setUpgradeOutbound(new UpgradeOutbound(this));
+ }
+
+ // Output methods
+ public abstract void flush() throws IOException;
+ public abstract void write(int b) throws IOException;
+
+ // Input methods
+ public abstract int read() throws IOException;
+ public abstract int read(byte[] bytes) throws IOException;
+
+ @Override
+ public final UpgradeInbound getUpgradeInbound() {
+ return upgradeInbound;
+ }
+
+ @Override
+ public final SocketState upgradeDispatch() throws IOException {
+ return upgradeInbound.onData();
+ }
+
+ @Override
+ public final boolean isUpgrade() {
+ return true;
+ }
+
+ @Override
+ public final void recycle(boolean socketClosing) {
+ // Currently a NO-OP as upgrade processors are not recycled.
+ }
+
+ // NO-OP methods for upgrade
+ @Override
+ public final Executor getExecutor() {
+ return null;
+ }
+
+ @Override
+ public final SocketState process(SocketWrapper<S> socketWrapper)
+ throws IOException {
+ return null;
+ }
+
+ @Override
+ public final SocketState event(SocketStatus status) throws IOException {
+ return null;
+ }
+
+ @Override
+ public final SocketState asyncDispatch(SocketStatus status) {
+ return null;
+ }
+
+ @Override
+ public final SocketState asyncPostProcess() {
+ return null;
+ }
+
+ @Override
+ public final boolean isComet() {
+ return false;
+ }
+
+ @Override
+ public final boolean isAsync() {
+ return false;
+ }
+
+ @Override
+ public final Request getRequest() {
+ return null;
+ }
+
+ @Override
+ public final void setSslSupport(SSLSupport sslSupport) {
+ // NOOP
+ }
+}
Modified: tomcat/tc7.0.x/trunk/test/org/apache/catalina/websocket/TestWebSocket.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/websocket/TestWebSocket.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/org/apache/catalina/websocket/TestWebSocket.java (original)
+++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/websocket/TestWebSocket.java Thu Mar 15 23:11:47 2012
@@ -1,83 +1,164 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.catalina.websocket;
-
-import java.io.InputStream;
-import java.io.Reader;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-
-import org.junit.Test;
-
-import org.apache.catalina.startup.TomcatBaseTest;
-
-public class TestWebSocket extends TomcatBaseTest {
-
- @Test
- public void testSimple() {
- // TODO: Write a test
- }
-
- private static final class StreamingWebSocketServlet
- extends WebSocketServlet {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- protected StreamInbound createWebSocketInbound() {
- return new SimpleStreamInbound();
- }
- }
-
- private static final class SimpleStreamInbound extends StreamInbound {
-
- @Override
- protected void onBinaryData(InputStream is) {
- // TODO Auto-generated method stub
- }
-
- @Override
- protected void onTextData(Reader r) {
- // TODO Auto-generated method stub
- }
- }
-
-
- private static final class MessageWebSocketServlet
- extends WebSocketServlet {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- protected StreamInbound createWebSocketInbound() {
- return new SimpleMessageInbound();
- }
- }
-
- private static final class SimpleMessageInbound extends MessageInbound {
-
- @Override
- protected void onBinaryMessage(ByteBuffer message) {
- // TODO Auto-generated method stub
- }
-
- @Override
- protected void onTextMessage(CharBuffer message) {
- // TODO Auto-generated method stub
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.websocket;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.CharChunk;
+
+public class TestWebSocket extends TomcatBaseTest {
+
+ private static final String CRLF = "\r\n";
+
+ private OutputStream os;
+ private InputStream is;
+ boolean isContinuation = false;
+
+ @Test
+ public void testSimple() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+ File appDir = new File(getBuildDirectory(), "webapps/examples");
+ tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
+
+ tomcat.start();
+
+ // Open the socket
+ final String encoding = "ISO-8859-1";
+ SocketAddress addr = new InetSocketAddress("localhost", getPort());
+ Socket socket = new Socket();
+ socket.setSoTimeout(10000);
+ socket.connect(addr, 10000);
+ os = socket.getOutputStream();
+ Writer writer = new OutputStreamWriter(os, encoding);
+ is = socket.getInputStream();
+ Reader r = new InputStreamReader(is, encoding);
+ BufferedReader reader = new BufferedReader(r);
+
+ // Send the WebSocket handshake
+ writer.write("GET /examples/websocket/echoStream HTTP/1.1" + CRLF);
+ writer.write("Host: foo" + CRLF);
+ writer.write("Upgrade: websocket" + CRLF);
+ writer.write("Connection: upgrade" + CRLF);
+ writer.write("Sec-WebSocket-Version: 13" + CRLF);
+ writer.write("Sec-WebSocket-Key: TODO" + CRLF);
+ writer.write(CRLF);
+ writer.flush();
+
+ // Make sure we got an upgrade response
+ String responseLine = reader.readLine();
+ assertTrue(responseLine.startsWith("HTTP/1.1 101"));
+
+ // Swallow the headers
+ String responseHeaderLine = reader.readLine();
+ while (!responseHeaderLine.equals("")) {
+ responseHeaderLine = reader.readLine();
+ }
+
+ // Now we can do WebSocket
+ sendMessage("foo", false);
+ sendMessage("foo", true);
+
+ assertEquals("foofoo",readMessage());
+
+ // Finished with the socket
+ socket.close();
+ }
+
+ private void sendMessage(String message, boolean finalFragment)
+ throws IOException{
+ ByteChunk bc = new ByteChunk(8192);
+ C2BConverter c2b = new C2BConverter(bc, "UTF-8");
+ c2b.convert(message);
+ c2b.flushBuffer();
+
+ int len = bc.getLength();
+ assertTrue(len < 126);
+
+
+ byte first;
+ if (isContinuation) {
+ first = Constants.OPCODE_CONTINUATION;
+ } else {
+ first = Constants.OPCODE_TEXT;
+ }
+ if (finalFragment) {
+ first = (byte) (0x80 | first);
+ }
+ os.write(first);
+
+ os.write(0x80 | len);
+
+ // Zero mask
+ os.write(0);
+ os.write(0);
+ os.write(0);
+ os.write(0);
+
+ // Payload
+ os.write(bc.getBytes(), bc.getStart(), len);
+
+ os.flush();
+
+ // Will the next frame be a continuation frame
+ isContinuation = !finalFragment;
+ }
+
+ private String readMessage() throws IOException {
+ ByteChunk bc = new ByteChunk(125);
+ CharChunk cc = new CharChunk(125);
+
+ // Skip first byte
+ is.read();
+
+ // Get payload length
+ int len = is.read() & 0x7F;
+ assertTrue(len < 126);
+
+ // Read payload
+ int read = 0;
+ while (read < len) {
+ read = read + is.read(bc.getBytes(), read, len - read);
+ }
+
+ bc.setEnd(len);
+
+ B2CConverter b2c = new B2CConverter("UTF-8");
+ b2c.convert(bc, cc, len);
+
+ return cc.toString();
+ }
+}
Propchange: tomcat/tc7.0.x/trunk/test/org/apache/catalina/websocket/TestWebSocket.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java (original)
+++ tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java Thu Mar 15 23:11:47 2012
@@ -1,50 +1,49 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package websocket;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-
-import org.apache.catalina.websocket.MessageInbound;
-import org.apache.catalina.websocket.StreamInbound;
-import org.apache.catalina.websocket.WebSocketServlet;
-
-
-public class EchoMessage extends WebSocketServlet {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- protected StreamInbound createWebSocketInbound() {
- return new EchoMessageInbound();
- }
-
- private static final class EchoMessageInbound extends MessageInbound {
-
- @Override
- protected void onBinaryMessage(ByteBuffer message) throws IOException {
- System.out.write(message.array(), 0, message.limit());
- System.out.print('\n');
- }
-
- @Override
- protected void onTextMessage(CharBuffer message) throws IOException {
- System.out.println(message);
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package websocket;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import org.apache.catalina.websocket.MessageInbound;
+import org.apache.catalina.websocket.StreamInbound;
+import org.apache.catalina.websocket.WebSocketServlet;
+
+
+public class EchoMessage extends WebSocketServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected StreamInbound createWebSocketInbound(String subProtocol) {
+ return new EchoMessageInbound();
+ }
+
+ private static final class EchoMessageInbound extends MessageInbound {
+
+ @Override
+ protected void onBinaryMessage(ByteBuffer message) throws IOException {
+ getOutbound().writeBinaryMessage(message);
+ }
+
+ @Override
+ protected void onTextMessage(CharBuffer message) throws IOException {
+ getOutbound().writeTextMessage(message);
+ }
+ }
+}
Propchange: tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java (original)
+++ tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java Thu Mar 15 23:11:47 2012
@@ -1,67 +1,67 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package websocket;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-
-import org.apache.catalina.websocket.StreamInbound;
-import org.apache.catalina.websocket.WebSocketServlet;
-import org.apache.catalina.websocket.WsOutbound;
-
-
-public class EchoStream extends WebSocketServlet {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- protected StreamInbound createWebSocketInbound() {
- return new EchoStreamInbound();
- }
-
- private static final class EchoStreamInbound extends StreamInbound {
-
- @Override
- protected void onBinaryData(InputStream is) throws IOException {
- // Simply echo the data to back to the client.
- WsOutbound outbound = getStreamOutbound();
-
- int i = is.read();
- while (i != -1) {
- outbound.writeBinaryData(i);
- i = is.read();
- }
-
- outbound.flush();
- }
-
- @Override
- protected void onTextData(Reader r) throws IOException {
- // Simply echo the data to back to the client.
- WsOutbound outbound = getStreamOutbound();
-
- int c = r.read();
- while (c != -1) {
- outbound.writeTextData((char) c);
- c = r.read();
- }
-
- outbound.flush();
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package websocket;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.catalina.websocket.StreamInbound;
+import org.apache.catalina.websocket.WebSocketServlet;
+import org.apache.catalina.websocket.WsOutbound;
+
+
+public class EchoStream extends WebSocketServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected StreamInbound createWebSocketInbound(String subProtocol) {
+ return new EchoStreamInbound();
+ }
+
+ private static final class EchoStreamInbound extends StreamInbound {
+
+ @Override
+ protected void onBinaryData(InputStream is) throws IOException {
+ // Simply echo the data to back to the client.
+ WsOutbound outbound = getOutbound();
+
+ int i = is.read();
+ while (i != -1) {
+ outbound.writeBinaryData(i);
+ i = is.read();
+ }
+
+ outbound.flush();
+ }
+
+ @Override
+ protected void onTextData(Reader r) throws IOException {
+ // Simply echo the data to back to the client.
+ WsOutbound outbound = getOutbound();
+
+ int c = r.read();
+ while (c != -1) {
+ outbound.writeTextData((char) c);
+ c = r.read();
+ }
+
+ outbound.flush();
+ }
+ }
+}
Propchange: tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.html
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.html?rev=1301263&r1=1301262&r2=1301263&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.html (original)
+++ tomcat/tc7.0.x/trunk/webapps/examples/websocket/index.html Thu Mar 15 23:11:47 2012
@@ -1,28 +1,28 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<HTML><HEAD><TITLE>Apache Tomcat WebSocket Examples</TITLE>
-<META http-equiv=Content-Type content="text/html">
-</HEAD>
-<BODY>
-<P>
-<H3>Apache Tomcat WebSocket Examples</H3>
-<P></P>
-<ul>
-<li><a href="echo.html">Echo example</a></li>
-</ul>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD><TITLE>Apache Tomcat WebSocket Examples</TITLE>
+<META http-equiv=Content-Type content="text/html">
+</HEAD>
+<BODY>
+<P>
+<H3>Apache Tomcat WebSocket Examples</H3>
+<P></P>
+<ul>
+<li><a href="echo.html">Echo example</a></li>
+</ul>
</BODY></HTML>
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org