17

(重複した質問であることは知っていますが、元の投稿者は間違った理由で質問しました。正しい理由で質問していると言っているわけではありませんが、見てみましょう。)

非標準のポート番号で実行される Web サービスがあります。ユーザーはポート番号を覚えているように見えますが、間違って https: ではなく http: を入力することがあります。そのポートで HTTP を提供し、同じポートで HTTPS にリダイレクトできるかどうか、誰かが尋ねています。それは悪いように聞こえます...私は使いやすさが好きですが、これを行うのはブラウザの仕事であるべきだと思いますか?

私が見た 1 つの解決策は、「Jetty の前に独自のプロキシを作成する」ことでした。このソリューションは機能しますが、Jetty 自体と同じくらい効率的なプロキシを作成できると確信していないため、うまく機能するとは思いません。さらに、プロキシ自体が効率的であっても、すべてのデータは追加のホップを通過する必要があり、いずれにせよトラフィックが遅くなることが保証されています.

これよりも良い方法はありますか?おそらく、Jetty 自体には、プロキシが導入する追加のホップを削除しながら、速度を利用できるようにするプロトコル検出ロジックをくさびにすることができる場所があります。

4

6 に答える 6

15

更新:単一のポートを HTTPS と HTTP リスナーの両方にリダイレクトする方法については、この回答を参照してください。何らかの理由でそのソリューションを使用しない場合は、以下を参照してください。

同じポートで http と https の両方からトラフィックをパイプすることはできません。Jetty は、2 つのまったく異なるコネクタを使用して、セキュア ポートと非セキュア ポートにバインドします。実際、私が遭遇したすべての Web サーバーは、2 つのプロトコルを 2 つの完全に別個のポートにバインドします。

使いやすさのために私が提案することの 1 つは、ユーザーからポートを完全に隠すデフォルト ポートを使用することです。By default http uses port 80, and by default https uses port 443. したがって、コネクタをそれぞれポート 80 とポート 443 で実行するように構成すると、ユーザーはポートを入力する必要がなくなり、開発チームはポートを入力する必要がなくなります。 HTML、CSS、JavaScript、およびその他のリソースの絶対パスにポート番号を含める必要があります。

Jetty は、Apache が Apache HTTP サーバーの背後で実行することを提案している古いバージョンの Tomcatとは異なり、スタンドアロンの Web サーバーとして設計されています。したがって、他の HTTP サーバーが実行されておらず、それらのポートを使用できない限り、Jetty をデフォルト ポートで問題なく実行するように構成できるはずです。これは経験から来ています。この方法で正確に Jetty を実行します。

最後に、プロトコルは複数のポートにバインドできます。したがって、現在 Jetty を http 用のポート 8080 と https 用の 8443 で実行している場合、これらのコネクタをアクティブのままにして、ポート 80 とポート 443 用にさらに 2 つのコネクタを追加できます。ポート番号を使用して、これを進める時間を与えます。

<!-- Legacy HTTP connector -->
<Call name="addConnector">
  <Arg>
      <New class="org.mortbay.jetty.nio.SelectChannelConnector">
        <Set name="host"><SystemProperty name="jetty.host" /></Set>
        <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
        <Set name="maxIdleTime">30000</Set>
        <Set name="Acceptors">2</Set>
        <Set name="statsOn">false</Set>
        <Set name="confidentialPort">8443</Set>
        <Set name="lowResourcesConnections">5000</Set>
        <Set name="lowResourcesMaxIdleTime">5000</Set>
      </New>
  </Arg>
</Call>
<!-- Second connector for http on port 80 -->
<Call name="addConnector">
  <Arg>
      <New class="org.mortbay.jetty.nio.SelectChannelConnector">
        <Set name="host"><SystemProperty name="jetty.host" /></Set>
        <Set name="port"><SystemProperty name="jetty.port" default="80"/></Set>
        <Set name="maxIdleTime">30000</Set>
        <Set name="Acceptors">2</Set>
        <Set name="statsOn">false</Set>
        <Set name="confidentialPort">8443</Set>
        <Set name="lowResourcesConnections">5000</Set>
        <Set name="lowResourcesMaxIdleTime">5000</Set>
      </New>
  </Arg>
</Call>

<!-- Legacy SSL Connector for https port 8443 -->
<Call name="addConnector">
 <Arg>
  <New class="org.mortbay.jetty.security.SslSocketConnector">
    <Set name="Port">8443</Set>
    <Set name="maxIdleTime">30000</Set>
    <Set name="handshakeTimeout">2000</Set>
    <Set name="keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="password">xxxxxx</Set>
    <Set name="keyPassword">xxxxxx</Set>
    <Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="trustPassword">OBF:xxxxx</Set>
    <Set name="handshakeTimeout">2000</Set>
    <!-- Set name="ThreadPool">
      <New class="org.mortbay.thread.BoundedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">250</Set>
     </New>
    </Set -->
  </New>
 </Arg>
