Imported Upstream version 3.2.0
[platform/upstream/libwebsockets.git] / plugins / protocol_fulltext_demo.c
1 /*
2  * ws protocol handler plugin for "fulltext demo"
3  *
4  * Written in 2010-2019 by Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  *
9  * The person who associated a work with this deed has dedicated
10  * the work to the public domain by waiving all of his or her rights
11  * to the work worldwide under copyright law, including all related
12  * and neighboring rights, to the extent allowed by law. You can copy,
13  * modify, distribute and perform the work, even for commercial purposes,
14  * all without asking permission.
15  *
16  * These test plugins are intended to be adapted for use in your code, which
17  * may be proprietary.  So unlike the library itself, they are licensed
18  * Public Domain.
19  */
20
21 #if !defined (LWS_PLUGIN_STATIC)
22 #define LWS_DLL
23 #define LWS_INTERNAL
24 #include <libwebsockets.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #ifdef WIN32
33 #include <io.h>
34 #endif
35 #include <stdio.h>
36
37 struct vhd_fts_demo {
38         const char *indexpath;
39 };
40
41 struct pss_fts_demo {
42         struct lwsac *result;
43         struct lws_fts_result_autocomplete *ac;
44         struct lws_fts_result_filepath *fp;
45
46         uint32_t *li;
47         int done;
48
49         uint8_t first:1;
50         uint8_t ac_done:1;
51
52         uint8_t fp_init_done:1;
53 };
54
55 static int
56 callback_fts(struct lws *wsi, enum lws_callback_reasons reason, void *user,
57              void *in, size_t len)
58 {
59         struct vhd_fts_demo *vhd = (struct vhd_fts_demo *)
60                 lws_protocol_vh_priv_get(lws_get_vhost(wsi),
61                                          lws_get_protocol(wsi));
62         struct pss_fts_demo *pss = (struct pss_fts_demo *)user;
63         uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start,
64                 *end = &buf[sizeof(buf) - LWS_PRE - 1];
65         struct lws_fts_search_params params;
66         const char *ccp = (const char *)in;
67         struct lws_fts_result *result;
68         struct lws_fts_file *jtf;
69         int n;
70
71         switch (reason) {
72
73         case LWS_CALLBACK_PROTOCOL_INIT:
74                 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
75                              lws_get_protocol(wsi),sizeof(struct vhd_fts_demo));
76                 if (!vhd)
77                         return 1;
78                 if (lws_pvo_get_str(in, "indexpath",
79                                     (const char **)&vhd->indexpath))
80                         return 1;
81
82                 return 0;
83
84         case LWS_CALLBACK_HTTP:
85
86                 pss->first = 1;
87                 pss->ac_done = 0;
88
89                 /*
90                  * we have a "subdirectory" selecting the task
91                  *
92                  * /a/ = autocomplete
93                  * /r/ = results
94                  */
95
96                 if (strncmp(ccp, "/a/", 3) && strncmp(ccp, "/r/", 3))
97                         goto reply_404;
98
99                 memset(&params, 0, sizeof(params));
100
101                 params.needle = ccp + 3;
102                 if (*(ccp + 1) == 'a')
103                         params.flags = LWSFTS_F_QUERY_AUTOCOMPLETE;
104                 if (*(ccp + 1) == 'r')
105                         params.flags = LWSFTS_F_QUERY_FILES |
106                                        LWSFTS_F_QUERY_FILE_LINES |
107                                        LWSFTS_F_QUERY_QUOTE_LINE;
108                 params.max_autocomplete = 10;
109                 params.max_files = 10;
110
111                 jtf = lws_fts_open(vhd->indexpath);
112                 if (!jtf) {
113                         lwsl_err("unable to open %s\n", vhd->indexpath);
114                         /* we'll inform the client in the JSON */
115                         goto reply_200;
116                 }
117
118                 result = lws_fts_search(jtf, &params);
119                 lws_fts_close(jtf);
120                 if (result) {
121                         pss->result = params.results_head;
122                         pss->ac = result->autocomplete_head;
123                         pss->fp = result->filepath_head;
124                 }
125                 /* NULL result will be told in the json as "indexed": 0 */
126
127 reply_200:
128                 if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
129                                                 "text/html",
130                                         LWS_ILLEGAL_HTTP_CONTENT_LEN, &p, end))
131                         return 1;
132
133                 if (lws_finalize_write_http_header(wsi, start, &p, end))
134                         return 1;
135
136                 lws_callback_on_writable(wsi);
137                 return 0;
138
139 reply_404:
140                 if (lws_add_http_common_headers(wsi, HTTP_STATUS_NOT_FOUND,
141                                                 "text/html",
142                                         LWS_ILLEGAL_HTTP_CONTENT_LEN, &p, end))
143                         return 1;
144
145                 if (lws_finalize_write_http_header(wsi, start, &p, end))
146                         return 1;
147                 return lws_http_transaction_completed(wsi);
148
149         case LWS_CALLBACK_CLOSED_HTTP:
150                 if (pss && pss->result)
151                         lwsac_free(&pss->result);
152                 break;
153
154         case LWS_CALLBACK_HTTP_WRITEABLE:
155
156                 if (!pss)
157                         break;
158
159                 n = LWS_WRITE_HTTP;
160                 if (pss->first)
161                         p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
162                                 "{\"indexed\": %d, \"ac\": [", !!pss->result);
163
164                 while (pss->ac && lws_ptr_diff(end, p) > 256) {
165                         p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
166                                 "%c{\"ac\": \"%s\",\"matches\": %d,"
167                                 "\"agg\": %d, \"elided\": %d}",
168                                 pss->first ? ' ' : ',', (char *)(pss->ac + 1),
169                                 pss->ac->instances, pss->ac->agg_instances,
170                                 pss->ac->elided);
171
172                         pss->first = 0;
173                         pss->ac = pss->ac->next;
174                 }
175
176                 if (!pss->ac_done && !pss->ac && pss->fp) {
177                         pss->ac_done = 1;
178
179                         p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
180                                           "], \"fp\": [");
181                 }
182
183                 while (pss->fp && lws_ptr_diff(end, p) > 256) {
184                         if (!pss->fp_init_done) {
185                                 p += lws_snprintf((char *)p,
186                                         lws_ptr_diff(end, p),
187                                         "%c{\"path\": \"%s\",\"matches\": %d,"
188                                         "\"origlines\": %d,"
189                                         "\"hits\": [", pss->first ? ' ' : ',',
190                                         ((char *)(pss->fp + 1)) +
191                                                 pss->fp->matches_length,
192                                         pss->fp->matches,
193                                         pss->fp->lines_in_file);
194
195                                 pss->li = ((uint32_t *)(pss->fp + 1));
196                                 pss->done = 0;
197                                 pss->fp_init_done = 1;
198                                 pss->first = 0;
199                         } else {
200                                 while (pss->done < pss->fp->matches &&
201                                        lws_ptr_diff(end, p) > 256) {
202
203                                         p += lws_snprintf((char *)p,
204                                                 lws_ptr_diff(end, p),
205                                                 "%c\n{\"l\":%d,\"o\":%d,"
206                                                 "\"s\":\"%s\"}",
207                                                 !pss->done ? ' ' : ',',
208                                                 pss->li[0], pss->li[1],
209                                                 *((const char **)&pss->li[2]));
210                                         pss->li += 2 + (sizeof(const char *) /
211                                                         sizeof(uint32_t));
212                                         pss->done++;
213                                 }
214
215                                 if (pss->done == pss->fp->matches) {
216                                         *p++ = ']';
217                                         pss->fp_init_done = 0;
218                                         pss->fp = pss->fp->next;
219                                         if (!pss->fp)
220                                                 *p++ = '}';
221                                 }
222                         }
223                 }
224
225                 if (!pss->ac && !pss->fp) {
226                         n = LWS_WRITE_HTTP_FINAL;
227                         p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
228                                                 "]}");
229                 }
230
231                 if (lws_write(wsi, (uint8_t *)start,
232                               lws_ptr_diff(p, start), n) !=
233                                               lws_ptr_diff(p, start))
234                         return 1;
235
236                 if (n == LWS_WRITE_HTTP_FINAL) {
237                         if (pss->result)
238                                 lwsac_free(&pss->result);
239                         if (lws_http_transaction_completed(wsi))
240                                 return -1;
241                 } else
242                         lws_callback_on_writable(wsi);
243
244                 return 0;
245
246         default:
247                 break;
248         }
249
250         return lws_callback_http_dummy(wsi, reason, user, in, len);
251 }
252
253
254 #define LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO \
255         { \
256                 "lws-test-fts", \
257                 callback_fts, \
258                 sizeof(struct pss_fts_demo), \
259                 0, \
260                 0, NULL, 0 \
261         }
262
263 #if !defined (LWS_PLUGIN_STATIC)
264
265 static const struct lws_protocols protocols[] = {
266         LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO
267 };
268
269 LWS_EXTERN LWS_VISIBLE int
270 init_protocol_fulltext_demo(struct lws_context *context,
271                         struct lws_plugin_capability *c)
272 {
273         if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
274                 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
275                          c->api_magic);
276                 return 1;
277         }
278
279         c->protocols = protocols;
280         c->count_protocols = LWS_ARRAY_SIZE(protocols);
281         c->extensions = NULL;
282         c->count_extensions = 0;
283
284         return 0;
285 }
286
287 LWS_EXTERN LWS_VISIBLE int
288 destroy_protocol_fulltext_demo(struct lws_context *context)
289 {
290         return 0;
291 }
292
293 #endif