Java nio socketchannel使用TLS1.2在safari和IOS中读取早期eos

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java nio socketchannel使用TLS1.2在safari和IOS中读取早期eos相关的知识,希望对你有一定的参考价值。

我有一个非常奇怪的问题,我在过去几天工作。

我在服务器端编写了一个代理应用程序。所有代理都负责管理来自不同应用程序(WebApplications,iosApps,android Apps等)的TLS / nonTLS请求和响应,并将流量代理到服务器上的应用程序。

我遇到的问题是,当我访问一个使用我的代理的WebApplication时,通过Safari和https(TLSv1.2),我随机获得了来自我的代理的响应。我调试了很多,这个问题是由我的连接读取功能引起的。超时是非常随机的,我测试我在10个请求中平均有8个超时。

这是代码:

public int read(ByteBuffer dst) throws IOException {

    if (!dst.hasRemaining()) {
        return 0;
    }
    if (peerAppData.hasRemaining()) {
        peerAppData.flip();
        return ByteBufferUtils.transferByteBuffer(peerAppData, dst);
    }
    peerNetData.compact();

    int bytesRead = socketChannel.read(peerNetData);

    if (bytesRead > 0) {
        peerNetData.flip();
        while (peerNetData.hasRemaining()) {
            peerAppData.compact();
            SSLEngineResult result = null;
            try {
                result = sslInfo.sslEngine.unwrap(peerNetData, peerAppData);
            } catch (SSLException e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
                // throw e;
            }
            switch (result.getStatus()) {
            case OK:
                peerAppData.flip();
                return ByteBufferUtils.transferByteBuffer(peerAppData, dst);
            case BUFFER_UNDERFLOW:
                peerAppData.flip();
                return ByteBufferUtils.transferByteBuffer(peerAppData, dst);
            case BUFFER_OVERFLOW:
                peerAppData = enlargeApplicationBuffer(peerAppData);
                break;
            case CLOSED:
                closeConnection();
                dst.clear();
                return -1;
            default:
                System.out.println("Invalid SSL status: " + result.getStatus());
                throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
            }
        }
    } else if (bytesRead < 0) {
        handleEndOfStream();
    }
    ByteBufferUtils.transferByteBuffer(peerAppData, dst);
    return bytesRead;
}

此代码适用于Chrome,Opera和Android。但是在Safari和IOS上,SocketChannel的第二次读取会随机返回-1。这导致连接关闭。这就解释了为什么我会在safari / IOS方面获得超时。

我有一段工作的代码,但我不能使用它,因为这不允许我代理像文件上传这样的数据流。这不能正确处理SSLEngineResult。

public int read(ByteBuffer dst) throws IOException {

    int bytesRead = 1;
    int totalBytesRead = 0;

    peerNetData.clear();

    while (bytesRead > 0) {
        bytesRead = socketChannel.read(peerNetData);

        if (bytesRead > 0) {
            totalBytesRead = totalBytesRead + bytesRead;
        }
    }

    peerNetData.flip();

    if (totalBytesRead < 0) {
        return bytesRead;
    }

    while (peerNetData.hasRemaining()) {
        SSLEngineResult result = sslInfo.sslEngine.unwrap(peerNetData, dst);
        if (result.getStatus() != SSLEngineResult.Status.OK) {
            return -1;
        }
    }

    peerNetData.compact();

    return totalBytesRead;
}

我真的不知道为什么这个代码只能在Safari浏览器或任何IOS设备的请求下失败。

你们有没有遇到过同样的问题?

在此先感谢,如果我错过了什么,请告诉我!

答案

如果您的代理的上游read()返回-1,则上游对等方关闭连接,您应该对下游对等方执行相同操作,而不是让它超时。

以上是关于Java nio socketchannel使用TLS1.2在safari和IOS中读取早期eos的主要内容,如果未能解决你的问题,请参考以下文章

Java NIO系列教程 SocketChannel

九Java NIO SocketChannel

Java NIO系列教程 SocketChannel

Java NIO 学习--ServerSocketChannel与SocketChannel

Java NIO SocketChannel

Java NIO系列教程-SocketChannel的最佳实践