我有一个非常奇怪的问题,我最近几天正在解决这个问题。
我在服务器端编写了一个代理应用程序。代理所做的只是管理来自不同应用程序(WebApplications、IOSApps、Android 应用程序等)的 TLS/非 TLS 请求和响应,并将流量代理到服务器上的应用程序。
我遇到的问题是,当我通过 Safari 和 https(TLSv1.2) 访问使用我的代理的 WebApplication 时,我随机没有收到来自代理的响应。我调试了很多,这个问题是在我的连接读取功能中引起的。超时是非常随机的,在我的测试中,我在 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 设备的请求下失败。
你们中有人遇到过同样的问题吗?
在此先感谢,如果我错过了什么,请告诉我!