</Call>



<!-- Default SSL Connector for https port 443 -->
<Call name="addConnector">
 <Arg>
  <New class="org.mortbay.jetty.security.SslSocketConnector">
    <Set name="Port">443</Set>
    <Set name="maxIdleTime">30000</Set>
    <Set name="handshakeTimeout">2000</Set>
    <Set name="keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="password">xxxxxx</Set>
    <Set name="keyPassword">xxxxxx</Set>
    <Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="trustPassword">OBF:xxxxx</Set>
    <Set name="handshakeTimeout">2000</Set>
    <!-- Set name="ThreadPool">
      <New class="org.mortbay.thread.BoundedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">250</Set>
     </New>
    </Set -->
  </New>
 </Arg>
</Call>

2 番目と 4 番目のコネクタの違いは、ポート番号だけです。つまり、コネクタ/プロトコルごとに複数のポートを構成できますが、同じポートに複数のプロトコル/コネクタを構成することはできません。

于 2012-06-25T01:07:32.723 に答える
10

更新: jetty-9.4.15.v20190215 の時点で、ポート統合のサポートが Jetty に組み込まれています。この回答を参照してください。

はい、できます

これは可能であり、私たちはそれを実行しました。このコードは Jetty 8 で動作します。Jetty 9 ではテストしていませんが、この回答には Jetty 9 の同様のコードがあります。

ちなみにこれはポート統合と呼ばれ、 Grizzlyを使ったGlassfishでは以前からサポートされているようです。

概要

org.eclipse.jetty.server.Connector基本的な考え方は、クライアントの要求の最初のバイトを先読みできる実装を作成することです。幸いなことに、HTTP と HTTPS の両方でクライアントが通信を開始します。HTTPS (および TLS/SSL 一般) の場合、最初のバイトは0x16(TLS) または>= 0x80(SSLv2) になります。HTTP の場合、最初のバイトは古き良き印刷可能な 7 ビット ASCII になります。ここで、最初のバイトに応じてConnector、SSL 接続またはプレーン接続のいずれかが生成されます。

ここのコードでは、JettySslSelectChannelConnector自体が を拡張SelectChannelConnectorし、newPlainConnection()メソッド (非 SSL 接続を生成するためにスーパークラスを呼び出す) とnewConnection()メソッド (SSL 接続を生成する) を持っているという事実を利用しています。そのため、クライアントからの最初のバイトを観察した後、新しいメソッドをConnector拡張してこれらのメソッドの 1 つに委譲できます。SslSelectChannelConnector

残念ながら、最初のバイトが利用可能になるAsyncConnection 前にのインスタンスを作成する必要があります。そのインスタンスの一部のメソッドは、最初のバイトが使用可能になる前に呼び出されることさえあります。LazyConnection implements AsyncConnectionそのため、デリゲートする接続の種類を後で把握できるを作成したり、認識される前にいくつかのメソッドに適切なデフォルトの応答を返すことさえできます。

NIO ベースでConnectorあるため、SocketChannel. 幸いなことに、「本物」に委譲するSocketChannelを作成するように拡張できますが、クライアントのメッセージの最初のバイトを検査して保存することができます。ReadAheadSocketChannelWrapperSocketChannel

いくつかの詳細

非常にハックなビット。Connectorオーバーライドする必要があるメソッドの 1 つはcustomize(Endpoint,Request). 最終的に SSL ベースEndpointになった場合は、スーパークラスに渡すだけです。それ以外の場合、スーパークラスは をスローしますが、それはそのスーパークラスに渡してにスキームを設定したClassCastExceptionでのみです。そのため、スーパークラスに渡しますが、例外が発生したときにスキームの設定を元に戻します。Request

また、サーブレットがHTTP と HTTPS のどちらが使用されたかを適切に判断できるように、isConfidential()とをオーバーライドします。isIntegral()HttpServletRequest.isSecure()

クライアントから最初のバイトを読み込もうとすると がスローされる可能性がありますが、 が予期されないIOException場所で試行する必要がIOExceptionある場合があります。その場合、例外を保持して後でスローします。

拡張は、Java >= 7 と Java 6 では異なるように見えます。後者の場合、Java 6にないSocketChannelメソッドをコメントアウトするだけです。SocketChannel

コード

public class PortUnificationSelectChannelConnector extends SslSelectChannelConnector {
    public PortUnificationSelectChannelConnector() {
        super();
    }

