extension.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #include "private-libwebsockets.h"
  2. #include "extension-permessage-deflate.h"
  3. LWS_VISIBLE void
  4. lws_context_init_extensions(struct lws_context_creation_info *info,
  5. struct lws_context *context)
  6. {
  7. lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
  8. }
  9. enum lws_ext_option_parser_states {
  10. LEAPS_SEEK_NAME,
  11. LEAPS_EAT_NAME,
  12. LEAPS_SEEK_VAL,
  13. LEAPS_EAT_DEC,
  14. LEAPS_SEEK_ARG_TERM
  15. };
  16. LWS_VISIBLE int
  17. lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
  18. void *ext_user, const struct lws_ext_options *opts,
  19. const char *in, int len)
  20. {
  21. enum lws_ext_option_parser_states leap = LEAPS_SEEK_NAME;
  22. unsigned int match_map = 0, n, m, w = 0, count_options = 0,
  23. pending_close_quote = 0;
  24. struct lws_ext_option_arg oa;
  25. oa.option_name = NULL;
  26. while (opts[count_options].name)
  27. count_options++;
  28. while (len) {
  29. lwsl_ext("'%c' %d", *in, leap);
  30. switch (leap) {
  31. case LEAPS_SEEK_NAME:
  32. if (*in == ' ')
  33. break;
  34. if (*in == ',') {
  35. len = 1;
  36. break;
  37. }
  38. match_map = (1 << count_options) - 1;
  39. leap = LEAPS_EAT_NAME;
  40. w = 0;
  41. /* fallthru */
  42. case LEAPS_EAT_NAME:
  43. oa.start = NULL;
  44. oa.len = 0;
  45. m = match_map;
  46. n = 0;
  47. pending_close_quote = 0;
  48. while (m) {
  49. if (m & 1) {
  50. lwsl_ext(" m=%d, n=%d, w=%d\n", m, n, w);
  51. if (*in == opts[n].name[w]) {
  52. if (!opts[n].name[w + 1]) {
  53. oa.option_index = n;
  54. lwsl_ext("hit %d\n", oa.option_index);
  55. leap = LEAPS_SEEK_VAL;
  56. if (len ==1)
  57. goto set_arg;
  58. break;
  59. }
  60. } else {
  61. match_map &= ~(1 << n);
  62. if (!match_map) {
  63. lwsl_ext("empty match map\n");
  64. return -1;
  65. }
  66. }
  67. }
  68. m >>= 1;
  69. n++;
  70. }
  71. w++;
  72. break;
  73. case LEAPS_SEEK_VAL:
  74. if (*in == ' ')
  75. break;
  76. if (*in == ',') {
  77. len = 1;
  78. break;
  79. }
  80. if (*in == ';' || len == 1) { /* ie,nonoptional */
  81. if (opts[oa.option_index].type == EXTARG_DEC)
  82. return -1;
  83. leap = LEAPS_SEEK_NAME;
  84. goto set_arg;
  85. }
  86. if (*in == '=') {
  87. w = 0;
  88. pending_close_quote = 0;
  89. if (opts[oa.option_index].type == EXTARG_NONE)
  90. return -1;
  91. leap = LEAPS_EAT_DEC;
  92. break;
  93. }
  94. return -1;
  95. case LEAPS_EAT_DEC:
  96. if (*in >= '0' && *in <= '9') {
  97. if (!w)
  98. oa.start = in;
  99. w++;
  100. if (len != 1)
  101. break;
  102. }
  103. if (!w && *in =='"') {
  104. pending_close_quote = 1;
  105. break;
  106. }
  107. if (!w)
  108. return -1;
  109. if (pending_close_quote && *in != '"' && len != 1)
  110. return -1;
  111. leap = LEAPS_SEEK_ARG_TERM;
  112. if (oa.start)
  113. oa.len = in - oa.start;
  114. if (len == 1)
  115. oa.len++;
  116. set_arg:
  117. ext->callback(lws_get_context(wsi),
  118. ext, wsi, LWS_EXT_CB_OPTION_SET,
  119. ext_user, (char *)&oa, 0);
  120. if (len == 1)
  121. break;
  122. if (pending_close_quote && *in == '"')
  123. break;
  124. /* fallthru */
  125. case LEAPS_SEEK_ARG_TERM:
  126. if (*in == ' ')
  127. break;
  128. if (*in == ';') {
  129. leap = LEAPS_SEEK_NAME;
  130. break;
  131. }
  132. if (*in == ',') {
  133. len = 1;
  134. break;
  135. }
  136. return -1;
  137. }
  138. len--;
  139. in++;
  140. }
  141. return 0;
  142. }
  143. /* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */
  144. int lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len)
  145. {
  146. int n, m, handled = 0;
  147. for (n = 0; n < wsi->count_act_ext; n++) {
  148. m = wsi->active_extensions[n]->callback(lws_get_context(wsi),
  149. wsi->active_extensions[n], wsi, reason,
  150. wsi->act_ext_user[n], arg, len);
  151. if (m < 0) {
  152. lwsl_ext("Ext '%s' failed to handle callback %d!\n",
  153. wsi->active_extensions[n]->name, reason);
  154. return -1;
  155. }
  156. /* valgrind... */
  157. if (reason == LWS_EXT_CB_DESTROY)
  158. wsi->act_ext_user[n] = NULL;
  159. if (m > handled)
  160. handled = m;
  161. }
  162. return handled;
  163. }
  164. int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi,
  165. int reason, void *arg, int len)
  166. {
  167. int n = 0, m, handled = 0;
  168. const struct lws_extension *ext;
  169. if (!wsi || !wsi->vhost)
  170. return 0;
  171. ext = wsi->vhost->extensions;
  172. while (ext && ext->callback && !handled) {
  173. m = ext->callback(context, ext, wsi, reason,
  174. (void *)(long)n, arg, len);
  175. if (m < 0) {
  176. lwsl_ext("Ext '%s' failed to handle callback %d!\n",
  177. wsi->active_extensions[n]->name, reason);
  178. return -1;
  179. }
  180. if (m)
  181. handled = 1;
  182. ext++;
  183. n++;
  184. }
  185. return 0;
  186. }
  187. int
  188. lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len)
  189. {
  190. struct lws_tokens eff_buf;
  191. int ret, m, n = 0;
  192. eff_buf.token = (char *)buf;
  193. eff_buf.token_len = len;
  194. /*
  195. * while we have original buf to spill ourselves, or extensions report
  196. * more in their pipeline
  197. */
  198. ret = 1;
  199. while (ret == 1) {
  200. /* default to nobody has more to spill */
  201. ret = 0;
  202. /* show every extension the new incoming data */
  203. m = lws_ext_cb_active(wsi,
  204. LWS_EXT_CB_PACKET_TX_PRESEND, &eff_buf, 0);
  205. if (m < 0)
  206. return -1;
  207. if (m) /* handled */
  208. ret = 1;
  209. if ((char *)buf != eff_buf.token)
  210. /*
  211. * extension recreated it:
  212. * need to buffer this if not all sent
  213. */
  214. wsi->u.ws.clean_buffer = 0;
  215. /* assuming they left us something to send, send it */
  216. if (eff_buf.token_len) {
  217. n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
  218. eff_buf.token_len);
  219. if (n < 0) {
  220. lwsl_info("closing from ext access\n");
  221. return -1;
  222. }
  223. /* always either sent it all or privately buffered */
  224. if (wsi->u.ws.clean_buffer)
  225. len = n;
  226. }
  227. lwsl_parser("written %d bytes to client\n", n);
  228. /* no extension has more to spill? Then we can go */
  229. if (!ret)
  230. break;
  231. /* we used up what we had */
  232. eff_buf.token = NULL;
  233. eff_buf.token_len = 0;
  234. /*
  235. * Did that leave the pipe choked?
  236. * Or we had to hold on to some of it?
  237. */
  238. if (!lws_send_pipe_choked(wsi) && !wsi->trunc_len)
  239. /* no we could add more, lets's do that */
  240. continue;
  241. lwsl_debug("choked\n");
  242. /*
  243. * Yes, he's choked. Don't spill the rest now get a callback
  244. * when he is ready to send and take care of it there
  245. */
  246. lws_callback_on_writable(wsi);
  247. wsi->extension_data_pending = 1;
  248. ret = 0;
  249. }
  250. return len;
  251. }
  252. int
  253. lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r,
  254. void *v, size_t len)
  255. {
  256. struct lws_context *context = wsi->context;
  257. int n, handled = 0;
  258. /* maybe an extension will take care of it for us */
  259. for (n = 0; n < wsi->count_act_ext && !handled; n++) {
  260. if (!wsi->active_extensions[n]->callback)
  261. continue;
  262. handled |= wsi->active_extensions[n]->callback(context,
  263. wsi->active_extensions[n], wsi,
  264. r, wsi->act_ext_user[n], v, len);
  265. }
  266. return handled;
  267. }
  268. int
  269. lws_set_extension_option(struct lws *wsi, const char *ext_name,
  270. const char *opt_name, const char *opt_val)
  271. {
  272. struct lws_ext_option_arg oa;
  273. int idx = 0;
  274. /* first identify if the ext is active on this wsi */
  275. while (idx < wsi->count_act_ext &&
  276. strcmp(wsi->active_extensions[idx]->name, ext_name))
  277. idx++;
  278. if (idx == wsi->count_act_ext)
  279. return -1; /* request ext not active on this wsi */
  280. oa.option_name = opt_name;
  281. oa.option_index = 0;
  282. oa.start = opt_val;
  283. oa.len = 0;
  284. return wsi->active_extensions[idx]->callback(
  285. wsi->context, wsi->active_extensions[idx], wsi,
  286. LWS_EXT_CB_NAMED_OPTION_SET, wsi->act_ext_user[idx], &oa, 0);
  287. }