2017-12-20 4 views
0

ich ein wirklich seltsamen Problem, das ich auf den letzten paar Tagen arbeite.Java nio Socket lesen früh eos in Safari und IOS mit TLS1.2

Ich schrieb eine Proxy-Anwendung auf meinem Serverside. Der gesamte Proxy verwaltet TLS/nonTLS-Anfragen und Antworten von verschiedenen Anwendungen (WebApplications, IOSApps, Android Apps usw.) und leitet den Datenverkehr an Anwendungen auf dem Server weiter.

Das Problem, auf das ich gestoßen bin, ist, wenn ich auf eine WebApplication zugreife, die meinen Proxy benutzt, über Safari und über https (TLSv1.2) bekomme ich zufällig keine Antworten von meinem Proxy. Ich debuggte viel und dieses Problem wird in meiner Lesefunktion der Verbindung verursacht. Das Timeout ist sehr zufällig, ich habe im Test durchschnittlich 8 Timeouts von 10 Anfragen.

Dies ist der 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; 
} 

Dieser Code funktioniert für Chrome, Opera und Android in Ordnung. Aber in Safari und IOS gibt der zweite Lesevorgang des SocketChannel nach dem Zufallsprinzip -1 zurück. Das bewirkt, dass die Verbindung geschlossen wird. Und das erklärt, warum ich auf der Safari/IOS Seite Auszeiten bekomme.

Ich habe ein Arbeits Stück Code, aber ich kann nicht verwendet werden, da diese mich nicht an dem Proxy-Upload einen Strom von Daten wie eine Datei nicht gestattet. Und das behandelt das SSLEngineResult nicht korrekt.

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

Ich weiß wirklich nicht, warum dieser Code nur auf Anfrage des Safari-Browsers oder eines IOS-Geräts fehlschlägt.

Hat jemand von euch schon einmal das gleiche Problem?

Vielen Dank im Voraus und lassen Sie es mich wissen, wenn ich etwas verpasst!

Antwort

0

Wenn der Upstream read() Ihres Proxys -1 zurückgegeben hat, hat der Upstream-Peer die Verbindung geschlossen, und Sie sollten das Gleiche für den Downstream-Peer tun, anstatt eine Zeitüberschreitung zuzulassen.

+0

Hey EJP, vielen Dank für Ihre Antwort. Aber warum wird der Upstream nur auf Safari und IOS geschlossen? Und warum nicht mit dem anderen Codesnippet Timeout. Sollte es sich dort nicht gleich verhalten? – R3tty

+0

Ich weiß natürlich nicht, aber was auch immer der Upstream-Peer tut, sollte treu zu dem Downstream Peer reflektiert werden. – EJP

+0

Hey EJP, sry für meine späte Antwort, ich war auf Urlaub. Also habe ich das seltsame Verhalten behoben. Das Problem war/ist, aus irgendeinem Grund einige safpacks/ios-Daten zurückgeben, wenn 760 Bytes nicht entpackt sind, aber es noch einige Daten in den PeerNetData gibt. In meinem Code würde ich die 760 Bytes in den Zielpuffer übertragen und zurückgeben. Das ist natürlich ein falsches Verhalten, normalerweise muss ich so lange weitermachen, bis in den PeerNetData keine Daten mehr vorhanden sind. Für mich musste ich einen Workaround dafür schreiben, denn wenn ich das tun würde, würde streamdata eine OutOfMemory-Ausnahme verursachen. Ich kann meinen Code veröffentlichen, wenn Sie möchten – R3tty