    public PortUnificationSelectChannelConnector(SslContextFactory sslContextFactory) {
        super(sslContextFactory);
    }

    @Override
    protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException {
        return super.newEndPoint(new ReadAheadSocketChannelWrapper(channel, 1), selectSet, key);
    }

    @Override
    protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endPoint) {
        return new LazyConnection((ReadAheadSocketChannelWrapper)channel, endPoint);
    }

    @Override
    public void customize(EndPoint endpoint, Request request) throws IOException {
        String scheme = request.getScheme();
        try {
            super.customize(endpoint, request);
        } catch (ClassCastException e) {
            request.setScheme(scheme);
        }
    }

    @Override
    public boolean isConfidential(Request request) {
        if (request.getAttribute("javax.servlet.request.cipher_suite") != null) return true;
        else return isForwarded() && request.getScheme().equalsIgnoreCase(HttpSchemes.HTTPS);
    }

    @Override
    public boolean isIntegral(Request request) {
        return isConfidential(request);
    }

    class LazyConnection implements AsyncConnection {
        private final ReadAheadSocketChannelWrapper channel;
        private final AsyncEndPoint endPoint;
        private final long timestamp;
        private AsyncConnection connection;

        public LazyConnection(ReadAheadSocketChannelWrapper channel, AsyncEndPoint endPoint) {
            this.channel = channel;
            this.endPoint = endPoint;
            this.timestamp = System.currentTimeMillis();
            this.connection = determineNewConnection(channel, endPoint, false);
        }

        public Connection handle() throws IOException {
            if (connection == null) {
                connection = determineNewConnection(channel, endPoint, false);
                channel.throwPendingException();
            }
            if (connection != null) return connection.handle();
            else return this;
        }

        public long getTimeStamp() {
            return timestamp;
        }

        public void onInputShutdown() throws IOException {
            if (connection == null) connection = determineNewConnection(channel, endPoint, true);
            connection.onInputShutdown();
        }

        public boolean isIdle() {
            if (connection == null) connection = determineNewConnection(channel, endPoint, false);
            if (connection != null) return connection.isIdle();
            else return false;
        }

        public boolean isSuspended() {
            if (connection == null) connection = determineNewConnection(channel, endPoint, false);
            if (connection != null) return connection.isSuspended();
            else return false;
        }

        public void onClose() {
            if (connection == null) connection = determineNewConnection(channel, endPoint, true);
            connection.onClose();
        }

        public void onIdleExpired(long l) {
            if (connection == null) connection = determineNewConnection(channel, endPoint, true);
            connection.onIdleExpired(l);
        }

        AsyncConnection determineNewConnection(ReadAheadSocketChannelWrapper channel, AsyncEndPoint endPoint, boolean force) {
            byte[] bytes = channel.getBytes();
            if ((bytes == null || bytes.length == 0) && !force) return null;
            if (looksLikeSsl(bytes)) {
                return PortUnificationSelectChannelConnector.super.newConnection(channel, endPoint);
            } else {
                return PortUnificationSelectChannelConnector.super.newPlainConnection(channel, endPoint);
            }
        }

        // TLS first byte is 0x16
        // SSLv2 first byte is >= 0x80
        // HTTP is guaranteed many bytes of ASCII
        private boolean looksLikeSsl(byte[] bytes) {
            if (bytes == null || bytes.length == 0) return false; // force HTTP
            byte b = bytes[0];
            return b >= 0x7F || (b < 0x20 && b != '\n' && b != '\r' && b != '\t');
        }
    }

    static class ReadAheadSocketChannelWrapper extends SocketChannel {
        private final SocketChannel channel;
        private final ByteBuffer start;
        private byte[] bytes;
        private IOException pendingException;
        private int leftToRead;

        public ReadAheadSocketChannelWrapper(SocketChannel channel, int readAheadLength) throws IOException {
            super(channel.provider());
            this.channel = channel;
            start = ByteBuffer.allocate(readAheadLength);
            leftToRead = readAheadLength;
            readAhead();
        }

        public synchronized void readAhead() throws IOException {
            if (leftToRead > 0) {
                int n = channel.read(start);
                if (n == -1) {
                    leftToRead = -1;
                } else {
                    leftToRead -= n;
                }
                if (leftToRead <= 0) {
                    start.flip();
                    bytes = new byte[start.remaining()];
                    start.get(bytes);
                    start.rewind();
                }
            }
        }

        public byte[] getBytes() {
            if (pendingException == null) {
                try {
                    readAhead();
                } catch (IOException e) {
                    pendingException = e;
                }
            }
            return bytes;
        }

        public void throwPendingException() throws IOException {
            if (pendingException != null) {
                IOException e = pendingException;
                pendingException = null;
                throw e;
            }
        }

        private int readFromStart(ByteBuffer dst) throws IOException {
            int sr = start.remaining();
            int dr = dst.remaining();
            if (dr == 0) return 0;
            int n = Math.min(dr, sr);
            dst.put(bytes, start.position(), n);
            start.position(start.position() + n);
            return n;
        }

        public synchronized int read(ByteBuffer dst) throws IOException {
            throwPendingException();
            readAhead();
            if (leftToRead > 0) return 0;
            int sr = start.remaining();
            if (sr > 0) {
                int n = readFromStart(dst);
                if (n < sr) return n;
            }
            return sr + channel.read(dst);
        }

        public synchronized long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
            throwPendingException();
            if (offset + length > dsts.length || length < 0 || offset < 0) {
                throw new IndexOutOfBoundsException();
            }
            readAhead();
            if (leftToRead > 0) return 0;
            int sr = start.remaining();
            int newOffset = offset;
            if (sr > 0) {
                int accum = 0;
                for (; newOffset < offset + length; newOffset++) {
                    accum += readFromStart(dsts[newOffset]);
                    if (accum == sr) break;
                }
                if (accum < sr) return accum;
            }
            return sr + channel.read(dsts, newOffset, length - newOffset + offset);
        }

        public int hashCode() {
            return channel.hashCode();
        }

        public boolean equals(Object obj) {
            return channel.equals(obj);
        }

        public String toString() {
            return channel.toString();
        }

        public Socket socket() {
            return channel.socket();
        }

        public boolean isConnected() {
            return channel.isConnected();
        }

        public boolean isConnectionPending() {
            return channel.isConnectionPending();
        }

        public boolean connect(SocketAddress remote) throws IOException {
            return channel.connect(remote);
        }

        public boolean finishConnect() throws IOException {
            return channel.finishConnect();
        }

        public int write(ByteBuffer src) throws IOException {
            return channel.write(src);
        }

        public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
            return channel.write(srcs, offset, length);
        }

        @Override
        protected void implCloseSelectableChannel() throws IOException {
            channel.close();
        }

        @Override
        protected void implConfigureBlocking(boolean block) throws IOException {
            channel.configureBlocking(block);
        }

