2017-12-20 8 views
0

私は本当に変わった問題を抱えています。Java nio socketchannelはTLS1.2でサファリとIOSで早期のEOSを読む

私のサーバサイドにプロキシアプリケーションを書きました。プロキシはすべて、異なるアプリケーション(WebApplications、IOSApps、Android Appsなど)からのTLS/nonTLS要求と応答を管理し、トラフィックをサーバー上のアプリケーションにプロキシします。

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

このコードは、クローム、オペラとAndroidのための正常に動作します。しかし、SafariとIOSでは、SocketChannelの2番目の読み込みは無作為に-1を返します。そのため、接続が閉じられます。そして、それは私がサファリ/ 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デバイスの要求に失敗するのはなぜか分かりません。

同じ問題があったことはありますか?

ありがとうございます。私が何かを見逃している場合はお知らせください!

答えて

0

プロキシのアップストリームread()が-1を返した場合、アップストリームピアは接続を閉じ、タイムアウトさせるのではなく、ダウンストリームピアに同じ操作を行う必要があります。

+0

ちょっとEJP、あなたの答えに感謝します。しかし、アップストリームはSafariとIOSだけで閉じられるのはなぜですか?そして、なぜ他のコードニットでタイムアウトしないのですか?そこに同じ行動をしてはいけませんか? – R3tty

+0

私には分かりませんが、上流のピアが何をしていても下流のピアに忠実に反映されるべきです。 – EJP

+0

ちょっとEJP、私の遅い応答のためにsry、私は休暇中だった。だから私は奇妙な行動を修正した。問題は、760Byteがアンラップされても、まだpeerNetDataに残っているデータが残っていると、何らかの理由でSafari/iosデータの一部のunwrapがOKに戻ります。私のコードでは、宛先バッファに760バイトを転送してリターンします。確かに間違った動作です、私は通常、peerNetDataに残りのデータがなくなるまで続ける必要があります。私にとっては、私がそれをするならば、streamdataはOutOfMemory例外を引き起こすので、私はそのための回避策を書く必要がありました。あなたが望むなら私は自分のコードを投稿することができます – R3tty

関連する問題