1 #include "private-libwebsockets.h"
3 #include "extension-permessage-deflate.h"
6 lws_context_init_extensions(struct lws_context_creation_info *info,
7 struct lws_context *context)
9 lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
12 enum lws_ext_option_parser_states {
21 lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
22 void *ext_user, const struct lws_ext_options *opts,
23 const char *in, int len)
25 enum lws_ext_option_parser_states leap = LEAPS_SEEK_NAME;
26 unsigned int match_map = 0, n, m, w = 0, count_options = 0,
27 pending_close_quote = 0;
28 struct lws_ext_option_arg oa;
30 oa.option_name = NULL;
32 while (opts[count_options].name)
35 lwsl_ext("'%c' %d", *in, leap);
44 match_map = (1 << count_options) - 1;
45 leap = LEAPS_EAT_NAME;
55 pending_close_quote = 0;
58 lwsl_ext(" m=%d, n=%d, w=%d\n", m, n, w);
60 if (*in == opts[n].name[w]) {
61 if (!opts[n].name[w + 1]) {
63 lwsl_ext("hit %d\n", oa.option_index);
64 leap = LEAPS_SEEK_VAL;
70 match_map &= ~(1 << n);
72 lwsl_ext("empty match map\n");
89 if (*in == ';' || len == 1) { /* ie,nonoptional */
90 if (opts[oa.option_index].type == EXTARG_DEC)
92 leap = LEAPS_SEEK_NAME;
97 pending_close_quote = 0;
98 if (opts[oa.option_index].type == EXTARG_NONE)
101 leap = LEAPS_EAT_DEC;
107 if (*in >= '0' && *in <= '9') {
114 if (!w && *in =='"') {
115 pending_close_quote = 1;
120 if (pending_close_quote && *in != '"' && len != 1)
122 leap = LEAPS_SEEK_ARG_TERM;
124 oa.len = in - oa.start;
129 ext->callback(lws_get_context(wsi),
130 ext, wsi, LWS_EXT_CB_OPTION_SET,
131 ext_user, (char *)&oa, 0);
134 if (pending_close_quote && *in == '"')
139 case LEAPS_SEEK_ARG_TERM:
143 leap = LEAPS_SEEK_NAME;
160 /* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */
162 int lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len)
164 int n, m, handled = 0;
166 for (n = 0; n < wsi->count_act_ext; n++) {
167 m = wsi->active_extensions[n]->callback(lws_get_context(wsi),
168 wsi->active_extensions[n], wsi, reason,
169 wsi->act_ext_user[n], arg, len);
171 lwsl_ext("Ext '%s' failed to handle callback %d!\n",
172 wsi->active_extensions[n]->name, reason);
176 if (reason == LWS_EXT_CB_DESTROY)
177 wsi->act_ext_user[n] = NULL;
185 int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi,
186 int reason, void *arg, int len)
188 int n = 0, m, handled = 0;
189 const struct lws_extension *ext;
191 if (!wsi || !wsi->vhost)
194 ext = wsi->vhost->extensions;
196 while (ext && ext->callback && !handled) {
197 m = ext->callback(context, ext, wsi, reason,
198 (void *)(long)n, arg, len);
200 lwsl_ext("Ext '%s' failed to handle callback %d!\n",
201 wsi->active_extensions[n]->name, reason);
215 lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len)
217 struct lws_tokens eff_buf;
220 eff_buf.token = (char *)buf;
221 eff_buf.token_len = len;
224 * while we have original buf to spill ourselves, or extensions report
225 * more in their pipeline
231 /* default to nobody has more to spill */
235 /* show every extension the new incoming data */
236 m = lws_ext_cb_active(wsi,
237 LWS_EXT_CB_PACKET_TX_PRESEND, &eff_buf, 0);
243 if ((char *)buf != eff_buf.token)
245 * extension recreated it:
246 * need to buffer this if not all sent
248 wsi->u.ws.clean_buffer = 0;
250 /* assuming they left us something to send, send it */
252 if (eff_buf.token_len) {
253 n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
256 lwsl_info("closing from ext access\n");
260 /* always either sent it all or privately buffered */
261 if (wsi->u.ws.clean_buffer)
265 lwsl_parser("written %d bytes to client\n", n);
267 /* no extension has more to spill? Then we can go */
272 /* we used up what we had */
274 eff_buf.token = NULL;
275 eff_buf.token_len = 0;
278 * Did that leave the pipe choked?
279 * Or we had to hold on to some of it?
282 if (!lws_send_pipe_choked(wsi) && !wsi->trunc_len)
283 /* no we could add more, lets's do that */
286 lwsl_debug("choked\n");
289 * Yes, he's choked. Don't spill the rest now get a callback
290 * when he is ready to send and take care of it there
292 lws_callback_on_writable(wsi);
293 wsi->extension_data_pending = 1;
301 lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r,
304 struct lws_context *context = wsi->context;
307 /* maybe an extension will take care of it for us */
309 for (n = 0; n < wsi->count_act_ext && !handled; n++) {
310 if (!wsi->active_extensions[n]->callback)
313 handled |= wsi->active_extensions[n]->callback(context,
314 wsi->active_extensions[n], wsi,
315 r, wsi->act_ext_user[n], v, len);
322 lws_set_extension_option(struct lws *wsi, const char *ext_name,
323 const char *opt_name, const char *opt_val)
325 struct lws_ext_option_arg oa;
328 /* first identify if the ext is active on this wsi */
329 while (idx < wsi->count_act_ext &&
330 strcmp(wsi->active_extensions[idx]->name, ext_name))
333 if (idx == wsi->count_act_ext)
334 return -1; /* request ext not active on this wsi */
336 oa.option_name = opt_name;
341 return wsi->active_extensions[idx]->callback(
342 wsi->context, wsi->active_extensions[idx], wsi,
343 LWS_EXT_CB_NAMED_OPTION_SET, wsi->act_ext_user[idx], &oa, 0);