📄 sslhttpchannelendpoint.java
字号:
// ========================================================================// Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.// ------------------------------------------------------------------------// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// ========================================================================package org.mortbay.jetty.security;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.SocketChannel;import javax.net.ssl.SSLEngine;import javax.net.ssl.SSLEngineResult;import javax.net.ssl.SSLException;import javax.net.ssl.SSLSession;import javax.net.ssl.SSLEngineResult.HandshakeStatus;import org.mortbay.io.Buffer;import org.mortbay.io.Buffers;import org.mortbay.io.nio.NIOBuffer;import org.mortbay.io.nio.SelectChannelEndPoint;import org.mortbay.io.nio.SelectorManager;import org.mortbay.jetty.nio.SelectChannelConnector;import org.mortbay.log.Log;/* ------------------------------------------------------------ *//** * SslHttpChannelEndPoint. * * @author Nik Gonzalez <ngonzalez@exist.com> * @author Greg Wilkins <gregw@mortbay.com> */public class SslHttpChannelEndPoint extends SelectChannelConnector.ConnectorEndPoint implements Runnable{ private static final ByteBuffer[] __NO_BUFFERS={}; private Buffers _buffers; private SSLEngine _engine; private ByteBuffer _inBuffer; private NIOBuffer _inNIOBuffer; private ByteBuffer _outBuffer; private NIOBuffer _outNIOBuffer; private NIOBuffer[] _reuseBuffer=new NIOBuffer[2]; private ByteBuffer[] _gather=new ByteBuffer[2]; private boolean _closing=false; private SSLEngineResult _result; private String _last; // ssl protected SSLSession _session; // TODO get rid of this // StringBuilder h = new StringBuilder(500); /* ------------------------------------------------------------ */ public SslHttpChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine) throws SSLException, IOException { super(channel,selectSet,key); _buffers=buffers; // ssl _engine=engine; _session=engine.getSession(); // TODO pool buffers and use only when needed. _outNIOBuffer=(NIOBuffer)buffers.getBuffer(_session.getPacketBufferSize()); _outBuffer=_outNIOBuffer.getByteBuffer(); _inNIOBuffer=(NIOBuffer)buffers.getBuffer(_session.getPacketBufferSize()); _inBuffer=_inNIOBuffer.getByteBuffer(); // h.append("CONSTRUCTED\n"); } // TODO get rid of these dumps public void dump() { System.err.println(_result); // System.err.println(h.toString()); // System.err.println("--"); } /* ------------------------------------------------------------ */ /* (non-Javadoc) * @see org.mortbay.io.nio.SelectChannelEndPoint#idleExpired() */ protected void idleExpired() { try { _selectSet.getManager().dispatch(new Runnable() { public void run() { doIdleExpired(); } }); } catch(Exception e) { Log.ignore(e); } } /* ------------------------------------------------------------ */ protected void doIdleExpired() { // h.append("IDLE EXPIRED\n"); super.idleExpired(); } /* ------------------------------------------------------------ */ public void close() throws IOException { // TODO - this really should not be done in a loop here - but with async callbacks. // h.append("CLOSE\n"); _closing=true; try { int tries=0; while (_outNIOBuffer.length()>0) { // TODO REMOVE loop check if (tries++>100) throw new IllegalStateException(); flush(); Thread.sleep(100); // TODO yuck } _engine.closeOutbound(); loop: while (isOpen() && !(_engine.isInboundDone() && _engine.isOutboundDone())) { // TODO REMOVE loop check if (tries++>100) throw new IllegalStateException(); if (_outNIOBuffer.length()>0) { flush(); Thread.sleep(100); // TODO yuck } switch(_engine.getHandshakeStatus()) { case FINISHED: case NOT_HANDSHAKING: break loop; case NEED_UNWRAP: Buffer buffer =_buffers.getBuffer(_engine.getSession().getApplicationBufferSize()); try { ByteBuffer bbuffer = ((NIOBuffer)buffer).getByteBuffer(); if (!unwrap(bbuffer) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP) { // h.append("break loop\n"); break loop; } } catch(SSLException e) { Log.ignore(e); } finally { _buffers.returnBuffer(buffer); } break; case NEED_TASK: { Runnable task; while ((task=_engine.getDelegatedTask())!=null) { task.run(); } break; } case NEED_WRAP: { if (_outNIOBuffer.length()>0) flush(); try { _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); _outBuffer.position(put); _result=null; _last="close wrap"; _result=_engine.wrap(__NO_BUFFERS,_outBuffer); _outNIOBuffer.setPutIndex(put+_result.bytesProduced()); } finally { _outBuffer.position(0); } flush(); break; } } } } catch(IOException e) { Log.ignore(e); } catch (InterruptedException e) { Log.ignore(e); } finally { super.close(); if (_inNIOBuffer!=null) _buffers.returnBuffer(_inNIOBuffer); if (_outNIOBuffer!=null) _buffers.returnBuffer(_outNIOBuffer); if (_reuseBuffer[0]!=null) _buffers.returnBuffer(_reuseBuffer[0]); if (_reuseBuffer[1]!=null) _buffers.returnBuffer(_reuseBuffer[1]); } } /* ------------------------------------------------------------ */ /* */ public int fill(Buffer buffer) throws IOException { ByteBuffer bbuf=extractInputBuffer(buffer); int size=buffer.length(); HandshakeStatus initialStatus = _engine.getHandshakeStatus(); synchronized (bbuf) { try { unwrap(bbuf); int tries=0, wraps=0; loop: while (true) { // TODO REMOVE loop check if (tries++>100) throw new IllegalStateException(); // h.append("Fill(Buffer)\n"); if (_outNIOBuffer.length()>0) flush(); // h.append("status=").append(_engine.getHandshakeStatus()).append('\n'); switch(_engine.getHandshakeStatus()) { case FINISHED: case NOT_HANDSHAKING: if (_closing) return -1; break loop; case NEED_UNWRAP: if (!unwrap(bbuf) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP) { // h.append("break loop\n"); break loop; } break; case NEED_TASK: { Runnable task; while ((task=_engine.getDelegatedTask())!=null) { // h.append("run task\n"); task.run(); } if(initialStatus==HandshakeStatus.NOT_HANDSHAKING && HandshakeStatus.NEED_UNWRAP==_engine.getHandshakeStatus() && wraps==0) { // This should be NEED_WRAP // The fix simply detects the signature of the bug and then close the connection (fail-fast) so that ff3 will delegate to using SSL instead of TLS. // This is a jvm bug on java1.6 where the SSLEngine expects more data from the initial handshake when the client(ff3-tls) already had given it. // See http://jira.codehaus.org/browse/JETTY-567 for more details return -1; } break; } case NEED_WRAP: { wraps++; synchronized(_outBuffer) { try { _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); _outBuffer.position(); _result=null; _last="fill wrap"; _result=_engine.wrap(__NO_BUFFERS,_outBuffer); switch(_result.getStatus()) { case BUFFER_OVERFLOW: case BUFFER_UNDERFLOW: Log.warn("wrap {}",_result); case CLOSED: _closing=true; } // h.append("wrap ").append(result).append('\n'); _outNIOBuffer.setPutIndex(put+_result.bytesProduced()); } finally { _outBuffer.position(0); } } flush(); break; } } } } catch(SSLException e) { Log.warn(e.toString()); Log.debug(e); throw e; } finally { buffer.setPutIndex(bbuf.position()); bbuf.position(0); } } return buffer.length()-size; } /* ------------------------------------------------------------ */ public int flush(Buffer buffer) throws IOException { return flush(buffer,null,null); } /* ------------------------------------------------------------ */ /* */ public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException { int consumed=0; int available=header.length(); if (buffer!=null) available+=buffer.length(); int tries=0; loop: while (true) { // TODO REMOVE loop check if (tries++>100) throw new IllegalStateException(); // h.append("Flush ").append(tries).append(' ').append(_outNIOBuffer.length()).append('\n'); if (_outNIOBuffer.length()>0) flush();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -