How do I serve https and http for Jetty from one port?

后端 未结 6 1066
日久生厌
日久生厌 2020-11-28 11:09

(I know it\'s a duplicate question but the original poster asked it for the wrong reason. I\'m not implying that I\'m asking it for the right reason, but let\'s see

6条回答
  •  臣服心动
    2020-11-28 11:45

    Based on the Answer "Yes We Can" i build the code that works with current jetty 9.3.11 and i think some would be interested.

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.ReadPendingException;
    import java.nio.channels.WritePendingException;
    import org.eclipse.jetty.util.Callback;
    import org.eclipse.jetty.io.Connection;
    import org.eclipse.jetty.io.EndPoint;
    
    public class MyReadAheadEndpoint implements EndPoint {
    /** real endpoint we are wrapping    */ private final EndPoint endPoint;
    /** buffer used to read start bytes  */ private final ByteBuffer start     ;
    /** how many N start bytes to read   */ private       int        leftToRead;
    /** first  N bytes                   */ private final byte[]     bytes     ;
    /** buffered exception to throw next */ private IOException pendingException = null;
    @Override public InetSocketAddress getLocalAddress            () { return endPoint.getLocalAddress(); }
    @Override public InetSocketAddress getRemoteAddress           () { return endPoint.getRemoteAddress(); }
    @Override public boolean           isOpen                     () { return endPoint.isOpen(); }
    @Override public long              getCreatedTimeStamp        () { return endPoint.getCreatedTimeStamp(); }
    @Override public boolean           isOutputShutdown           () { return endPoint.isOutputShutdown(); }
    @Override public boolean           isInputShutdown            () { return endPoint.isInputShutdown(); }
    @Override public void              shutdownOutput             () { endPoint.shutdownOutput(); }
    @Override public void              close                      () { endPoint.close(); }
    @Override public Object            getTransport               () { return endPoint.getTransport(); }
    @Override public long              getIdleTimeout             () { return endPoint.getIdleTimeout(); }
    @Override public Connection        getConnection              () { return endPoint.getConnection(); }
    @Override public void              onOpen                     () { endPoint.onOpen(); }
    @Override public void              onClose                    () { endPoint.onClose(); }
    @Override public boolean           isOptimizedForDirectBuffers() { return endPoint.isOptimizedForDirectBuffers(); }
    @Override public boolean           isFillInterested           () { return endPoint.isFillInterested(); }
    @Override public boolean           flush                      (final ByteBuffer... v) throws IOException { return endPoint.flush(v); }
    @Override public void              setIdleTimeout             (final long          v) { endPoint.setIdleTimeout(v); }
    @Override public void              write                      (final Callback      v, final ByteBuffer... b) throws WritePendingException { endPoint.write(v, b); }
    @Override public void              setConnection              (final Connection    v) { endPoint.setConnection(v); }
    @Override public void              upgrade                    (final Connection    v) { endPoint.upgrade(v); }
    @Override public void              fillInterested  (final Callback   v) throws ReadPendingException { endPoint.fillInterested(v); }
    @Override public int               hashCode() { return endPoint.hashCode(); }
    @Override public boolean           equals(final Object obj) { return endPoint.equals(obj); }
    @Override public String            toString() { return endPoint.toString(); }
    public byte[] getBytes() { if (pendingException == null) { try { readAhead(); } catch (final IOException e) { pendingException = e; } } return bytes; }
    private void throwPendingException() throws IOException { if (pendingException != null) { final IOException e = pendingException; pendingException = null; throw e; } }
    
    public MyReadAheadEndpoint(final EndPoint channel, final int readAheadLength){
        this.endPoint = channel;
        start = ByteBuffer.wrap(bytes = new byte[readAheadLength]);
        start.flip();
        leftToRead = readAheadLength;
    }
    
    private synchronized void readAhead() throws IOException {
        if (leftToRead > 0) {
            final int n = endPoint.fill(start);
            if (n == -1) { leftToRead = -1; }
            else         {  leftToRead -= n; }
            if (leftToRead <= 0) start.rewind();
        }
    }
    
    private int readFromStart(final ByteBuffer dst) throws IOException {
        final int n = Math.min(dst.remaining(), start.remaining());
        if (n > 0)  {
            dst.put(bytes, start.position(), n);
            start.position(start.position() + n);
            dst.flip();
        }
        return n;
    }
    
    @Override public synchronized int fill(final ByteBuffer dst) throws IOException {
        throwPendingException();
        if (leftToRead > 0) readAhead();
        if (leftToRead > 0) return 0;
        final int sr = start.remaining();
        if (sr > 0) {
            dst.compact();
            final int n = readFromStart(dst);
            if (n < sr) return n;
        }
        return sr + endPoint.fill(dst);
    }
    

    }

    import org.eclipse.jetty.io.Connection;
    import org.eclipse.jetty.io.EndPoint;
    import org.eclipse.jetty.io.ssl.SslConnection;
    import org.eclipse.jetty.server.Connector;
    import org.eclipse.jetty.server.ConnectionFactory;
    import org.eclipse.jetty.server.AbstractConnectionFactory;
    import org.eclipse.jetty.http.HttpVersion;
    import org.eclipse.jetty.util.ssl.SslContextFactory;
    import org.eclipse.jetty.util.annotation.Name;
    public class MySslConnectionFactory extends AbstractConnectionFactory {
    private final SslContextFactory _sslContextFactory;
    private final String _nextProtocol;
    
    public MySslConnectionFactory() { this(HttpVersion.HTTP_1_1.asString()); }
    
    public MySslConnectionFactory(@Name("next") final String nextProtocol) { this((SslContextFactory)null, nextProtocol); }
    
    public MySslConnectionFactory(@Name("sslContextFactory") final SslContextFactory factory, @Name("next") final String nextProtocol) {
        super("SSL");
        this._sslContextFactory = factory == null?new SslContextFactory():factory;
        this._nextProtocol = nextProtocol;
        this.addBean(this._sslContextFactory);
    }
    
    public SslContextFactory getSslContextFactory() { return this._sslContextFactory; }
    
    @Override protected void doStart() throws Exception {
        super.doStart();
        final SSLEngine engine = this._sslContextFactory.newSSLEngine();
        engine.setUseClientMode(false);
        final SSLSession session = engine.getSession();
        if(session.getPacketBufferSize() > this.getInputBufferSize()) this.setInputBufferSize(session.getPacketBufferSize());
    }
    
    @Override public Connection newConnection(final Connector connector, final EndPoint realEndPoint) {
        final MyReadAheadEndpoint aheadEndpoint = new MyReadAheadEndpoint(realEndPoint, 1);
        final byte[] bytes = aheadEndpoint.getBytes();
        final boolean isSSL;
        if (bytes == null || bytes.length == 0) {
            System.out.println("NO-Data in newConnection : "+aheadEndpoint.getRemoteAddress());
            isSSL = true;
        } else {
            final byte b = bytes[0];    // TLS first byte is 0x16 , SSLv2 first byte is >= 0x80 , HTTP is guaranteed many bytes of ASCII
            isSSL = b >= 0x7F || (b < 0x20 && b != '\n' && b != '\r' && b != '\t');
            if(!isSSL) System.out.println("newConnection["+isSSL+"] : "+aheadEndpoint.getRemoteAddress());
        }
        final EndPoint      plainEndpoint;
        final SslConnection sslConnection;
        if (isSSL) {
            final SSLEngine engine = this._sslContextFactory.newSSLEngine(aheadEndpoint.getRemoteAddress());
            engine.setUseClientMode(false);
            sslConnection = this.newSslConnection(connector, aheadEndpoint, engine);
            sslConnection.setRenegotiationAllowed(this._sslContextFactory.isRenegotiationAllowed());
            this.configure(sslConnection, connector, aheadEndpoint);
            plainEndpoint = sslConnection.getDecryptedEndPoint();
        } else {
            sslConnection = null;
            plainEndpoint = aheadEndpoint;
        }
        final ConnectionFactory next = connector.getConnectionFactory(_nextProtocol);
        final Connection connection = next.newConnection(connector, plainEndpoint);
        plainEndpoint.setConnection(connection);
        return sslConnection == null ? connection : sslConnection;
    }
    
    protected SslConnection newSslConnection(final Connector connector, final EndPoint endPoint, final SSLEngine engine) {
        return new SslConnection(connector.getByteBufferPool(), connector.getExecutor(), endPoint, engine);
    }
    
    @Override public String toString() {
        return String.format("%s@%x{%s->%s}", new Object[]{this.getClass().getSimpleName(), Integer.valueOf(this.hashCode()), this.getProtocol(), this._nextProtocol});
    }
    

    }

提交回复
热议问题