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>
This commit is contained in:
parent
5555c98728
commit
0922650b53
6 changed files with 144 additions and 92 deletions
|
@ -263,25 +263,18 @@ It has the following notes:
|
|||
|
||||
1) To enable it, reconfigure with --enable-x-google-mux
|
||||
|
||||
2) It conflicts with deflate-stream, use the -u switch on
|
||||
the test client to disable deflate-stream
|
||||
|
||||
3) It deviates from the google standard by sending full
|
||||
2) It deviates from the google standard by sending full
|
||||
headers in the addchannel subcommand rather than just
|
||||
changed ones from original connect
|
||||
|
||||
4) Quota is not implemented yet
|
||||
3) Quota is not implemented yet
|
||||
|
||||
5) Close of subchannel is not really implemented yet
|
||||
|
||||
6) Google opcode 0xf is changed to 0x7 to account for
|
||||
v7 protocol changes to opcode layout
|
||||
|
||||
However despite those caveats, in fact it can run the
|
||||
test client reliably over one socket (both dumb-increment
|
||||
and lws-mirror-protocol), you can open a browser on the
|
||||
same test server too and see the circles, etc.
|
||||
However despite those caveats, in fact it can run the
|
||||
test client reliably over one socket (both dumb-increment
|
||||
and lws-mirror-protocol), you can open a browser on the
|
||||
same test server too and see the circles, etc.
|
||||
|
||||
It also works compatibly with deflate-stream automatically.
|
||||
|
||||
2011-05-23 Andy Green <andy@warmcat.com>
|
||||
2011-05-28 Andy Green <andy@warmcat.com>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
155
lib/parsers.c
155
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 *
|
||||
|
|
Loading…
Add table
Reference in a new issue