protocol_lws_deaddrop.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
  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. #if !defined (LWS_PLUGIN_STATIC)
  25. #define LWS_DLL
  26. #define LWS_INTERNAL
  27. #include <libwebsockets.h>
  28. #endif
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <fcntl.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <dirent.h>
  35. #ifdef WIN32
  36. #include <io.h>
  37. #endif
  38. #include <stdio.h>
  39. #include <errno.h>
  40. struct dir_entry {
  41. lws_list_ptr next; /* sorted by mtime */
  42. char user[32];
  43. unsigned long long size;
  44. time_t mtime;
  45. };
  46. /* filename follows */
  47. #define lp_to_dir_entry(p, _n) lws_list_ptr_container(p, struct dir_entry, _n)
  48. struct pss_deaddrop;
  49. struct vhd_deaddrop {
  50. struct lws_context *context;
  51. struct lws_vhost *vh;
  52. const struct lws_protocols *protocol;
  53. struct pss_deaddrop *pss_head;
  54. const char *upload_dir;
  55. struct lwsac *lwsac_head;
  56. struct dir_entry *dire_head;
  57. int filelist_version;
  58. unsigned long long max_size;
  59. };
  60. struct pss_deaddrop {
  61. struct lws_spa *spa;
  62. struct vhd_deaddrop *vhd;
  63. struct lws *wsi;
  64. char result[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE];
  65. char filename[256];
  66. char user[32];
  67. unsigned long long file_length;
  68. lws_filefd_type fd;
  69. int response_code;
  70. struct pss_deaddrop *pss_list;
  71. struct lwsac *lwsac_head;
  72. struct dir_entry *dire;
  73. int filelist_version;
  74. uint8_t completed:1;
  75. uint8_t sent_headers:1;
  76. uint8_t sent_body:1;
  77. uint8_t first:1;
  78. };
  79. static const char * const param_names[] = {
  80. "text",
  81. "send",
  82. "file",
  83. "upload",
  84. };
  85. enum enum_param_names {
  86. EPN_TEXT,
  87. EPN_SEND,
  88. EPN_FILE,
  89. EPN_UPLOAD,
  90. };
  91. static int
  92. de_mtime_sort(lws_list_ptr a, lws_list_ptr b)
  93. {
  94. struct dir_entry *p1 = lp_to_dir_entry(a, next),
  95. *p2 = lp_to_dir_entry(b, next);
  96. return (int)(p2->mtime - p1->mtime);
  97. }
  98. static void
  99. start_sending_dir(struct pss_deaddrop *pss)
  100. {
  101. if (pss->vhd->lwsac_head)
  102. lwsac_reference(pss->vhd->lwsac_head);
  103. pss->lwsac_head = pss->vhd->lwsac_head;
  104. pss->dire = pss->vhd->dire_head;
  105. pss->filelist_version = pss->vhd->filelist_version;
  106. pss->first = 1;
  107. }
  108. static int
  109. scan_upload_dir(struct vhd_deaddrop *vhd)
  110. {
  111. char filepath[256], subdir[3][128], *p;
  112. int m, sp = 0, initial, found = 0;
  113. struct lwsac *lwsac_head = NULL;
  114. lws_list_ptr sorted_head = NULL;
  115. struct dir_entry *dire;
  116. struct dirent *de;
  117. struct stat s;
  118. DIR *dir[3];
  119. initial = strlen(vhd->upload_dir) + 1;
  120. lws_strncpy(subdir[sp], vhd->upload_dir, sizeof(subdir[sp]));
  121. dir[sp] = opendir(vhd->upload_dir);
  122. if (!dir[sp]) {
  123. lwsl_err("%s: Unable to walk upload dir '%s'\n", __func__,
  124. vhd->upload_dir);
  125. return -1;
  126. }
  127. do {
  128. de = readdir(dir[sp]);
  129. if (!de) {
  130. closedir(dir[sp]);
  131. #if !defined(__COVERITY__)
  132. if (!sp)
  133. #endif
  134. break;
  135. #if !defined(__COVERITY__)
  136. sp--;
  137. continue;
  138. #endif
  139. }
  140. p = filepath;
  141. for (m = 0; m <= sp; m++)
  142. p += lws_snprintf(p, (filepath + sizeof(filepath)) - p,
  143. "%s/", subdir[m]);
  144. lws_snprintf(p, (filepath + sizeof(filepath)) - p, "%s",
  145. de->d_name);
  146. /* ignore temp files */
  147. if (de->d_name[strlen(de->d_name) - 1] == '~')
  148. continue;
  149. #if defined(__COVERITY__)
  150. s.st_size = 0;
  151. s.st_mtime = 0;
  152. #else
  153. /* coverity[toctou] */
  154. if (stat(filepath, &s))
  155. continue;
  156. if (S_ISDIR(s.st_mode)) {
  157. if (!strcmp(de->d_name, ".") ||
  158. !strcmp(de->d_name, ".."))
  159. continue;
  160. sp++;
  161. if (sp == LWS_ARRAY_SIZE(dir)) {
  162. lwsl_err("%s: Skipping too-deep subdir %s\n",
  163. __func__, filepath);
  164. sp--;
  165. continue;
  166. }
  167. lws_strncpy(subdir[sp], de->d_name, sizeof(subdir[sp]));
  168. dir[sp] = opendir(filepath);
  169. if (!dir[sp]) {
  170. lwsl_err("%s: Unable to open subdir '%s'\n",
  171. __func__, filepath);
  172. goto bail;
  173. }
  174. continue;
  175. }
  176. #endif
  177. m = strlen(filepath + initial) + 1;
  178. dire = lwsac_use(&lwsac_head, sizeof(*dire) + m, 0);
  179. if (!dire) {
  180. lwsac_free(&lwsac_head);
  181. goto bail;
  182. }
  183. dire->next = NULL;
  184. dire->size = s.st_size;
  185. dire->mtime = s.st_mtime;
  186. dire->user[0] = '\0';
  187. #if !defined(__COVERITY__)
  188. if (sp)
  189. lws_strncpy(dire->user, subdir[1], sizeof(dire->user));
  190. #endif
  191. found++;
  192. memcpy(&dire[1], filepath + initial, m);
  193. lws_list_ptr_insert(&sorted_head, &dire->next, de_mtime_sort);
  194. } while (1);
  195. /* the old lwsac continues to live while someone else is consuming it */
  196. if (vhd->lwsac_head)
  197. lwsac_detach(&vhd->lwsac_head);
  198. /* we replace it with the fresh one */
  199. vhd->lwsac_head = lwsac_head;
  200. if (sorted_head)
  201. vhd->dire_head = lp_to_dir_entry(sorted_head, next);
  202. else
  203. vhd->dire_head = NULL;
  204. vhd->filelist_version++;
  205. lwsl_info("%s: found %d\n", __func__, found);
  206. lws_start_foreach_llp(struct pss_deaddrop **, ppss, vhd->pss_head) {
  207. start_sending_dir(*ppss);
  208. lws_callback_on_writable((*ppss)->wsi);
  209. } lws_end_foreach_llp(ppss, pss_list);
  210. return 0;
  211. bail:
  212. while (sp >= 0)
  213. closedir(dir[sp--]);
  214. return -1;
  215. }
  216. static int
  217. file_upload_cb(void *data, const char *name, const char *filename,
  218. char *buf, int len, enum lws_spa_fileupload_states state)
  219. {
  220. struct pss_deaddrop *pss = (struct pss_deaddrop *)data;
  221. char filename2[256];
  222. int n;
  223. (void)n;
  224. switch (state) {
  225. case LWS_UFS_OPEN:
  226. lws_urldecode(filename2, filename, sizeof(filename2) - 1);
  227. lws_filename_purify_inplace(filename2);
  228. if (pss->user[0]) {
  229. lws_filename_purify_inplace(pss->user);
  230. lws_snprintf(pss->filename, sizeof(pss->filename),
  231. "%s/%s", pss->vhd->upload_dir, pss->user);
  232. if (mkdir(pss->filename
  233. #if !defined(WIN32)
  234. , 0700
  235. #endif
  236. ) < 0)
  237. lwsl_debug("%s: mkdir failed\n", __func__);
  238. lws_snprintf(pss->filename, sizeof(pss->filename),
  239. "%s/%s/%s~", pss->vhd->upload_dir,
  240. pss->user, filename2);
  241. } else
  242. lws_snprintf(pss->filename, sizeof(pss->filename),
  243. "%s/%s~", pss->vhd->upload_dir, filename2);
  244. lwsl_notice("%s: filename '%s'\n", __func__, pss->filename);
  245. pss->fd = (lws_filefd_type)(long long)lws_open(pss->filename,
  246. O_CREAT | O_TRUNC | O_RDWR, 0600);
  247. if (pss->fd == LWS_INVALID_FILE) {
  248. pss->response_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
  249. lwsl_err("%s: unable to open %s (errno %d)\n", __func__,
  250. pss->filename, errno);
  251. return -1;
  252. }
  253. break;
  254. case LWS_UFS_FINAL_CONTENT:
  255. case LWS_UFS_CONTENT:
  256. if (len) {
  257. pss->file_length += len;
  258. /* if the file length is too big, drop it */
  259. if (pss->file_length > pss->vhd->max_size) {
  260. pss->response_code =
  261. HTTP_STATUS_REQ_ENTITY_TOO_LARGE;
  262. close((int)(lws_intptr_t)pss->fd);
  263. pss->fd = LWS_INVALID_FILE;
  264. unlink(pss->filename);
  265. return -1;
  266. }
  267. if (pss->fd != LWS_INVALID_FILE) {
  268. n = write((int)(lws_intptr_t)pss->fd, buf, len);
  269. lwsl_debug("%s: write %d says %d\n", __func__,
  270. len, n);
  271. lws_set_timeout(pss->wsi, PENDING_TIMEOUT_HTTP_CONTENT, 30);
  272. }
  273. }
  274. if (state == LWS_UFS_CONTENT)
  275. break;
  276. if (pss->fd != LWS_INVALID_FILE)
  277. close((int)(lws_intptr_t)pss->fd);
  278. /* the temp filename without the ~ */
  279. lws_strncpy(filename2, pss->filename, sizeof(filename2));
  280. filename2[strlen(filename2) - 1] = '\0';
  281. if (rename(pss->filename, filename2) < 0)
  282. lwsl_err("%s: unable to rename\n", __func__);
  283. pss->fd = LWS_INVALID_FILE;
  284. pss->response_code = HTTP_STATUS_OK;
  285. scan_upload_dir(pss->vhd);
  286. break;
  287. case LWS_UFS_CLOSE:
  288. break;
  289. }
  290. return 0;
  291. }
  292. /*
  293. * returns length in bytes
  294. */
  295. static int
  296. format_result(struct pss_deaddrop *pss)
  297. {
  298. unsigned char *p, *start, *end;
  299. p = (unsigned char *)pss->result + LWS_PRE;
  300. start = p;
  301. end = p + sizeof(pss->result) - LWS_PRE - 1;
  302. p += lws_snprintf((char *)p, end -p,
  303. "<!DOCTYPE html><html lang=\"en\"><head>"
  304. "<meta charset=utf-8 http-equiv=\"Content-Language\" "
  305. "content=\"en\"/>"
  306. "</head>");
  307. p += lws_snprintf((char *)p, end - p, "</body></html>");
  308. return (int)lws_ptr_diff(p, start);
  309. }
  310. static int
  311. callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
  312. void *user, void *in, size_t len)
  313. {
  314. struct vhd_deaddrop *vhd = (struct vhd_deaddrop *)
  315. lws_protocol_vh_priv_get(lws_get_vhost(wsi),
  316. lws_get_protocol(wsi));
  317. struct pss_deaddrop *pss = (struct pss_deaddrop *)user;
  318. uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE],
  319. *start = &buf[LWS_PRE], *p = start,
  320. *end = &buf[sizeof(buf) - LWS_PRE - 1];
  321. char fname[256], *wp;
  322. const char *cp;
  323. int n, m, was;
  324. switch (reason) {
  325. case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
  326. lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
  327. lws_get_protocol(wsi),
  328. sizeof(struct vhd_deaddrop));
  329. vhd = (struct vhd_deaddrop *)
  330. lws_protocol_vh_priv_get(lws_get_vhost(wsi),
  331. lws_get_protocol(wsi));
  332. vhd->context = lws_get_context(wsi);
  333. vhd->vh = lws_get_vhost(wsi);
  334. vhd->protocol = lws_get_protocol(wsi);
  335. vhd->max_size = 20 * 1024 * 1024; /* default without pvo */
  336. if (!lws_pvo_get_str(in, "max-size", &cp))
  337. vhd->max_size = atoll(cp);
  338. if (lws_pvo_get_str(in, "upload-dir", &vhd->upload_dir)) {
  339. lwsl_err("%s: requires 'upload-dir' pvo\n", __func__);
  340. return -1;
  341. }
  342. scan_upload_dir(vhd);
  343. lwsl_notice(" deaddrop: vh %s, upload dir %s, max size %llu\n",
  344. lws_get_vhost_name(vhd->vh), vhd->upload_dir,
  345. vhd->max_size);
  346. break;
  347. case LWS_CALLBACK_PROTOCOL_DESTROY:
  348. lwsac_free(&vhd->lwsac_head);
  349. break;
  350. /* WS-related */
  351. case LWS_CALLBACK_ESTABLISHED:
  352. pss->vhd = vhd;
  353. pss->wsi = wsi;
  354. /* add ourselves to the list of live pss held in the vhd */
  355. pss->pss_list = vhd->pss_head;
  356. vhd->pss_head = pss;
  357. m = lws_hdr_copy(wsi, pss->user, sizeof(pss->user),
  358. WSI_TOKEN_HTTP_AUTHORIZATION);
  359. if (m > 0)
  360. lwsl_info("%s: basic auth user: %s\n",
  361. __func__, pss->user);
  362. else
  363. pss->user[0] = '\0';
  364. start_sending_dir(pss);
  365. lws_callback_on_writable(wsi);
  366. return 0;
  367. case LWS_CALLBACK_CLOSED:
  368. if (pss->lwsac_head)
  369. lwsac_unreference(&pss->lwsac_head);
  370. /* remove our closing pss from the list of live pss */
  371. lws_start_foreach_llp(struct pss_deaddrop **,
  372. ppss, vhd->pss_head) {
  373. if (*ppss == pss) {
  374. *ppss = pss->pss_list;
  375. break;
  376. }
  377. } lws_end_foreach_llp(ppss, pss_list);
  378. return 0;
  379. case LWS_CALLBACK_RECEIVE:
  380. /* we get this kind of thing {"del":"agreen/no-entry.svg"} */
  381. if (!pss || len < 10)
  382. break;
  383. if (strncmp((const char *)in, "{\"del\":\"", 8))
  384. break;
  385. cp = strchr((const char *)in, '/');
  386. if (cp) {
  387. n = ((void *)cp - in) - 8;
  388. if ((int)strlen(pss->user) != n ||
  389. memcmp(pss->user, ((const char *)in) + 8, n)) {
  390. lwsl_notice("%s: del: auth mismatch "
  391. " '%s' '%s' (%d)\n",
  392. __func__, pss->user,
  393. ((const char *)in) + 8, n);
  394. break;
  395. }
  396. }
  397. lws_strncpy(fname, ((const char *)in) + 8, sizeof(fname));
  398. lws_filename_purify_inplace(fname);
  399. wp = strchr((const char *)fname, '\"');
  400. if (wp)
  401. *wp = '\0';
  402. lws_snprintf((char *)buf, sizeof(buf), "%s/%s", vhd->upload_dir,
  403. fname);
  404. lwsl_notice("%s: del: path %s\n", __func__, (const char *)buf);
  405. if (unlink((const char *)buf) < 0)
  406. lwsl_err("%s: unlink %s failed\n", __func__,
  407. (const char *)buf);
  408. scan_upload_dir(vhd);
  409. break;
  410. case LWS_CALLBACK_SERVER_WRITEABLE:
  411. if (pss->lwsac_head && !pss->dire)
  412. return 0;
  413. was = 0;
  414. if (pss->first) {
  415. p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
  416. "{\"max_size\":%llu, \"files\": [",
  417. vhd->max_size);
  418. was = 1;
  419. }
  420. m = 5;
  421. while (m-- && pss->dire) {
  422. p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
  423. "%c{\"name\":\"%s\", "
  424. "\"size\":%llu,"
  425. "\"mtime\":%llu,"
  426. "\"yours\":%d}",
  427. pss->first ? ' ' : ',',
  428. (const char *)&pss->dire[1],
  429. pss->dire->size,
  430. (unsigned long long)pss->dire->mtime,
  431. !strcmp(pss->user, pss->dire->user) &&
  432. pss->user[0]);
  433. pss->first = 0;
  434. pss->dire = lp_to_dir_entry(pss->dire->next, next);
  435. }
  436. if (!pss->dire) {
  437. p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
  438. "]}");
  439. if (pss->lwsac_head) {
  440. lwsac_unreference(&pss->lwsac_head);
  441. pss->lwsac_head = NULL;
  442. }
  443. }
  444. n = lws_write(wsi, start, lws_ptr_diff(p, start),
  445. lws_write_ws_flags(LWS_WRITE_TEXT, was,
  446. !pss->dire));
  447. if (n < 0) {
  448. lwsl_notice("%s: ws write failed\n", __func__);
  449. return 1;
  450. }
  451. if (pss->dire) {
  452. lws_callback_on_writable(wsi);
  453. return 0;
  454. }
  455. /* ie, we finished */
  456. if (pss->filelist_version != pss->vhd->filelist_version) {
  457. lwsl_info("%s: restart send\n", __func__);
  458. /* what we just sent is already out of date */
  459. start_sending_dir(pss);
  460. lws_callback_on_writable(wsi);
  461. }
  462. return 0;
  463. /* POST-related */
  464. case LWS_CALLBACK_HTTP_BODY:
  465. /* create the POST argument parser if not already existing */
  466. if (!pss->spa) {
  467. pss->vhd = vhd;
  468. pss->wsi = wsi;
  469. pss->spa = lws_spa_create(wsi, param_names,
  470. LWS_ARRAY_SIZE(param_names),
  471. 1024, file_upload_cb, pss);
  472. if (!pss->spa)
  473. return -1;
  474. pss->filename[0] = '\0';
  475. pss->file_length = 0;
  476. /* catchall */
  477. pss->response_code = HTTP_STATUS_SERVICE_UNAVAILABLE;
  478. m = lws_hdr_copy(wsi, pss->user, sizeof(pss->user),
  479. WSI_TOKEN_HTTP_AUTHORIZATION);
  480. if (m > 0)
  481. lwsl_info("basic auth user: %s\n", pss->user);
  482. else
  483. pss->user[0] = '\0';
  484. }
  485. /* let it parse the POST data */
  486. if (lws_spa_process(pss->spa, in, (int)len)) {
  487. lwsl_notice("spa saw a problem\n");
  488. /* some problem happened */
  489. lws_spa_finalize(pss->spa);
  490. pss->completed = 1;
  491. lws_callback_on_writable(wsi);
  492. }
  493. break;
  494. case LWS_CALLBACK_HTTP_BODY_COMPLETION:
  495. /* call to inform no more payload data coming */
  496. lws_spa_finalize(pss->spa);
  497. pss->completed = 1;
  498. lws_callback_on_writable(wsi);
  499. break;
  500. case LWS_CALLBACK_HTTP_WRITEABLE:
  501. if (!pss->completed)
  502. break;
  503. p = (unsigned char *)pss->result + LWS_PRE;
  504. start = p;
  505. end = p + sizeof(pss->result) - LWS_PRE - 1;
  506. if (!pss->sent_headers) {
  507. n = format_result(pss);
  508. if (lws_add_http_header_status(wsi, pss->response_code,
  509. &p, end))
  510. goto bail;
  511. if (lws_add_http_header_by_token(wsi,
  512. WSI_TOKEN_HTTP_CONTENT_TYPE,
  513. (unsigned char *)"text/html", 9,
  514. &p, end))
  515. goto bail;
  516. if (lws_add_http_header_content_length(wsi, n, &p, end))
  517. goto bail;
  518. if (lws_finalize_http_header(wsi, &p, end))
  519. goto bail;
  520. /* first send the headers ... */
  521. n = lws_write(wsi, start, lws_ptr_diff(p, start),
  522. LWS_WRITE_HTTP_HEADERS |
  523. LWS_WRITE_H2_STREAM_END);
  524. if (n < 0)
  525. goto bail;
  526. pss->sent_headers = 1;
  527. lws_callback_on_writable(wsi);
  528. break;
  529. }
  530. if (!pss->sent_body) {
  531. n = format_result(pss);
  532. n = lws_write(wsi, (unsigned char *)start, n,
  533. LWS_WRITE_HTTP_FINAL);
  534. pss->sent_body = 1;
  535. if (n < 0) {
  536. lwsl_err("%s: writing body failed\n", __func__);
  537. return 1;
  538. }
  539. goto try_to_reuse;
  540. }
  541. break;
  542. case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
  543. /* called when our wsi user_space is going to be destroyed */
  544. if (pss->spa) {
  545. lws_spa_destroy(pss->spa);
  546. pss->spa = NULL;
  547. }
  548. break;
  549. default:
  550. break;
  551. }
  552. return 0;
  553. bail:
  554. return 1;
  555. try_to_reuse:
  556. if (lws_http_transaction_completed(wsi))
  557. return -1;
  558. return 0;
  559. }
  560. #define LWS_PLUGIN_PROTOCOL_DEADDROP \
  561. { \
  562. "lws-deaddrop", \
  563. callback_deaddrop, \
  564. sizeof(struct pss_deaddrop), \
  565. 1024, \
  566. 0, NULL, 0 \
  567. }
  568. #if !defined (LWS_PLUGIN_STATIC)
  569. static const struct lws_protocols protocols[] = {
  570. LWS_PLUGIN_PROTOCOL_DEADDROP
  571. };
  572. LWS_VISIBLE const lws_plugin_protocol_t deaddrop = {
  573. .hdr = {
  574. "deaddrop",
  575. "lws_protocol_plugin",
  576. LWS_PLUGIN_API_MAGIC
  577. },
  578. .protocols = protocols,
  579. .count_protocols = LWS_ARRAY_SIZE(protocols),
  580. .extensions = NULL,
  581. .count_extensions = 0,
  582. };
  583. #endif