[gtk+] broadway: Initial support fro V7+ websockets
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] broadway: Initial support fro V7+ websockets
- Date: Thu, 10 Nov 2011 09:13:44 +0000 (UTC)
commit 14a17873de4451eb981bdb5325559efafeeda5f4
Author: Michael Meeks <michael meeks suse com>
Date: Thu Nov 10 10:12:28 2011 +0100
broadway: Initial support fro V7+ websockets
Allows more modern browsers eg. firefox 5+ to use gtk/broadway
Auto-detects protocol version, and can switch between them at
as you connect a different browser.
This works to some extent, but seems to hang sometimes, for
instance the "button box" test in testgtk never shows up.
gdk/broadway/broadway.c | 189 +++++++++++++---------
gdk/broadway/broadway.h | 13 ++-
gdk/broadway/broadway.js | 19 ++-
gdk/broadway/gdkdisplay-broadway.c | 313 +++++++++++++++++++++++++++++-------
4 files changed, 386 insertions(+), 148 deletions(-)
---
diff --git a/gdk/broadway/broadway.c b/gdk/broadway/broadway.c
index 9f27746..b104758 100644
--- a/gdk/broadway/broadway.c
+++ b/gdk/broadway/broadway.c
@@ -175,30 +175,84 @@ struct BroadwayOutput {
GOutputStream *out;
int error;
guint32 serial;
+ gboolean proto_v7_plus;
};
static void
-broadway_output_write_header (BroadwayOutput *output)
-{
- g_output_stream_write (output->out, "\0", 1, NULL, NULL);
+broadway_output_send_cmd (BroadwayOutput *output,
+ gboolean fin, BroadwayWSOpCode code,
+ const void *buf, gsize count)
+{
+ gboolean mask = FALSE;
+ guchar header[16];
+ size_t p;
+
+ gboolean mid_header = count > 125 && count <= 65535;
+ gboolean long_header = count > 65535;
+
+ /* NB. big-endian spec => bit 0 == MSB */
+ header[0] = ( (fin ? 0x80 : 0) | (code & 0x0f) );
+ header[1] = ( (mask ? 0x80 : 0) |
+ (mid_header ? 126 : long_header ? 127 : count) );
+ p = 2;
+ if (mid_header)
+ {
+ *(guint16 *)(header + p) = GUINT16_TO_BE( (guint16)count );
+ p += 2;
+ }
+ else if (long_header)
+ {
+ *(guint64 *)(header + p) = GUINT64_TO_BE( count );
+ p += 8;
+ }
+ // FIXME: if we are paranoid we should 'mask' the data
+ // FIXME: we should really emit these as a single write
+ g_output_stream_write_all (output->out, header, p, NULL, NULL, NULL);
+ g_output_stream_write_all (output->out, buf, count, NULL, NULL, NULL);
}
static void
-broadway_output_write (BroadwayOutput *output,
- const void *buf, gsize count)
+broadway_output_sendmsg (BroadwayOutput *output,
+ const void *buf, gsize count)
{
- g_output_stream_write_all (output->out, buf, count, NULL, NULL, NULL);
+ if (!output->proto_v7_plus)
+ g_output_stream_write_all (output->out, buf, count, NULL, NULL, NULL);
+ else
+ broadway_output_send_cmd (output, TRUE, BROADWAY_WS_TEXT, buf, count);
+}
+
+void broadway_output_pong (BroadwayOutput *output)
+{
+ if (output->proto_v7_plus)
+ broadway_output_send_cmd (output, TRUE, BROADWAY_WS_CNX_PONG, NULL, 0);
}
static void
-send_boundary (BroadwayOutput *output)
+broadway_output_sendmsg_initiate (BroadwayOutput *output)
+{
+ if (!output->proto_v7_plus)
+ g_output_stream_write (output->out, "\0", 1, NULL, NULL);
+ else
+ {
+ }
+}
+
+int
+broadway_output_flush (BroadwayOutput *output)
{
- broadway_output_write (output, "\xff", 1);
- broadway_output_write (output, "\0", 1);
+ if (!output->proto_v7_plus)
+ {
+ broadway_output_sendmsg (output, "\xff", 1);
+ broadway_output_sendmsg (output, "\0", 1);
+ return !output->error;
+ }
+ else /* no need to flush */
+ return !output->error;
}
BroadwayOutput *
-broadway_output_new(GOutputStream *out, guint32 serial)
+broadway_output_new(GOutputStream *out, guint32 serial,
+ gboolean proto_v7_plus)
{
BroadwayOutput *output;
@@ -206,8 +260,9 @@ broadway_output_new(GOutputStream *out, guint32 serial)
output->out = g_object_ref (out);
output->serial = serial;
+ output->proto_v7_plus = proto_v7_plus;
- broadway_output_write_header (output);
+ broadway_output_sendmsg_initiate (output);
return output;
}
@@ -225,13 +280,6 @@ broadway_output_get_next_serial (BroadwayOutput *output)
return output->serial;
}
-int
-broadway_output_flush (BroadwayOutput *output)
-{
- send_boundary (output);
- return !output->error;
-}
-
/************************************************************************
* Core rendering operations *
@@ -291,7 +339,7 @@ broadway_output_copy_rectangles (BroadwayOutput *output, int id,
assert (p == len);
- broadway_output_write (output, buf, len);
+ broadway_output_sendmsg (output, buf, len);
free (buf);
}
@@ -309,7 +357,7 @@ broadway_output_grab_pointer (BroadwayOutput *output,
assert (p == sizeof (buf));
- broadway_output_write (output, buf, sizeof (buf));
+ broadway_output_sendmsg (output, buf, sizeof (buf));
}
guint32
@@ -324,7 +372,7 @@ broadway_output_ungrab_pointer (BroadwayOutput *output)
assert (p == sizeof (buf));
- broadway_output_write (output, buf, sizeof (buf));
+ broadway_output_sendmsg (output, buf, sizeof (buf));
return serial;
}
@@ -347,7 +395,7 @@ broadway_output_new_surface(BroadwayOutput *output,
assert (p == sizeof (buf));
- broadway_output_write (output, buf, sizeof (buf));
+ broadway_output_sendmsg (output, buf, sizeof (buf));
}
void
@@ -361,7 +409,7 @@ broadway_output_show_surface(BroadwayOutput *output, int id)
assert (p == sizeof (buf));
- broadway_output_write (output, buf, sizeof (buf));
+ broadway_output_sendmsg (output, buf, sizeof (buf));
}
void
@@ -375,7 +423,7 @@ broadway_output_hide_surface(BroadwayOutput *output, int id)
assert (p == sizeof (buf));
- broadway_output_write (output, buf, sizeof (buf));
+ broadway_output_sendmsg (output, buf, sizeof (buf));
}
void
@@ -389,7 +437,7 @@ broadway_output_destroy_surface(BroadwayOutput *output, int id)
assert (p == sizeof (buf));
- broadway_output_write (output, buf, sizeof (buf));
+ broadway_output_sendmsg (output, buf, sizeof (buf));
}
@@ -427,7 +475,7 @@ broadway_output_move_resize_surface (BroadwayOutput *output,
}
assert (p <= sizeof (buf));
- broadway_output_write (output, buf, p);
+ broadway_output_sendmsg (output, buf, p);
}
void
@@ -445,7 +493,7 @@ broadway_output_set_transient_for (BroadwayOutput *output,
assert (p == sizeof (buf));
- broadway_output_write (output, buf, sizeof (buf));
+ broadway_output_sendmsg (output, buf, sizeof (buf));
}
@@ -453,27 +501,31 @@ void
broadway_output_put_rgb (BroadwayOutput *output, int id, int x, int y,
int w, int h, int byte_stride, void *data)
{
- char buf[HEADER_LEN + 15];
- gsize len;
- char *url;
+ gsize buf_size;
+ gsize url_len;
+ char *url, *buf;
int p;
+ url = to_png_rgb (w, h, byte_stride, (guint32*)data);
+ url_len = strlen (url);
+
+ buf_size = HEADER_LEN + 15 + url_len;
+ buf = g_malloc (buf_size);
+
p = write_header (output, buf, 'i');
append_uint16 (id, buf, &p);
append_uint16 (x, buf, &p);
append_uint16 (y, buf, &p);
- url = to_png_rgb (w, h, byte_stride, (guint32*)data);
- len = strlen (url);
- append_uint32 (len, buf, &p);
-
- assert (p == sizeof (buf));
+ append_uint32 (url_len, buf, &p);
- broadway_output_write (output, buf, sizeof (buf));
+ g_assert (p == HEADER_LEN + 15);
+ strncpy (buf + p, url, url_len);
- broadway_output_write (output, url, len);
+ broadway_output_sendmsg (output, buf, buf_size);
+ g_free (buf);
free (url);
}
@@ -704,37 +756,40 @@ void
broadway_output_put_rgba (BroadwayOutput *output, int id, int x, int y,
int w, int h, int byte_stride, void *data)
{
- char buf[HEADER_LEN + 15];
- gsize len;
- char *url;
BroadwayBox *rects;
int p, i, n_rects;
- guint8 *subdata;
rects = rgba_find_rects (data, w, h, byte_stride, &n_rects);
for (i = 0; i < n_rects; i++)
{
+ gsize url_len, buf_size;
+ char *buf, *url;
+ guint8 *subdata;
+
subdata = (guint8 *)data + rects[i].x1 * 4 + rects[i].y1 * byte_stride;
+ url = to_png_rgba (rects[i].x2 - rects[i].x1,
+ rects[i].y2 - rects[i].y1,
+ byte_stride, (guint32*)subdata);
+
+ url_len = strlen (url);
+ buf_size = HEADER_LEN + 15 + url_len;
+ buf = g_malloc (buf_size);
+
p = write_header (output, buf, 'i');
append_uint16 (id, buf, &p);
append_uint16 (x + rects[i].x1, buf, &p);
append_uint16 (y + rects[i].y1, buf, &p);
- url = to_png_rgba (rects[i].x2 - rects[i].x1,
- rects[i].y2 - rects[i].y1,
- byte_stride, (guint32*)subdata);
- len = strlen (url);
- append_uint32 (len, buf, &p);
-
- assert (p == sizeof (buf));
+ append_uint32 (url_len, buf, &p);
+ g_assert (p == HEADER_LEN + 15);
+ strncpy (buf + p, url, url_len);
- broadway_output_write (output, buf, sizeof (buf));
-
- broadway_output_write (output, url, len);
+ broadway_output_sendmsg (output, buf, buf_size);
free (url);
+ g_free (buf);
}
free (rects);
@@ -750,35 +805,7 @@ broadway_output_surface_flush (BroadwayOutput *output,
p = write_header (output, buf, 'f');
append_uint16 (id, buf, &p);
- assert (p == sizeof (buf));
-
- broadway_output_write (output, buf, sizeof (buf));
-}
-
-#if 0
-static void
-send_image_a (BroadwayOutput *output, int id, int x, int y,
- int w, int h, int byte_stride, guint8 *data)
-{
- char buf[HEADER_LEN + 15];
- gsize len;
- char *url;
-
- p = write_header (output, buf, 'i');
- append_uint16 (id, buf, &p);
- append_uint16 (x, buf, &p);
- append_uint16 (y, buf, &p);
-
- url = to_png_a (w, h, byte_stride, data);
- len = strlen (url);
- append_uint32 (len, buf, &p);
-
- assert (p == sizeof (buf));
-
- broadway_output_write (output, buf, sizeof (buf));
+ g_assert (p == sizeof (buf));
- broadway_output_write (output, url, len);
-
- free (url);
+ broadway_output_sendmsg (output, buf, sizeof (buf));
}
-#endif
diff --git a/gdk/broadway/broadway.h b/gdk/broadway/broadway.h
index 1258265..731e9c1 100644
--- a/gdk/broadway/broadway.h
+++ b/gdk/broadway/broadway.h
@@ -8,8 +8,18 @@ typedef struct {
int width, height;
} BroadwayRect;
+typedef enum {
+ BROADWAY_WS_CONTINUATION = 0,
+ BROADWAY_WS_TEXT = 1,
+ BROADWAY_WS_BINARY = 2,
+ BROADWAY_WS_CNX_CLOSE = 8,
+ BROADWAY_WS_CNX_PING = 9,
+ BROADWAY_WS_CNX_PONG = 0xa
+} BroadwayWSOpCode;
+
BroadwayOutput *broadway_output_new (GOutputStream *out,
- guint32 serial);
+ guint32 serial,
+ gboolean proto_v7_plus);
void broadway_output_free (BroadwayOutput *output);
int broadway_output_flush (BroadwayOutput *output);
int broadway_output_has_error (BroadwayOutput *output);
@@ -66,3 +76,4 @@ void broadway_output_grab_pointer (BroadwayOutput *output,
int id,
gboolean owner_event);
guint32 broadway_output_ungrab_pointer (BroadwayOutput *output);
+void broadway_output_pong (BroadwayOutput *output);
diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js
index 357620e..90b9d53 100644
--- a/gdk/broadway/broadway.js
+++ b/gdk/broadway/broadway.js
@@ -2769,10 +2769,19 @@ function connect()
useToplevelWindows = true;
}
+ var loc = window.location.toString().replace("http:", "ws:");
+ loc = loc.substr(0, loc.lastIndexOf('/')) + "/socket";
+ var ws = null;
+
if ("WebSocket" in window) {
- var loc = window.location.toString().replace("http:", "ws:");
- loc = loc.substr(0, loc.lastIndexOf('/')) + "/socket";
- var ws = new WebSocket(loc, "broadway");
+ ws = new WebSocket(loc, "broadway");
+ } else if ("MozWebSocket" in window) { // Firefox 6
+ ws = new MozWebSocket(loc);
+ } else {
+ alert("WebSocket not supported, input will not work!");
+ return;
+ }
+
ws.onopen = function() {
inputSocket = ws;
var w, h;
@@ -2797,9 +2806,7 @@ function connect()
ws.onmessage = function(event) {
handleMessage(event.data);
};
- } else {
- alert("WebSocket not supported, input will not work!");
- }
+
setupDocument(document);
window.onunload = function (ev) {
for (var i = 0; i < toplevelWindows.length; i++)
diff --git a/gdk/broadway/gdkdisplay-broadway.c b/gdk/broadway/gdkdisplay-broadway.c
index c0431bc..87fc1c8 100644
--- a/gdk/broadway/gdkdisplay-broadway.c
+++ b/gdk/broadway/gdkdisplay-broadway.c
@@ -48,6 +48,10 @@
static void gdk_broadway_display_dispose (GObject *object);
static void gdk_broadway_display_finalize (GObject *object);
+#if 0
+#define DEBUG_WEBSOCKETS 1
+#endif
+
G_DEFINE_TYPE (GdkBroadwayDisplay, gdk_broadway_display, GDK_TYPE_DISPLAY)
static void
@@ -128,7 +132,7 @@ typedef struct HttpRequest {
GString *request;
} HttpRequest;
-static void start_output (HttpRequest *request);
+static void start_output (HttpRequest *request, gboolean proto_v7_plus);
static void
http_request_free (HttpRequest *request)
@@ -146,6 +150,7 @@ struct BroadwayInput {
GSource *source;
gboolean seen_time;
gint64 time_base;
+ gboolean proto_v7_plus;
};
static void
@@ -229,7 +234,7 @@ parse_input_message (BroadwayInput *input, const char *message)
5 seconds after last_seen_time, to avoid issues that could appear when
a long hiatus due to a reconnect seems to be instant */
input->time_base = time_ - (broadway_display->last_seen_time + 5000);
- }
+ }
time_ = time_ - input->time_base;
}
@@ -309,47 +314,158 @@ parse_input_message (BroadwayInput *input, const char *message)
}
+static inline void
+hex_dump (guchar *data, gsize len)
+{
+#ifdef DEBUG_WEBSOCKETS
+ gsize i, j;
+ for (j = 0; j < len + 15; j += 16)
+ {
+ fprintf (stderr, "0x%.4x ", j);
+ for (i = 0; i < 16; i++)
+ {
+ if ((j + i) < len)
+ fprintf (stderr, "%.2x ", data[j+i]);
+ else
+ fprintf (stderr, " ");
+ if (i == 8)
+ fprintf (stderr, " ");
+ }
+ fprintf (stderr, " | ");
+
+ for (i = 0; i < 16; i++)
+ if ((j + i) < len && g_ascii_isalnum(data[j+i]))
+ fprintf (stderr, "%c", data[j+i]);
+ else
+ fprintf (stderr, ".");
+ fprintf (stderr, "\n");
+ }
+#endif
+}
+
static void
parse_input (BroadwayInput *input)
{
GdkBroadwayDisplay *broadway_display;
- char *buf, *ptr;
- gsize len;
broadway_display = GDK_BROADWAY_DISPLAY (input->display);
- buf = (char *)input->buffer->data;
- len = input->buffer->len;
-
- if (len == 0)
+ if (!input->buffer->len)
return;
- if (buf[0] != 0)
+ if (input->proto_v7_plus)
{
- broadway_display->input = NULL;
- broadway_input_free (input);
- return;
- }
+ hex_dump (input->buffer->data, input->buffer->len);
- while ((ptr = memchr (buf, 0xff, len)) != NULL)
- {
- *ptr = 0;
- ptr++;
+ while (input->buffer->len > 2)
+ {
+ gsize len, payload_len;
+ BroadwayWSOpCode code;
+ gboolean is_mask, fin;
+ guchar *buf, *data;
+
+ buf = input->buffer->data;
+ len = input->buffer->len;
+
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("Parse input first byte 0x%2x 0x%2x\n", buf[0], buf[1]);
+#endif
+
+ fin = buf[0] & 0x80;
+ code = buf[0] & 0x0f;
+ payload_len = buf[1] & 0x7f;
+ is_mask = buf[1] & 0x80;
+ data = buf + 2;
+
+ if (payload_len > 125)
+ {
+ if (len < 4)
+ return;
+ payload_len = GUINT16_FROM_BE( *(guint16 *) data );
+ data += 2;
+ }
+ else if (payload_len > 126)
+ {
+ if (len < 10)
+ return;
+ payload_len = GUINT64_FROM_BE( *(guint64 *) data );
+ data += 8;
+ }
+ if (data - buf + payload_len > len)
+ return; /* wait to accumulate more */
- parse_input_message (input, buf + 1);
+ if (is_mask)
+ {
+ gsize i;
+ for (i = 0; i < payload_len; i++)
+ data[i + 4] ^= data[i%4];
+ data += 4;
+ }
- len -= ptr - buf;
- buf = ptr;
+ switch (code) {
+ case BROADWAY_WS_CNX_CLOSE:
+ break; /* hang around anyway */
+ case BROADWAY_WS_TEXT:
+ if (!fin)
+ {
+#ifdef DEBUG_WEBSOCKETS
+ g_warning ("can't yet accept fragmented input");
+#endif
+ }
+ else
+ parse_input_message (input, (char *)data);
+ break;
+ case BROADWAY_WS_CNX_PING:
+ broadway_output_pong (broadway_display->output);
+ break;
+ case BROADWAY_WS_CNX_PONG:
+ break; /* we never send pings, but tolerate pongs */
+ case BROADWAY_WS_BINARY:
+ case BROADWAY_WS_CONTINUATION:
+ default:
+ {
+ g_warning ("fragmented or unknown input code 0x%2x with fin set", code);
+ break;
+ }
+ }
- if (len > 0 && buf[0] != 0)
+ g_byte_array_remove_range (input->buffer, 0, data - buf + payload_len);
+ }
+ }
+ else /* old style protocol */
+ {
+ char *buf, *ptr;
+ gsize len;
+
+ buf = (char *)input->buffer->data;
+ len = input->buffer->len;
+
+ if (buf[0] != 0)
{
broadway_display->input = NULL;
broadway_input_free (input);
- break;
+ return;
}
- }
- g_byte_array_remove_range (input->buffer, 0, buf - (char *)input->buffer->data);
+ while ((ptr = memchr (buf, 0xff, len)) != NULL)
+ {
+ *ptr = 0;
+ ptr++;
+
+ parse_input_message (input, buf + 1);
+
+ len -= ptr - buf;
+ buf = ptr;
+
+ if (len > 0 && buf[0] != 0)
+ {
+ broadway_display->input = NULL;
+ broadway_input_free (input);
+ break;
+ }
+ }
+ g_byte_array_remove_range (input->buffer, 0, buf - (char *)input->buffer->data);
+ }
}
@@ -404,7 +520,7 @@ _gdk_broadway_display_read_all_input_nonblocking (GdkDisplay *display)
broadway_input_free (input);
if (res < 0)
{
- g_print ("input error %s", error->message);
+ g_print ("input error %s\n", error->message);
g_error_free (error);
}
return;
@@ -537,6 +653,32 @@ send_error (HttpRequest *request,
http_request_free (request);
}
+/* magic from: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 */
+#define SEC_WEB_SOCKET_KEY_MAGIC "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+
+/* 'x3JJHMbDL1EzLkh9GBhXDw==' generates 'HSmrc0sMlYUkAGmm5OPpG2HaGWk=' */
+static gchar *
+generate_handshake_response_wsietf_v7 (const gchar *key)
+{
+ guchar digest[20];
+ gsize digest_len;
+ GChecksum *checksum;
+
+ checksum = g_checksum_new (G_CHECKSUM_SHA1);
+ if (!checksum)
+ return NULL;
+
+ g_checksum_update (checksum, (guchar *)key, -1);
+ g_checksum_update (checksum, (guchar *)SEC_WEB_SOCKET_KEY_MAGIC, -1);
+
+ g_checksum_get_digest (checksum, digest, &digest_len);
+ g_checksum_free (checksum);
+
+ g_assert (digest_len == 20);
+
+ return g_base64_encode (digest, digest_len);
+}
+
static void
start_input (HttpRequest *request)
{
@@ -556,6 +698,8 @@ start_input (HttpRequest *request)
const void *data_buffer;
gsize data_buffer_size;
GInputStream *in;
+ char *key_v7;
+ gboolean proto_v7_plus;
broadway_display = GDK_BROADWAY_DISPLAY (request->display);
@@ -565,12 +709,16 @@ start_input (HttpRequest *request)
return;
}
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("incoming request:\n%s\n", request->request->str);
+#endif
lines = g_strsplit (request->request->str, "\n", 0);
num_key1 = 0;
num_key2 = 0;
key1 = 0;
key2 = 0;
+ key_v7 = NULL;
origin = NULL;
host = NULL;
for (i = 0; lines[i] != NULL; i++)
@@ -605,6 +753,10 @@ start_input (HttpRequest *request)
key2 /= num_space;
num_key2++;
}
+ else if ((p = parse_line (lines[i], "Sec-WebSocket-Key")))
+ {
+ key_v7 = p;
+ }
else if ((p = parse_line (lines[i], "Origin")))
{
origin = p;
@@ -613,56 +765,97 @@ start_input (HttpRequest *request)
{
host = p;
}
+ else if ((p = parse_line (lines[i], "Sec-WebSocket-Origin")))
+ {
+ origin = p;
+ }
}
- if (num_key1 != 1 || num_key2 != 1 || origin == NULL || host == NULL)
+ if (origin == NULL || host == NULL)
{
g_strfreev (lines);
send_error (request, 400, "Bad websocket request");
return;
}
- 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))
+ if (key_v7 != NULL)
{
- g_strfreev (lines);
- send_error (request, 400, "Bad websocket request");
- return;
+ char* accept = generate_handshake_response_wsietf_v7 (key_v7);
+ res = g_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Accept: %s\r\n"
+ "Sec-WebSocket-Origin: %s\r\n"
+ "Sec-WebSocket-Location: ws://%s/socket\r\n"
+ "Sec-WebSocket-Protocol: broadway\r\n"
+ "\r\n", accept, origin, host);
+ g_free (accept);
+
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("v7 proto response:\n%s", res);
+#endif
+
+ 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);
+ proto_v7_plus = TRUE;
}
+ else
+ {
+ if (num_key1 != 1 || num_key2 != 1)
+ {
+ g_strfreev (lines);
+ send_error (request, 400, "Bad websocket request");
+ return;
+ }
- 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);
+ 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;
- 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/socket\r\n"
- "Sec-WebSocket-Protocol: broadway\r\n"
- "\r\n",
- origin, host);
+ if (!g_input_stream_read_all (G_INPUT_STREAM (request->data), challenge+8, 8, NULL, NULL, NULL))
+ {
+ g_strfreev (lines);
+ send_error (request, 400, "Bad websocket request");
+ return;
+ }
- 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);
+ 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/socket\r\n"
+ "Sec-WebSocket-Protocol: broadway\r\n"
+ "\r\n",
+ origin, host);
+
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("legacy response:\n%s", res);
+#endif
+ 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);
+ proto_v7_plus = FALSE;
+ }
input = g_new0 (BroadwayInput, 1);
input->display = request->display;
input->connection = g_object_ref (request->connection);
+ input->proto_v7_plus = proto_v7_plus;
data_buffer = g_buffered_input_stream_peek_buffer (G_BUFFERED_INPUT_STREAM (request->data), &data_buffer_size);
input->buffer = g_byte_array_sized_new (data_buffer_size);
@@ -670,7 +863,7 @@ start_input (HttpRequest *request)
broadway_display->input = input;
- start_output (request);
+ start_output (request, proto_v7_plus);
/* This will free and close the data input stream, but we got all the buffered content already */
http_request_free (request);
@@ -688,7 +881,7 @@ start_input (HttpRequest *request)
}
static void
-start_output (HttpRequest *request)
+start_output (HttpRequest *request, gboolean proto_v7_plus)
{
GSocket *socket;
GdkBroadwayDisplay *broadway_display;
@@ -708,7 +901,7 @@ start_output (HttpRequest *request)
broadway_display->output =
broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- broadway_display->saved_serial);
+ broadway_display->saved_serial, proto_v7_plus);
_gdk_broadway_resync_windows ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]