/jetty-8.1.5.v20120716/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD00.java
Java | 522 lines | 384 code | 74 blank | 64 comment | 27 complexity | 5b322f8126d2fa13b18b50e56f5435cf MD5 | raw file
Possible License(s): Apache-2.0
- /*******************************************************************************
- * Copyright (c) 2011 Intalio, Inc.
- * ======================================================================
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- *
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * The Apache License v2.0 is available at
- * http://www.opensource.org/licenses/apache2.0.php
- *
- * You may elect to redistribute this code under either of these licenses.
- *******************************************************************************/
- // ========================================================================
- // Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
- // ------------------------------------------------------------------------
- // All rights reserved. This program and the accompanying materials
- // are made available under the terms of the Eclipse Public License v1.0
- // and Apache License v2.0 which accompanies this distribution.
- // The Eclipse Public License is available at
- // http://www.eclipse.org/legal/epl-v10.html
- // The Apache License v2.0 is available at
- // http://www.opensource.org/licenses/apache2.0.php
- // You may elect to redistribute this code under either of these licenses.
- // ========================================================================
- package org.eclipse.jetty.websocket;
- import java.io.IOException;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.Collections;
- import java.util.List;
- import org.eclipse.jetty.io.AbstractConnection;
- import org.eclipse.jetty.io.AsyncEndPoint;
- import org.eclipse.jetty.io.Buffer;
- import org.eclipse.jetty.io.ByteArrayBuffer;
- import org.eclipse.jetty.io.Connection;
- import org.eclipse.jetty.io.EndPoint;
- import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
- import org.eclipse.jetty.util.StringUtil;
- import org.eclipse.jetty.util.log.Log;
- import org.eclipse.jetty.util.log.Logger;
- import org.eclipse.jetty.websocket.WebSocket.OnFrame;
- public class WebSocketConnectionD00 extends AbstractConnection implements WebSocketConnection, WebSocket.FrameConnection
- {
- private static final Logger LOG = Log.getLogger(WebSocketConnectionD00.class);
- public final static byte LENGTH_FRAME=(byte)0x80;
- public final static byte SENTINEL_FRAME=(byte)0x00;
- private final WebSocketParser _parser;
- private final WebSocketGenerator _generator;
- private final WebSocket _websocket;
- private final String _protocol;
- private String _key1;
- private String _key2;
- private ByteArrayBuffer _hixieBytes;
- public WebSocketConnectionD00(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol)
- throws IOException
- {
- super(endpoint,timestamp);
- _endp.setMaxIdleTime(maxIdleTime);
- _websocket = websocket;
- _protocol=protocol;
- _generator = new WebSocketGeneratorD00(buffers, _endp);
- _parser = new WebSocketParserD00(buffers, endpoint, new FrameHandlerD00(_websocket));
- }
- /* ------------------------------------------------------------ */
- public org.eclipse.jetty.websocket.WebSocket.Connection getConnection()
- {
- return this;
- }
- /* ------------------------------------------------------------ */
- public void setHixieKeys(String key1,String key2)
- {
- _key1=key1;
- _key2=key2;
- _hixieBytes=new IndirectNIOBuffer(16);
- }
- /* ------------------------------------------------------------ */
- public Connection handle() throws IOException
- {
- try
- {
- // handle stupid hixie random bytes
- if (_hixieBytes!=null)
- {
- // take any available bytes from the parser buffer, which may have already been read
- Buffer buffer=_parser.getBuffer();
- if (buffer!=null && buffer.length()>0)
- {
- int l=buffer.length();
- if (l>(8-_hixieBytes.length()))
- l=8-_hixieBytes.length();
- _hixieBytes.put(buffer.peek(buffer.getIndex(),l));
- buffer.skip(l);
- }
- // while we are not blocked
- while(_endp.isOpen())
- {
- // do we now have enough
- if (_hixieBytes.length()==8)
- {
- // we have the silly random bytes
- // so let's work out the stupid 16 byte reply.
- doTheHixieHixieShake();
- _endp.flush(_hixieBytes);
- _hixieBytes=null;
- _endp.flush();
- break;
- }
- // no, then let's fill
- int filled=_endp.fill(_hixieBytes);
- if (filled<0)
- {
- _endp.flush();
- _endp.close();
- break;
- }
- }
- if (_websocket instanceof OnFrame)
- ((OnFrame)_websocket).onHandshake(this);
- _websocket.onOpen(this);
- return this;
- }
- // handle the framing protocol
- boolean progress=true;
- while (progress)
- {
- int flushed=_generator.flush();
- int filled=_parser.parseNext();
- progress = flushed>0 || filled>0;
- _endp.flush();
- if (_endp instanceof AsyncEndPoint && ((AsyncEndPoint)_endp).hasProgressed())
- progress=true;
- }
- }
- catch(IOException e)
- {
- LOG.debug(e);
- try
- {
- if (_endp.isOpen())
- _endp.close();
- }
- catch(IOException e2)
- {
- LOG.ignore(e2);
- }
- throw e;
- }
- finally
- {
- if (_endp.isOpen())
- {
- if (_endp.isInputShutdown() && _generator.isBufferEmpty())
- _endp.close();
- else
- checkWriteable();
- checkWriteable();
- }
- }
- return this;
- }
- /* ------------------------------------------------------------ */
- public void onInputShutdown() throws IOException
- {
- // TODO
- }
- /* ------------------------------------------------------------ */
- private void doTheHixieHixieShake()
- {
- byte[] result=WebSocketConnectionD00.doTheHixieHixieShake(
- WebSocketConnectionD00.hixieCrypt(_key1),
- WebSocketConnectionD00.hixieCrypt(_key2),
- _hixieBytes.asArray());
- _hixieBytes.clear();
- _hixieBytes.put(result);
- }
- /* ------------------------------------------------------------ */
- public boolean isOpen()
- {
- return _endp!=null&&_endp.isOpen();
- }
- /* ------------------------------------------------------------ */
- public boolean isIdle()
- {
- return _parser.isBufferEmpty() && _generator.isBufferEmpty();
- }
- /* ------------------------------------------------------------ */
- public boolean isSuspended()
- {
- return false;
- }
- /* ------------------------------------------------------------ */
- public void onClose()
- {
- _websocket.onClose(WebSocketConnectionD06.CLOSE_NORMAL,"");
- }
- /* ------------------------------------------------------------ */
- /**
- */
- public void sendMessage(String content) throws IOException
- {
- byte[] data = content.getBytes(StringUtil.__UTF8);
- _generator.addFrame((byte)0,SENTINEL_FRAME,data,0,data.length);
- _generator.flush();
- checkWriteable();
- }
- /* ------------------------------------------------------------ */
- public void sendMessage(byte[] data, int offset, int length) throws IOException
- {
- _generator.addFrame((byte)0,LENGTH_FRAME,data,offset,length);
- _generator.flush();
- checkWriteable();
- }
- /* ------------------------------------------------------------ */
- public boolean isMore(byte flags)
- {
- return (flags&0x8) != 0;
- }
- /* ------------------------------------------------------------ */
- /**
- * {@inheritDoc}
- */
- public void sendControl(byte code, byte[] content, int offset, int length) throws IOException
- {
- }
- /* ------------------------------------------------------------ */
- public void sendFrame(byte flags,byte opcode, byte[] content, int offset, int length) throws IOException
- {
- _generator.addFrame((byte)0,opcode,content,offset,length);
- _generator.flush();
- checkWriteable();
- }
- /* ------------------------------------------------------------ */
- public void close(int code, String message)
- {
- throw new UnsupportedOperationException();
- }
- /* ------------------------------------------------------------ */
- public void disconnect()
- {
- close();
- }
- /* ------------------------------------------------------------ */
- public void close()
- {
- try
- {
- _generator.flush();
- _endp.close();
- }
- catch(IOException e)
- {
- LOG.ignore(e);
- }
- }
- public void shutdown()
- {
- close();
- }
- /* ------------------------------------------------------------ */
- public void fillBuffersFrom(Buffer buffer)
- {
- _parser.fill(buffer);
- }
- /* ------------------------------------------------------------ */
- private void checkWriteable()
- {
- if (!_generator.isBufferEmpty() && _endp instanceof AsyncEndPoint)
- ((AsyncEndPoint)_endp).scheduleWrite();
- }
- /* ------------------------------------------------------------ */
- static long hixieCrypt(String key)
- {
- // Don't ask me what all this is about.
- // I think it's pretend secret stuff, kind of
- // like talking in pig latin!
- long number=0;
- int spaces=0;
- for (char c : key.toCharArray())
- {
- if (Character.isDigit(c))
- number=number*10+(c-'0');
- else if (c==' ')
- spaces++;
- }
- return number/spaces;
- }
- public static byte[] doTheHixieHixieShake(long key1,long key2,byte[] key3)
- {
- try
- {
- MessageDigest md = MessageDigest.getInstance("MD5");
- byte [] fodder = new byte[16];
- fodder[0]=(byte)(0xff&(key1>>24));
- fodder[1]=(byte)(0xff&(key1>>16));
- fodder[2]=(byte)(0xff&(key1>>8));
- fodder[3]=(byte)(0xff&key1);
- fodder[4]=(byte)(0xff&(key2>>24));
- fodder[5]=(byte)(0xff&(key2>>16));
- fodder[6]=(byte)(0xff&(key2>>8));
- fodder[7]=(byte)(0xff&key2);
- System.arraycopy(key3, 0, fodder, 8, 8);
- md.update(fodder);
- return md.digest();
- }
- catch (NoSuchAlgorithmException e)
- {
- throw new IllegalStateException(e);
- }
- }
- public void setMaxTextMessageSize(int size)
- {
- }
- public void setMaxIdleTime(int ms)
- {
- try
- {
- _endp.setMaxIdleTime(ms);
- }
- catch(IOException e)
- {
- LOG.warn(e);
- }
- }
- public void setMaxBinaryMessageSize(int size)
- {
- }
- public int getMaxTextMessageSize()
- {
- return -1;
- }
- public int getMaxIdleTime()
- {
- return _endp.getMaxIdleTime();
- }
- public int getMaxBinaryMessageSize()
- {
- return -1;
- }
- public String getProtocol()
- {
- return _protocol;
- }
- protected void onFrameHandshake()
- {
- if (_websocket instanceof OnFrame)
- {
- ((OnFrame)_websocket).onHandshake(this);
- }
- }
- protected void onWebsocketOpen()
- {
- _websocket.onOpen(this);
- }
- static class FrameHandlerD00 implements WebSocketParser.FrameHandler
- {
- final WebSocket _websocket;
- FrameHandlerD00(WebSocket websocket)
- {
- _websocket=websocket;
- }
- public void onFrame(byte flags, byte opcode, Buffer buffer)
- {
- try
- {
- byte[] array=buffer.array();
- if (opcode==0)
- {
- if (_websocket instanceof WebSocket.OnTextMessage)
- ((WebSocket.OnTextMessage)_websocket).onMessage(buffer.toString(StringUtil.__UTF8));
- }
- else
- {
- if (_websocket instanceof WebSocket.OnBinaryMessage)
- ((WebSocket.OnBinaryMessage)_websocket).onMessage(array,buffer.getIndex(),buffer.length());
- }
- }
- catch(Throwable th)
- {
- LOG.warn(th);
- }
- }
- public void close(int code,String message)
- {
- }
- }
- public boolean isMessageComplete(byte flags)
- {
- return true;
- }
- public byte binaryOpcode()
- {
- return LENGTH_FRAME;
- }
- public byte textOpcode()
- {
- return SENTINEL_FRAME;
- }
- public boolean isControl(byte opcode)
- {
- return false;
- }
- public boolean isText(byte opcode)
- {
- return (opcode&LENGTH_FRAME)==0;
- }
- public boolean isBinary(byte opcode)
- {
- return (opcode&LENGTH_FRAME)!=0;
- }
- public boolean isContinuation(byte opcode)
- {
- return false;
- }
- public boolean isClose(byte opcode)
- {
- return false;
- }
- public boolean isPing(byte opcode)
- {
- return false;
- }
- public boolean isPong(byte opcode)
- {
- return false;
- }
- public List<Extension> getExtensions()
- {
- return Collections.emptyList();
- }
- public byte continuationOpcode()
- {
- return 0;
- }
- public byte finMask()
- {
- return 0;
- }
- public void setAllowFrameFragmentation(boolean allowFragmentation)
- {
- }
- public boolean isAllowFrameFragmentation()
- {
- return false;
- }
- }