• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
callback_fts(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)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_VISIBLE int
init_protocol_fulltext_demo(struct lws_context * context,struct lws_plugin_capability * c)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_VISIBLE int
destroy_protocol_fulltext_demo(struct lws_context * context)288 destroy_protocol_fulltext_demo(struct lws_context *context)
289 {
290 	return 0;
291 }
292 
293 #endif
294