103928aee4356845252ac6b662d5c72c29903813eJake Slack//
203928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
303928aee4356845252ac6b662d5c72c29903813eJake Slack//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
403928aee4356845252ac6b662d5c72c29903813eJake Slack//  ------------------------------------------------------------------------
503928aee4356845252ac6b662d5c72c29903813eJake Slack//  All rights reserved. This program and the accompanying materials
603928aee4356845252ac6b662d5c72c29903813eJake Slack//  are made available under the terms of the Eclipse Public License v1.0
703928aee4356845252ac6b662d5c72c29903813eJake Slack//  and Apache License v2.0 which accompanies this distribution.
803928aee4356845252ac6b662d5c72c29903813eJake Slack//
903928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Eclipse Public License is available at
1003928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.eclipse.org/legal/epl-v10.html
1103928aee4356845252ac6b662d5c72c29903813eJake Slack//
1203928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Apache License v2.0 is available at
1303928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.opensource.org/licenses/apache2.0.php
1403928aee4356845252ac6b662d5c72c29903813eJake Slack//
1503928aee4356845252ac6b662d5c72c29903813eJake Slack//  You may elect to redistribute this code under either of these licenses.
1603928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
1703928aee4356845252ac6b662d5c72c29903813eJake Slack//
1803928aee4356845252ac6b662d5c72c29903813eJake Slack
1903928aee4356845252ac6b662d5c72c29903813eJake Slackpackage org.eclipse.jetty.websocket;
2003928aee4356845252ac6b662d5c72c29903813eJake Slack
2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException;
2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.UnsupportedEncodingException;
2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.security.MessageDigest;
2403928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Collections;
2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.List;
2603928aee4356845252ac6b662d5c72c29903813eJake Slack
2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.AbstractConnection;
2803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.AsyncEndPoint;
2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Buffer;
3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.ByteArrayBuffer;
3103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Connection;
3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.EndPoint;
3303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.B64Code;
3403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.StringUtil;
3503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.Utf8StringBuilder;
3603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Log;
3703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Logger;
3803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.websocket.WebSocket.OnBinaryMessage;
3903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.websocket.WebSocket.OnControl;
4003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.websocket.WebSocket.OnFrame;
4103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
4203928aee4356845252ac6b662d5c72c29903813eJake Slack
4303928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class WebSocketConnectionD08 extends AbstractConnection implements WebSocketConnection
4403928aee4356845252ac6b662d5c72c29903813eJake Slack{
4503928aee4356845252ac6b662d5c72c29903813eJake Slack    private static final Logger LOG = Log.getLogger(WebSocketConnectionD08.class);
4603928aee4356845252ac6b662d5c72c29903813eJake Slack
4703928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_CONTINUATION = 0x00;
4803928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_TEXT = 0x01;
4903928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_BINARY = 0x02;
5003928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_EXT_DATA = 0x03;
5103928aee4356845252ac6b662d5c72c29903813eJake Slack
5203928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_CONTROL = 0x08;
5303928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_CLOSE = 0x08;
5403928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_PING = 0x09;
5503928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_PONG = 0x0A;
5603928aee4356845252ac6b662d5c72c29903813eJake Slack    final static byte OP_EXT_CTRL = 0x0B;
5703928aee4356845252ac6b662d5c72c29903813eJake Slack
5803928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int CLOSE_NORMAL=1000;
5903928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int CLOSE_SHUTDOWN=1001;
6003928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int CLOSE_PROTOCOL=1002;
6103928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int CLOSE_BADDATA=1003;
6203928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int CLOSE_NOCODE=1005;
6303928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int CLOSE_NOCLOSE=1006;
6403928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int CLOSE_NOTUTF8=1007;
6503928aee4356845252ac6b662d5c72c29903813eJake Slack
6603928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int FLAG_FIN=0x8;
6703928aee4356845252ac6b662d5c72c29903813eJake Slack
6803928aee4356845252ac6b662d5c72c29903813eJake Slack    final static int VERSION=8;
6903928aee4356845252ac6b662d5c72c29903813eJake Slack
7003928aee4356845252ac6b662d5c72c29903813eJake Slack    static boolean isLastFrame(byte flags)
7103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
7203928aee4356845252ac6b662d5c72c29903813eJake Slack        return (flags&FLAG_FIN)!=0;
7303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
7403928aee4356845252ac6b662d5c72c29903813eJake Slack
7503928aee4356845252ac6b662d5c72c29903813eJake Slack    static boolean isControlFrame(byte opcode)
7603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
7703928aee4356845252ac6b662d5c72c29903813eJake Slack        return (opcode&OP_CONTROL)!=0;
7803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
7903928aee4356845252ac6b662d5c72c29903813eJake Slack
8003928aee4356845252ac6b662d5c72c29903813eJake Slack    private final static byte[] MAGIC;
8103928aee4356845252ac6b662d5c72c29903813eJake Slack    private final List<Extension> _extensions;
8203928aee4356845252ac6b662d5c72c29903813eJake Slack    private final WebSocketParserD08 _parser;
8303928aee4356845252ac6b662d5c72c29903813eJake Slack    private final WebSocketGeneratorD08 _generator;
8403928aee4356845252ac6b662d5c72c29903813eJake Slack    private final WebSocketGenerator _outbound;
8503928aee4356845252ac6b662d5c72c29903813eJake Slack    private final WebSocket _webSocket;
8603928aee4356845252ac6b662d5c72c29903813eJake Slack    private final OnFrame _onFrame;
8703928aee4356845252ac6b662d5c72c29903813eJake Slack    private final OnBinaryMessage _onBinaryMessage;
8803928aee4356845252ac6b662d5c72c29903813eJake Slack    private final OnTextMessage _onTextMessage;
8903928aee4356845252ac6b662d5c72c29903813eJake Slack    private final OnControl _onControl;
9003928aee4356845252ac6b662d5c72c29903813eJake Slack    private final String _protocol;
9103928aee4356845252ac6b662d5c72c29903813eJake Slack    private final int _draft;
9203928aee4356845252ac6b662d5c72c29903813eJake Slack    private final ClassLoader _context;
9303928aee4356845252ac6b662d5c72c29903813eJake Slack    private volatile int _closeCode;
9403928aee4356845252ac6b662d5c72c29903813eJake Slack    private volatile String _closeMessage;
9503928aee4356845252ac6b662d5c72c29903813eJake Slack    private volatile boolean _closedIn;
9603928aee4356845252ac6b662d5c72c29903813eJake Slack    private volatile boolean _closedOut;
9703928aee4356845252ac6b662d5c72c29903813eJake Slack    private int _maxTextMessageSize=-1;
9803928aee4356845252ac6b662d5c72c29903813eJake Slack    private int _maxBinaryMessageSize=-1;
9903928aee4356845252ac6b662d5c72c29903813eJake Slack
10003928aee4356845252ac6b662d5c72c29903813eJake Slack    static
10103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
10203928aee4356845252ac6b662d5c72c29903813eJake Slack        try
10303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
10403928aee4356845252ac6b662d5c72c29903813eJake Slack            MAGIC="258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(StringUtil.__ISO_8859_1);
10503928aee4356845252ac6b662d5c72c29903813eJake Slack        }
10603928aee4356845252ac6b662d5c72c29903813eJake Slack        catch (UnsupportedEncodingException e)
10703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
10803928aee4356845252ac6b662d5c72c29903813eJake Slack            throw new RuntimeException(e);
10903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
11003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
11103928aee4356845252ac6b662d5c72c29903813eJake Slack
11203928aee4356845252ac6b662d5c72c29903813eJake Slack    private final WebSocket.FrameConnection _connection = new WSFrameConnection();
11303928aee4356845252ac6b662d5c72c29903813eJake Slack
11403928aee4356845252ac6b662d5c72c29903813eJake Slack
11503928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
11603928aee4356845252ac6b662d5c72c29903813eJake Slack    public WebSocketConnectionD08(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol, List<Extension> extensions,int draft)
11703928aee4356845252ac6b662d5c72c29903813eJake Slack        throws IOException
11803928aee4356845252ac6b662d5c72c29903813eJake Slack    {
11903928aee4356845252ac6b662d5c72c29903813eJake Slack        this(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol,extensions,draft,null);
12003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
12103928aee4356845252ac6b662d5c72c29903813eJake Slack
12203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
12303928aee4356845252ac6b662d5c72c29903813eJake Slack    public WebSocketConnectionD08(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol, List<Extension> extensions,int draft, MaskGen maskgen)
12403928aee4356845252ac6b662d5c72c29903813eJake Slack        throws IOException
12503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
12603928aee4356845252ac6b662d5c72c29903813eJake Slack        super(endpoint,timestamp);
12703928aee4356845252ac6b662d5c72c29903813eJake Slack
12803928aee4356845252ac6b662d5c72c29903813eJake Slack        _context=Thread.currentThread().getContextClassLoader();
12903928aee4356845252ac6b662d5c72c29903813eJake Slack
13003928aee4356845252ac6b662d5c72c29903813eJake Slack        _draft=draft;
13103928aee4356845252ac6b662d5c72c29903813eJake Slack        _endp.setMaxIdleTime(maxIdleTime);
13203928aee4356845252ac6b662d5c72c29903813eJake Slack
13303928aee4356845252ac6b662d5c72c29903813eJake Slack        _webSocket = websocket;
13403928aee4356845252ac6b662d5c72c29903813eJake Slack        _onFrame=_webSocket instanceof OnFrame ? (OnFrame)_webSocket : null;
13503928aee4356845252ac6b662d5c72c29903813eJake Slack        _onTextMessage=_webSocket instanceof OnTextMessage ? (OnTextMessage)_webSocket : null;
13603928aee4356845252ac6b662d5c72c29903813eJake Slack        _onBinaryMessage=_webSocket instanceof OnBinaryMessage ? (OnBinaryMessage)_webSocket : null;
13703928aee4356845252ac6b662d5c72c29903813eJake Slack        _onControl=_webSocket instanceof OnControl ? (OnControl)_webSocket : null;
13803928aee4356845252ac6b662d5c72c29903813eJake Slack        _generator = new WebSocketGeneratorD08(buffers, _endp,maskgen);
13903928aee4356845252ac6b662d5c72c29903813eJake Slack
14003928aee4356845252ac6b662d5c72c29903813eJake Slack        _extensions=extensions;
14103928aee4356845252ac6b662d5c72c29903813eJake Slack        WebSocketParser.FrameHandler _frameHandler= new WSFrameHandler();
14203928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_extensions!=null)
14303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
14403928aee4356845252ac6b662d5c72c29903813eJake Slack            int e=0;
14503928aee4356845252ac6b662d5c72c29903813eJake Slack            for (Extension extension : _extensions)
14603928aee4356845252ac6b662d5c72c29903813eJake Slack            {
14703928aee4356845252ac6b662d5c72c29903813eJake Slack                extension.bind(
14803928aee4356845252ac6b662d5c72c29903813eJake Slack                        _connection,
14903928aee4356845252ac6b662d5c72c29903813eJake Slack                        e==extensions.size()-1?_frameHandler:extensions.get(e+1),
15003928aee4356845252ac6b662d5c72c29903813eJake Slack                        e==0?_generator:extensions.get(e-1));
15103928aee4356845252ac6b662d5c72c29903813eJake Slack                e++;
15203928aee4356845252ac6b662d5c72c29903813eJake Slack            }
15303928aee4356845252ac6b662d5c72c29903813eJake Slack        }
15403928aee4356845252ac6b662d5c72c29903813eJake Slack
15503928aee4356845252ac6b662d5c72c29903813eJake Slack        _outbound=(_extensions==null||_extensions.size()==0)?_generator:extensions.get(extensions.size()-1);
15603928aee4356845252ac6b662d5c72c29903813eJake Slack        WebSocketParser.FrameHandler _inbound=(_extensions==null||_extensions.size()==0)?_frameHandler:extensions.get(0);
15703928aee4356845252ac6b662d5c72c29903813eJake Slack
15803928aee4356845252ac6b662d5c72c29903813eJake Slack        _parser = new WebSocketParserD08(buffers, endpoint,_inbound,maskgen==null);
15903928aee4356845252ac6b662d5c72c29903813eJake Slack
16003928aee4356845252ac6b662d5c72c29903813eJake Slack        _protocol=protocol;
16103928aee4356845252ac6b662d5c72c29903813eJake Slack
16203928aee4356845252ac6b662d5c72c29903813eJake Slack    }
16303928aee4356845252ac6b662d5c72c29903813eJake Slack
16403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
16503928aee4356845252ac6b662d5c72c29903813eJake Slack    public WebSocket.Connection getConnection()
16603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
16703928aee4356845252ac6b662d5c72c29903813eJake Slack        return _connection;
16803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
16903928aee4356845252ac6b662d5c72c29903813eJake Slack
17003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
17103928aee4356845252ac6b662d5c72c29903813eJake Slack    public List<Extension> getExtensions()
17203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
17303928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_extensions==null)
17403928aee4356845252ac6b662d5c72c29903813eJake Slack            return Collections.emptyList();
17503928aee4356845252ac6b662d5c72c29903813eJake Slack
17603928aee4356845252ac6b662d5c72c29903813eJake Slack        return _extensions;
17703928aee4356845252ac6b662d5c72c29903813eJake Slack    }
17803928aee4356845252ac6b662d5c72c29903813eJake Slack
17903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
18003928aee4356845252ac6b662d5c72c29903813eJake Slack    public Connection handle() throws IOException
18103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18203928aee4356845252ac6b662d5c72c29903813eJake Slack        Thread current = Thread.currentThread();
18303928aee4356845252ac6b662d5c72c29903813eJake Slack        ClassLoader oldcontext = current.getContextClassLoader();
18403928aee4356845252ac6b662d5c72c29903813eJake Slack        current.setContextClassLoader(_context);
18503928aee4356845252ac6b662d5c72c29903813eJake Slack        try
18603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
18703928aee4356845252ac6b662d5c72c29903813eJake Slack            // handle the framing protocol
18803928aee4356845252ac6b662d5c72c29903813eJake Slack            boolean progress=true;
18903928aee4356845252ac6b662d5c72c29903813eJake Slack
19003928aee4356845252ac6b662d5c72c29903813eJake Slack            while (progress)
19103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
19203928aee4356845252ac6b662d5c72c29903813eJake Slack                int flushed=_generator.flushBuffer();
19303928aee4356845252ac6b662d5c72c29903813eJake Slack                int filled=_parser.parseNext();
19403928aee4356845252ac6b662d5c72c29903813eJake Slack
19503928aee4356845252ac6b662d5c72c29903813eJake Slack                progress = flushed>0 || filled>0;
19603928aee4356845252ac6b662d5c72c29903813eJake Slack                _endp.flush();
19703928aee4356845252ac6b662d5c72c29903813eJake Slack
19803928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_endp instanceof AsyncEndPoint && ((AsyncEndPoint)_endp).hasProgressed())
19903928aee4356845252ac6b662d5c72c29903813eJake Slack                    progress=true;
20003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
20103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
20203928aee4356845252ac6b662d5c72c29903813eJake Slack        catch(IOException e)
20303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
20403928aee4356845252ac6b662d5c72c29903813eJake Slack            try
20503928aee4356845252ac6b662d5c72c29903813eJake Slack            {
20603928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_endp.isOpen())
20703928aee4356845252ac6b662d5c72c29903813eJake Slack                    _endp.close();
20803928aee4356845252ac6b662d5c72c29903813eJake Slack            }
20903928aee4356845252ac6b662d5c72c29903813eJake Slack            catch(IOException e2)
21003928aee4356845252ac6b662d5c72c29903813eJake Slack            {
21103928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.ignore(e2);
21203928aee4356845252ac6b662d5c72c29903813eJake Slack            }
21303928aee4356845252ac6b662d5c72c29903813eJake Slack            throw e;
21403928aee4356845252ac6b662d5c72c29903813eJake Slack        }
21503928aee4356845252ac6b662d5c72c29903813eJake Slack        finally
21603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
21703928aee4356845252ac6b662d5c72c29903813eJake Slack            current.setContextClassLoader(oldcontext);
21803928aee4356845252ac6b662d5c72c29903813eJake Slack            _parser.returnBuffer();
21903928aee4356845252ac6b662d5c72c29903813eJake Slack            _generator.returnBuffer();
22003928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_endp.isOpen())
22103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
22203928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_closedIn && _closedOut && _outbound.isBufferEmpty())
22303928aee4356845252ac6b662d5c72c29903813eJake Slack                    _endp.close();
22403928aee4356845252ac6b662d5c72c29903813eJake Slack                else if (_endp.isInputShutdown() && !_closedIn)
22503928aee4356845252ac6b662d5c72c29903813eJake Slack                    closeIn(CLOSE_NOCLOSE,null);
22603928aee4356845252ac6b662d5c72c29903813eJake Slack                else
22703928aee4356845252ac6b662d5c72c29903813eJake Slack                    checkWriteable();
22803928aee4356845252ac6b662d5c72c29903813eJake Slack            }
22903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
23003928aee4356845252ac6b662d5c72c29903813eJake Slack        return this;
23103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
23203928aee4356845252ac6b662d5c72c29903813eJake Slack
23303928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
23403928aee4356845252ac6b662d5c72c29903813eJake Slack    public void onInputShutdown() throws IOException
23503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
23603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (!_closedIn)
23703928aee4356845252ac6b662d5c72c29903813eJake Slack            _endp.close();
23803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
23903928aee4356845252ac6b662d5c72c29903813eJake Slack
24003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
24103928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isIdle()
24203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
24303928aee4356845252ac6b662d5c72c29903813eJake Slack        return _parser.isBufferEmpty() && _outbound.isBufferEmpty();
24403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
24503928aee4356845252ac6b662d5c72c29903813eJake Slack
24603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
24703928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
24803928aee4356845252ac6b662d5c72c29903813eJake Slack    public void onIdleExpired(long idleForMs)
24903928aee4356845252ac6b662d5c72c29903813eJake Slack    {
25003928aee4356845252ac6b662d5c72c29903813eJake Slack        closeOut(WebSocketConnectionD08.CLOSE_NORMAL,"Idle for "+idleForMs+"ms > "+_endp.getMaxIdleTime()+"ms");
25103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
25203928aee4356845252ac6b662d5c72c29903813eJake Slack
25303928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
25403928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean isSuspended()
25503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
25603928aee4356845252ac6b662d5c72c29903813eJake Slack        return false;
25703928aee4356845252ac6b662d5c72c29903813eJake Slack    }
25803928aee4356845252ac6b662d5c72c29903813eJake Slack
25903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
26003928aee4356845252ac6b662d5c72c29903813eJake Slack    public void onClose()
26103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
26203928aee4356845252ac6b662d5c72c29903813eJake Slack        final boolean closed;
26303928aee4356845252ac6b662d5c72c29903813eJake Slack        synchronized (this)
26403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
26503928aee4356845252ac6b662d5c72c29903813eJake Slack            closed=_closeCode==0;
26603928aee4356845252ac6b662d5c72c29903813eJake Slack            if (closed)
26703928aee4356845252ac6b662d5c72c29903813eJake Slack                _closeCode=WebSocketConnectionD08.CLOSE_NOCLOSE;
26803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
26903928aee4356845252ac6b662d5c72c29903813eJake Slack        if (closed)
27003928aee4356845252ac6b662d5c72c29903813eJake Slack            _webSocket.onClose(WebSocketConnectionD08.CLOSE_NOCLOSE,"closed");
27103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
27203928aee4356845252ac6b662d5c72c29903813eJake Slack
27303928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
27403928aee4356845252ac6b662d5c72c29903813eJake Slack    public void closeIn(int code,String message)
27503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
27603928aee4356845252ac6b662d5c72c29903813eJake Slack        LOG.debug("ClosedIn {} {} {}",this,code,message);
27703928aee4356845252ac6b662d5c72c29903813eJake Slack
27803928aee4356845252ac6b662d5c72c29903813eJake Slack        final boolean closed_out;
27903928aee4356845252ac6b662d5c72c29903813eJake Slack        final boolean tell_app;
28003928aee4356845252ac6b662d5c72c29903813eJake Slack        synchronized (this)
28103928aee4356845252ac6b662d5c72c29903813eJake Slack        {
28203928aee4356845252ac6b662d5c72c29903813eJake Slack            closed_out=_closedOut;
28303928aee4356845252ac6b662d5c72c29903813eJake Slack            _closedIn=true;
28403928aee4356845252ac6b662d5c72c29903813eJake Slack            tell_app=_closeCode==0;
28503928aee4356845252ac6b662d5c72c29903813eJake Slack            if (tell_app)
28603928aee4356845252ac6b662d5c72c29903813eJake Slack            {
28703928aee4356845252ac6b662d5c72c29903813eJake Slack                _closeCode=code;
28803928aee4356845252ac6b662d5c72c29903813eJake Slack                _closeMessage=message;
28903928aee4356845252ac6b662d5c72c29903813eJake Slack            }
29003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
29103928aee4356845252ac6b662d5c72c29903813eJake Slack
29203928aee4356845252ac6b662d5c72c29903813eJake Slack        try
29303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
29403928aee4356845252ac6b662d5c72c29903813eJake Slack            if (!closed_out)
29503928aee4356845252ac6b662d5c72c29903813eJake Slack                closeOut(code,message);
29603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
29703928aee4356845252ac6b662d5c72c29903813eJake Slack        finally
29803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
29903928aee4356845252ac6b662d5c72c29903813eJake Slack            if  (tell_app)
30003928aee4356845252ac6b662d5c72c29903813eJake Slack                _webSocket.onClose(code,message);
30103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
30203928aee4356845252ac6b662d5c72c29903813eJake Slack    }
30303928aee4356845252ac6b662d5c72c29903813eJake Slack
30403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
30503928aee4356845252ac6b662d5c72c29903813eJake Slack    public void closeOut(int code,String message)
30603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
30703928aee4356845252ac6b662d5c72c29903813eJake Slack        LOG.debug("ClosedOut {} {} {}",this,code,message);
30803928aee4356845252ac6b662d5c72c29903813eJake Slack
30903928aee4356845252ac6b662d5c72c29903813eJake Slack        final boolean closed_out;
31003928aee4356845252ac6b662d5c72c29903813eJake Slack        final boolean tell_app;
31103928aee4356845252ac6b662d5c72c29903813eJake Slack        synchronized (this)
31203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
31303928aee4356845252ac6b662d5c72c29903813eJake Slack            closed_out=_closedOut;
31403928aee4356845252ac6b662d5c72c29903813eJake Slack            _closedOut=true;
31503928aee4356845252ac6b662d5c72c29903813eJake Slack            tell_app=_closeCode==0;
31603928aee4356845252ac6b662d5c72c29903813eJake Slack            if (tell_app)
31703928aee4356845252ac6b662d5c72c29903813eJake Slack            {
31803928aee4356845252ac6b662d5c72c29903813eJake Slack                _closeCode=code;
31903928aee4356845252ac6b662d5c72c29903813eJake Slack                _closeMessage=message;
32003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
32103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
32203928aee4356845252ac6b662d5c72c29903813eJake Slack
32303928aee4356845252ac6b662d5c72c29903813eJake Slack        try
32403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
32503928aee4356845252ac6b662d5c72c29903813eJake Slack            if (tell_app)
32603928aee4356845252ac6b662d5c72c29903813eJake Slack                _webSocket.onClose(code,message);
32703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
32803928aee4356845252ac6b662d5c72c29903813eJake Slack        finally
32903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
33003928aee4356845252ac6b662d5c72c29903813eJake Slack            try
33103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
33203928aee4356845252ac6b662d5c72c29903813eJake Slack                if (!closed_out)
33303928aee4356845252ac6b662d5c72c29903813eJake Slack                {
33403928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (code<=0)
33503928aee4356845252ac6b662d5c72c29903813eJake Slack                        code=WebSocketConnectionD08.CLOSE_NORMAL;
33603928aee4356845252ac6b662d5c72c29903813eJake Slack                    byte[] bytes = ("xx"+(message==null?"":message)).getBytes(StringUtil.__ISO_8859_1);
33703928aee4356845252ac6b662d5c72c29903813eJake Slack                    bytes[0]=(byte)(code/0x100);
33803928aee4356845252ac6b662d5c72c29903813eJake Slack                    bytes[1]=(byte)(code%0x100);
33903928aee4356845252ac6b662d5c72c29903813eJake Slack                    _outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD08.OP_CLOSE,bytes,0,bytes.length);
34003928aee4356845252ac6b662d5c72c29903813eJake Slack                }
34103928aee4356845252ac6b662d5c72c29903813eJake Slack                _outbound.flush();
34203928aee4356845252ac6b662d5c72c29903813eJake Slack
34303928aee4356845252ac6b662d5c72c29903813eJake Slack            }
34403928aee4356845252ac6b662d5c72c29903813eJake Slack            catch(IOException e)
34503928aee4356845252ac6b662d5c72c29903813eJake Slack            {
34603928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.ignore(e);
34703928aee4356845252ac6b662d5c72c29903813eJake Slack            }
34803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
34903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
35003928aee4356845252ac6b662d5c72c29903813eJake Slack
35103928aee4356845252ac6b662d5c72c29903813eJake Slack    public void shutdown()
35203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
35303928aee4356845252ac6b662d5c72c29903813eJake Slack        final WebSocket.Connection connection = _connection;
35403928aee4356845252ac6b662d5c72c29903813eJake Slack        if (connection != null)
35503928aee4356845252ac6b662d5c72c29903813eJake Slack            connection.close(CLOSE_SHUTDOWN, null);
35603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
35703928aee4356845252ac6b662d5c72c29903813eJake Slack
35803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
35903928aee4356845252ac6b662d5c72c29903813eJake Slack    public void fillBuffersFrom(Buffer buffer)
36003928aee4356845252ac6b662d5c72c29903813eJake Slack    {
36103928aee4356845252ac6b662d5c72c29903813eJake Slack        _parser.fill(buffer);
36203928aee4356845252ac6b662d5c72c29903813eJake Slack    }
36303928aee4356845252ac6b662d5c72c29903813eJake Slack
36403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
36503928aee4356845252ac6b662d5c72c29903813eJake Slack    private void checkWriteable()
36603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
36703928aee4356845252ac6b662d5c72c29903813eJake Slack        if (!_outbound.isBufferEmpty() && _endp instanceof AsyncEndPoint)
36803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
36903928aee4356845252ac6b662d5c72c29903813eJake Slack            ((AsyncEndPoint)_endp).scheduleWrite();
37003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
37103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
37203928aee4356845252ac6b662d5c72c29903813eJake Slack
37303928aee4356845252ac6b662d5c72c29903813eJake Slack    protected void onFrameHandshake()
37403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
37503928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_onFrame != null)
37603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
37703928aee4356845252ac6b662d5c72c29903813eJake Slack            _onFrame.onHandshake(_connection);
37803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
37903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
38003928aee4356845252ac6b662d5c72c29903813eJake Slack
38103928aee4356845252ac6b662d5c72c29903813eJake Slack    protected void onWebSocketOpen()
38203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
38303928aee4356845252ac6b662d5c72c29903813eJake Slack        _webSocket.onOpen(_connection);
38403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
38503928aee4356845252ac6b662d5c72c29903813eJake Slack
38603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
38703928aee4356845252ac6b662d5c72c29903813eJake Slack    private class WSFrameConnection implements WebSocket.FrameConnection
38803928aee4356845252ac6b662d5c72c29903813eJake Slack    {
38903928aee4356845252ac6b662d5c72c29903813eJake Slack        private volatile boolean _disconnecting;
39003928aee4356845252ac6b662d5c72c29903813eJake Slack
39103928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
39203928aee4356845252ac6b662d5c72c29903813eJake Slack        public void sendMessage(String content) throws IOException
39303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
39403928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_closedOut)
39503928aee4356845252ac6b662d5c72c29903813eJake Slack                throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
39603928aee4356845252ac6b662d5c72c29903813eJake Slack            byte[] data = content.getBytes(StringUtil.__UTF8);
39703928aee4356845252ac6b662d5c72c29903813eJake Slack            _outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD08.OP_TEXT,data,0,data.length);
39803928aee4356845252ac6b662d5c72c29903813eJake Slack            checkWriteable();
39903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
40003928aee4356845252ac6b662d5c72c29903813eJake Slack
40103928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
40203928aee4356845252ac6b662d5c72c29903813eJake Slack        public void sendMessage(byte[] content, int offset, int length) throws IOException
40303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
40403928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_closedOut)
40503928aee4356845252ac6b662d5c72c29903813eJake Slack                throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
40603928aee4356845252ac6b662d5c72c29903813eJake Slack            _outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD08.OP_BINARY,content,offset,length);
40703928aee4356845252ac6b662d5c72c29903813eJake Slack            checkWriteable();
40803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
40903928aee4356845252ac6b662d5c72c29903813eJake Slack
41003928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
41103928aee4356845252ac6b662d5c72c29903813eJake Slack        public void sendFrame(byte flags,byte opcode, byte[] content, int offset, int length) throws IOException
41203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
41303928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_closedOut)
41403928aee4356845252ac6b662d5c72c29903813eJake Slack                throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
41503928aee4356845252ac6b662d5c72c29903813eJake Slack            _outbound.addFrame(flags,opcode,content,offset,length);
41603928aee4356845252ac6b662d5c72c29903813eJake Slack            checkWriteable();
41703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
41803928aee4356845252ac6b662d5c72c29903813eJake Slack
41903928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
42003928aee4356845252ac6b662d5c72c29903813eJake Slack        public void sendControl(byte ctrl, byte[] data, int offset, int length) throws IOException
42103928aee4356845252ac6b662d5c72c29903813eJake Slack        {
42203928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_closedOut)
42303928aee4356845252ac6b662d5c72c29903813eJake Slack                throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
42403928aee4356845252ac6b662d5c72c29903813eJake Slack            _outbound.addFrame((byte)FLAG_FIN,ctrl,data,offset,length);
42503928aee4356845252ac6b662d5c72c29903813eJake Slack            checkWriteable();
42603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
42703928aee4356845252ac6b662d5c72c29903813eJake Slack
42803928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
42903928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isMessageComplete(byte flags)
43003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
43103928aee4356845252ac6b662d5c72c29903813eJake Slack            return isLastFrame(flags);
43203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
43303928aee4356845252ac6b662d5c72c29903813eJake Slack
43403928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
43503928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isOpen()
43603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
43703928aee4356845252ac6b662d5c72c29903813eJake Slack            return _endp!=null&&_endp.isOpen();
43803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
43903928aee4356845252ac6b662d5c72c29903813eJake Slack
44003928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
44103928aee4356845252ac6b662d5c72c29903813eJake Slack        public void close(int code, String message)
44203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
44303928aee4356845252ac6b662d5c72c29903813eJake Slack            if (_disconnecting)
44403928aee4356845252ac6b662d5c72c29903813eJake Slack                return;
44503928aee4356845252ac6b662d5c72c29903813eJake Slack            _disconnecting=true;
44603928aee4356845252ac6b662d5c72c29903813eJake Slack            WebSocketConnectionD08.this.closeOut(code,message);
44703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
44803928aee4356845252ac6b662d5c72c29903813eJake Slack
44903928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
45003928aee4356845252ac6b662d5c72c29903813eJake Slack        public void setMaxIdleTime(int ms)
45103928aee4356845252ac6b662d5c72c29903813eJake Slack        {
45203928aee4356845252ac6b662d5c72c29903813eJake Slack            try
45303928aee4356845252ac6b662d5c72c29903813eJake Slack            {
45403928aee4356845252ac6b662d5c72c29903813eJake Slack                _endp.setMaxIdleTime(ms);
45503928aee4356845252ac6b662d5c72c29903813eJake Slack            }
45603928aee4356845252ac6b662d5c72c29903813eJake Slack            catch(IOException e)
45703928aee4356845252ac6b662d5c72c29903813eJake Slack            {
45803928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.warn(e);
45903928aee4356845252ac6b662d5c72c29903813eJake Slack            }
46003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
46103928aee4356845252ac6b662d5c72c29903813eJake Slack
46203928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
46303928aee4356845252ac6b662d5c72c29903813eJake Slack        public void setMaxTextMessageSize(int size)
46403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
46503928aee4356845252ac6b662d5c72c29903813eJake Slack            _maxTextMessageSize=size;
46603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
46703928aee4356845252ac6b662d5c72c29903813eJake Slack
46803928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
46903928aee4356845252ac6b662d5c72c29903813eJake Slack        public void setMaxBinaryMessageSize(int size)
47003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
47103928aee4356845252ac6b662d5c72c29903813eJake Slack            _maxBinaryMessageSize=size;
47203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
47303928aee4356845252ac6b662d5c72c29903813eJake Slack
47403928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
47503928aee4356845252ac6b662d5c72c29903813eJake Slack        public int getMaxIdleTime()
47603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
47703928aee4356845252ac6b662d5c72c29903813eJake Slack            return _endp.getMaxIdleTime();
47803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
47903928aee4356845252ac6b662d5c72c29903813eJake Slack
48003928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
48103928aee4356845252ac6b662d5c72c29903813eJake Slack        public int getMaxTextMessageSize()
48203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
48303928aee4356845252ac6b662d5c72c29903813eJake Slack            return _maxTextMessageSize;
48403928aee4356845252ac6b662d5c72c29903813eJake Slack        }
48503928aee4356845252ac6b662d5c72c29903813eJake Slack
48603928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
48703928aee4356845252ac6b662d5c72c29903813eJake Slack        public int getMaxBinaryMessageSize()
48803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
48903928aee4356845252ac6b662d5c72c29903813eJake Slack            return _maxBinaryMessageSize;
49003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
49103928aee4356845252ac6b662d5c72c29903813eJake Slack
49203928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
49303928aee4356845252ac6b662d5c72c29903813eJake Slack        public String getProtocol()
49403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
49503928aee4356845252ac6b662d5c72c29903813eJake Slack            return _protocol;
49603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
49703928aee4356845252ac6b662d5c72c29903813eJake Slack
49803928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
49903928aee4356845252ac6b662d5c72c29903813eJake Slack        public byte binaryOpcode()
50003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
50103928aee4356845252ac6b662d5c72c29903813eJake Slack            return OP_BINARY;
50203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
50303928aee4356845252ac6b662d5c72c29903813eJake Slack
50403928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
50503928aee4356845252ac6b662d5c72c29903813eJake Slack        public byte textOpcode()
50603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
50703928aee4356845252ac6b662d5c72c29903813eJake Slack            return OP_TEXT;
50803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
50903928aee4356845252ac6b662d5c72c29903813eJake Slack
51003928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
51103928aee4356845252ac6b662d5c72c29903813eJake Slack        public byte continuationOpcode()
51203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
51303928aee4356845252ac6b662d5c72c29903813eJake Slack            return OP_CONTINUATION;
51403928aee4356845252ac6b662d5c72c29903813eJake Slack        }
51503928aee4356845252ac6b662d5c72c29903813eJake Slack
51603928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
51703928aee4356845252ac6b662d5c72c29903813eJake Slack        public byte finMask()
51803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
51903928aee4356845252ac6b662d5c72c29903813eJake Slack            return FLAG_FIN;
52003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
52103928aee4356845252ac6b662d5c72c29903813eJake Slack
52203928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
52303928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isControl(byte opcode)
52403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
52503928aee4356845252ac6b662d5c72c29903813eJake Slack            return isControlFrame(opcode);
52603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
52703928aee4356845252ac6b662d5c72c29903813eJake Slack
52803928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
52903928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isText(byte opcode)
53003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
53103928aee4356845252ac6b662d5c72c29903813eJake Slack            return opcode==OP_TEXT;
53203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
53303928aee4356845252ac6b662d5c72c29903813eJake Slack
53403928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
53503928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isBinary(byte opcode)
53603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
53703928aee4356845252ac6b662d5c72c29903813eJake Slack            return opcode==OP_BINARY;
53803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
53903928aee4356845252ac6b662d5c72c29903813eJake Slack
54003928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
54103928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isContinuation(byte opcode)
54203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
54303928aee4356845252ac6b662d5c72c29903813eJake Slack            return opcode==OP_CONTINUATION;
54403928aee4356845252ac6b662d5c72c29903813eJake Slack        }
54503928aee4356845252ac6b662d5c72c29903813eJake Slack
54603928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
54703928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isClose(byte opcode)
54803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
54903928aee4356845252ac6b662d5c72c29903813eJake Slack            return opcode==OP_CLOSE;
55003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
55103928aee4356845252ac6b662d5c72c29903813eJake Slack
55203928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
55303928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isPing(byte opcode)
55403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
55503928aee4356845252ac6b662d5c72c29903813eJake Slack            return opcode==OP_PING;
55603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
55703928aee4356845252ac6b662d5c72c29903813eJake Slack
55803928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
55903928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isPong(byte opcode)
56003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
56103928aee4356845252ac6b662d5c72c29903813eJake Slack            return opcode==OP_PONG;
56203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
56303928aee4356845252ac6b662d5c72c29903813eJake Slack
56403928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
56503928aee4356845252ac6b662d5c72c29903813eJake Slack        public void disconnect()
56603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
56703928aee4356845252ac6b662d5c72c29903813eJake Slack            close(CLOSE_NORMAL,null);
56803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
56903928aee4356845252ac6b662d5c72c29903813eJake Slack
57003928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
57103928aee4356845252ac6b662d5c72c29903813eJake Slack        public void close()
57203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
57303928aee4356845252ac6b662d5c72c29903813eJake Slack            close(CLOSE_NORMAL,null);
57403928aee4356845252ac6b662d5c72c29903813eJake Slack        }
57503928aee4356845252ac6b662d5c72c29903813eJake Slack
57603928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
57703928aee4356845252ac6b662d5c72c29903813eJake Slack        public void setAllowFrameFragmentation(boolean allowFragmentation)
57803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
57903928aee4356845252ac6b662d5c72c29903813eJake Slack            _parser.setFakeFragments(allowFragmentation);
58003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
58103928aee4356845252ac6b662d5c72c29903813eJake Slack
58203928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
58303928aee4356845252ac6b662d5c72c29903813eJake Slack        public boolean isAllowFrameFragmentation()
58403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
58503928aee4356845252ac6b662d5c72c29903813eJake Slack            return _parser.isFakeFragments();
58603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
58703928aee4356845252ac6b662d5c72c29903813eJake Slack
58803928aee4356845252ac6b662d5c72c29903813eJake Slack        /* ------------------------------------------------------------ */
58903928aee4356845252ac6b662d5c72c29903813eJake Slack        @Override
59003928aee4356845252ac6b662d5c72c29903813eJake Slack        public String toString()
59103928aee4356845252ac6b662d5c72c29903813eJake Slack        {
59203928aee4356845252ac6b662d5c72c29903813eJake Slack            return String.format("%s[D08]@%x l(%s:%d)<->r(%s:%d)",
59303928aee4356845252ac6b662d5c72c29903813eJake Slack                    getClass().getSimpleName(),
59403928aee4356845252ac6b662d5c72c29903813eJake Slack                    hashCode(),
59503928aee4356845252ac6b662d5c72c29903813eJake Slack                    _endp.getLocalAddr(),
59603928aee4356845252ac6b662d5c72c29903813eJake Slack                    _endp.getLocalPort(),
59703928aee4356845252ac6b662d5c72c29903813eJake Slack                    _endp.getRemoteAddr(),
59803928aee4356845252ac6b662d5c72c29903813eJake Slack                    _endp.getRemotePort());
59903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
60003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
60103928aee4356845252ac6b662d5c72c29903813eJake Slack
60203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
60303928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
60403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
60503928aee4356845252ac6b662d5c72c29903813eJake Slack    private class WSFrameHandler implements WebSocketParser.FrameHandler
60603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
60703928aee4356845252ac6b662d5c72c29903813eJake Slack        private final Utf8StringBuilder _utf8 = new Utf8StringBuilder();
60803928aee4356845252ac6b662d5c72c29903813eJake Slack        private ByteArrayBuffer _aggregate;
60903928aee4356845252ac6b662d5c72c29903813eJake Slack        private byte _opcode=-1;
61003928aee4356845252ac6b662d5c72c29903813eJake Slack
61103928aee4356845252ac6b662d5c72c29903813eJake Slack        public void onFrame(final byte flags, final byte opcode, final Buffer buffer)
61203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
61303928aee4356845252ac6b662d5c72c29903813eJake Slack            boolean lastFrame = isLastFrame(flags);
61403928aee4356845252ac6b662d5c72c29903813eJake Slack
61503928aee4356845252ac6b662d5c72c29903813eJake Slack            synchronized(WebSocketConnectionD08.this)
61603928aee4356845252ac6b662d5c72c29903813eJake Slack            {
61703928aee4356845252ac6b662d5c72c29903813eJake Slack                // Ignore incoming after a close
61803928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_closedIn)
61903928aee4356845252ac6b662d5c72c29903813eJake Slack                    return;
62003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
62103928aee4356845252ac6b662d5c72c29903813eJake Slack            try
62203928aee4356845252ac6b662d5c72c29903813eJake Slack            {
62303928aee4356845252ac6b662d5c72c29903813eJake Slack                byte[] array=buffer.array();
62403928aee4356845252ac6b662d5c72c29903813eJake Slack
62503928aee4356845252ac6b662d5c72c29903813eJake Slack                // Deliver frame if websocket is a FrameWebSocket
62603928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_onFrame!=null)
62703928aee4356845252ac6b662d5c72c29903813eJake Slack                {
62803928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (_onFrame.onFrame(flags,opcode,array,buffer.getIndex(),buffer.length()))
62903928aee4356845252ac6b662d5c72c29903813eJake Slack                        return;
63003928aee4356845252ac6b662d5c72c29903813eJake Slack                }
63103928aee4356845252ac6b662d5c72c29903813eJake Slack
63203928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_onControl!=null && isControlFrame(opcode))
63303928aee4356845252ac6b662d5c72c29903813eJake Slack                {
63403928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (_onControl.onControl(opcode,array,buffer.getIndex(),buffer.length()))
63503928aee4356845252ac6b662d5c72c29903813eJake Slack                        return;
63603928aee4356845252ac6b662d5c72c29903813eJake Slack                }
63703928aee4356845252ac6b662d5c72c29903813eJake Slack
63803928aee4356845252ac6b662d5c72c29903813eJake Slack                switch(opcode)
63903928aee4356845252ac6b662d5c72c29903813eJake Slack                {
64003928aee4356845252ac6b662d5c72c29903813eJake Slack                    case WebSocketConnectionD08.OP_CONTINUATION:
64103928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
64203928aee4356845252ac6b662d5c72c29903813eJake Slack                        // If text, append to the message buffer
64303928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (_onTextMessage!=null && _opcode==WebSocketConnectionD08.OP_TEXT)
64403928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
64503928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (_utf8.append(buffer.array(),buffer.getIndex(),buffer.length(),_connection.getMaxTextMessageSize()))
64603928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
64703928aee4356845252ac6b662d5c72c29903813eJake Slack                                // If this is the last fragment, deliver the text buffer
64803928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (lastFrame)
64903928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
65003928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _opcode=-1;
65103928aee4356845252ac6b662d5c72c29903813eJake Slack                                    String msg =_utf8.toString();
65203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _utf8.reset();
65303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _onTextMessage.onMessage(msg);
65403928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
65503928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
65603928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
65703928aee4356845252ac6b662d5c72c29903813eJake Slack                                textMessageTooLarge();
65803928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
65903928aee4356845252ac6b662d5c72c29903813eJake Slack
66003928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (_opcode>=0 && _connection.getMaxBinaryMessageSize()>=0)
66103928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
66203928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (checkBinaryMessageSize(_aggregate.length(),buffer.length()))
66303928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
66403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _aggregate.put(buffer);
66503928aee4356845252ac6b662d5c72c29903813eJake Slack
66603928aee4356845252ac6b662d5c72c29903813eJake Slack                                // If this is the last fragment, deliver
66703928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (lastFrame && _onBinaryMessage!=null)
66803928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
66903928aee4356845252ac6b662d5c72c29903813eJake Slack                                    try
67003928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
67103928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _onBinaryMessage.onMessage(_aggregate.array(),_aggregate.getIndex(),_aggregate.length());
67203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
67303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    finally
67403928aee4356845252ac6b662d5c72c29903813eJake Slack                                    {
67503928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _opcode=-1;
67603928aee4356845252ac6b662d5c72c29903813eJake Slack                                        _aggregate.clear();
67703928aee4356845252ac6b662d5c72c29903813eJake Slack                                    }
67803928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
67903928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
68003928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
68103928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
68203928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
68303928aee4356845252ac6b662d5c72c29903813eJake Slack                    case WebSocketConnectionD08.OP_PING:
68403928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
68503928aee4356845252ac6b662d5c72c29903813eJake Slack                        LOG.debug("PING {}",this);
68603928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (!_closedOut)
68703928aee4356845252ac6b662d5c72c29903813eJake Slack                            _connection.sendControl(WebSocketConnectionD08.OP_PONG,buffer.array(),buffer.getIndex(),buffer.length());
68803928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
68903928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
69003928aee4356845252ac6b662d5c72c29903813eJake Slack
69103928aee4356845252ac6b662d5c72c29903813eJake Slack                    case WebSocketConnectionD08.OP_PONG:
69203928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
69303928aee4356845252ac6b662d5c72c29903813eJake Slack                        LOG.debug("PONG {}",this);
69403928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
69503928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
69603928aee4356845252ac6b662d5c72c29903813eJake Slack
69703928aee4356845252ac6b662d5c72c29903813eJake Slack                    case WebSocketConnectionD08.OP_CLOSE:
69803928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
69903928aee4356845252ac6b662d5c72c29903813eJake Slack                        int code=WebSocketConnectionD08.CLOSE_NOCODE;
70003928aee4356845252ac6b662d5c72c29903813eJake Slack                        String message=null;
70103928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (buffer.length()>=2)
70203928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
70303928aee4356845252ac6b662d5c72c29903813eJake Slack                            code=buffer.array()[buffer.getIndex()]*0x100+buffer.array()[buffer.getIndex()+1];
70403928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (buffer.length()>2)
70503928aee4356845252ac6b662d5c72c29903813eJake Slack                                message=new String(buffer.array(),buffer.getIndex()+2,buffer.length()-2,StringUtil.__UTF8);
70603928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
70703928aee4356845252ac6b662d5c72c29903813eJake Slack                        closeIn(code,message);
70803928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
70903928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
71003928aee4356845252ac6b662d5c72c29903813eJake Slack
71103928aee4356845252ac6b662d5c72c29903813eJake Slack                    case WebSocketConnectionD08.OP_TEXT:
71203928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
71303928aee4356845252ac6b662d5c72c29903813eJake Slack                        if(_onTextMessage!=null)
71403928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
71503928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (_connection.getMaxTextMessageSize()<=0)
71603928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
71703928aee4356845252ac6b662d5c72c29903813eJake Slack                                // No size limit, so handle only final frames
71803928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (lastFrame)
71903928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _onTextMessage.onMessage(buffer.toString(StringUtil.__UTF8));
72003928aee4356845252ac6b662d5c72c29903813eJake Slack                                else
72103928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
72203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    LOG.warn("Frame discarded. Text aggregation disabled for {}",_endp);
72303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _connection.close(WebSocketConnectionD08.CLOSE_BADDATA,"Text frame aggregation disabled");
72403928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
72503928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
72603928aee4356845252ac6b662d5c72c29903813eJake Slack                            // append bytes to message buffer (if they fit)
72703928aee4356845252ac6b662d5c72c29903813eJake Slack                            else if (_utf8.append(buffer.array(),buffer.getIndex(),buffer.length(),_connection.getMaxTextMessageSize()))
72803928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
72903928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (lastFrame)
73003928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
73103928aee4356845252ac6b662d5c72c29903813eJake Slack                                    String msg =_utf8.toString();
73203928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _utf8.reset();
73303928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _onTextMessage.onMessage(msg);
73403928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
73503928aee4356845252ac6b662d5c72c29903813eJake Slack                                else
73603928aee4356845252ac6b662d5c72c29903813eJake Slack                                {
73703928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _opcode=WebSocketConnectionD08.OP_TEXT;
73803928aee4356845252ac6b662d5c72c29903813eJake Slack                                }
73903928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
74003928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
74103928aee4356845252ac6b662d5c72c29903813eJake Slack                                textMessageTooLarge();
74203928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
74303928aee4356845252ac6b662d5c72c29903813eJake Slack                        break;
74403928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
74503928aee4356845252ac6b662d5c72c29903813eJake Slack
74603928aee4356845252ac6b662d5c72c29903813eJake Slack                    default:
74703928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
74803928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (_onBinaryMessage!=null && checkBinaryMessageSize(0,buffer.length()))
74903928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
75003928aee4356845252ac6b662d5c72c29903813eJake Slack                            if (lastFrame)
75103928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
75203928aee4356845252ac6b662d5c72c29903813eJake Slack                                _onBinaryMessage.onMessage(array,buffer.getIndex(),buffer.length());
75303928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
75403928aee4356845252ac6b662d5c72c29903813eJake Slack                            else if (_connection.getMaxBinaryMessageSize()>=0)
75503928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
75603928aee4356845252ac6b662d5c72c29903813eJake Slack                                _opcode=opcode;
75703928aee4356845252ac6b662d5c72c29903813eJake Slack                                if (_aggregate==null)
75803928aee4356845252ac6b662d5c72c29903813eJake Slack                                    _aggregate=new ByteArrayBuffer(_connection.getMaxBinaryMessageSize());
75903928aee4356845252ac6b662d5c72c29903813eJake Slack                                _aggregate.put(buffer);
76003928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
76103928aee4356845252ac6b662d5c72c29903813eJake Slack                            else
76203928aee4356845252ac6b662d5c72c29903813eJake Slack                            {
76303928aee4356845252ac6b662d5c72c29903813eJake Slack                                LOG.warn("Frame discarded. Binary aggregation disabed for {}",_endp);
76403928aee4356845252ac6b662d5c72c29903813eJake Slack                                _connection.close(WebSocketConnectionD08.CLOSE_BADDATA,"Binary frame aggregation disabled");
76503928aee4356845252ac6b662d5c72c29903813eJake Slack                            }
76603928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
76703928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
76803928aee4356845252ac6b662d5c72c29903813eJake Slack                }
76903928aee4356845252ac6b662d5c72c29903813eJake Slack            }
77003928aee4356845252ac6b662d5c72c29903813eJake Slack            catch(Throwable e)
77103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
77203928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.warn("{} for {}",e,_endp, e);
77303928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.debug(e);
77403928aee4356845252ac6b662d5c72c29903813eJake Slack                errorClose(WebSocketConnectionRFC6455.CLOSE_SERVER_ERROR,"Internal Server Error: "+e);
77503928aee4356845252ac6b662d5c72c29903813eJake Slack            }
77603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
77703928aee4356845252ac6b662d5c72c29903813eJake Slack
77803928aee4356845252ac6b662d5c72c29903813eJake Slack        private void errorClose(int code, String message)
77903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
78003928aee4356845252ac6b662d5c72c29903813eJake Slack            _connection.close(code,message);
78103928aee4356845252ac6b662d5c72c29903813eJake Slack
78203928aee4356845252ac6b662d5c72c29903813eJake Slack            // Brutally drop the connection
78303928aee4356845252ac6b662d5c72c29903813eJake Slack            try
78403928aee4356845252ac6b662d5c72c29903813eJake Slack            {
78503928aee4356845252ac6b662d5c72c29903813eJake Slack                _endp.close();
78603928aee4356845252ac6b662d5c72c29903813eJake Slack            }
78703928aee4356845252ac6b662d5c72c29903813eJake Slack            catch (IOException e)
78803928aee4356845252ac6b662d5c72c29903813eJake Slack            {
78903928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.warn(e.toString());
79003928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.debug(e);
79103928aee4356845252ac6b662d5c72c29903813eJake Slack            }
79203928aee4356845252ac6b662d5c72c29903813eJake Slack        }
79303928aee4356845252ac6b662d5c72c29903813eJake Slack
79403928aee4356845252ac6b662d5c72c29903813eJake Slack        private boolean checkBinaryMessageSize(int bufferLen, int length)
79503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
79603928aee4356845252ac6b662d5c72c29903813eJake Slack            int max = _connection.getMaxBinaryMessageSize();
79703928aee4356845252ac6b662d5c72c29903813eJake Slack            if (max>0 && (bufferLen+length)>max)
79803928aee4356845252ac6b662d5c72c29903813eJake Slack            {
79903928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.warn("Binary message too large > {}B for {}",_connection.getMaxBinaryMessageSize(),_endp);
80003928aee4356845252ac6b662d5c72c29903813eJake Slack                _connection.close(WebSocketConnectionD08.CLOSE_BADDATA,"Message size > "+_connection.getMaxBinaryMessageSize());
80103928aee4356845252ac6b662d5c72c29903813eJake Slack                _opcode=-1;
80203928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_aggregate!=null)
80303928aee4356845252ac6b662d5c72c29903813eJake Slack                    _aggregate.clear();
80403928aee4356845252ac6b662d5c72c29903813eJake Slack                return false;
80503928aee4356845252ac6b662d5c72c29903813eJake Slack            }
80603928aee4356845252ac6b662d5c72c29903813eJake Slack            return true;
80703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
80803928aee4356845252ac6b662d5c72c29903813eJake Slack
80903928aee4356845252ac6b662d5c72c29903813eJake Slack        private void textMessageTooLarge()
81003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
81103928aee4356845252ac6b662d5c72c29903813eJake Slack            LOG.warn("Text message too large > {} chars for {}",_connection.getMaxTextMessageSize(),_endp);
81203928aee4356845252ac6b662d5c72c29903813eJake Slack            _connection.close(WebSocketConnectionD08.CLOSE_BADDATA,"Text message size > "+_connection.getMaxTextMessageSize()+" chars");
81303928aee4356845252ac6b662d5c72c29903813eJake Slack
81403928aee4356845252ac6b662d5c72c29903813eJake Slack            _opcode=-1;
81503928aee4356845252ac6b662d5c72c29903813eJake Slack            _utf8.reset();
81603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
81703928aee4356845252ac6b662d5c72c29903813eJake Slack
81803928aee4356845252ac6b662d5c72c29903813eJake Slack        public void close(int code,String message)
81903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
82003928aee4356845252ac6b662d5c72c29903813eJake Slack            if (code!=CLOSE_NORMAL)
82103928aee4356845252ac6b662d5c72c29903813eJake Slack                LOG.warn("Close: "+code+" "+message);
82203928aee4356845252ac6b662d5c72c29903813eJake Slack            _connection.close(code,message);
82303928aee4356845252ac6b662d5c72c29903813eJake Slack        }
82403928aee4356845252ac6b662d5c72c29903813eJake Slack
82503928aee4356845252ac6b662d5c72c29903813eJake Slack        @Override
82603928aee4356845252ac6b662d5c72c29903813eJake Slack        public String toString()
82703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
82803928aee4356845252ac6b662d5c72c29903813eJake Slack            return WebSocketConnectionD08.this.toString()+"FH";
82903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
83003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
83103928aee4356845252ac6b662d5c72c29903813eJake Slack
83203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
83303928aee4356845252ac6b662d5c72c29903813eJake Slack    public static String hashKey(String key)
83403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
83503928aee4356845252ac6b662d5c72c29903813eJake Slack        try
83603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
83703928aee4356845252ac6b662d5c72c29903813eJake Slack            MessageDigest md = MessageDigest.getInstance("SHA1");
83803928aee4356845252ac6b662d5c72c29903813eJake Slack            md.update(key.getBytes("UTF-8"));
83903928aee4356845252ac6b662d5c72c29903813eJake Slack            md.update(MAGIC);
84003928aee4356845252ac6b662d5c72c29903813eJake Slack            return new String(B64Code.encode(md.digest()));
84103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
84203928aee4356845252ac6b662d5c72c29903813eJake Slack        catch (Exception e)
84303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
84403928aee4356845252ac6b662d5c72c29903813eJake Slack            throw new RuntimeException(e);
84503928aee4356845252ac6b662d5c72c29903813eJake Slack        }
84603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
84703928aee4356845252ac6b662d5c72c29903813eJake Slack
84803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
84903928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
85003928aee4356845252ac6b662d5c72c29903813eJake Slack    public String toString()
85103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
85203928aee4356845252ac6b662d5c72c29903813eJake Slack        return String.format("WS/D%d p=%s g=%s", _draft, _parser, _generator);
85303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
85403928aee4356845252ac6b662d5c72c29903813eJake Slack}
855