From 49f8b0de1ae192688c0a0a8c69e1891959abb3d1 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 18 Oct 2011 21:59:49 +1100 Subject: [PATCH] Websocket partially refactored and passing tests --- .../jetty/client/AsyncHttpConnection.java | 125 +++++++----------- .../jetty/io/nio/SelectChannelEndPoint.java | 3 +- .../jetty/server/AsyncHttpConnection.java | 5 +- .../org/eclipse/jetty/util/log/StdErrLog.java | 6 +- .../websocket/WebSocketClientFactory.java | 20 ++- .../websocket/WebSocketConnectionD13.java | 65 ++++----- .../jetty/websocket/WebSocketFactory.java | 2 + .../websocket/WebSocketGeneratorD13.java | 15 ++- .../jetty/websocket/WebSocketParserD13.java | 57 +++++--- .../websocket/WebSocketGeneratorD13Test.java | 38 ++++++ .../websocket/WebSocketMessageD13Test.java | 4 +- .../websocket/WebSocketParserD13Test.java | 69 +++++++--- 12 files changed, 248 insertions(+), 161 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java index cdb555e7af4..ea0d8f2b127 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java @@ -40,57 +40,48 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async { try { - int no_progress = 0; - + boolean progress=true; boolean failed = false; - while (_endp.isBufferingInput() || _endp.isOpen()) + + // While the endpoint is open + // AND we have more characters to read OR we made some progress + while (_endp.isOpen() && + (_parser.isMoreInBuffer() || _endp.isBufferingInput() || progress)) { + + // If no exchange, skipCRLF or close on unexpected characters + HttpExchange exchange; synchronized (this) { - while (_exchange == null) + exchange=_exchange; + } + + if (exchange == null) + { + long filled = _parser.fill(); + if (filled < 0) + close(); + else { - if (_endp.isBlocking()) + // Hopefully just space? + _parser.skipCRLF(); + if (_parser.isMoreInBuffer()) { - try - { - this.wait(); - } - catch (InterruptedException e) - { - throw new InterruptedIOException(); - } - } - else - { - long filled = _parser.fill(); - if (filled < 0) - { - close(); - } - else - { - // Hopefully just space? - _parser.skipCRLF(); - if (_parser.isMoreInBuffer()) - { - LOG.warn("Unexpected data received but no request sent"); - close(); - } - } - return this; + LOG.warn("Unexpected data received but no request sent"); + close(); } } + return this; } try { - if (_exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT) + if (exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT) { - no_progress = 0; + progress=true; commitRequest(); } - long io = 0; _endp.flush(); if (_generator.isComplete()) @@ -98,47 +89,38 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async if (!_requestComplete) { _requestComplete = true; - _exchange.getEventListener().onRequestComplete(); + exchange.getEventListener().onRequestComplete(); } } else { - // Write as much of the request as possible - synchronized (this) - { - if (_exchange == null) - continue; - } - long flushed = _generator.flushBuffer(); - io += flushed; - - if (!_generator.isComplete()) + progress|=(flushed>0); + + if (_generator.isComplete()) { - if (_exchange!=null) + InputStream in = exchange.getRequestContentSource(); + if (in != null) { - InputStream in = _exchange.getRequestContentSource(); - if (in != null) + if (_requestContentChunk == null || _requestContentChunk.length() == 0) { - if (_requestContentChunk == null || _requestContentChunk.length() == 0) - { - _requestContentChunk = _exchange.getRequestContentChunk(); + _requestContentChunk = _exchange.getRequestContentChunk(); - if (_requestContentChunk != null) - _generator.addContent(_requestContentChunk,false); - else - _generator.complete(); + if (_requestContentChunk != null) + _generator.addContent(_requestContentChunk,false); + else + _generator.complete(); - flushed = _generator.flushBuffer(); - io += flushed; - } + flushed = _generator.flushBuffer(); + progress|=(flushed>0); } - else - _generator.complete(); } else _generator.complete(); } + else + _generator.complete(); + } if (_generator.isComplete() && !_requestComplete) @@ -151,25 +133,12 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async if (!_parser.isComplete() && (_generator.isComplete() || _generator.isCommitted() && !_endp.isBlocking())) { if (_parser.parseAvailable()) - io++; + progress=true; if (_parser.isIdle() && (_endp.isInputShutdown() || !_endp.isOpen())) throw new EOFException(); } - - if (io > 0) - no_progress = 0; - else if (no_progress++ >= 1 && !_endp.isBlocking()) - { - // SSL may need an extra flush as it may have made "no progress" while actually doing a handshake. - if (_endp instanceof SslSelectChannelEndPoint && !_generator.isComplete() && !_generator.isEmpty()) - { - long flushed = _generator.flushBuffer(); - if (flushed>0) - continue; - } - return this; - } + } catch (Throwable e) { @@ -270,10 +239,10 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async reset(true); - no_progress = 0; + progress=true; if (_exchange != null) { - HttpExchange exchange=_exchange; + exchange=_exchange; _exchange = null; // Reset the maxIdleTime because it may have been changed diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java index 6840746ca3e..e134379c802 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java @@ -579,8 +579,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo if (next!=_connection) { LOG.debug("{} replaced {}",next,_connection); + Connection old=_connection; _connection=next; - _manager.endPointUpgraded(this,_connection); + _manager.endPointUpgraded(this,old); continue; } break; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncHttpConnection.java index f18b29e14d4..518dd0a1f30 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncHttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncHttpConnection.java @@ -82,7 +82,6 @@ public class AsyncHttpConnection extends HttpConnection implements AsyncConnecti { // Reset the parser/generator progress=true; - reset(); // look for a switched connection instance? if (_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101) @@ -91,11 +90,13 @@ public class AsyncHttpConnection extends HttpConnection implements AsyncConnecti if (switched!=null) connection=switched; } + + reset(); // TODO Is this required? if (!_generator.isPersistent() && !_endp.isOutputShutdown()) { - System.err.println("Safety net oshut!!!"); + LOG.warn("Safety net oshut!!!"); _endp.shutdownOutput(); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java index 5e0037539a8..87d8530205d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java @@ -540,9 +540,9 @@ public class StdErrLog implements Logger { StdErrLog sel = new StdErrLog(fullname); // Preserve configuration for new loggers configuration - //sel.setPrintLongNames(_printLongNames); - //sel.setLevel(_level); - //sel.setSource(_source); + sel.setPrintLongNames(_printLongNames); + // Let Level come from configured Properties instead - sel.setLevel(_level); + sel.setSource(_source); logger = __loggers.putIfAbsent(fullname,sel); if (logger == null) { diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java index eb2a936af8d..46b0ed3a99e 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketClientFactory.java @@ -227,7 +227,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle @Override protected void endPointUpgraded(ConnectedEndPoint endpoint, Connection oldConnection) { - throw new IllegalStateException(); + LOG.debug("upgrade {} -> {}",oldConnection,endpoint.getConnection()); } @Override @@ -364,7 +364,6 @@ public class WebSocketClientFactory extends AggregateLifeCycle { future.handshakeFailed(e); } - } public Connection handle() throws IOException @@ -388,7 +387,15 @@ public class WebSocketClientFactory extends AggregateLifeCycle { Buffer header=_parser.getHeaderBuffer(); MaskGen maskGen=_future.getMaskGen(); - WebSocketConnectionD13 connection = new WebSocketConnectionD13(_future.getWebSocket(),_endp,_buffers,System.currentTimeMillis(),_future.getMaxIdleTime(),_future.getProtocol(),null,10,maskGen); + WebSocketConnectionD13 connection = + new WebSocketConnectionD13(_future.getWebSocket(), + _endp, + _buffers,System.currentTimeMillis(), + _future.getMaxIdleTime(), + _future.getProtocol(), + null, + WebSocketConnectionD13.VERSION, + maskGen); if (header.hasContent()) connection.fillBuffersFrom(header); @@ -406,7 +413,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle public void onInputShutdown() throws IOException { - // TODO + _endp.close(); } public boolean isIdle() @@ -426,5 +433,10 @@ public class WebSocketClientFactory extends AggregateLifeCycle else _future.handshakeFailed(new EOFException()); } + + public String toString() + { + return "HS"+super.toString(); + } } } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java index 98eca911647..a937988ab42 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java @@ -40,6 +40,30 @@ import org.eclipse.jetty.websocket.WebSocket.OnControl; import org.eclipse.jetty.websocket.WebSocket.OnFrame; import org.eclipse.jetty.websocket.WebSocket.OnTextMessage; + +/* ------------------------------------------------------------ */ +/** + *
+ *    0                   1                   2                   3
+ *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *   +-+-+-+-+-------+-+-------------+-------------------------------+
+ *   |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
+ *   |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
+ *   |N|V|V|V|       |S|             |   (if payload len==126/127)   |
+ *   | |1|2|3|       |K|             |                               |
+ *   +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+ *   |     Extended payload length continued, if payload len == 127  |
+ *   + - - - - - - - - - - - - - - - +-------------------------------+
+ *   |                               |Masking-key, if MASK set to 1  |
+ *   +-------------------------------+-------------------------------+
+ *   | Masking-key (continued)       |          Payload Data         |
+ *   +-------------------------------- - - - - - - - - - - - - - - - +
+ *   :                     Payload Data continued ...                :
+ *   + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ *   |                     Payload Data continued ...                |
+ *   +---------------------------------------------------------------+
+ * 
+ */ public class WebSocketConnectionD13 extends AbstractConnection implements WebSocketConnection { private static final Logger LOG = Log.getLogger(WebSocketConnectionD13.class); @@ -225,12 +249,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc int filled=_parser.parseNext(); progress = flushed>0 || filled>0; - - if (filled<0 || flushed<0) - { - _endp.close(); - break; - } } } catch(IOException e) @@ -267,7 +285,8 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc /* ------------------------------------------------------------ */ public void onInputShutdown() throws IOException { - // TODO + if (!_closedIn) + _endp.close(); } /* ------------------------------------------------------------ */ @@ -309,11 +328,11 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc { LOG.debug("ClosedIn {} {}",this,message); - final boolean close; + final boolean closed_out; final boolean tell_app; synchronized (this) { - close=_closedOut; + closed_out=_closedOut; _closedIn=true; tell_app=_closeCode==0; if (tell_app) @@ -330,17 +349,8 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc } finally { - try - { - if (close) - _endp.close(); - else - closeOut(code,message); - } - catch(IOException e) - { - LOG.ignore(e); - } + if (!closed_out) + closeOut(code,message); } } @@ -349,13 +359,11 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc { LOG.debug("ClosedOut {} {}",this,message); - final boolean close; + final boolean closed_out; final boolean tell_app; - final boolean send_close; synchronized (this) { - close=_closedIn; - send_close=!_closedOut; + closed_out=_closedOut; _closedOut=true; tell_app=_closeCode==0; if (tell_app) @@ -374,21 +382,16 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc { try { - if (send_close) + if (!closed_out) { if (code<=0) code=WebSocketConnectionD13.CLOSE_NORMAL; - byte[] bytes = ("xx"+(message==null?"":message)).getBytes(StringUtil.__ISO_8859_1); + byte[] bytes = (message==null?"xx":("xx"+message)).getBytes(StringUtil.__ISO_8859_1); bytes[0]=(byte)(code/0x100); bytes[1]=(byte)(code%0x100); _outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD13.OP_CLOSE,bytes,0,bytes.length); _outbound.flush(); - if (close) - _endp.shutdownOutput(); } - else if (close) - _endp.close(); - } catch(IOException e) { diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java index e2d57d5a426..fd14c96be3a 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java @@ -205,6 +205,7 @@ public class WebSocketFactory extensions_requested.add(tok.nextToken()); } + final WebSocketConnection connection; final List extensions; switch (draft) @@ -251,6 +252,7 @@ public class WebSocketFactory connection.fillBuffersFrom(((HttpParser)http.getParser()).getBodyBuffer()); // Tell jetty about the new connection + LOG.debug("Websocket upgrade {} {} {} {}",request.getRequestURI(),draft,protocol,connection); request.setAttribute("org.eclipse.jetty.io.Connection", connection); } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13.java index 2f923520fe7..9ab21985fff 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13.java @@ -18,6 +18,7 @@ import java.io.IOException; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.TypeUtil; /* ------------------------------------------------------------ */ @@ -36,6 +37,7 @@ public class WebSocketGeneratorD13 implements WebSocketGenerator private int _m; private boolean _opsent; private final MaskGen _maskGen; + private boolean _closed; public WebSocketGeneratorD13(WebSocketBuffers buffers, EndPoint endp) { @@ -60,6 +62,11 @@ public class WebSocketGeneratorD13 implements WebSocketGenerator { // System.err.printf("<< %s %s %s\n",TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),length); + if (_closed) + throw new EofException("Closed"); + if (opcode==WebSocketConnectionD13.OP_CLOSE) + _closed=true; + boolean mask=_maskGen!=null; if (_buffer==null) @@ -131,7 +138,6 @@ public class WebSocketGeneratorD13 implements WebSocketGenerator _buffer.put(_mask); } - // write payload int remaining = payload; while (remaining > 0) @@ -183,7 +189,12 @@ public class WebSocketGeneratorD13 implements WebSocketGenerator throw new EofException(); if (_buffer!=null) - return _endp.flush(_buffer); + { + int flushed=_endp.flush(_buffer); + if (_closed&&_buffer.length()==0) + _endp.shutdownOutput(); + return flushed; + } return 0; } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParserD13.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParserD13.java index 5b21494df50..9196d6c65c1 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParserD13.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParserD13.java @@ -18,6 +18,7 @@ import java.io.IOException; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -34,7 +35,7 @@ public class WebSocketParserD13 implements WebSocketParser public enum State { - START(0), OPCODE(1), LENGTH_7(1), LENGTH_16(2), LENGTH_63(8), MASK(4), PAYLOAD(0), DATA(0), SKIP(1); + START(0), OPCODE(1), LENGTH_7(1), LENGTH_16(2), LENGTH_63(8), MASK(4), PAYLOAD(0), DATA(0), SKIP(1), SEEK_EOF(1); int _needs; @@ -125,11 +126,12 @@ public class WebSocketParserD13 implements WebSocketParser { if (_buffer==null) _buffer=_buffers.getBuffer(); - int total_filled=0; - int events=0; + + boolean progress=false; + int filled=-1; // Loop until a datagram call back or can't fill anymore - while(true) + while(!progress && (!_endp.isInputShutdown()||_endp.isBufferingInput()||_buffer.length()>0)) { int available=_buffer.length(); @@ -158,35 +160,38 @@ public class WebSocketParserD13 implements WebSocketParser } // System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length()); - events++; _bytesNeeded-=data.length(); + progress=true; _handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionD13.FLAG_FIN)), _opcode, data); _opcode=WebSocketConnectionD13.OP_CONTINUATION; } if (_buffer.space() == 0) - throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity()); + throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity()); } // catch IOExceptions (probably EOF) and try to parse what we have try { - int filled=_endp.isOpen()?_endp.fill(_buffer):-1; - if (filled<=0) - return (total_filled+events)>0?(total_filled+events):filled; - total_filled+=filled; + filled=_endp.isInputShutdown()?-1:_endp.fill(_buffer); available=_buffer.length(); + // System.err.printf(">> filled %d/%d%n",filled,available); + if (filled<=0) + break; } catch(IOException e) { LOG.debug(e); - return (total_filled+events)>0?(total_filled+events):-1; + filled=-1; + break; } } - + // Did we get enough? + if (available<(_state==State.SKIP?1:_bytesNeeded)) + break; + // if we are here, then we have sufficient bytes to process the current state. - // Parse the buffer byte by byte (unless it is STATE_DATA) byte b; while (_state!=State.DATA && available>=(_state==State.SKIP?1:_bytesNeeded)) @@ -195,7 +200,7 @@ public class WebSocketParserD13 implements WebSocketParser { case START: _skip=false; - _state=State.OPCODE; + _state=_opcode==WebSocketConnectionD13.OP_CLOSE?State.SEEK_EOF:State.OPCODE; _bytesNeeded=_state.getNeeds(); continue; @@ -207,9 +212,9 @@ public class WebSocketParserD13 implements WebSocketParser if (WebSocketConnectionD13.isControlFrame(_opcode)&&!WebSocketConnectionD13.isLastFrame(_flags)) { - events++; LOG.warn("Fragmented Control from "+_endp); _handler.close(WebSocketConnectionD13.CLOSE_PROTOCOL,"Fragmented control"); + progress=true; _skip=true; } @@ -249,7 +254,7 @@ public class WebSocketParserD13 implements WebSocketParser { if (_length>_buffer.capacity() && !_fragmentFrames) { - events++; + progress=true; _handler.close(WebSocketConnectionD13.CLOSE_POLICY_VIOLATION,"frame size "+_length+">"+_buffer.capacity()); _skip=true; } @@ -268,7 +273,7 @@ public class WebSocketParserD13 implements WebSocketParser _bytesNeeded=(int)_length; if (_length>=_buffer.capacity() && !_fragmentFrames) { - events++; + progress=true; _handler.close(WebSocketConnectionD13.CLOSE_POLICY_VIOLATION,"frame size "+_length+">"+_buffer.capacity()); _skip=true; } @@ -296,12 +301,19 @@ public class WebSocketParserD13 implements WebSocketParser case SKIP: int skip=Math.min(available,_bytesNeeded); + progress=true; _buffer.skip(skip); available-=skip; _bytesNeeded-=skip; if (_bytesNeeded==0) _state=State.START; - + break; + + case SEEK_EOF: + progress=true; + _buffer.skip(available); + available=0; + break; } } @@ -311,7 +323,7 @@ public class WebSocketParserD13 implements WebSocketParser { _buffer.skip(_bytesNeeded); _state=State.START; - events++; + progress=true; _handler.close(WebSocketConnectionD13.CLOSE_PROTOCOL,"Not masked"); } else @@ -328,15 +340,18 @@ public class WebSocketParserD13 implements WebSocketParser } // System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length()); - events++; + + progress=true; _handler.onFrame(_flags, _opcode, data); _bytesNeeded=0; _state=State.START; } - return total_filled+events; + break; } } + + return progress?1:filled; } /* ------------------------------------------------------------ */ diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13Test.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13Test.java index bc0585447e7..696a70abc48 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13Test.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorD13Test.java @@ -1,9 +1,11 @@ package org.eclipse.jetty.websocket; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; +import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.util.StringUtil; import org.junit.Before; import org.junit.Test; @@ -196,5 +198,41 @@ public class WebSocketGeneratorD13Test for (int i=0;i0); assertEquals("Hello World",_handler._data.get(0)); assertEquals(0x8,_handler._flags); assertEquals(0x1,_handler._opcode); @@ -150,7 +151,7 @@ public class WebSocketParserD13Test int progress =_parser.parseNext(); - assertEquals(bytes.length+7,progress); + assertTrue(progress>0); assertEquals(string,_handler._data.get(0)); assertEquals(0x8,_handler._flags); assertEquals(0x1,_handler._opcode); @@ -178,7 +179,7 @@ public class WebSocketParserD13Test int progress =_parser.parseNext(); - assertEquals(bytes.length+9,progress); + assertTrue(progress>0); assertEquals(string,_handler._data.get(0)); assertEquals(0x8,_handler._flags); assertEquals(0x1,_handler._opcode); @@ -219,7 +220,7 @@ public class WebSocketParserD13Test int progress =parser.parseNext(); parser.returnBuffer(); - assertEquals(bytes.length+11,progress); + assertTrue(progress>0); assertEquals(string,_handler._data.get(0)); assertTrue(parser.isBufferEmpty()); assertTrue(parser.getBuffer()==null); @@ -239,7 +240,7 @@ public class WebSocketParserD13Test int progress =_parser.parseNext(); - assertEquals(24,progress); + assertTrue(progress>0); assertEquals(0,_handler._data.size()); assertFalse(_parser.isBufferEmpty()); assertFalse(_parser.getBuffer()==null); @@ -247,7 +248,7 @@ public class WebSocketParserD13Test progress =_parser.parseNext(); _parser.returnBuffer(); - assertEquals(1,progress); + assertTrue(progress>0); assertEquals("Hello World",_handler._data.get(0)); assertTrue(_parser.isBufferEmpty()); assertTrue(_parser.getBuffer()==null); @@ -268,18 +269,18 @@ public class WebSocketParserD13Test int progress =_parser.parseNext(); assertTrue(progress>0); - assertEquals(WebSocketConnectionD13.CLOSE_POLICY_VIOLATION,_handler._code); + + for (int i=0;i<2048;i++) _in.put((byte)'a'); progress =_parser.parseNext(); - assertEquals(2048,progress); + assertTrue(progress>0); assertEquals(0,_handler._data.size()); assertEquals(0,_handler._utf8.length()); _handler._code=0; - _handler._message=null; _in.putUnmasked((byte)0x81); _in.putUnmasked((byte)0xFE); @@ -291,8 +292,7 @@ public class WebSocketParserD13Test progress =_parser.parseNext(); assertTrue(progress>0); - assertEquals(1,_handler._data.size()); - assertEquals(1024,_handler._data.get(0).length()); + assertEquals(0,_handler._data.size()); } @Test @@ -323,6 +323,43 @@ public class WebSocketParserD13Test assertEquals(('a'+i%26),mesg.charAt(i)); } + @Test + public void testClose() throws Exception + { + String string = "Game Over"; + byte[] bytes = string.getBytes("UTF-8"); + + _in.putUnmasked((byte)(0x80|0x08)); + _in.putUnmasked((byte)(0x80|(2+bytes.length))); + _in.sendMask(); + _in.put((byte)(1000/0x100)); + _in.put((byte)(1000%0x100)); + _in.put(bytes); + + int progress =_parser.parseNext(); + + assertTrue(progress>0); + assertEquals(string,_handler._data.get(0).substring(2)); + assertEquals(0x8,_handler._flags); + assertEquals(0x8,_handler._opcode); + _parser.returnBuffer(); + assertTrue(_parser.isBufferEmpty()); + assertTrue(_parser.getBuffer()==null); + + _in.clear(); + _in.put(bytes); + _endPoint.setIn(_in); + progress =_parser.parseNext(); + assertTrue(progress>0); + + _endPoint.shutdownInput(); + + progress =_parser.parseNext(); + assertEquals(-1,progress); + + } + + private class Handler implements WebSocketParser.FrameHandler { Utf8StringBuilder _utf8 = new Utf8StringBuilder(); @@ -330,7 +367,6 @@ public class WebSocketParserD13Test private byte _flags; private byte _opcode; int _code; - String _message; int _frames; public void onFrame(byte flags, byte opcode, Buffer buffer) @@ -353,7 +389,6 @@ public class WebSocketParserD13Test public void close(int code,String message) { _code=code; - _message=message; } } }