diff --git a/README.coding.md b/README.coding.md index f369937d..d03b613a 100644 --- a/README.coding.md +++ b/README.coding.md @@ -394,3 +394,25 @@ LWS_SERVER_OPTION_LIBEV LWS_SERVER_OPTION_LIBUV to indicate it will use either of the event libraries. + + +Extension option control from user code +--------------------------------------- + +User code may set per-connection extension options now, using a new api +"lws_set_extension_option()". + +This should be called from the ESTABLISHED callback like this + + lws_set_extension_option(wsi, "permessage-deflate", + "rx_buf_size", "12"); /* 1 << 12 */ + +If the extension is not active (missing or not negotiated for the +connection, or extensions are disabled on the library) the call is +just returns -1. Otherwise the connection's extension has its +named option changed. + +The extension may decide to alter or disallow the change, in the +example above permessage-deflate restricts the size of his rx +output buffer also considering the protocol's rx_buf_size member. + diff --git a/changelog b/changelog index 3142d559..a13eabef 100644 --- a/changelog +++ b/changelog @@ -185,6 +185,24 @@ LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS. If you give this, non-ssl connections to the server listen port are accepted and receive a 301 redirect to / on the same host and port using https:// +8) User code may set per-connection extension options now, using a new api +"lws_set_extension_option()". + +This should be called from the ESTABLISHED callback like this + + lws_set_extension_option(wsi, "permessage-deflate", + "rx_buf_size", "12"); /* 1 << 12 */ + +If the extension is not active (missing or not negotiated for the +connection, or extensions are disabled on the library) the call is +just returns -1. Otherwise the connection's extension has its +named option changed. + +The extension may decide to alter or disallow the change, in the +example above permessage-deflate restricts the size of his rx +output buffer also considering the protocol's rx_buf_size member. + + New application lwsws --------------------- diff --git a/lib/extension-permessage-deflate.c b/lib/extension-permessage-deflate.c index 3621410f..65f28caa 100644 --- a/lib/extension-permessage-deflate.c +++ b/lib/extension-permessage-deflate.c @@ -41,6 +41,28 @@ const struct lws_ext_options lws_ext_pm_deflate_options[] = { { NULL, 0 }, /* sentinel */ }; +static void +lws_extension_pmdeflate_restrict_args(struct lws *wsi, + struct lws_ext_pm_deflate_priv *priv) +{ + int n, extra; + + /* cap the RX buf at the nearest power of 2 to protocol rx buf */ + + n = LWS_MAX_SOCKET_IO_BUF; + if (wsi->protocol->rx_buffer_size) + n = wsi->protocol->rx_buffer_size; + + extra = 7; + while (n >= 1 << (extra + 1)) + extra++; + + if (extra < priv->args[PMD_RX_BUF_PWR2]) { + priv->args[PMD_RX_BUF_PWR2] = extra; + lwsl_err(" Capping pmd rx to %d\n", 1 << extra); + } +} + LWS_VISIBLE int lws_extension_callback_pm_deflate(struct lws_context *context, const struct lws_extension *ext, @@ -56,6 +78,20 @@ lws_extension_callback_pm_deflate(struct lws_context *context, struct lws_ext_option_arg *oa; switch (reason) { + case LWS_EXT_CB_NAMED_OPTION_SET: + oa = in; + if (!oa->option_name) + break; + for (n = 0; n < ARRAY_SIZE(lws_ext_pm_deflate_options); n++) + if (!strcmp(lws_ext_pm_deflate_options[n].name, oa->option_name)) + break; + + if (n == ARRAY_SIZE(lws_ext_pm_deflate_options)) + break; + oa->option_index = n; + + /* fallthru */ + case LWS_EXT_CB_OPTION_SET: oa = in; lwsl_info("%s: option set: idx %d, %s, len %d\n", __func__, @@ -64,7 +100,10 @@ lws_extension_callback_pm_deflate(struct lws_context *context, priv->args[oa->option_index] = atoi(oa->start); else priv->args[oa->option_index] = 1; + + lws_extension_pmdeflate_restrict_args(wsi, priv); break; + case LWS_EXT_CB_OPTION_CONFIRM: if (priv->args[PMD_SERVER_MAX_WINDOW_BITS] < 8 || priv->args[PMD_SERVER_MAX_WINDOW_BITS] > 15 || @@ -94,7 +133,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context, /* fill in pointer to options list */ if (in) - *((const struct lws_ext_options **)in) = lws_ext_pm_deflate_options; + *((const struct lws_ext_options **)in) = + lws_ext_pm_deflate_options; /* fallthru */ @@ -114,22 +154,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context, priv->args[PMD_COMP_LEVEL] = 1; priv->args[PMD_MEM_LEVEL] = 8; - /* cap the RX buf at the nearest power of 2 to protocol rx buf */ - - n = LWS_MAX_SOCKET_IO_BUF; - if (wsi->protocol->rx_buffer_size) - n = wsi->protocol->rx_buffer_size; - - extra = 7; - while (n >= 1 << (extra + 1)) - extra++; - - if (extra < priv->args[PMD_RX_BUF_PWR2]) { - priv->args[PMD_RX_BUF_PWR2] = extra; - lwsl_err(" Capping pmd rx to %d\n", 1 << extra); - } - lwsl_err(" ok\n"); - + lws_extension_pmdeflate_restrict_args(wsi, priv); break; case LWS_EXT_CB_DESTROY: diff --git a/lib/extension.c b/lib/extension.c index df24dd55..580e8a6c 100644 --- a/lib/extension.c +++ b/lib/extension.c @@ -27,6 +27,8 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi, pending_close_quote = 0; struct lws_ext_option_arg oa; + oa.option_name = NULL; + while (opts[count_options].name) count_options++; while (len) { @@ -315,3 +317,37 @@ lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r return handled; } + +/** + * lws_set_extension_option(): set extension option if possible + * + * @wsi: websocket connection + * @ext_name: name of ext, like "permessage-deflate" + * @opt_name: name of option, like "rx_buf_size" + * @opt_val: value to set option to + */ + +int +lws_set_extension_option(struct lws *wsi, const char *ext_name, + const char *opt_name, const char *opt_val) +{ + struct lws_ext_option_arg oa; + int idx = 0; + + /* first identify if the ext is active on this wsi */ + while (idx < wsi->count_act_ext && + strcmp(wsi->active_extensions[idx]->name, ext_name)) + idx++; + + if (idx == wsi->count_act_ext) + return -1; /* request ext not active on this wsi */ + + oa.option_name = opt_name; + oa.option_index = 0; + oa.start = opt_val; + oa.len = 0; + + return wsi->active_extensions[idx]->callback( + wsi->context, wsi->active_extensions[idx], wsi, + LWS_EXT_CB_NAMED_OPTION_SET, wsi->act_ext_user[idx], &oa, 0); +} diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 99588164..c537c1b5 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -2024,3 +2024,12 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt) return 0; } #endif + +#ifdef LWS_NO_EXTENSIONS +LWS_EXTERN int +lws_set_extension_option(struct lws *wsi, const char *ext_name, + const char *opt_name, const char *opt_val) +{ + return -1; +} +#endif diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 5cbaaadc..41a2c27b 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -514,6 +514,7 @@ enum lws_extension_callback_reasons { LWS_EXT_CB_OPTION_DEFAULT = 23, LWS_EXT_CB_OPTION_SET = 24, LWS_EXT_CB_OPTION_CONFIRM = 25, + LWS_EXT_CB_NAMED_OPTION_SET = 26, /****** add new things just above ---^ ******/ }; @@ -1279,6 +1280,7 @@ struct lws_ext_options { }; struct lws_ext_option_arg { + const char *option_name; /* may be NULL, option_index used then */ int option_index; const char *start; int len; @@ -1331,6 +1333,10 @@ extern int lws_extension_callback_pm_deflate( struct lws *wsi, enum lws_extension_callback_reasons reason, void *user, void *in, size_t len); +LWS_EXTERN int +lws_set_extension_option(struct lws *wsi, const char *ext_name, + const char *opt_name, const char *opt_val); + /** * struct lws_context_creation_info - parameters to create context with