簡體   English   中英

Safari 5 / iOS,WebSocket握手有時僅適用

[英]Safari 5 / iOS, WebSocket handshake only works sometimes

我在Java中創建了一個類,該類使我可以使用WebSocket協議包裝現有套接字。 我的所有工作都適用於RFC6445協議,並且一切都適用於chrome和FF。 但是Safari和iOS使用的是hixie76 / HyBi00協議(根據Wikipedia)。

我一切正常,Safari和iOS正確握手並開始發送/接收消息……至少在大多數時間里。

大約20-30%的時間,握手失敗並且Safari關閉了連接。 (Java在嘗試讀取第一幀時會讀取-1字節)。 Safari不會在控制台中報告任何錯誤,而只是調用onclose事件處理程序。

為什么握手僅在部分時間有效?

這是我的握手代碼:

注意:不會引發任何異常,並且“握手完成”將寫入控制台。 但是隨后在嘗試讀取第一幀時,連接被關閉。 (Java在inst.read()上返回-1)

// Headers are read in a previous method which wraps the socket using RFC6445
// protocol. If it detects 2 keys it will call this and pass in the headers.
public static MessagingWebSocket wrapOldProtocol(HashMap<String, String> headers, PushbackInputStream pin, Socket sock) throws IOException, NoSuchAlgorithmException {
    // SPEC
    // http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#page-32

    // Read the "key3" value. This is 8 random bytes after the headers.
    byte[] key3 = new byte[8];
    for ( int i=0; i<key3.length; i++ ) {
        key3[i] = (byte)pin.read();
    }

    // Grab the two keys we need to use for the handshake
    String key1 = headers.get("Sec-WebSocket-Key1");
    String key2 = headers.get("Sec-WebSocket-Key2");

    // Count the spaces in both keys
    // Abort the connection is either key has 0 spaces
    int spaces1 = StringUtils.countMatches(key1, " ");
    int spaces2 = StringUtils.countMatches(key2, " ");
    if ( spaces1 == 0 || spaces2 == 0 ) {
        throw new IOException("Bad Handshake Request, Possible Cross-protocol attack");
    }

    // Strip all non-digit characters from each key
    // Use the remaining value as a base-10 integer.
    // Abort if either number is not a multiple of it's #spaces counterpart
    // Need to use long because the values are unsigned
    long num1 = Long.parseLong( key1.replaceAll("\\D", "") );
    long num2 = Long.parseLong( key2.replaceAll("\\D", "") );
    if ( !(num1 % spaces1 == 0) || !(num2 % spaces2 == 0) ) {
        throw new IOException("Bad Handshake Request. Possible non-conforming client");
    }

    // Part1/2 is key num divided by the # of spaces
    int part1 = (int)(num1 / spaces1);
    int part2 = (int)(num2 / spaces2);

    // Now calculate the challenge response
    // MD5( num1 + num2 + key3 )  ... concat, not add
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(ByteBuffer.allocate(4).putInt(part1));
    md.update(ByteBuffer.allocate(4).putInt(part2));
    md.update(key3);
    byte[] response = md.digest();

    // Now build the server handshake response
    // Ignore Sec-WebSocket-Protocol (we don't use this)
    String origin = headers.get("Origin");
    String location = "ws://" + headers.get("Host") + "/";

    StringBuilder sb = new StringBuilder();
    sb.append("HTTP/1.1 101 WebSocket Protocol Handshake").append("\r\n");
    sb.append("Upgrade: websocket").append("\r\n");
    sb.append("Connection: Upgrade").append("\r\n");
    sb.append("Sec-WebSocket-Origin: ").append(origin).append("\r\n");
    sb.append("Sec-WebSocket-Location: ").append(location).append("\r\n");
    sb.append("\r\n");

    // Anything left in the buffer?
    if ( pin.available() > 0 ) {
        throw new IOException("Unexpected bytes after handshake!");
    }

    // Send the handshake & challenge response
    OutputStream out = sock.getOutputStream();
    out.write(sb.toString().getBytes());
    out.write(response);
    out.flush();

    System.out.println("[MessagingWebSocket] Handshake Complete.");

    // Return the wrapper socket class.
    MessagingWebSocket ws = new MessagingWebSocket(sock);
    ws.oldProtocol = true;
    return ws;
}

謝謝!

注意:我不是在尋找WebSocket的第三方替代品,例如jWebSocket,Jetty和Socket.IO。 我已經知道很多。

您的MD5摘要方法有一個錯誤:協議描述如下: http : //tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-5.2

byte[] bytes = new byte[16];    
BytesUtil.fillBytesWithArray(bytes, 0, 3, BytesUtil.intTobyteArray(part1));
BytesUtil.fillBytesWithArray(bytes, 4, 7, BytesUtil.intTobyteArray(part2));
BytesUtil.fillBytesWithArray(bytes, 8, 15, key3);

我認為您的問題是由Little Endian和Big Endian引起的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM