--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/org.chromium.sdk/src/org/chromium/sdk/internal/transport/Handshaker.java Wed Dec 23 17:13:18 2009 -0800
@@ -0,0 +1,142 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.sdk.internal.transport;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RunnableFuture;
+
+import org.chromium.sdk.internal.transport.Message.MalformedMessageException;
+
+/**
+ * Handshaker handles "handshake" part of communication. It may write and read whatever it needs
+ * before regular message-based communication has started.
+ */
+public interface Handshaker {
+ /**
+ * Performs handshake. This method is blocking. After it has successfully finished, input/output
+ * should be ready for normal message-based communication. In case method fails with IOException,
+ * input and output are returned in undefined state.
+ * @throws IOException if handshake process failed physically (input or output has unexpectedly
+ * closed) or logically (if unexpected message came from remote).
+ */
+ void perform(BufferedReader input, Writer output) throws IOException;
+
+ /**
+ * Implementation of handshake from Google Chrome Developer Tools Protocol. Used when we
+ * connect to browser.
+ */
+ Handshaker CHROMIUM = new Handshaker() {
+ public void perform(BufferedReader input, Writer output) throws IOException {
+ output.write(OUTGOING_MESSAGE);
+ output.flush();
+
+ // TODO(prybin): expose this as a parameter or get rid of this option if we don't need it.
+ final boolean ignoreUnexpectedResponses = false;
+
+ while (true) {
+ if (Thread.interrupted()) {
+ throw new IOException("Interrupted");
+ }
+ String line = input.readLine();
+ if (line == null) {
+ throw new IOException("Connection closed");
+ }
+ if (INCOMING_TEXT.equals(line)) {
+ break;
+ }
+ if (!ignoreUnexpectedResponses) {
+ throw new IOException("Unexpected handshake: " + line);
+ }
+ }
+ }
+
+ /**
+ * A handshake string to be sent by a browser on the connection start,
+ * specified by the protocol design doc (without trailing cr/lf).
+ */
+ private static final String INCOMING_TEXT = "ChromeDevToolsHandshake";
+
+ /**
+ * A handshake string that we send to a browser on the connection start,
+ * specified by the protocol design doc (including trailing cr/lf).
+ */
+ private static final String OUTGOING_MESSAGE = "ChromeDevToolsHandshake\r\n";
+ };
+
+ /**
+ * Stateful handshaker implementation for Standalone V8 protocol.
+ */
+ class StandaloneV8 implements Handshaker {
+ public interface RemoteInfo {
+ String getProtocolVersion();
+ String getV8VmVersion();
+ String getEmbeddingHostName();
+ }
+
+ public Future<RemoteInfo> getRemoteInfo() {
+ return runnableFuture;
+ }
+
+ private final RunnableFuture<RemoteInfo> runnableFuture =
+ new FutureTask<RemoteInfo>(new HandshakeTaks());
+
+ private BufferedReader input = null;
+
+ public void perform(BufferedReader input, Writer output) throws IOException {
+ this.input = input;
+ runnableFuture.run();
+
+ // Check for possible exceptions
+ try {
+ runnableFuture.get();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (ExecutionException e) {
+ throw new IOException("Failed to perform handshake", e);
+ }
+
+ }
+
+ class HandshakeTaks implements Callable<RemoteInfo> {
+ public RemoteInfo call() throws IOException {
+ final Message message;
+ try {
+ message = Message.fromBufferedReader(input);
+ } catch (MalformedMessageException e) {
+ throw new IOException("Unrecognized handshake message from remote", e);
+ }
+ if (message == null) {
+ throw new IOException("End of stream");
+ }
+ final String protocolVersion = message.getHeader("Protocol-Version", null);
+ if (protocolVersion == null) {
+ throw new IOException("Absent protocol version");
+ }
+ final String vmVersion = message.getHeader("V8-Version", null);
+ if (vmVersion == null) {
+ throw new IOException("Absent V8 VM version");
+ }
+ RemoteInfo remoteInfo = new RemoteInfo() {
+ public String getProtocolVersion() {
+ return protocolVersion;
+ }
+ public String getV8VmVersion() {
+ return vmVersion;
+ }
+ public String getEmbeddingHostName() {
+ return message.getHeader("Embedding-Host", null);
+ }
+ };
+ return remoteInfo;
+ }
+ }
+ }
+}