1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci#include "extension-permessage-deflate.h"
28d4afb5ceSopenharmony_ci
29d4afb5ceSopenharmony_civoid
30d4afb5ceSopenharmony_cilws_context_init_extensions(const struct lws_context_creation_info *info,
31d4afb5ceSopenharmony_ci			    struct lws_context *context)
32d4afb5ceSopenharmony_ci{
33d4afb5ceSopenharmony_ci	lwsl_cx_info(context, " LWS_MAX_EXTENSIONS_ACTIVE: %u", LWS_MAX_EXTENSIONS_ACTIVE);
34d4afb5ceSopenharmony_ci}
35d4afb5ceSopenharmony_ci
36d4afb5ceSopenharmony_cienum lws_ext_option_parser_states {
37d4afb5ceSopenharmony_ci	LEAPS_SEEK_NAME,
38d4afb5ceSopenharmony_ci	LEAPS_EAT_NAME,
39d4afb5ceSopenharmony_ci	LEAPS_SEEK_VAL,
40d4afb5ceSopenharmony_ci	LEAPS_EAT_DEC,
41d4afb5ceSopenharmony_ci	LEAPS_SEEK_ARG_TERM
42d4afb5ceSopenharmony_ci};
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_ciint
45d4afb5ceSopenharmony_cilws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
46d4afb5ceSopenharmony_ci		      void *ext_user, const struct lws_ext_options *opts,
47d4afb5ceSopenharmony_ci		      const char *in, int len)
48d4afb5ceSopenharmony_ci{
49d4afb5ceSopenharmony_ci	enum lws_ext_option_parser_states leap = LEAPS_SEEK_NAME;
50d4afb5ceSopenharmony_ci	unsigned int match_map = 0, n, m, w = 0, count_options = 0,
51d4afb5ceSopenharmony_ci		     pending_close_quote = 0;
52d4afb5ceSopenharmony_ci	struct lws_ext_option_arg oa;
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ci	oa.option_name = NULL;
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_ci	while (opts[count_options].name)
57d4afb5ceSopenharmony_ci		count_options++;
58d4afb5ceSopenharmony_ci	while (len) {
59d4afb5ceSopenharmony_ci		lwsl_wsi_ext(wsi, "'%c' %d", *in, leap);
60d4afb5ceSopenharmony_ci		switch (leap) {
61d4afb5ceSopenharmony_ci		case LEAPS_SEEK_NAME:
62d4afb5ceSopenharmony_ci			if (*in == ' ')
63d4afb5ceSopenharmony_ci				break;
64d4afb5ceSopenharmony_ci			if (*in == ',') {
65d4afb5ceSopenharmony_ci				len = 1;
66d4afb5ceSopenharmony_ci				break;
67d4afb5ceSopenharmony_ci			}
68d4afb5ceSopenharmony_ci			match_map = (unsigned int)(1 << count_options) - 1;
69d4afb5ceSopenharmony_ci			leap = LEAPS_EAT_NAME;
70d4afb5ceSopenharmony_ci			w = 0;
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_ci		/* fallthru */
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci		case LEAPS_EAT_NAME:
75d4afb5ceSopenharmony_ci			oa.start = NULL;
76d4afb5ceSopenharmony_ci			oa.len = 0;
77d4afb5ceSopenharmony_ci			m = match_map;
78d4afb5ceSopenharmony_ci			n = 0;
79d4afb5ceSopenharmony_ci			pending_close_quote = 0;
80d4afb5ceSopenharmony_ci			while (m) {
81d4afb5ceSopenharmony_ci				if (!(m & 1)) {
82d4afb5ceSopenharmony_ci					m >>= 1;
83d4afb5ceSopenharmony_ci					n++;
84d4afb5ceSopenharmony_ci					continue;
85d4afb5ceSopenharmony_ci				}
86d4afb5ceSopenharmony_ci				lwsl_wsi_ext(wsi, "    m=%d, n=%d, w=%d", m, n, w);
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_ci				if (*in == opts[n].name[w]) {
89d4afb5ceSopenharmony_ci					if (!opts[n].name[w + 1]) {
90d4afb5ceSopenharmony_ci						oa.option_index = (int)n;
91d4afb5ceSopenharmony_ci						lwsl_wsi_ext(wsi, "hit %d",
92d4afb5ceSopenharmony_ci							 oa.option_index);
93d4afb5ceSopenharmony_ci						leap = LEAPS_SEEK_VAL;
94d4afb5ceSopenharmony_ci						if (len == 1)
95d4afb5ceSopenharmony_ci							goto set_arg;
96d4afb5ceSopenharmony_ci						break;
97d4afb5ceSopenharmony_ci					}
98d4afb5ceSopenharmony_ci				} else {
99d4afb5ceSopenharmony_ci					match_map &= (unsigned int)~(1 << n);
100d4afb5ceSopenharmony_ci					if (!match_map) {
101d4afb5ceSopenharmony_ci						lwsl_wsi_ext(wsi, "empty match map");
102d4afb5ceSopenharmony_ci						return -1;
103d4afb5ceSopenharmony_ci					}
104d4afb5ceSopenharmony_ci				}
105d4afb5ceSopenharmony_ci
106d4afb5ceSopenharmony_ci				m >>= 1;
107d4afb5ceSopenharmony_ci				n++;
108d4afb5ceSopenharmony_ci			}
109d4afb5ceSopenharmony_ci			w++;
110d4afb5ceSopenharmony_ci			break;
111d4afb5ceSopenharmony_ci		case LEAPS_SEEK_VAL:
112d4afb5ceSopenharmony_ci			if (*in == ' ')
113d4afb5ceSopenharmony_ci				break;
114d4afb5ceSopenharmony_ci			if (*in == ',') {
115d4afb5ceSopenharmony_ci				len = 1;
116d4afb5ceSopenharmony_ci				break;
117d4afb5ceSopenharmony_ci			}
118d4afb5ceSopenharmony_ci			if (*in == ';' || len == 1) { /* ie,nonoptional */
119d4afb5ceSopenharmony_ci				if (opts[oa.option_index].type == EXTARG_DEC)
120d4afb5ceSopenharmony_ci					return -1;
121d4afb5ceSopenharmony_ci				leap = LEAPS_SEEK_NAME;
122d4afb5ceSopenharmony_ci				goto set_arg;
123d4afb5ceSopenharmony_ci			}
124d4afb5ceSopenharmony_ci			if (*in == '=') {
125d4afb5ceSopenharmony_ci				w = 0;
126d4afb5ceSopenharmony_ci				pending_close_quote = 0;
127d4afb5ceSopenharmony_ci				if (opts[oa.option_index].type == EXTARG_NONE)
128d4afb5ceSopenharmony_ci					return -1;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci				leap = LEAPS_EAT_DEC;
131d4afb5ceSopenharmony_ci				break;
132d4afb5ceSopenharmony_ci			}
133d4afb5ceSopenharmony_ci			return -1;
134d4afb5ceSopenharmony_ci
135d4afb5ceSopenharmony_ci		case LEAPS_EAT_DEC:
136d4afb5ceSopenharmony_ci			if (*in >= '0' && *in <= '9') {
137d4afb5ceSopenharmony_ci				if (!w)
138d4afb5ceSopenharmony_ci					oa.start = in;
139d4afb5ceSopenharmony_ci				w++;
140d4afb5ceSopenharmony_ci				if (len != 1)
141d4afb5ceSopenharmony_ci					break;
142d4afb5ceSopenharmony_ci			}
143d4afb5ceSopenharmony_ci			if (!w && *in =='"') {
144d4afb5ceSopenharmony_ci				pending_close_quote = 1;
145d4afb5ceSopenharmony_ci				break;
146d4afb5ceSopenharmony_ci			}
147d4afb5ceSopenharmony_ci			if (!w)
148d4afb5ceSopenharmony_ci				return -1;
149d4afb5ceSopenharmony_ci			if (pending_close_quote && *in != '"' && len != 1)
150d4afb5ceSopenharmony_ci				return -1;
151d4afb5ceSopenharmony_ci			leap = LEAPS_SEEK_ARG_TERM;
152d4afb5ceSopenharmony_ci			if (oa.start)
153d4afb5ceSopenharmony_ci				oa.len = lws_ptr_diff(in, oa.start);
154d4afb5ceSopenharmony_ci			if (len == 1)
155d4afb5ceSopenharmony_ci				oa.len++;
156d4afb5ceSopenharmony_ci
157d4afb5ceSopenharmony_ciset_arg:
158d4afb5ceSopenharmony_ci			ext->callback(lws_get_context(wsi),
159d4afb5ceSopenharmony_ci				ext, wsi, LWS_EXT_CB_OPTION_SET,
160d4afb5ceSopenharmony_ci				ext_user, (char *)&oa, 0);
161d4afb5ceSopenharmony_ci			if (len == 1)
162d4afb5ceSopenharmony_ci				break;
163d4afb5ceSopenharmony_ci			if (pending_close_quote && *in == '"')
164d4afb5ceSopenharmony_ci				break;
165d4afb5ceSopenharmony_ci
166d4afb5ceSopenharmony_ci			/* fallthru */
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci		case LEAPS_SEEK_ARG_TERM:
169d4afb5ceSopenharmony_ci			if (*in == ' ')
170d4afb5ceSopenharmony_ci				break;
171d4afb5ceSopenharmony_ci			if (*in == ';') {
172d4afb5ceSopenharmony_ci				leap = LEAPS_SEEK_NAME;
173d4afb5ceSopenharmony_ci				break;
174d4afb5ceSopenharmony_ci			}
175d4afb5ceSopenharmony_ci			if (*in == ',') {
176d4afb5ceSopenharmony_ci				len = 1;
177d4afb5ceSopenharmony_ci				break;
178d4afb5ceSopenharmony_ci			}
179d4afb5ceSopenharmony_ci			return -1;
180d4afb5ceSopenharmony_ci		}
181d4afb5ceSopenharmony_ci		len--;
182d4afb5ceSopenharmony_ci		in++;
183d4afb5ceSopenharmony_ci	}
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci	return 0;
186d4afb5ceSopenharmony_ci}
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci/* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */
190d4afb5ceSopenharmony_ci
191d4afb5ceSopenharmony_ciint lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len)
192d4afb5ceSopenharmony_ci{
193d4afb5ceSopenharmony_ci	int n, m, handled = 0;
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci	if (!wsi->ws)
196d4afb5ceSopenharmony_ci		return 0;
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci	for (n = 0; n < wsi->ws->count_act_ext; n++) {
199d4afb5ceSopenharmony_ci		m = wsi->ws->active_extensions[n]->callback(
200d4afb5ceSopenharmony_ci			lws_get_context(wsi), wsi->ws->active_extensions[n],
201d4afb5ceSopenharmony_ci			wsi, (enum lws_extension_callback_reasons)reason, wsi->ws->act_ext_user[n], arg, (size_t)len);
202d4afb5ceSopenharmony_ci		if (m < 0) {
203d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "Ext '%s' failed to handle callback %d!",
204d4afb5ceSopenharmony_ci				 wsi->ws->active_extensions[n]->name, reason);
205d4afb5ceSopenharmony_ci			return -1;
206d4afb5ceSopenharmony_ci		}
207d4afb5ceSopenharmony_ci		/* valgrind... */
208d4afb5ceSopenharmony_ci		if (reason == LWS_EXT_CB_DESTROY)
209d4afb5ceSopenharmony_ci			wsi->ws->act_ext_user[n] = NULL;
210d4afb5ceSopenharmony_ci		if (m > handled)
211d4afb5ceSopenharmony_ci			handled = m;
212d4afb5ceSopenharmony_ci	}
213d4afb5ceSopenharmony_ci
214d4afb5ceSopenharmony_ci	return handled;
215d4afb5ceSopenharmony_ci}
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ciint lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi,
218d4afb5ceSopenharmony_ci			int reason, void *arg, int len)
219d4afb5ceSopenharmony_ci{
220d4afb5ceSopenharmony_ci	int n = 0, m, handled = 0;
221d4afb5ceSopenharmony_ci	const struct lws_extension *ext;
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	if (!wsi || !wsi->a.vhost || !wsi->ws)
224d4afb5ceSopenharmony_ci		return 0;
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	ext = wsi->a.vhost->ws.extensions;
227d4afb5ceSopenharmony_ci
228d4afb5ceSopenharmony_ci	while (ext && ext->callback && !handled) {
229d4afb5ceSopenharmony_ci		m = ext->callback(context, ext, wsi, (enum lws_extension_callback_reasons)reason,
230d4afb5ceSopenharmony_ci				  (void *)(lws_intptr_t)n, arg, (size_t)len);
231d4afb5ceSopenharmony_ci		if (m < 0) {
232d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "Ext '%s' failed to handle callback %d!",
233d4afb5ceSopenharmony_ci				 wsi->ws->active_extensions[n]->name, reason);
234d4afb5ceSopenharmony_ci			return -1;
235d4afb5ceSopenharmony_ci		}
236d4afb5ceSopenharmony_ci		if (m)
237d4afb5ceSopenharmony_ci			handled = 1;
238d4afb5ceSopenharmony_ci
239d4afb5ceSopenharmony_ci		ext++;
240d4afb5ceSopenharmony_ci		n++;
241d4afb5ceSopenharmony_ci	}
242d4afb5ceSopenharmony_ci
243d4afb5ceSopenharmony_ci	return 0;
244d4afb5ceSopenharmony_ci}
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ciint
247d4afb5ceSopenharmony_cilws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len)
248d4afb5ceSopenharmony_ci{
249d4afb5ceSopenharmony_ci	struct lws_tokens ebuf;
250d4afb5ceSopenharmony_ci	int ret, m, n = 0;
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci	ebuf.token = buf;
253d4afb5ceSopenharmony_ci	ebuf.len = (int)len;
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_ci	/*
256d4afb5ceSopenharmony_ci	 * while we have original buf to spill ourselves, or extensions report
257d4afb5ceSopenharmony_ci	 * more in their pipeline
258d4afb5ceSopenharmony_ci	 */
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci	ret = 1;
261d4afb5ceSopenharmony_ci	while (ret == 1) {
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci		/* default to nobody has more to spill */
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_ci		ret = 0;
266d4afb5ceSopenharmony_ci
267d4afb5ceSopenharmony_ci		/* show every extension the new incoming data */
268d4afb5ceSopenharmony_ci		m = lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_TX_PRESEND,
269d4afb5ceSopenharmony_ci				      &ebuf, 0);
270d4afb5ceSopenharmony_ci		if (m < 0)
271d4afb5ceSopenharmony_ci			return -1;
272d4afb5ceSopenharmony_ci		if (m) /* handled */
273d4afb5ceSopenharmony_ci			ret = 1;
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci		if (buf != ebuf.token)
276d4afb5ceSopenharmony_ci			/*
277d4afb5ceSopenharmony_ci			 * extension recreated it:
278d4afb5ceSopenharmony_ci			 * need to buffer this if not all sent
279d4afb5ceSopenharmony_ci			 */
280d4afb5ceSopenharmony_ci			wsi->ws->clean_buffer = 0;
281d4afb5ceSopenharmony_ci
282d4afb5ceSopenharmony_ci		/* assuming they left us something to send, send it */
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ci		if (ebuf.len) {
285d4afb5ceSopenharmony_ci			n = lws_issue_raw(wsi, ebuf.token, (size_t)ebuf.len);
286d4afb5ceSopenharmony_ci			if (n < 0) {
287d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "closing from ext access");
288d4afb5ceSopenharmony_ci				return -1;
289d4afb5ceSopenharmony_ci			}
290d4afb5ceSopenharmony_ci
291d4afb5ceSopenharmony_ci			/* always either sent it all or privately buffered */
292d4afb5ceSopenharmony_ci			if (wsi->ws->clean_buffer)
293d4afb5ceSopenharmony_ci				len = (size_t)n;
294d4afb5ceSopenharmony_ci
295d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "written %d bytes to client", n);
296d4afb5ceSopenharmony_ci		}
297d4afb5ceSopenharmony_ci
298d4afb5ceSopenharmony_ci		/* no extension has more to spill?  Then we can go */
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci		if (!ret)
301d4afb5ceSopenharmony_ci			break;
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_ci		/* we used up what we had */
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci		ebuf.token = NULL;
306d4afb5ceSopenharmony_ci		ebuf.len = 0;
307d4afb5ceSopenharmony_ci
308d4afb5ceSopenharmony_ci		/*
309d4afb5ceSopenharmony_ci		 * Did that leave the pipe choked?
310d4afb5ceSopenharmony_ci		 * Or we had to hold on to some of it?
311d4afb5ceSopenharmony_ci		 */
312d4afb5ceSopenharmony_ci
313d4afb5ceSopenharmony_ci		if (!lws_send_pipe_choked(wsi) && !lws_has_buffered_out(wsi))
314d4afb5ceSopenharmony_ci			/* no we could add more, lets's do that */
315d4afb5ceSopenharmony_ci			continue;
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "choked");
318d4afb5ceSopenharmony_ci
319d4afb5ceSopenharmony_ci		/*
320d4afb5ceSopenharmony_ci		 * Yes, he's choked.  Don't spill the rest now get a callback
321d4afb5ceSopenharmony_ci		 * when he is ready to send and take care of it there
322d4afb5ceSopenharmony_ci		 */
323d4afb5ceSopenharmony_ci		lws_callback_on_writable(wsi);
324d4afb5ceSopenharmony_ci		wsi->ws->extension_data_pending = 1;
325d4afb5ceSopenharmony_ci		ret = 0;
326d4afb5ceSopenharmony_ci	}
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci	return (int)len;
329d4afb5ceSopenharmony_ci}
330d4afb5ceSopenharmony_ci
331d4afb5ceSopenharmony_ciint
332d4afb5ceSopenharmony_cilws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r,
333d4afb5ceSopenharmony_ci			  void *v, size_t len)
334d4afb5ceSopenharmony_ci{
335d4afb5ceSopenharmony_ci	struct lws_context *context = wsi->a.context;
336d4afb5ceSopenharmony_ci	int n, handled = 0;
337d4afb5ceSopenharmony_ci
338d4afb5ceSopenharmony_ci	if (!wsi->ws)
339d4afb5ceSopenharmony_ci		return 0;
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci	/* maybe an extension will take care of it for us */
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_ci	for (n = 0; n < wsi->ws->count_act_ext && !handled; n++) {
344d4afb5ceSopenharmony_ci		if (!wsi->ws->active_extensions[n]->callback)
345d4afb5ceSopenharmony_ci			continue;
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci		handled |= wsi->ws->active_extensions[n]->callback(context,
348d4afb5ceSopenharmony_ci			wsi->ws->active_extensions[n], wsi,
349d4afb5ceSopenharmony_ci			r, wsi->ws->act_ext_user[n], v, len);
350d4afb5ceSopenharmony_ci	}
351d4afb5ceSopenharmony_ci
352d4afb5ceSopenharmony_ci	return handled;
353d4afb5ceSopenharmony_ci}
354d4afb5ceSopenharmony_ci
355d4afb5ceSopenharmony_ciint
356d4afb5ceSopenharmony_cilws_set_extension_option(struct lws *wsi, const char *ext_name,
357d4afb5ceSopenharmony_ci			 const char *opt_name, const char *opt_val)
358d4afb5ceSopenharmony_ci{
359d4afb5ceSopenharmony_ci	struct lws_ext_option_arg oa;
360d4afb5ceSopenharmony_ci	int idx = 0;
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci	if (!wsi->ws)
363d4afb5ceSopenharmony_ci		return 0;
364d4afb5ceSopenharmony_ci
365d4afb5ceSopenharmony_ci	/* first identify if the ext is active on this wsi */
366d4afb5ceSopenharmony_ci	while (idx < wsi->ws->count_act_ext &&
367d4afb5ceSopenharmony_ci	       strcmp(wsi->ws->active_extensions[idx]->name, ext_name))
368d4afb5ceSopenharmony_ci		idx++;
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ci	if (idx == wsi->ws->count_act_ext)
371d4afb5ceSopenharmony_ci		return -1; /* request ext not active on this wsi */
372d4afb5ceSopenharmony_ci
373d4afb5ceSopenharmony_ci	oa.option_name = opt_name;
374d4afb5ceSopenharmony_ci	oa.option_index = 0;
375d4afb5ceSopenharmony_ci	oa.start = opt_val;
376d4afb5ceSopenharmony_ci	oa.len = 0;
377d4afb5ceSopenharmony_ci
378d4afb5ceSopenharmony_ci	return wsi->ws->active_extensions[idx]->callback(wsi->a.context,
379d4afb5ceSopenharmony_ci			wsi->ws->active_extensions[idx], wsi,
380d4afb5ceSopenharmony_ci			LWS_EXT_CB_NAMED_OPTION_SET, wsi->ws->act_ext_user[idx],
381d4afb5ceSopenharmony_ci			&oa, 0);
382d4afb5ceSopenharmony_ci}
383