//        public SocketAddress getLocalAddress() throws IOException {
//            return channel.getLocalAddress();
//        }
//
//        public <T> T getOption(java.net.SocketOption<T> name) throws IOException {
//            return channel.getOption(name);
//        }
//
//        public Set<java.net.SocketOption<?>> supportedOptions() {
//            return channel.supportedOptions();
//        }
//
//        public SocketChannel bind(SocketAddress local) throws IOException {
//            return channel.bind(local);
//        }
//
//        public SocketAddress getRemoteAddress() throws IOException {
//            return channel.getRemoteAddress();
//        }
//
//        public <T> SocketChannel setOption(java.net.SocketOption<T> name, T value) throws IOException {
//            return channel.setOption(name, value);
//        }
//
//        public SocketChannel shutdownInput() throws IOException {
//            return channel.shutdownInput();
//        }
//
//        public SocketChannel shutdownOutput() throws IOException {
//            return channel.shutdownOutput();
//        }
    }
}
于 2014-07-22T15:05:47.000 に答える
5

「はい、できます」という回答に基づいて、現在の桟橋 9.3.11 で動作するコードを作成しました。興味がある人もいると思います。

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});
}

}

于 2016-10-16T22:15:21.347 に答える
-2

Jetty を取り上げても、サーバーは受信接続が HTTP か SSL/TLS かを検出する必要があるため、これは実際には不可能です。TLS プロトコルは、この使用法をサポートするように設計されていないため、実装はハックになります (どちらも見つかりません)。

着信接続が TLS か SSH かを区別できるSSL-SSH マルチプレクサが存在し、OpenVPNには非 OpenVPN 接続を別のポートにプロキシする「ポート共有」機能があります。

考えられるアプローチの 1 つは、パケット内の文字列に一致する iptables ルールを使用することです。HTTP 要求の最初のパケットには「HTTP/」を含める必要がありますが、TLS ClientHello パケットには含めません。接続は、TLS を使用しない別のポートにリダイレクトされる可能性があります。これは、パケット全体で文字列を検索するため、追加のオーバーヘッドが発生することに注意してください。これは非常にハックなソリューションです。

iptables --table nat --append PREROUTING --protocol tcp --dport 10433 --match string --string "HTTP/" --REDIRECT 1080
于 2012-06-25T05:24:49.367 に答える