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