forked from AuroraMiddleware/gtk
broadway: Remove support for old browsers
Require binary array buffers and modern WebSocket protocol support.
This commit is contained in:
parent
d61bcf13d3
commit
f2e30144f8
@ -7,56 +7,6 @@
|
||||
|
||||
#include "broadway-output.h"
|
||||
|
||||
/************************************************************************
|
||||
* Base64 functions *
|
||||
************************************************************************/
|
||||
|
||||
static const char base64_alphabet[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
#if 0 /* Unused for now */
|
||||
static void
|
||||
base64_uint8 (guint8 v, char *c)
|
||||
{
|
||||
c[0] = base64_alphabet[(v >> 0) & 0x3f];
|
||||
c[1] = base64_alphabet[(v >> 6) & 0x3];
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
base64_uint16 (guint32 v, char *c)
|
||||
{
|
||||
c[0] = base64_alphabet[(v >> 0) & 0x3f];
|
||||
c[1] = base64_alphabet[(v >> 6) & 0x3f];
|
||||
c[2] = base64_alphabet[(v >> 12) & 0xf];
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
base64_uint24 (guint32 v, char *c)
|
||||
{
|
||||
c[0] = base64_alphabet[(v >> 0) & 0x3f];
|
||||
c[1] = base64_alphabet[(v >> 6) & 0x3f];
|
||||
c[2] = base64_alphabet[(v >> 12) & 0x3f];
|
||||
c[3] = base64_alphabet[(v >> 18) & 0x3f];
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
base64_uint32 (guint32 v, char *c)
|
||||
{
|
||||
c[0] = base64_alphabet[(v >> 0) & 0x3f];
|
||||
c[1] = base64_alphabet[(v >> 6) & 0x3f];
|
||||
c[2] = base64_alphabet[(v >> 12) & 0x3f];
|
||||
c[3] = base64_alphabet[(v >> 18) & 0x3f];
|
||||
c[4] = base64_alphabet[(v >> 24) & 0x3f];
|
||||
c[5] = base64_alphabet[(v >> 30) & 0x2];
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* conversion of raw image data to png data: uris *
|
||||
***********************************************************/
|
||||
|
||||
static cairo_status_t
|
||||
write_png_data (void *closure,
|
||||
const unsigned char *data,
|
||||
@ -93,118 +43,6 @@ to_png_rgba (GString *buf, int w, int h, int byte_stride, guint32 *data)
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
struct PngTarget {
|
||||
GString *buf;
|
||||
int state;
|
||||
int save;
|
||||
};
|
||||
|
||||
static cairo_status_t
|
||||
write_png_url (void *closure,
|
||||
const unsigned char *data,
|
||||
unsigned int data_len)
|
||||
{
|
||||
struct PngTarget *target = closure;
|
||||
gsize res, old_len;
|
||||
|
||||
old_len = target->buf->len;
|
||||
g_string_set_size (target->buf,
|
||||
old_len + (data_len / 3 + 1) * 4 + 4);
|
||||
|
||||
res = g_base64_encode_step (data, data_len, FALSE,
|
||||
target->buf->str + old_len,
|
||||
&target->state, &target->save);
|
||||
|
||||
g_string_set_size (target->buf, old_len + res);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
to_png_url_rgb (GString *buf, int w, int h, int byte_stride, guint32 *data)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
struct PngTarget target;
|
||||
gsize res, old_len;
|
||||
|
||||
target.buf = buf;
|
||||
target.state = 0;
|
||||
target.save = 0;
|
||||
|
||||
g_string_append (buf, "data:image/png;base64,");
|
||||
|
||||
surface = cairo_image_surface_create_for_data ((guchar *)data,
|
||||
CAIRO_FORMAT_RGB24, w, h, byte_stride);
|
||||
|
||||
cairo_surface_write_to_png_stream (surface, write_png_url, &target);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
old_len = buf->len;
|
||||
|
||||
g_string_set_size (buf, old_len + 4);
|
||||
res = g_base64_encode_close (FALSE,
|
||||
buf->str + old_len,
|
||||
&target.state, &target.save);
|
||||
g_string_set_size (buf, old_len + res);
|
||||
}
|
||||
|
||||
static void
|
||||
to_png_url_rgba (GString *buf, int w, int h, int byte_stride, guint32 *data)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
struct PngTarget target;
|
||||
gsize res, old_len;
|
||||
|
||||
target.buf = buf;
|
||||
target.state = 0;
|
||||
target.save = 0;
|
||||
|
||||
g_string_append (buf, "data:image/png;base64,");
|
||||
|
||||
surface = cairo_image_surface_create_for_data ((guchar *)data,
|
||||
CAIRO_FORMAT_ARGB32, w, h, byte_stride);
|
||||
|
||||
cairo_surface_write_to_png_stream (surface, write_png_url, &target);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
old_len = buf->len;
|
||||
|
||||
g_string_set_size (buf, old_len + 4);
|
||||
res = g_base64_encode_close (FALSE,
|
||||
buf->str + old_len,
|
||||
&target.state, &target.save);
|
||||
g_string_set_size (buf, old_len + res);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static char *
|
||||
to_png_a (int w, int h, int byte_stride, guint8 *data)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
struct PngTarget target;
|
||||
gsize res, old_len;
|
||||
|
||||
target.url = g_string_new ("data:image/png;base64,");
|
||||
target.state = 0;
|
||||
target.save = 0;
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_A8, w, h, byte_stride);
|
||||
|
||||
cairo_surface_write_to_png_stream (surface, write_png_url, &target);
|
||||
|
||||
old_len = target.url->len;
|
||||
|
||||
g_string_set_size (target.url, old_len + 4);
|
||||
res = g_base64_encode_close (FALSE,
|
||||
target.url->str + old_len,
|
||||
&target.state, &target.save);
|
||||
g_string_set_size (target.url, old_len + res);
|
||||
|
||||
return g_string_free (target.url, FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Basic I/O primitives *
|
||||
************************************************************************/
|
||||
@ -214,8 +52,6 @@ struct BroadwayOutput {
|
||||
GString *buf;
|
||||
int error;
|
||||
guint32 serial;
|
||||
gboolean proto_v7_plus;
|
||||
gboolean binary;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -251,19 +87,9 @@ broadway_output_send_cmd (BroadwayOutput *output,
|
||||
g_output_stream_write_all (output->out, buf, count, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
broadway_output_send_cmd_pre_v7 (BroadwayOutput *output,
|
||||
const void *buf, gsize count)
|
||||
{
|
||||
g_output_stream_write_all (output->out, "\0", 1, NULL, NULL, NULL);
|
||||
g_output_stream_write_all (output->out, buf, count, NULL, NULL, NULL);
|
||||
g_output_stream_write_all (output->out, "\xff", 1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void broadway_output_pong (BroadwayOutput *output)
|
||||
{
|
||||
if (output->proto_v7_plus)
|
||||
broadway_output_send_cmd (output, TRUE, BROADWAY_WS_CNX_PONG, NULL, 0);
|
||||
broadway_output_send_cmd (output, TRUE, BROADWAY_WS_CNX_PONG, NULL, 0);
|
||||
}
|
||||
|
||||
int
|
||||
@ -272,14 +98,8 @@ broadway_output_flush (BroadwayOutput *output)
|
||||
if (output->buf->len == 0)
|
||||
return TRUE;
|
||||
|
||||
if (!output->proto_v7_plus)
|
||||
broadway_output_send_cmd_pre_v7 (output, output->buf->str, output->buf->len);
|
||||
else if (output->binary)
|
||||
broadway_output_send_cmd (output, TRUE, BROADWAY_WS_BINARY,
|
||||
output->buf->str, output->buf->len);
|
||||
else
|
||||
broadway_output_send_cmd (output, TRUE, BROADWAY_WS_TEXT,
|
||||
output->buf->str, output->buf->len);
|
||||
broadway_output_send_cmd (output, TRUE, BROADWAY_WS_BINARY,
|
||||
output->buf->str, output->buf->len);
|
||||
|
||||
g_string_set_size (output->buf, 0);
|
||||
|
||||
@ -288,8 +108,7 @@ broadway_output_flush (BroadwayOutput *output)
|
||||
}
|
||||
|
||||
BroadwayOutput *
|
||||
broadway_output_new (GOutputStream *out, guint32 serial,
|
||||
gboolean proto_v7_plus, gboolean binary)
|
||||
broadway_output_new (GOutputStream *out, guint32 serial)
|
||||
{
|
||||
BroadwayOutput *output;
|
||||
|
||||
@ -298,8 +117,6 @@ broadway_output_new (GOutputStream *out, guint32 serial,
|
||||
output->out = g_object_ref (out);
|
||||
output->buf = g_string_new ("");
|
||||
output->serial = serial;
|
||||
output->proto_v7_plus = proto_v7_plus;
|
||||
output->binary = binary;
|
||||
|
||||
return output;
|
||||
}
|
||||
@ -338,40 +155,25 @@ append_char (BroadwayOutput *output, char c)
|
||||
static void
|
||||
append_bool (BroadwayOutput *output, gboolean val)
|
||||
{
|
||||
if (output->binary)
|
||||
g_string_append_c (output->buf, val ? 1: 0);
|
||||
else
|
||||
g_string_append_c (output->buf, val ? '1': '0');
|
||||
g_string_append_c (output->buf, val ? 1: 0);
|
||||
}
|
||||
|
||||
static void
|
||||
append_flags (BroadwayOutput *output, guint32 val)
|
||||
{
|
||||
if (output->binary)
|
||||
g_string_append_c (output->buf, val);
|
||||
else
|
||||
g_string_append_c (output->buf, val + '0');
|
||||
g_string_append_c (output->buf, val);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
append_uint16 (BroadwayOutput *output, guint32 v)
|
||||
{
|
||||
gsize old_len = output->buf->len;
|
||||
guint8 *buf;
|
||||
|
||||
if (output->binary)
|
||||
{
|
||||
g_string_set_size (output->buf, old_len + 2);
|
||||
buf = (guint8 *)output->buf->str + old_len;
|
||||
buf[0] = (v >> 0) & 0xff;
|
||||
buf[1] = (v >> 8) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_set_size (output->buf, old_len + 3);
|
||||
base64_uint16 (v, output->buf->str + old_len);
|
||||
}
|
||||
g_string_set_size (output->buf, old_len + 2);
|
||||
buf = (guint8 *)output->buf->str + old_len;
|
||||
buf[0] = (v >> 0) & 0xff;
|
||||
buf[1] = (v >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -380,38 +182,23 @@ append_uint32 (BroadwayOutput *output, guint32 v)
|
||||
gsize old_len = output->buf->len;
|
||||
guint8 *buf;
|
||||
|
||||
if (output->binary)
|
||||
{
|
||||
g_string_set_size (output->buf, old_len + 4);
|
||||
buf = (guint8 *)output->buf->str + old_len;
|
||||
buf[0] = (v >> 0) & 0xff;
|
||||
buf[1] = (v >> 8) & 0xff;
|
||||
buf[2] = (v >> 16) & 0xff;
|
||||
buf[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_set_size (output->buf, old_len + 6);
|
||||
base64_uint32 (v, output->buf->str + old_len);
|
||||
}
|
||||
g_string_set_size (output->buf, old_len + 4);
|
||||
buf = (guint8 *)output->buf->str + old_len;
|
||||
buf[0] = (v >> 0) & 0xff;
|
||||
buf[1] = (v >> 8) & 0xff;
|
||||
buf[2] = (v >> 16) & 0xff;
|
||||
buf[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static void
|
||||
overwrite_uint32 (BroadwayOutput *output, gsize pos, guint32 v)
|
||||
{
|
||||
if (output->binary)
|
||||
{
|
||||
guint8 *buf = (guint8 *)output->buf->str + pos;
|
||||
guint8 *buf = (guint8 *)output->buf->str + pos;
|
||||
|
||||
buf[0] = (v >> 0) & 0xff;
|
||||
buf[1] = (v >> 8) & 0xff;
|
||||
buf[2] = (v >> 16) & 0xff;
|
||||
buf[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
base64_uint32 (v, output->buf->str + pos);
|
||||
}
|
||||
buf[0] = (v >> 0) & 0xff;
|
||||
buf[1] = (v >> 8) & 0xff;
|
||||
buf[2] = (v >> 16) & 0xff;
|
||||
buf[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
@ -576,10 +363,7 @@ broadway_output_put_rgb (BroadwayOutput *output, int id, int x, int y,
|
||||
append_uint32 (output, 0);
|
||||
|
||||
image_start = output->buf->len;
|
||||
if (output->binary)
|
||||
to_png_rgb (output->buf, w, h, byte_stride, (guint32*)data);
|
||||
else
|
||||
to_png_url_rgb (output->buf, w, h, byte_stride, (guint32*)data);
|
||||
to_png_rgb (output->buf, w, h, byte_stride, (guint32*)data);
|
||||
|
||||
len = output->buf->len - image_start;
|
||||
|
||||
@ -834,14 +618,9 @@ broadway_output_put_rgba (BroadwayOutput *output, int id, int x, int y,
|
||||
image_start = output->buf->len;
|
||||
|
||||
subdata = (guint8 *)data + rects[i].x1 * 4 + rects[i].y1 * byte_stride;
|
||||
if (output->binary)
|
||||
to_png_rgba (output->buf, rects[i].x2 - rects[i].x1,
|
||||
rects[i].y2 - rects[i].y1,
|
||||
byte_stride, (guint32*)subdata);
|
||||
else
|
||||
to_png_url_rgba (output->buf, rects[i].x2 - rects[i].x1,
|
||||
rects[i].y2 - rects[i].y1,
|
||||
byte_stride, (guint32*)subdata);
|
||||
to_png_rgba (output->buf, rects[i].x2 - rects[i].x1,
|
||||
rects[i].y2 - rects[i].y1,
|
||||
byte_stride, (guint32*)subdata);
|
||||
|
||||
len = output->buf->len - image_start;
|
||||
|
||||
|
@ -17,9 +17,7 @@ typedef enum {
|
||||
} BroadwayWSOpCode;
|
||||
|
||||
BroadwayOutput *broadway_output_new (GOutputStream *out,
|
||||
guint32 serial,
|
||||
gboolean proto_v7_plus,
|
||||
gboolean binary);
|
||||
guint32 serial);
|
||||
void broadway_output_free (BroadwayOutput *output);
|
||||
int broadway_output_flush (BroadwayOutput *output);
|
||||
int broadway_output_has_error (BroadwayOutput *output);
|
||||
|
@ -96,8 +96,6 @@ struct BroadwayInput {
|
||||
GSource *source;
|
||||
gboolean seen_time;
|
||||
gint64 time_base;
|
||||
gboolean proto_v7_plus;
|
||||
gboolean binary;
|
||||
gboolean active;
|
||||
};
|
||||
|
||||
@ -557,138 +555,97 @@ hex_dump (guchar *data, gsize len)
|
||||
static void
|
||||
parse_input (BroadwayInput *input)
|
||||
{
|
||||
BroadwayServer *server = input->server;
|
||||
|
||||
if (!input->buffer->len)
|
||||
return;
|
||||
|
||||
if (input->proto_v7_plus)
|
||||
hex_dump (input->buffer->data, input->buffer->len);
|
||||
|
||||
while (input->buffer->len > 2)
|
||||
{
|
||||
hex_dump (input->buffer->data, input->buffer->len);
|
||||
gsize len, payload_len;
|
||||
BroadwayWSOpCode code;
|
||||
gboolean is_mask, fin;
|
||||
guchar *buf, *data, *mask;
|
||||
|
||||
while (input->buffer->len > 2)
|
||||
{
|
||||
gsize len, payload_len;
|
||||
BroadwayWSOpCode code;
|
||||
gboolean is_mask, fin;
|
||||
guchar *buf, *data, *mask;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mask = NULL;
|
||||
if (is_mask)
|
||||
{
|
||||
if (data - buf + 4 > len)
|
||||
return;
|
||||
mask = data;
|
||||
data += 4;
|
||||
}
|
||||
|
||||
if (data - buf + payload_len > len)
|
||||
return; /* wait to accumulate more */
|
||||
|
||||
if (is_mask)
|
||||
{
|
||||
gsize i;
|
||||
for (i = 0; i < payload_len; i++)
|
||||
data[i] ^= mask[i%4];
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
char *terminated = g_strndup((char *)data, payload_len);
|
||||
parse_input_message (input, terminated);
|
||||
g_free (terminated);
|
||||
}
|
||||
break;
|
||||
case BROADWAY_WS_CNX_PING:
|
||||
broadway_output_pong (input->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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
buf = input->buffer->data;
|
||||
len = input->buffer->len;
|
||||
|
||||
if (buf[0] != 0)
|
||||
{
|
||||
if (server->input == input)
|
||||
server->input = NULL;
|
||||
broadway_input_free (input);
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG_WEBSOCKETS
|
||||
g_print ("Parse input first byte 0x%2x 0x%2x\n", buf[0], buf[1]);
|
||||
#endif
|
||||
|
||||
while ((ptr = memchr (buf, 0xff, len)) != NULL)
|
||||
{
|
||||
*ptr = 0;
|
||||
ptr++;
|
||||
fin = buf[0] & 0x80;
|
||||
code = buf[0] & 0x0f;
|
||||
payload_len = buf[1] & 0x7f;
|
||||
is_mask = buf[1] & 0x80;
|
||||
data = buf + 2;
|
||||
|
||||
parse_input_message (input, buf + 1);
|
||||
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;
|
||||
}
|
||||
|
||||
len -= ptr - buf;
|
||||
buf = ptr;
|
||||
mask = NULL;
|
||||
if (is_mask)
|
||||
{
|
||||
if (data - buf + 4 > len)
|
||||
return;
|
||||
mask = data;
|
||||
data += 4;
|
||||
}
|
||||
|
||||
if (len > 0 && buf[0] != 0)
|
||||
{
|
||||
if (server->input == input)
|
||||
server->input = NULL;
|
||||
broadway_input_free (input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_byte_array_remove_range (input->buffer, 0, buf - (char *)input->buffer->data);
|
||||
if (data - buf + payload_len > len)
|
||||
return; /* wait to accumulate more */
|
||||
|
||||
if (is_mask)
|
||||
{
|
||||
gsize i;
|
||||
for (i = 0; i < payload_len; i++)
|
||||
data[i] ^= mask[i%4];
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
char *terminated = g_strndup((char *)data, payload_len);
|
||||
parse_input_message (input, terminated);
|
||||
g_free (terminated);
|
||||
}
|
||||
break;
|
||||
case BROADWAY_WS_CNX_PING:
|
||||
broadway_output_pong (input->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;
|
||||
}
|
||||
}
|
||||
|
||||
g_byte_array_remove_range (input->buffer, 0, data - buf + payload_len);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1002,25 +959,18 @@ generate_handshake_response_wsietf_v7 (const gchar *key)
|
||||
}
|
||||
|
||||
static void
|
||||
start_input (HttpRequest *request, gboolean binary)
|
||||
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;
|
||||
BroadwayInput *input;
|
||||
const void *data_buffer;
|
||||
gsize data_buffer_size;
|
||||
GInputStream *in;
|
||||
char *key_v7;
|
||||
gboolean proto_v7_plus;
|
||||
char *key;
|
||||
GSocket *socket;
|
||||
int flag = 1;
|
||||
|
||||
@ -1029,61 +979,19 @@ start_input (HttpRequest *request, gboolean binary)
|
||||
#endif
|
||||
lines = g_strsplit (request->request->str, "\n", 0);
|
||||
|
||||
num_key1 = 0;
|
||||
num_key2 = 0;
|
||||
key1 = 0;
|
||||
key2 = 0;
|
||||
key_v7 = NULL;
|
||||
key = NULL;
|
||||
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], "Sec-WebSocket-Key")))
|
||||
{
|
||||
key_v7 = p;
|
||||
}
|
||||
if ((p = parse_line (lines[i], "Sec-WebSocket-Key")))
|
||||
key = p;
|
||||
else if ((p = parse_line (lines[i], "Origin")))
|
||||
{
|
||||
origin = p;
|
||||
}
|
||||
origin = p;
|
||||
else if ((p = parse_line (lines[i], "Host")))
|
||||
{
|
||||
host = p;
|
||||
}
|
||||
host = p;
|
||||
else if ((p = parse_line (lines[i], "Sec-WebSocket-Origin")))
|
||||
{
|
||||
origin = p;
|
||||
}
|
||||
origin = p;
|
||||
}
|
||||
|
||||
if (host == NULL)
|
||||
@ -1093,9 +1001,9 @@ start_input (HttpRequest *request, gboolean binary)
|
||||
return;
|
||||
}
|
||||
|
||||
if (key_v7 != NULL)
|
||||
if (key != NULL)
|
||||
{
|
||||
char* accept = generate_handshake_response_wsietf_v7 (key_v7);
|
||||
char* accept = generate_handshake_response_wsietf_v7 (key);
|
||||
res = g_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
@ -1115,58 +1023,12 @@ start_input (HttpRequest *request, gboolean binary)
|
||||
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;
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
res = g_strdup_printf ("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
|
||||
"Upgrade: WebSocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"%s%s%s"
|
||||
"Sec-WebSocket-Location: ws://%s/socket\r\n"
|
||||
"Sec-WebSocket-Protocol: broadway\r\n"
|
||||
"\r\n",
|
||||
origin?"Sec-WebSocket-Origin: ":"", origin?origin:"", origin?"\r\n":"",
|
||||
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;
|
||||
g_strfreev (lines);
|
||||
send_error (request, 400, "Bad websocket request");
|
||||
return;
|
||||
}
|
||||
|
||||
socket = g_socket_connection_get_socket (request->connection);
|
||||
@ -1176,16 +1038,13 @@ start_input (HttpRequest *request, gboolean binary)
|
||||
input = g_new0 (BroadwayInput, 1);
|
||||
input->server = request->server;
|
||||
input->connection = g_object_ref (request->connection);
|
||||
input->proto_v7_plus = proto_v7_plus;
|
||||
input->binary = binary;
|
||||
|
||||
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);
|
||||
g_byte_array_append (input->buffer, data_buffer, data_buffer_size);
|
||||
|
||||
input->output =
|
||||
broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
|
||||
0, proto_v7_plus, binary);
|
||||
broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)), 0);
|
||||
|
||||
/* This will free and close the data input stream, but we got all the buffered content already */
|
||||
http_request_free (request);
|
||||
@ -1316,9 +1175,7 @@ got_request (HttpRequest *request)
|
||||
else if (strcmp (escaped, "/broadway.js") == 0)
|
||||
send_data (request, "text/javascript", broadway_js, G_N_ELEMENTS(broadway_js) - 1);
|
||||
else if (strcmp (escaped, "/socket") == 0)
|
||||
start_input (request, FALSE);
|
||||
else if (strcmp (escaped, "/socket-bin") == 0)
|
||||
start_input (request, TRUE);
|
||||
start_input (request);
|
||||
else
|
||||
send_error (request, 404, "File not found");
|
||||
|
||||
|
@ -67,71 +67,6 @@ function logStackTrace(len) {
|
||||
log(callstack[i]);
|
||||
}
|
||||
|
||||
var base64Values = [
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
|
||||
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
|
||||
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255
|
||||
];
|
||||
|
||||
function base64_8(str, index) {
|
||||
var v =
|
||||
(base64Values[str.charCodeAt(index)]) +
|
||||
(base64Values[str.charCodeAt(index+1)] << 6);
|
||||
return v;
|
||||
}
|
||||
|
||||
function base64_16(str, index) {
|
||||
var v =
|
||||
(base64Values[str.charCodeAt(index)]) +
|
||||
(base64Values[str.charCodeAt(index+1)] << 6) +
|
||||
(base64Values[str.charCodeAt(index+2)] << 12);
|
||||
return v;
|
||||
}
|
||||
|
||||
function base64_16s(str, index) {
|
||||
var v = base64_16(str, index);
|
||||
if (v > 32767)
|
||||
return v - 65536;
|
||||
else
|
||||
return v;
|
||||
}
|
||||
|
||||
function base64_24(str, index) {
|
||||
var v =
|
||||
(base64Values[str.charCodeAt(index)]) +
|
||||
(base64Values[str.charCodeAt(index+1)] << 6) +
|
||||
(base64Values[str.charCodeAt(index+2)] << 12) +
|
||||
(base64Values[str.charCodeAt(index+3)] << 18);
|
||||
return v;
|
||||
}
|
||||
|
||||
function base64_32(str, index) {
|
||||
var v =
|
||||
(base64Values[str.charCodeAt(index)]) +
|
||||
(base64Values[str.charCodeAt(index+1)] << 6) +
|
||||
(base64Values[str.charCodeAt(index+2)] << 12) +
|
||||
(base64Values[str.charCodeAt(index+3)] << 18) +
|
||||
(base64Values[str.charCodeAt(index+4)] << 24) +
|
||||
(base64Values[str.charCodeAt(index+5)] << 30);
|
||||
return v;
|
||||
}
|
||||
|
||||
function createXHR()
|
||||
{
|
||||
try { return new XMLHttpRequest(); } catch(e) {}
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
|
||||
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resizeCanvas(canvas, w, h)
|
||||
{
|
||||
/* Canvas resize clears the data, so we need to save it first */
|
||||
@ -653,45 +588,6 @@ function handleOutstanding()
|
||||
}
|
||||
}
|
||||
|
||||
function TextCommands(message) {
|
||||
this.data = message;
|
||||
this.length = message.length;
|
||||
this.pos = 0;
|
||||
}
|
||||
|
||||
TextCommands.prototype.get_char = function() {
|
||||
return this.data[this.pos++];
|
||||
};
|
||||
TextCommands.prototype.get_bool = function() {
|
||||
return this.get_char() == '1';
|
||||
};
|
||||
TextCommands.prototype.get_flags = function() {
|
||||
return this.get_char() - 48;
|
||||
}
|
||||
TextCommands.prototype.get_16 = function() {
|
||||
var n = base64_16(this.data, this.pos);
|
||||
this.pos = this.pos + 3;
|
||||
return n;
|
||||
};
|
||||
TextCommands.prototype.get_16s = function() {
|
||||
var n = base64_16s(this.data, this.pos);
|
||||
this.pos = this.pos + 3;
|
||||
return n;
|
||||
};
|
||||
TextCommands.prototype.get_32 = function() {
|
||||
var n = base64_32(this.data, this.pos);
|
||||
this.pos = this.pos + 6;
|
||||
return n;
|
||||
};
|
||||
TextCommands.prototype.get_image_url = function() {
|
||||
var size = this.get_32();
|
||||
var url = this.data.slice(this.pos, this.pos + size);
|
||||
this.pos = this.pos + size;
|
||||
return url;
|
||||
};
|
||||
TextCommands.prototype.free_image_url = function(url) {
|
||||
};
|
||||
|
||||
function BinCommands(message) {
|
||||
this.arraybuffer = message;
|
||||
this.u8 = new Uint8Array(message);
|
||||
@ -748,11 +644,7 @@ BinCommands.prototype.free_image_url = function(url) {
|
||||
|
||||
function handleMessage(message)
|
||||
{
|
||||
var cmd;
|
||||
if (message instanceof ArrayBuffer)
|
||||
cmd = new BinCommands(message);
|
||||
else
|
||||
cmd = new TextCommands(message);
|
||||
var cmd = new BinCommands(message);
|
||||
outstandingCommands.push(cmd);
|
||||
if (outstandingCommands.length == 1) {
|
||||
handleOutstanding();
|
||||
@ -2614,18 +2506,6 @@ function setupDocument(document)
|
||||
}
|
||||
}
|
||||
|
||||
function newWS(loc) {
|
||||
var ws = null;
|
||||
if ("WebSocket" in window) {
|
||||
ws = new WebSocket(loc, "broadway");
|
||||
} else if ("MozWebSocket" in window) { // Firefox 6
|
||||
ws = new MozWebSocket(loc);
|
||||
} else {
|
||||
alert("WebSocket not supported, broadway will not work!");
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
setupDocument(document);
|
||||
@ -2677,14 +2557,8 @@ function connect()
|
||||
|
||||
var loc = window.location.toString().replace("http:", "ws:").replace("https:", "wss:");
|
||||
loc = loc.substr(0, loc.lastIndexOf('/')) + "/socket";
|
||||
|
||||
var supports_binary = newWS (loc + "-test").binaryType == "blob";
|
||||
if (supports_binary) {
|
||||
ws = newWS (loc + "-bin");
|
||||
ws.binaryType = "arraybuffer";
|
||||
} else {
|
||||
ws = newWS (loc);
|
||||
}
|
||||
ws = new WebSocket(loc, "broadway");
|
||||
ws.binaryType = "arraybuffer";
|
||||
|
||||
ws.onopen = function() {
|
||||
inputSocket = ws;
|
||||
|
Loading…
Reference in New Issue
Block a user