简体   繁体   中英

Java nio socketchannel read early eos in safari and IOS with TLS1.2

i have a really weird problem, which i am working on the last couple days.

I wrote a proxy application on my serverside. All the proxy does is managing TLS/nonTLS requests and responses from different Applications (WebApplications, IOSApps, Android Apps, etc.) and proxy the traffic to applications on the server.

The problem i run into is, when i access a WebApplication, which uses my proxy, via Safari and over https(TLSv1.2) i get randomly no responses from my proxy. I debugged a lot and this problem is caused in my read function of the connection. The timeout is very random, i my test i got an average of 8 timeouts out of 10 requests.

This is the code:

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

This code works fine for Chrome, Opera and Android. But on Safari and IOS, randomly the second read of the SocketChannel returns -1. That causes, that the connection gets closed. And that explains why i get timeouts on the safari/IOS side.

I have a working piece of code, but i cannot use this, because this does not allow me to proxy a stream of data like a file upload. And this does not handle the SSLEngineResult correctly.

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

I really don't know why this code only fails on request of the safari browser or any IOS device.

Has any of you ever had the same problem?

Thanks in advance and please let me know if i missed something!

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM