summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndy Green <andy@warmcat.com>2011-05-28 10:19:19 +0100
committerAndy Green <andy@warmcat.com>2011-05-28 10:19:19 +0100
commit0922650b53bf03101c5d5a5a3fb95f5971affc89 (patch)
tree90f361dc5d25312d70941e2ea296f0ccb86880e0 /lib
parent5555c987283361dec4516d26a65081b3d578f5db (diff)
extensions fix deflate stream vs mux and veto it on mux children
This patch gets deflate-stream working with x-google-mux. It adds a clean veto system where are extension can veto the proposal of any extension when opening a new connection. x-google-mux uses that in its callback to defeat any use of deflate-stream on mux children. However deflate stream is allowed on the parent connection and works transparently now alongside x-google-mux. Signed-off-by: Andy Green <andy@warmcat.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/extension-x-google-mux.c32
-rw-r--r--lib/libwebsockets.c21
-rw-r--r--lib/libwebsockets.h1
-rw-r--r--lib/parsers.c155
-rw-r--r--lib/private-libwebsockets.h4
5 files changed, 136 insertions, 77 deletions
diff --git a/lib/extension-x-google-mux.c b/lib/extension-x-google-mux.c
index 13bc461..95253b4 100644
--- a/lib/extension-x-google-mux.c
+++ b/lib/extension-x-google-mux.c
@@ -5,6 +5,7 @@
static int ongoing_subchannel;
static struct libwebsocket * tag_with_parent = NULL;
+static int client_handshake_generation_is_for_mux_child;
static int lws_addheader_mux_opcode(unsigned char *pb, int len)
{
@@ -96,8 +97,10 @@ static int lws_ext_x_google_mux__send_addchannel(
wsi_child->ietf_spec_revision = wsi->ietf_spec_revision;
+ client_handshake_generation_is_for_mux_child = 1;
p = libwebsockets_generate_client_handshake(context, wsi_child,
delta_headers);
+ client_handshake_generation_is_for_mux_child = 0;
delta_headers_len = p - delta_headers;
subcommand_length = lws_mux_subcommand_header(
@@ -122,7 +125,7 @@ static int lws_ext_x_google_mux__send_addchannel(
/* send the request to the server */
- n = lws_issue_raw(wsi, &send_buf[LWS_SEND_BUFFER_PRE_PADDING],
+ n = lws_issue_raw_ext_access(wsi, &send_buf[LWS_SEND_BUFFER_PRE_PADDING],
pb - &send_buf[LWS_SEND_BUFFER_PRE_PADDING]);
parent_conn->defeat_mux_opcode_wrapping = 0;
@@ -443,6 +446,10 @@ bail2:
wsi->xor_mask = xor_no_mask;
child_conn = lws_get_extension_user_matching_ext(wsi_child,
this_ext);
+ if (!child_conn) {
+ fprintf(stderr, "wsi_child %p has no child conn!", (void *)wsi_child);
+ break;
+ }
child_conn->wsi_parent = wsi;
conn->sticky_mux_used = 1;
child_conn->subchannel = conn->block_subchannel;
@@ -526,7 +533,7 @@ bail2:
* afterwards
*/
if (conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET >= conn->highest_child_subchannel) {
- fprintf(stderr, "Illegal subchannel\n");
+ fprintf(stderr, "Illegal subchannel %d\n", conn->block_subchannel);
return -1;
}
@@ -541,6 +548,11 @@ bail2:
} else
wsi_child = conn->wsi_children[conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET];
+ if (!wsi_child) {
+ fprintf(stderr, "Bad subchannel %d\n", conn->block_subchannel);
+ return -1;
+ }
+
switch (wsi_child->mode) {
/* client receives something */
@@ -1078,7 +1090,7 @@ handle_additions:
* recurse to allow nesting
*/
- lws_issue_raw(wsi_parent, basepin, (pin - basepin) + len);
+ lws_issue_raw_ext_access(wsi_parent, basepin, (pin - basepin) + len);
return 1; /* handled */
@@ -1144,7 +1156,7 @@ handle_additions:
memcpy(pb, in, len);
pb += len;
- lws_issue_raw(wsi->extension_handles, &send_buf[LWS_SEND_BUFFER_PRE_PADDING],
+ lws_issue_raw_ext_access(wsi->extension_handles, &send_buf[LWS_SEND_BUFFER_PRE_PADDING],
pb - &send_buf[LWS_SEND_BUFFER_PRE_PADDING]);
@@ -1190,6 +1202,18 @@ handle_additions:
}
break;
+ case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION:
+
+ /* disallow deflate-stream if we are a mux child connection */
+
+ if (strcmp(in, "deflate-stream") == 0 &&
+ client_handshake_generation_is_for_mux_child) {
+
+ fprintf(stderr, "mux banned deflate-stream on child connection\n");
+ return 1; /* disallow */
+ }
+ break;
+
default:
break;
}
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 0021eb4..90e1fbe 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -784,6 +784,7 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
char *p = pkt;
int n;
struct libwebsocket_extension *ext;
+ struct libwebsocket_extension *ext1;
int ext_count = 0;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 + MAX_BROADCAST_PAYLOAD +
LWS_SEND_BUFFER_POST_PADDING];
@@ -957,6 +958,24 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
while (ext && ext->callback) {
n = 0;
+ ext1 = context->extensions;
+ while (ext1 && ext1->callback) {
+
+ n |= ext1->callback(context, ext1, wsi,
+ LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
+ NULL, (char *)ext->name, 0);
+
+ ext1++;
+ }
+
+ if (n) {
+
+ /* an extension vetos us */
+ fprintf(stderr, "ext %s vetoed\n", (char *)ext->name);
+ ext++;
+ continue;
+ }
+
n = context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
wsi->user_space, (char *)ext->name, 0);
@@ -1010,6 +1029,8 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
issue_hdr:
+ puts(pkt);
+
/* done with these now */
free(wsi->c_path);
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 49bf648..2ab918d 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -83,6 +83,7 @@ enum libwebsocket_extension_callback_reasons {
LWS_EXT_CALLBACK_CONSTRUCT,
LWS_EXT_CALLBACK_CLIENT_CONSTRUCT,
LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE,
+ LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
LWS_EXT_CALLBACK_DESTROY,
LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING,
LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED,
diff --git a/lib/parsers.c b/lib/parsers.c
index 3e3ac19..7ad040e 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -1450,6 +1450,87 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
return 0;
}
+int
+lws_issue_raw_ext_access(struct libwebsocket *wsi,
+ unsigned char *buf, size_t len)
+{
+ int ret;
+ struct lws_tokens eff_buf;
+ int m;
+ int n;
+
+ eff_buf.token = (char *)buf;
+ eff_buf.token_len = len;
+
+ /*
+ * while we have original buf to spill ourselves, or extensions report
+ * more in their pipeline
+ */
+
+ ret = 1;
+ while (ret == 1) {
+
+ /* default to nobody has more to spill */
+
+ ret = 0;
+
+ /* show every extension the new incoming data */
+
+ for (n = 0; n < wsi->count_active_extensions; n++) {
+ m = wsi->active_extensions[n]->callback(
+ wsi->protocol->owning_server,
+ wsi->active_extensions[n], wsi,
+ LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
+ wsi->active_extensions_user[n], &eff_buf, 0);
+ if (m < 0) {
+ fprintf(stderr, "Extension reports fatal error\n");
+ return -1;
+ }
+ if (m)
+ /*
+ * at least one extension told us he has more
+ * to spill, so we will go around again after
+ */
+ ret = 1;
+ }
+
+ /* assuming they left us something to send, send it */
+
+ if (eff_buf.token_len)
+ if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
+ eff_buf.token_len))
+ return -1;
+
+ /* we used up what we had */
+
+ eff_buf.token = NULL;
+ eff_buf.token_len = 0;
+
+ /*
+ * Did that leave the pipe choked?
+ */
+
+ if (!lws_send_pipe_choked(wsi))
+ /* no we could add more */
+ continue;
+
+ fprintf(stderr, "choked\n");
+
+ /*
+ * Yes, he's choked. Don't spill the rest now get a callback
+ * when he is ready to send and take care of it there
+ */
+ libwebsocket_callback_on_writable(
+ wsi->protocol->owning_server, wsi);
+ wsi->extension_data_pending = 1;
+ ret = 0;
+ }
+
+ debug("written %d bytes to client\n", eff_buf.token_len);
+
+ return 0;
+}
+
/**
* libwebsocket_write() - Apply protocol then write data to client
* @wsi: Websocket instance (available from user callback)
@@ -1479,12 +1560,9 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
size_t len, enum libwebsocket_write_protocol protocol)
{
int n;
- int m;
int pre = 0;
int post = 0;
int shift = 7;
- struct lws_tokens eff_buf;
- int ret;
int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT && wsi->xor_mask != xor_no_mask;
unsigned char *dropmask = NULL;
unsigned char is_masked_bit = 0;
@@ -1780,76 +1858,7 @@ send_raw:
* callback returns 1 in case it wants to spill more buffers
*/
- eff_buf.token = (char *)buf - pre;
- eff_buf.token_len = len + pre + post;
-
- /*
- * while we have original buf to spill ourselves, or extensions report
- * more in their pipeline
- */
-
- ret = 1;
- while (ret == 1) {
-
- /* default to nobody has more to spill */
-
- ret = 0;
-
- /* show every extension the new incoming data */
-
- for (n = 0; n < wsi->count_active_extensions; n++) {
- m = wsi->active_extensions[n]->callback(
- wsi->protocol->owning_server,
- wsi->active_extensions[n], wsi,
- LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
- wsi->active_extensions_user[n], &eff_buf, 0);
- if (m < 0) {
- fprintf(stderr, "Extension reports fatal error\n");
- return -1;
- }
- if (m)
- /*
- * at least one extension told us he has more
- * to spill, so we will go around again after
- */
- ret = 1;
- }
-
- /* assuming they left us something to send, send it */
-
- if (eff_buf.token_len)
- if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
- eff_buf.token_len))
- return -1;
-
- /* we used up what we had */
-
- eff_buf.token = NULL;
- eff_buf.token_len = 0;
-
- /*
- * Did that leave the pipe choked?
- */
-
- if (!lws_send_pipe_choked(wsi))
- /* no we could add more */
- continue;
-
- fprintf(stderr, "choked\n");
-
- /*
- * Yes, he's choked. Don't spill the rest now get a callback
- * when he is ready to send and take care of it there
- */
- libwebsocket_callback_on_writable(
- wsi->protocol->owning_server, wsi);
- wsi->extension_data_pending = 1;
- ret = 0;
- }
-
- debug("written %d bytes to client\n", eff_buf.token_len);
-
- return 0;
+ return lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post);
}
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index bf2865d..e706bf5 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -415,6 +415,10 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context,
extern int
libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c);
+extern int
+lws_issue_raw_ext_access(struct libwebsocket *wsi,
+ unsigned char *buf, size_t len);
+
#ifndef LWS_OPENSSL_SUPPORT
unsigned char *