| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.sdk.internal.websocket; | |
| 6 | |
| 7 import java.io.BufferedInputStream; | |
| 8 import java.io.ByteArrayOutputStream; | |
| 9 import java.io.IOException; | |
| 10 import java.io.OutputStream; | |
| 11 import java.net.InetSocketAddress; | |
| 12 import java.util.Random; | |
| 13 | |
| 14 import org.chromium.sdk.ConnectionLogger; | |
| 15 import org.chromium.sdk.internal.transport.SocketWrapper; | |
| 16 import org.chromium.sdk.internal.transport.SocketWrapper.LoggableInputStream; | |
| 17 import org.chromium.sdk.internal.transport.SocketWrapper.LoggableOutputStream; | |
| 18 | |
| 19 /** | |
| 20 * WebSocket connection. Sends and receives messages. Implements HyBi-00 protoco
l specification. | |
| 21 */ | |
| 22 public class Hybi00WsConnection | |
| 23 extends AbstractWsConnection<LoggableInputStream, LoggableOutputStream> { | |
| 24 | |
| 25 public static Hybi00WsConnection connect(InetSocketAddress endpoint, int timeo
ut, | |
| 26 String resourceId, String origin, ConnectionLogger connectionLogger) throw
s IOException { | |
| 27 SocketWrapper socketWrapper = | |
| 28 new SocketWrapper(endpoint, timeout, connectionLogger, LOGGER_CHARSET); | |
| 29 | |
| 30 boolean handshakeDone = false; | |
| 31 Exception handshakeException = null; | |
| 32 try { | |
| 33 Hybi00Handshake.performHandshake(socketWrapper, endpoint, resourceId, orig
in, | |
| 34 HANDSHAKE_RANDOM); | |
| 35 handshakeDone = true; | |
| 36 } catch (RuntimeException e) { | |
| 37 handshakeException = e; | |
| 38 throw e; | |
| 39 } catch (IOException e) { | |
| 40 handshakeException = e; | |
| 41 throw e; | |
| 42 } finally { | |
| 43 if (!handshakeDone) { | |
| 44 socketWrapper.getShutdownRelay().sendSignal(null, handshakeException); | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 return new Hybi00WsConnection(socketWrapper, connectionLogger); | |
| 49 } | |
| 50 | |
| 51 private Hybi00WsConnection(SocketWrapper socketWrapper, | |
| 52 ConnectionLogger connectionLogger) { | |
| 53 super(socketWrapper, connectionLogger); | |
| 54 } | |
| 55 | |
| 56 @Override | |
| 57 public void sendTextualMessage(String message) throws IOException { | |
| 58 byte[] bytes = message.getBytes(UTF_8_CHARSET); | |
| 59 LoggableOutputStream loggableWriter = getSocketWrapper().getLoggableOutput()
; | |
| 60 OutputStream output = loggableWriter.getOutputStream(); | |
| 61 synchronized (this) { | |
| 62 output.write((byte) 0); | |
| 63 output.write(bytes); | |
| 64 output.write((byte) 255); | |
| 65 output.flush(); | |
| 66 } | |
| 67 loggableWriter.markSeparatorForLog(); | |
| 68 } | |
| 69 | |
| 70 @Override | |
| 71 protected CloseReason runListenLoop(LoggableInputStream loggableReader) | |
| 72 throws IOException, InterruptedException { | |
| 73 BufferedInputStream input = new BufferedInputStream(loggableReader.getInputS
tream()); | |
| 74 while (true) { | |
| 75 loggableReader.markSeparatorForLog(); | |
| 76 int firstByte; | |
| 77 try { | |
| 78 firstByte = input.read(); | |
| 79 } catch (IOException e) { | |
| 80 if (isClosingGracefully()) { | |
| 81 return CloseReason.USER_REQUEST; | |
| 82 } else { | |
| 83 throw e; | |
| 84 } | |
| 85 } | |
| 86 if (firstByte == -1) { | |
| 87 if (isClosingGracefully()) { | |
| 88 return CloseReason.USER_REQUEST; | |
| 89 } else { | |
| 90 throw new IOException("Unexpected end of stream"); | |
| 91 } | |
| 92 } | |
| 93 if ((firstByte & 0x80) == 0) { | |
| 94 ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); | |
| 95 while (true) { | |
| 96 int i = input.read(); | |
| 97 if (i == -1) { | |
| 98 throw new IOException("End of stream"); | |
| 99 } | |
| 100 byte b = (byte) i; | |
| 101 if (b == (byte) 0xFF) { | |
| 102 break; | |
| 103 } | |
| 104 byteBuffer.write(b); | |
| 105 } | |
| 106 byte[] messageBytes = byteBuffer.toByteArray(); | |
| 107 final String text = new String(messageBytes, UTF_8_CHARSET); | |
| 108 getDispatchQueue().put(new MessageDispatcher() { | |
| 109 @Override | |
| 110 public boolean dispatch(Listener userListener) { | |
| 111 userListener.textMessageRecieved(text); | |
| 112 return false; | |
| 113 } | |
| 114 }); | |
| 115 } else { | |
| 116 long len = 0; | |
| 117 while (true) { | |
| 118 int lengthByte = input.read(); | |
| 119 if (lengthByte == -1) { | |
| 120 throw new IOException("End of stream"); | |
| 121 } | |
| 122 len = len * 10 + (lengthByte & 0x7F); | |
| 123 if (len > Integer.MAX_VALUE) { | |
| 124 throw new IOException("Message too long"); | |
| 125 } | |
| 126 if ((lengthByte & 0x80) == 0) { | |
| 127 break; | |
| 128 } | |
| 129 } | |
| 130 long needSkip = len; | |
| 131 while (needSkip > 0) { | |
| 132 long skipped = input.skip(needSkip); | |
| 133 needSkip -= skipped; | |
| 134 } | |
| 135 if (firstByte == (byte) 0xFF && len == 0) { | |
| 136 return CloseReason.REMOTE_CLOSE_REQUEST; | |
| 137 } else { | |
| 138 final long finalLen = len; | |
| 139 getDispatchQueue().put(new MessageDispatcher() { | |
| 140 @Override | |
| 141 public boolean dispatch(Listener userListener) { | |
| 142 userListener.errorMessage( | |
| 143 new Exception("Unexpected binary message of length " + finalLe
n)); | |
| 144 return false; | |
| 145 } | |
| 146 }); | |
| 147 } | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 private static final Random HANDSHAKE_RANDOM = new Random(); | |
| 153 } | |
| OLD | NEW |