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