[gtk+/broadway: 21/71] Initial sketch of websockets support



commit 852b317b4f1f09b248ef7b28954ac28ba4560646
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Nov 19 14:13:13 2010 +0100

    Initial sketch of websockets support

 gdk/broadway/broadway.js           |   15 ++++
 gdk/broadway/gdkdisplay-broadway.c |  160 +++++++++++++++++++++++++++++++++++-
 2 files changed, 172 insertions(+), 3 deletions(-)
---
diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js
index 0d5749f..615f971 100644
--- a/gdk/broadway/broadway.js
+++ b/gdk/broadway/broadway.js
@@ -278,6 +278,21 @@ function handleLoad(event)
   if (outstanding_commands.length == 1) {
     handleOutstanding()
   }
+
+  if ("WebSocket" in window) {
+    var loc = window.location.toString().replace("http:", "ws:");
+    loc = loc.substr(0, loc.lastIndexOf('/')) + "/input";
+    var ws = new WebSocket(loc, "broadway");
+    ws.onopen = function() {
+      ws.send("Message to send1");
+      ws.send("Message to send2");
+    };
+    ws.onmessage = function (evt) { var msg = evt.data;
+    };
+    ws.onclose = function() { };
+  } else {
+     alert("WebSocket not supported, input will not work!");
+  }
 }
 
 function connect()
diff --git a/gdk/broadway/gdkdisplay-broadway.c b/gdk/broadway/gdkdisplay-broadway.c
index b31cdc2..9f73102 100644
--- a/gdk/broadway/gdkdisplay-broadway.c
+++ b/gdk/broadway/gdkdisplay-broadway.c
@@ -153,6 +153,160 @@ set_fd_blocking (int fd)
   fcntl (fd, F_SETFL, arg);
 }
 
+static char *
+parse_line (char *line, char *key)
+{
+  char *p;
+
+  if (!g_str_has_prefix (line, key))
+    return NULL;
+  p = line + strlen (key);
+  if (*p != ':')
+    return NULL;
+  p++;
+  /* Skip optional initial space */
+  if (*p == ' ')
+    p++;
+  return p;
+}
+
+static void
+got_input (GInputStream *stream,
+	   GAsyncResult *result,
+	   HttpRequest *request)
+{
+  char *message;
+  gsize len;
+  GError *error = NULL;
+
+  message = g_data_input_stream_read_upto_finish (G_DATA_INPUT_STREAM (stream), result, &len, &error);
+  if (message == NULL)
+    {
+      g_print (error->message);
+      g_error_free (error);
+      exit (1);
+    }
+  g_assert (message[0] == 0);
+  g_print ("message: %s\n", message+1);
+  /* Skip past ending 0xff */
+  g_data_input_stream_read_byte (request->data, NULL, NULL);
+  g_data_input_stream_read_upto_async (request->data, "\xff", 1, 0, NULL,
+				       (GAsyncReadyCallback)got_input, request);
+}
+
+static void
+start_input (HttpRequest *request)
+{
+  char **lines;
+  char *p;
+  int num_key1, num_key2;
+  guint64 key1, key2;
+  int num_space;
+  int i;
+  guint8 challenge[16];
+  char *res;
+  gsize len;
+  GChecksum *checksum;
+  char *origin, *host;
+
+  lines = g_strsplit (request->request->str, "\n", 0);
+
+  num_key1 = 0;
+  num_key2 = 0;
+  key1 = 0;
+  key2 = 0;
+  origin = NULL;
+  host = NULL;
+  for (i = 0; lines[i] != NULL; i++)
+    {
+      if ((p = parse_line (lines[i], "Sec-WebSocket-Key1")))
+	{
+	  num_space = 0;
+	  while (*p != 0)
+	    {
+	      if (g_ascii_isdigit (*p))
+		key1 = key1 * 10 + g_ascii_digit_value (*p);
+	      else if (*p == ' ')
+		num_space++;
+
+	      p++;
+	    }
+	  key1 /= num_space;
+	  num_key1++;
+	}
+      else if ((p = parse_line (lines[i], "Sec-WebSocket-Key2")))
+	{
+	  num_space = 0;
+	  while (*p != 0)
+	    {
+	      if (g_ascii_isdigit (*p))
+		key2 = key2 * 10 + g_ascii_digit_value (*p);
+	      else if (*p == ' ')
+		num_space++;
+
+	      p++;
+	    }
+	  key2 /= num_space;
+	  num_key2++;
+	}
+      else if ((p = parse_line (lines[i], "Origin")))
+	{
+	  origin = p;
+	}
+      else if ((p = parse_line (lines[i], "Host")))
+	{
+	  host = p;
+	}
+    }
+
+
+  if (num_key1 != 1 || num_key2 != 1 || origin == NULL || host == NULL)
+    {
+      g_print ("error");
+      exit (1);
+    }
+
+  challenge[0] = (key1 >> 24) & 0xff;
+  challenge[1] = (key1 >> 16) & 0xff;
+  challenge[2] = (key1 >>  8) & 0xff;
+  challenge[3] = (key1 >>  0) & 0xff;
+  challenge[4] = (key2 >> 24) & 0xff;
+  challenge[5] = (key2 >> 16) & 0xff;
+  challenge[6] = (key2 >>  8) & 0xff;
+  challenge[7] = (key2 >>  0) & 0xff;
+
+  if (!g_input_stream_read_all (G_INPUT_STREAM (request->data), challenge+8, 8, NULL, NULL, NULL))
+    {
+      g_print ("error");
+      exit (1);
+    }
+
+  checksum = g_checksum_new (G_CHECKSUM_MD5);
+  g_checksum_update (checksum, challenge, 16);
+  len = 16;
+  g_checksum_get_digest (checksum, challenge, &len);
+  g_checksum_free (checksum);
+
+  res = g_strdup_printf ("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
+			 "Upgrade: WebSocket\r\n"
+			 "Connection: Upgrade\r\n"
+			 "Sec-WebSocket-Origin: %s\r\n"
+			 "Sec-WebSocket-Location: ws://%s/input\r\n"
+			 "Sec-WebSocket-Protocol: broadway\r\n"
+			 "\r\n",
+			 origin, host);
+
+  /* TODO: This should really be async */
+  g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+			     res, strlen (res), NULL, NULL, NULL);
+  g_free (res);
+  g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+			     challenge, 16, NULL, NULL, NULL);
+
+  g_data_input_stream_read_upto_async (request->data, "\xff", 1, 0, NULL,
+				       (GAsyncReadyCallback)got_input, request);
+}
+
 static void
 start_output (HttpRequest *request)
 {
@@ -160,8 +314,6 @@ start_output (HttpRequest *request)
   GdkDisplayBroadway *display_broadway;
   int fd;
 
-  g_print ("start_output\n");
-
   socket = g_socket_connection_get_socket (request->connection);
 
   display_broadway = GDK_DISPLAY_BROADWAY (request->display);
@@ -256,12 +408,14 @@ got_request (HttpRequest *request)
     send_data (request, "text/javascript", broadway_js, G_N_ELEMENTS(broadway_js) - 1);
   else if (strcmp (escaped, "/output") == 0)
     start_output (request);
+  else if (strcmp (escaped, "/input") == 0)
+    start_input (request);
   else
     send_error (request, 404, "File not found");
 }
 
 static void
-got_http_request_line (GOutputStream *stream,
+got_http_request_line (GInputStream *stream,
 		       GAsyncResult *result,
 		       HttpRequest *request)
 {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]