xref: /aosp_15_r20/external/libwebsockets/lib/misc/cache-ttl/file.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Copyright (C) 2010 - 2021 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker  * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker  * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker  * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker  *
24*1c60b9acSAndroid Build Coastguard Worker  * Implements a cache backing store compatible with netscape cookies.txt format
25*1c60b9acSAndroid Build Coastguard Worker  * There is one entry per "line", and fields are tab-delimited
26*1c60b9acSAndroid Build Coastguard Worker  *
27*1c60b9acSAndroid Build Coastguard Worker  * We need to know the format here, because while the unique cookie tag consists
28*1c60b9acSAndroid Build Coastguard Worker  * of "hostname|urlpath|cookiename", that does not appear like that in the file;
29*1c60b9acSAndroid Build Coastguard Worker  * we have to go parse the fields and synthesize the corresponding tag.
30*1c60b9acSAndroid Build Coastguard Worker  *
31*1c60b9acSAndroid Build Coastguard Worker  * We rely on all the fields except the cookie value fitting in a 256 byte
32*1c60b9acSAndroid Build Coastguard Worker  * buffer, and allow eating multiple buffers to get a huge cookie values.
33*1c60b9acSAndroid Build Coastguard Worker  *
34*1c60b9acSAndroid Build Coastguard Worker  * Because the cookie file is a device-wide asset, although lws will change it
35*1c60b9acSAndroid Build Coastguard Worker  * from the lws thread without conflict, there may be other processes that will
36*1c60b9acSAndroid Build Coastguard Worker  * change it by removal and regenerating the file asynchronously.  For that
37*1c60b9acSAndroid Build Coastguard Worker  * reason, file handles are opened fresh each time we want to use the file, so
38*1c60b9acSAndroid Build Coastguard Worker  * we always get the latest version.
39*1c60b9acSAndroid Build Coastguard Worker  *
40*1c60b9acSAndroid Build Coastguard Worker  * When updating the file ourselves, we use a lockfile to ensure our process
41*1c60b9acSAndroid Build Coastguard Worker  * has exclusive access.
42*1c60b9acSAndroid Build Coastguard Worker  *
43*1c60b9acSAndroid Build Coastguard Worker  *
44*1c60b9acSAndroid Build Coastguard Worker  * Tag Matching rules
45*1c60b9acSAndroid Build Coastguard Worker  *
46*1c60b9acSAndroid Build Coastguard Worker  * There are three kinds of tag matching rules
47*1c60b9acSAndroid Build Coastguard Worker  *
48*1c60b9acSAndroid Build Coastguard Worker  * 1) specific - tag strigs must be the same
49*1c60b9acSAndroid Build Coastguard Worker  * 2) wilcard - tags matched using optional wildcards
50*1c60b9acSAndroid Build Coastguard Worker  * 3) wildcard + lookup - wildcard, but path part matches using cookie scope rules
51*1c60b9acSAndroid Build Coastguard Worker  *
52*1c60b9acSAndroid Build Coastguard Worker  */
53*1c60b9acSAndroid Build Coastguard Worker 
54*1c60b9acSAndroid Build Coastguard Worker #include <private-lib-core.h>
55*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-misc-cache-ttl.h"
56*1c60b9acSAndroid Build Coastguard Worker 
57*1c60b9acSAndroid Build Coastguard Worker typedef enum nsc_iterator_ret {
58*1c60b9acSAndroid Build Coastguard Worker 	NIR_CONTINUE		= 0,
59*1c60b9acSAndroid Build Coastguard Worker 	NIR_FINISH_OK		= 1,
60*1c60b9acSAndroid Build Coastguard Worker 	NIR_FINISH_ERROR	= -1
61*1c60b9acSAndroid Build Coastguard Worker } nsc_iterator_ret_t;
62*1c60b9acSAndroid Build Coastguard Worker 
63*1c60b9acSAndroid Build Coastguard Worker typedef enum cbreason {
64*1c60b9acSAndroid Build Coastguard Worker 	LCN_SOL			= (1 << 0),
65*1c60b9acSAndroid Build Coastguard Worker 	LCN_EOL			= (1 << 1)
66*1c60b9acSAndroid Build Coastguard Worker } cbreason_t;
67*1c60b9acSAndroid Build Coastguard Worker 
68*1c60b9acSAndroid Build Coastguard Worker typedef int (*nsc_cb_t)(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
69*1c60b9acSAndroid Build Coastguard Worker 			const char *buf, size_t size);
70*1c60b9acSAndroid Build Coastguard Worker 
71*1c60b9acSAndroid Build Coastguard Worker static void
72*1c60b9acSAndroid Build Coastguard Worker expiry_cb(lws_sorted_usec_list_t *sul);
73*1c60b9acSAndroid Build Coastguard Worker 
74*1c60b9acSAndroid Build Coastguard Worker static int
nsc_backing_open_lock(lws_cache_nscookiejar_t * cache,int mode,const char * par)75*1c60b9acSAndroid Build Coastguard Worker nsc_backing_open_lock(lws_cache_nscookiejar_t *cache, int mode, const char *par)
76*1c60b9acSAndroid Build Coastguard Worker {
77*1c60b9acSAndroid Build Coastguard Worker 	int sanity = 50;
78*1c60b9acSAndroid Build Coastguard Worker 	char lock[128];
79*1c60b9acSAndroid Build Coastguard Worker 	int fd_lock, fd;
80*1c60b9acSAndroid Build Coastguard Worker 
81*1c60b9acSAndroid Build Coastguard Worker 	lwsl_debug("%s: %s\n", __func__, par);
82*1c60b9acSAndroid Build Coastguard Worker 
83*1c60b9acSAndroid Build Coastguard Worker 	lws_snprintf(lock, sizeof(lock), "%s.LCK",
84*1c60b9acSAndroid Build Coastguard Worker 			cache->cache.info.u.nscookiejar.filepath);
85*1c60b9acSAndroid Build Coastguard Worker 
86*1c60b9acSAndroid Build Coastguard Worker 	do {
87*1c60b9acSAndroid Build Coastguard Worker 		fd_lock = open(lock, LWS_O_CREAT | O_EXCL, 0600);
88*1c60b9acSAndroid Build Coastguard Worker 		if (fd_lock >= 0) {
89*1c60b9acSAndroid Build Coastguard Worker 			close(fd_lock);
90*1c60b9acSAndroid Build Coastguard Worker 			break;
91*1c60b9acSAndroid Build Coastguard Worker 		}
92*1c60b9acSAndroid Build Coastguard Worker 
93*1c60b9acSAndroid Build Coastguard Worker 		if (!sanity--) {
94*1c60b9acSAndroid Build Coastguard Worker 			lwsl_warn("%s: unable to lock %s: errno %d\n", __func__,
95*1c60b9acSAndroid Build Coastguard Worker 					lock, errno);
96*1c60b9acSAndroid Build Coastguard Worker 			return -1;
97*1c60b9acSAndroid Build Coastguard Worker 		}
98*1c60b9acSAndroid Build Coastguard Worker 
99*1c60b9acSAndroid Build Coastguard Worker #if defined(WIN32)
100*1c60b9acSAndroid Build Coastguard Worker 		Sleep(100);
101*1c60b9acSAndroid Build Coastguard Worker #else
102*1c60b9acSAndroid Build Coastguard Worker 		usleep(100000);
103*1c60b9acSAndroid Build Coastguard Worker #endif
104*1c60b9acSAndroid Build Coastguard Worker 	} while (1);
105*1c60b9acSAndroid Build Coastguard Worker 
106*1c60b9acSAndroid Build Coastguard Worker 	fd = open(cache->cache.info.u.nscookiejar.filepath,
107*1c60b9acSAndroid Build Coastguard Worker 		      LWS_O_CREAT | mode, 0600);
108*1c60b9acSAndroid Build Coastguard Worker 
109*1c60b9acSAndroid Build Coastguard Worker 	if (fd == -1) {
110*1c60b9acSAndroid Build Coastguard Worker 		lwsl_warn("%s: unable to open or create %s\n", __func__,
111*1c60b9acSAndroid Build Coastguard Worker 				cache->cache.info.u.nscookiejar.filepath);
112*1c60b9acSAndroid Build Coastguard Worker 		unlink(lock);
113*1c60b9acSAndroid Build Coastguard Worker 	}
114*1c60b9acSAndroid Build Coastguard Worker 
115*1c60b9acSAndroid Build Coastguard Worker 	return fd;
116*1c60b9acSAndroid Build Coastguard Worker }
117*1c60b9acSAndroid Build Coastguard Worker 
118*1c60b9acSAndroid Build Coastguard Worker static void
nsc_backing_close_unlock(lws_cache_nscookiejar_t * cache,int fd)119*1c60b9acSAndroid Build Coastguard Worker nsc_backing_close_unlock(lws_cache_nscookiejar_t *cache, int fd)
120*1c60b9acSAndroid Build Coastguard Worker {
121*1c60b9acSAndroid Build Coastguard Worker 	char lock[128];
122*1c60b9acSAndroid Build Coastguard Worker 
123*1c60b9acSAndroid Build Coastguard Worker 	lwsl_debug("%s\n", __func__);
124*1c60b9acSAndroid Build Coastguard Worker 
125*1c60b9acSAndroid Build Coastguard Worker 	lws_snprintf(lock, sizeof(lock), "%s.LCK",
126*1c60b9acSAndroid Build Coastguard Worker 			cache->cache.info.u.nscookiejar.filepath);
127*1c60b9acSAndroid Build Coastguard Worker 	if (fd >= 0)
128*1c60b9acSAndroid Build Coastguard Worker 		close(fd);
129*1c60b9acSAndroid Build Coastguard Worker 	unlink(lock);
130*1c60b9acSAndroid Build Coastguard Worker }
131*1c60b9acSAndroid Build Coastguard Worker 
132*1c60b9acSAndroid Build Coastguard Worker /*
133*1c60b9acSAndroid Build Coastguard Worker  * We're going to call the callback with chunks of the file with flags
134*1c60b9acSAndroid Build Coastguard Worker  * indicating we're giving it the start of a line and / or giving it the end
135*1c60b9acSAndroid Build Coastguard Worker  * of a line.
136*1c60b9acSAndroid Build Coastguard Worker  *
137*1c60b9acSAndroid Build Coastguard Worker  * It's like this because the cookie value may be huge (and to a lesser extent
138*1c60b9acSAndroid Build Coastguard Worker  * the path may also be big).
139*1c60b9acSAndroid Build Coastguard Worker  *
140*1c60b9acSAndroid Build Coastguard Worker  * If it's the start of a line (flags on the cb has LCN_SOL), then the buffer
141*1c60b9acSAndroid Build Coastguard Worker  * contains up to the first 256 chars of the line, it's enough to match with.
142*1c60b9acSAndroid Build Coastguard Worker  *
143*1c60b9acSAndroid Build Coastguard Worker  * We cannot hold the file open inbetweentimes, since other processes may
144*1c60b9acSAndroid Build Coastguard Worker  * regenerate it, so we need to bind to a new inode.  We open it with an
145*1c60b9acSAndroid Build Coastguard Worker  * exclusive flock() so other processes can't replace conflicting changes
146*1c60b9acSAndroid Build Coastguard Worker  * while we also write changes, without having to wait and see our changes.
147*1c60b9acSAndroid Build Coastguard Worker  */
148*1c60b9acSAndroid Build Coastguard Worker 
149*1c60b9acSAndroid Build Coastguard Worker static int
nscookiejar_iterate(lws_cache_nscookiejar_t * cache,int fd,nsc_cb_t cb,void * opaque)150*1c60b9acSAndroid Build Coastguard Worker nscookiejar_iterate(lws_cache_nscookiejar_t *cache, int fd,
151*1c60b9acSAndroid Build Coastguard Worker 		    nsc_cb_t cb, void *opaque)
152*1c60b9acSAndroid Build Coastguard Worker {
153*1c60b9acSAndroid Build Coastguard Worker 	int m = 0, n = 0, e, r = LCN_SOL, ignore = 0, ret = 0;
154*1c60b9acSAndroid Build Coastguard Worker 	char temp[256], eof = 0;
155*1c60b9acSAndroid Build Coastguard Worker 
156*1c60b9acSAndroid Build Coastguard Worker 	if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
157*1c60b9acSAndroid Build Coastguard Worker 		return -1;
158*1c60b9acSAndroid Build Coastguard Worker 
159*1c60b9acSAndroid Build Coastguard Worker 	do { /* for as many buffers in the file */
160*1c60b9acSAndroid Build Coastguard Worker 
161*1c60b9acSAndroid Build Coastguard Worker 		int n1;
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker 		lwsl_debug("%s: n %d, m %d\n", __func__, n, m);
164*1c60b9acSAndroid Build Coastguard Worker 
165*1c60b9acSAndroid Build Coastguard Worker read:
166*1c60b9acSAndroid Build Coastguard Worker 		n1 = (int)read(fd, temp + n, sizeof(temp) - (size_t)n);
167*1c60b9acSAndroid Build Coastguard Worker 
168*1c60b9acSAndroid Build Coastguard Worker 		lwsl_debug("%s: n1 %d\n", __func__, n1);
169*1c60b9acSAndroid Build Coastguard Worker 
170*1c60b9acSAndroid Build Coastguard Worker 		if (n1 <= 0) {
171*1c60b9acSAndroid Build Coastguard Worker 			eof = 1;
172*1c60b9acSAndroid Build Coastguard Worker 			if (m == n)
173*1c60b9acSAndroid Build Coastguard Worker 				continue;
174*1c60b9acSAndroid Build Coastguard Worker 		} else
175*1c60b9acSAndroid Build Coastguard Worker 			n += n1;
176*1c60b9acSAndroid Build Coastguard Worker 
177*1c60b9acSAndroid Build Coastguard Worker 		while (m < n) {
178*1c60b9acSAndroid Build Coastguard Worker 
179*1c60b9acSAndroid Build Coastguard Worker 			m++;
180*1c60b9acSAndroid Build Coastguard Worker 
181*1c60b9acSAndroid Build Coastguard Worker 			if (temp[m - 1] != '\n')
182*1c60b9acSAndroid Build Coastguard Worker 				continue;
183*1c60b9acSAndroid Build Coastguard Worker 
184*1c60b9acSAndroid Build Coastguard Worker 			/* ie, we hit EOL */
185*1c60b9acSAndroid Build Coastguard Worker 
186*1c60b9acSAndroid Build Coastguard Worker 			if (temp[0] == '#')
187*1c60b9acSAndroid Build Coastguard Worker 				/* lines starting with # are comments */
188*1c60b9acSAndroid Build Coastguard Worker 				e = 0;
189*1c60b9acSAndroid Build Coastguard Worker 			else
190*1c60b9acSAndroid Build Coastguard Worker 				e = cb(cache, opaque, r | LCN_EOL, temp,
191*1c60b9acSAndroid Build Coastguard Worker 				       (size_t)m - 1);
192*1c60b9acSAndroid Build Coastguard Worker 			r = LCN_SOL;
193*1c60b9acSAndroid Build Coastguard Worker 			ignore = 0;
194*1c60b9acSAndroid Build Coastguard Worker 			/*
195*1c60b9acSAndroid Build Coastguard Worker 			 * Move back remainder and prefill the gap that opened
196*1c60b9acSAndroid Build Coastguard Worker 			 * up: we want to pass enough in the start chunk so the
197*1c60b9acSAndroid Build Coastguard Worker 			 * cb can classify it even if it can't get all the
198*1c60b9acSAndroid Build Coastguard Worker 			 * value part in one go
199*1c60b9acSAndroid Build Coastguard Worker 			 */
200*1c60b9acSAndroid Build Coastguard Worker 			memmove(temp, temp + m, (size_t)(n - m));
201*1c60b9acSAndroid Build Coastguard Worker 			n -= m;
202*1c60b9acSAndroid Build Coastguard Worker 			m = 0;
203*1c60b9acSAndroid Build Coastguard Worker 
204*1c60b9acSAndroid Build Coastguard Worker 			if (e) {
205*1c60b9acSAndroid Build Coastguard Worker 				ret = e;
206*1c60b9acSAndroid Build Coastguard Worker 				goto bail;
207*1c60b9acSAndroid Build Coastguard Worker 			}
208*1c60b9acSAndroid Build Coastguard Worker 
209*1c60b9acSAndroid Build Coastguard Worker 			goto read;
210*1c60b9acSAndroid Build Coastguard Worker 		}
211*1c60b9acSAndroid Build Coastguard Worker 
212*1c60b9acSAndroid Build Coastguard Worker 		if (m) {
213*1c60b9acSAndroid Build Coastguard Worker 			/* we ran out of buffer */
214*1c60b9acSAndroid Build Coastguard Worker 			if (ignore || (r == LCN_SOL && n && temp[0] == '#')) {
215*1c60b9acSAndroid Build Coastguard Worker 				e = 0;
216*1c60b9acSAndroid Build Coastguard Worker 				ignore = 1;
217*1c60b9acSAndroid Build Coastguard Worker 			} else {
218*1c60b9acSAndroid Build Coastguard Worker 				e = cb(cache, opaque,
219*1c60b9acSAndroid Build Coastguard Worker 				       r | (n == m && eof ? LCN_EOL : 0),
220*1c60b9acSAndroid Build Coastguard Worker 				       temp, (size_t)m);
221*1c60b9acSAndroid Build Coastguard Worker 
222*1c60b9acSAndroid Build Coastguard Worker 				m = 0;
223*1c60b9acSAndroid Build Coastguard Worker 				n = 0;
224*1c60b9acSAndroid Build Coastguard Worker 			}
225*1c60b9acSAndroid Build Coastguard Worker 
226*1c60b9acSAndroid Build Coastguard Worker 			if (e) {
227*1c60b9acSAndroid Build Coastguard Worker 				/*
228*1c60b9acSAndroid Build Coastguard Worker 				 * We have to call off the whole thing if any
229*1c60b9acSAndroid Build Coastguard Worker 				 * step, eg, OOMs
230*1c60b9acSAndroid Build Coastguard Worker 				 */
231*1c60b9acSAndroid Build Coastguard Worker 				ret = e;
232*1c60b9acSAndroid Build Coastguard Worker 				goto bail;
233*1c60b9acSAndroid Build Coastguard Worker 			}
234*1c60b9acSAndroid Build Coastguard Worker 			r = 0;
235*1c60b9acSAndroid Build Coastguard Worker 		}
236*1c60b9acSAndroid Build Coastguard Worker 
237*1c60b9acSAndroid Build Coastguard Worker 	} while (!eof || n != m);
238*1c60b9acSAndroid Build Coastguard Worker 
239*1c60b9acSAndroid Build Coastguard Worker 	ret = 0;
240*1c60b9acSAndroid Build Coastguard Worker 
241*1c60b9acSAndroid Build Coastguard Worker bail:
242*1c60b9acSAndroid Build Coastguard Worker 
243*1c60b9acSAndroid Build Coastguard Worker 	return ret;
244*1c60b9acSAndroid Build Coastguard Worker }
245*1c60b9acSAndroid Build Coastguard Worker 
246*1c60b9acSAndroid Build Coastguard Worker /*
247*1c60b9acSAndroid Build Coastguard Worker  * lookup() just handles wildcard resolution, it doesn't deal with moving the
248*1c60b9acSAndroid Build Coastguard Worker  * hits to L1.  That has to be done individually by non-wildcard names.
249*1c60b9acSAndroid Build Coastguard Worker  */
250*1c60b9acSAndroid Build Coastguard Worker 
251*1c60b9acSAndroid Build Coastguard Worker enum {
252*1c60b9acSAndroid Build Coastguard Worker 	NSC_COL_HOST		= 0, /* wc idx 0 */
253*1c60b9acSAndroid Build Coastguard Worker 	NSC_COL_PATH		= 2, /* wc idx 1 */
254*1c60b9acSAndroid Build Coastguard Worker 	NSC_COL_EXPIRY		= 4,
255*1c60b9acSAndroid Build Coastguard Worker 	NSC_COL_NAME		= 5, /* wc idx 2 */
256*1c60b9acSAndroid Build Coastguard Worker 
257*1c60b9acSAndroid Build Coastguard Worker 	NSC_COL_COUNT		= 6
258*1c60b9acSAndroid Build Coastguard Worker };
259*1c60b9acSAndroid Build Coastguard Worker 
260*1c60b9acSAndroid Build Coastguard Worker /*
261*1c60b9acSAndroid Build Coastguard Worker  * This performs the specialized wildcard that knows about cookie path match
262*1c60b9acSAndroid Build Coastguard Worker  * rules.
263*1c60b9acSAndroid Build Coastguard Worker  *
264*1c60b9acSAndroid Build Coastguard Worker  * To defeat the lookup path matching, lie to it about idx being NSC_COL_PATH
265*1c60b9acSAndroid Build Coastguard Worker  */
266*1c60b9acSAndroid Build Coastguard Worker 
267*1c60b9acSAndroid Build Coastguard Worker static int
nsc_match(const char * wc,size_t wc_len,const char * col,size_t col_len,int idx)268*1c60b9acSAndroid Build Coastguard Worker nsc_match(const char *wc, size_t wc_len, const char *col, size_t col_len,
269*1c60b9acSAndroid Build Coastguard Worker 	  int idx)
270*1c60b9acSAndroid Build Coastguard Worker {
271*1c60b9acSAndroid Build Coastguard Worker 	size_t n = 0;
272*1c60b9acSAndroid Build Coastguard Worker 
273*1c60b9acSAndroid Build Coastguard Worker 	if (idx != NSC_COL_PATH)
274*1c60b9acSAndroid Build Coastguard Worker 		return lws_strcmp_wildcard(wc, wc_len, col, col_len);
275*1c60b9acSAndroid Build Coastguard Worker 
276*1c60b9acSAndroid Build Coastguard Worker 	/*
277*1c60b9acSAndroid Build Coastguard Worker 	 * Cookie path match is special, if we lookup on a path like /my/path,
278*1c60b9acSAndroid Build Coastguard Worker 	 * we must match on cookie paths for every dir level including /, so
279*1c60b9acSAndroid Build Coastguard Worker 	 * match on /, /my, and /my/path.  But we must not match on /m or
280*1c60b9acSAndroid Build Coastguard Worker 	 * /my/pa etc.  If we lookup on /, we must not match /my/path
281*1c60b9acSAndroid Build Coastguard Worker 	 *
282*1c60b9acSAndroid Build Coastguard Worker 	 * Let's go through wc checking at / and for every complete subpath if
283*1c60b9acSAndroid Build Coastguard Worker 	 * it is an explicit match
284*1c60b9acSAndroid Build Coastguard Worker 	 */
285*1c60b9acSAndroid Build Coastguard Worker 
286*1c60b9acSAndroid Build Coastguard Worker 	if (!strcmp(col, wc))
287*1c60b9acSAndroid Build Coastguard Worker 		return 0; /* exact hit */
288*1c60b9acSAndroid Build Coastguard Worker 
289*1c60b9acSAndroid Build Coastguard Worker 	while (n <= wc_len) {
290*1c60b9acSAndroid Build Coastguard Worker 		if (n == wc_len || wc[n] == '/') {
291*1c60b9acSAndroid Build Coastguard Worker 			if (n && col_len <= n && !strncmp(wc, col, n))
292*1c60b9acSAndroid Build Coastguard Worker 				return 0; /* hit */
293*1c60b9acSAndroid Build Coastguard Worker 
294*1c60b9acSAndroid Build Coastguard Worker 			if (n != wc_len && col_len <= n + 1 &&
295*1c60b9acSAndroid Build Coastguard Worker 			    !strncmp(wc, col, n + 1)) /* check for trailing / */
296*1c60b9acSAndroid Build Coastguard Worker 				return 0; /* hit */
297*1c60b9acSAndroid Build Coastguard Worker 		}
298*1c60b9acSAndroid Build Coastguard Worker 		n++;
299*1c60b9acSAndroid Build Coastguard Worker 	}
300*1c60b9acSAndroid Build Coastguard Worker 
301*1c60b9acSAndroid Build Coastguard Worker 	return 1; /* fail */
302*1c60b9acSAndroid Build Coastguard Worker }
303*1c60b9acSAndroid Build Coastguard Worker 
304*1c60b9acSAndroid Build Coastguard Worker static const uint8_t nsc_cols[] = { NSC_COL_HOST, NSC_COL_PATH, NSC_COL_NAME };
305*1c60b9acSAndroid Build Coastguard Worker 
306*1c60b9acSAndroid Build Coastguard Worker static int
lws_cache_nscookiejar_tag_match(struct lws_cache_ttl_lru * cache,const char * wc,const char * tag,char lookup)307*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_tag_match(struct lws_cache_ttl_lru *cache,
308*1c60b9acSAndroid Build Coastguard Worker 				const char *wc, const char *tag, char lookup)
309*1c60b9acSAndroid Build Coastguard Worker {
310*1c60b9acSAndroid Build Coastguard Worker 	const char *wc_end = wc + strlen(wc), *tag_end = tag + strlen(tag),
311*1c60b9acSAndroid Build Coastguard Worker 			*start_wc, *start_tag;
312*1c60b9acSAndroid Build Coastguard Worker 	int n = 0;
313*1c60b9acSAndroid Build Coastguard Worker 
314*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cache("%s: '%s' vs '%s'\n", __func__, wc, tag);
315*1c60b9acSAndroid Build Coastguard Worker 
316*1c60b9acSAndroid Build Coastguard Worker 	/*
317*1c60b9acSAndroid Build Coastguard Worker 	 * Given a well-formed host|path|name tag and a wildcard term,
318*1c60b9acSAndroid Build Coastguard Worker 	 * make the determination if the tag matches the wildcard or not,
319*1c60b9acSAndroid Build Coastguard Worker 	 * using lookup rules that apply at this cache level.
320*1c60b9acSAndroid Build Coastguard Worker 	 */
321*1c60b9acSAndroid Build Coastguard Worker 
322*1c60b9acSAndroid Build Coastguard Worker 	while (n < 3) {
323*1c60b9acSAndroid Build Coastguard Worker 		start_wc = wc;
324*1c60b9acSAndroid Build Coastguard Worker 		while (wc < wc_end && *wc != LWSCTAG_SEP)
325*1c60b9acSAndroid Build Coastguard Worker 			wc++;
326*1c60b9acSAndroid Build Coastguard Worker 
327*1c60b9acSAndroid Build Coastguard Worker 		start_tag = tag;
328*1c60b9acSAndroid Build Coastguard Worker 		while (tag < tag_end && *tag != LWSCTAG_SEP)
329*1c60b9acSAndroid Build Coastguard Worker 			tag++;
330*1c60b9acSAndroid Build Coastguard Worker 
331*1c60b9acSAndroid Build Coastguard Worker 		lwsl_cache("%s:   '%.*s' vs '%.*s'\n", __func__,
332*1c60b9acSAndroid Build Coastguard Worker 				lws_ptr_diff(wc, start_wc), start_wc,
333*1c60b9acSAndroid Build Coastguard Worker 				lws_ptr_diff(tag, start_tag), start_tag);
334*1c60b9acSAndroid Build Coastguard Worker 		if (nsc_match(start_wc, lws_ptr_diff_size_t(wc, start_wc),
335*1c60b9acSAndroid Build Coastguard Worker 			      start_tag, lws_ptr_diff_size_t(tag, start_tag),
336*1c60b9acSAndroid Build Coastguard Worker 			      lookup ? nsc_cols[n] : NSC_COL_HOST)) {
337*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cache("%s: fail\n", __func__);
338*1c60b9acSAndroid Build Coastguard Worker 			return 1;
339*1c60b9acSAndroid Build Coastguard Worker 		}
340*1c60b9acSAndroid Build Coastguard Worker 
341*1c60b9acSAndroid Build Coastguard Worker 		if (wc < wc_end)
342*1c60b9acSAndroid Build Coastguard Worker 			wc++;
343*1c60b9acSAndroid Build Coastguard Worker 		if (tag < tag_end)
344*1c60b9acSAndroid Build Coastguard Worker 			tag++;
345*1c60b9acSAndroid Build Coastguard Worker 
346*1c60b9acSAndroid Build Coastguard Worker 		n++;
347*1c60b9acSAndroid Build Coastguard Worker 	}
348*1c60b9acSAndroid Build Coastguard Worker 
349*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cache("%s: hit\n", __func__);
350*1c60b9acSAndroid Build Coastguard Worker 
351*1c60b9acSAndroid Build Coastguard Worker 	return 0; /* match */
352*1c60b9acSAndroid Build Coastguard Worker }
353*1c60b9acSAndroid Build Coastguard Worker 
354*1c60b9acSAndroid Build Coastguard Worker /*
355*1c60b9acSAndroid Build Coastguard Worker  * Converts the start of a cookie file line into a tag
356*1c60b9acSAndroid Build Coastguard Worker  */
357*1c60b9acSAndroid Build Coastguard Worker 
358*1c60b9acSAndroid Build Coastguard Worker static int
nsc_line_to_tag(const char * buf,size_t size,char * tag,size_t max_tag,lws_usec_t * pexpiry)359*1c60b9acSAndroid Build Coastguard Worker nsc_line_to_tag(const char *buf, size_t size, char *tag, size_t max_tag,
360*1c60b9acSAndroid Build Coastguard Worker 		lws_usec_t *pexpiry)
361*1c60b9acSAndroid Build Coastguard Worker {
362*1c60b9acSAndroid Build Coastguard Worker 	int n, idx = 0, tl = 0;
363*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t expiry = 0;
364*1c60b9acSAndroid Build Coastguard Worker 	size_t bn = 0;
365*1c60b9acSAndroid Build Coastguard Worker 	char col[64];
366*1c60b9acSAndroid Build Coastguard Worker 
367*1c60b9acSAndroid Build Coastguard Worker 	if (size < 3)
368*1c60b9acSAndroid Build Coastguard Worker 		return 1;
369*1c60b9acSAndroid Build Coastguard Worker 
370*1c60b9acSAndroid Build Coastguard Worker 	while (bn < size && idx <= NSC_COL_NAME) {
371*1c60b9acSAndroid Build Coastguard Worker 
372*1c60b9acSAndroid Build Coastguard Worker 		n = 0;
373*1c60b9acSAndroid Build Coastguard Worker 		while (bn < size && n < (int)sizeof(col) - 1 &&
374*1c60b9acSAndroid Build Coastguard Worker 		       buf[bn] != '\t')
375*1c60b9acSAndroid Build Coastguard Worker 			col[n++] = buf[bn++];
376*1c60b9acSAndroid Build Coastguard Worker 		col[n] = '\0';
377*1c60b9acSAndroid Build Coastguard Worker 		if (buf[bn] == '\t')
378*1c60b9acSAndroid Build Coastguard Worker 			bn++;
379*1c60b9acSAndroid Build Coastguard Worker 
380*1c60b9acSAndroid Build Coastguard Worker 		switch (idx) {
381*1c60b9acSAndroid Build Coastguard Worker 		case NSC_COL_EXPIRY:
382*1c60b9acSAndroid Build Coastguard Worker 			expiry = (lws_usec_t)((unsigned long long)atoll(col) *
383*1c60b9acSAndroid Build Coastguard Worker 					(lws_usec_t)LWS_US_PER_SEC);
384*1c60b9acSAndroid Build Coastguard Worker 			break;
385*1c60b9acSAndroid Build Coastguard Worker 
386*1c60b9acSAndroid Build Coastguard Worker 		case NSC_COL_HOST:
387*1c60b9acSAndroid Build Coastguard Worker 		case NSC_COL_PATH:
388*1c60b9acSAndroid Build Coastguard Worker 		case NSC_COL_NAME:
389*1c60b9acSAndroid Build Coastguard Worker 
390*1c60b9acSAndroid Build Coastguard Worker 			/*
391*1c60b9acSAndroid Build Coastguard Worker 			 * As we match the pieces of the wildcard,
392*1c60b9acSAndroid Build Coastguard Worker 			 * compose the matches into a specific tag
393*1c60b9acSAndroid Build Coastguard Worker 			 */
394*1c60b9acSAndroid Build Coastguard Worker 
395*1c60b9acSAndroid Build Coastguard Worker 			if (tl + n + 2 > (int)max_tag)
396*1c60b9acSAndroid Build Coastguard Worker 				return 1;
397*1c60b9acSAndroid Build Coastguard Worker 			if (tl)
398*1c60b9acSAndroid Build Coastguard Worker 				tag[tl++] = LWSCTAG_SEP;
399*1c60b9acSAndroid Build Coastguard Worker 			memcpy(tag + tl, col, (size_t)n);
400*1c60b9acSAndroid Build Coastguard Worker 			tl += n;
401*1c60b9acSAndroid Build Coastguard Worker 			tag[tl] = '\0';
402*1c60b9acSAndroid Build Coastguard Worker 			break;
403*1c60b9acSAndroid Build Coastguard Worker 		default:
404*1c60b9acSAndroid Build Coastguard Worker 			break;
405*1c60b9acSAndroid Build Coastguard Worker 		}
406*1c60b9acSAndroid Build Coastguard Worker 
407*1c60b9acSAndroid Build Coastguard Worker 		idx++;
408*1c60b9acSAndroid Build Coastguard Worker 	}
409*1c60b9acSAndroid Build Coastguard Worker 
410*1c60b9acSAndroid Build Coastguard Worker 	if (pexpiry)
411*1c60b9acSAndroid Build Coastguard Worker 		*pexpiry = expiry;
412*1c60b9acSAndroid Build Coastguard Worker 
413*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: %.*s: tag '%s'\n", __func__, (int)size, buf, tag);
414*1c60b9acSAndroid Build Coastguard Worker 
415*1c60b9acSAndroid Build Coastguard Worker 	return 0;
416*1c60b9acSAndroid Build Coastguard Worker }
417*1c60b9acSAndroid Build Coastguard Worker 
418*1c60b9acSAndroid Build Coastguard Worker struct nsc_lookup_ctx {
419*1c60b9acSAndroid Build Coastguard Worker 	const char		*wildcard_key;
420*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_owner_t	*results_owner;
421*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_match_t	*match; /* current match if any */
422*1c60b9acSAndroid Build Coastguard Worker 	size_t			wklen;
423*1c60b9acSAndroid Build Coastguard Worker };
424*1c60b9acSAndroid Build Coastguard Worker 
425*1c60b9acSAndroid Build Coastguard Worker 
426*1c60b9acSAndroid Build Coastguard Worker static int
nsc_lookup_cb(lws_cache_nscookiejar_t * cache,void * opaque,int flags,const char * buf,size_t size)427*1c60b9acSAndroid Build Coastguard Worker nsc_lookup_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
428*1c60b9acSAndroid Build Coastguard Worker 	      const char *buf, size_t size)
429*1c60b9acSAndroid Build Coastguard Worker {
430*1c60b9acSAndroid Build Coastguard Worker 	struct nsc_lookup_ctx *ctx = (struct nsc_lookup_ctx *)opaque;
431*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t expiry;
432*1c60b9acSAndroid Build Coastguard Worker 	char tag[200];
433*1c60b9acSAndroid Build Coastguard Worker 	int tl;
434*1c60b9acSAndroid Build Coastguard Worker 
435*1c60b9acSAndroid Build Coastguard Worker 	if (!(flags & LCN_SOL)) {
436*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->match)
437*1c60b9acSAndroid Build Coastguard Worker 			ctx->match->payload_size += size;
438*1c60b9acSAndroid Build Coastguard Worker 
439*1c60b9acSAndroid Build Coastguard Worker 		return NIR_CONTINUE;
440*1c60b9acSAndroid Build Coastguard Worker 	}
441*1c60b9acSAndroid Build Coastguard Worker 
442*1c60b9acSAndroid Build Coastguard Worker 	/*
443*1c60b9acSAndroid Build Coastguard Worker 	 * There should be enough in buf to match or reject it... let's
444*1c60b9acSAndroid Build Coastguard Worker 	 * synthesize a tag from the text "line" and then check the tags for
445*1c60b9acSAndroid Build Coastguard Worker 	 * a match
446*1c60b9acSAndroid Build Coastguard Worker 	 */
447*1c60b9acSAndroid Build Coastguard Worker 
448*1c60b9acSAndroid Build Coastguard Worker 	ctx->match = NULL; /* new SOL means stop tracking payload len */
449*1c60b9acSAndroid Build Coastguard Worker 
450*1c60b9acSAndroid Build Coastguard Worker 	if (nsc_line_to_tag(buf, size, tag, sizeof(tag), &expiry))
451*1c60b9acSAndroid Build Coastguard Worker 		return NIR_CONTINUE;
452*1c60b9acSAndroid Build Coastguard Worker 
453*1c60b9acSAndroid Build Coastguard Worker 	if (lws_cache_nscookiejar_tag_match(&cache->cache,
454*1c60b9acSAndroid Build Coastguard Worker 					    ctx->wildcard_key, tag, 1))
455*1c60b9acSAndroid Build Coastguard Worker 		return NIR_CONTINUE;
456*1c60b9acSAndroid Build Coastguard Worker 
457*1c60b9acSAndroid Build Coastguard Worker 	tl = (int)strlen(tag);
458*1c60b9acSAndroid Build Coastguard Worker 
459*1c60b9acSAndroid Build Coastguard Worker 	/*
460*1c60b9acSAndroid Build Coastguard Worker 	 * ... it looks like a match then... create new match
461*1c60b9acSAndroid Build Coastguard Worker 	 * object with the specific tag, and add it to the owner list
462*1c60b9acSAndroid Build Coastguard Worker 	 */
463*1c60b9acSAndroid Build Coastguard Worker 
464*1c60b9acSAndroid Build Coastguard Worker 	ctx->match = lws_fi(&cache->cache.info.cx->fic, "cache_lookup_oom") ? NULL :
465*1c60b9acSAndroid Build Coastguard Worker 			lws_malloc(sizeof(*ctx->match) + (unsigned int)tl + 1u,
466*1c60b9acSAndroid Build Coastguard Worker 				__func__);
467*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->match)
468*1c60b9acSAndroid Build Coastguard Worker 		/* caller of lookup will clean results list on fail */
469*1c60b9acSAndroid Build Coastguard Worker 		return NIR_FINISH_ERROR;
470*1c60b9acSAndroid Build Coastguard Worker 
471*1c60b9acSAndroid Build Coastguard Worker 	ctx->match->payload_size = size;
472*1c60b9acSAndroid Build Coastguard Worker 	ctx->match->tag_size = (size_t)tl;
473*1c60b9acSAndroid Build Coastguard Worker 	ctx->match->expiry = expiry;
474*1c60b9acSAndroid Build Coastguard Worker 
475*1c60b9acSAndroid Build Coastguard Worker 	memset(&ctx->match->list, 0, sizeof(ctx->match->list));
476*1c60b9acSAndroid Build Coastguard Worker 	memcpy(&ctx->match[1], tag, (size_t)tl + 1u);
477*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_add_tail(&ctx->match->list, ctx->results_owner);
478*1c60b9acSAndroid Build Coastguard Worker 
479*1c60b9acSAndroid Build Coastguard Worker 	return NIR_CONTINUE;
480*1c60b9acSAndroid Build Coastguard Worker }
481*1c60b9acSAndroid Build Coastguard Worker 
482*1c60b9acSAndroid Build Coastguard Worker static int
lws_cache_nscookiejar_lookup(struct lws_cache_ttl_lru * _c,const char * wildcard_key,lws_dll2_owner_t * results_owner)483*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_lookup(struct lws_cache_ttl_lru *_c,
484*1c60b9acSAndroid Build Coastguard Worker 			     const char *wildcard_key,
485*1c60b9acSAndroid Build Coastguard Worker 			     lws_dll2_owner_t *results_owner)
486*1c60b9acSAndroid Build Coastguard Worker {
487*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
488*1c60b9acSAndroid Build Coastguard Worker 	struct nsc_lookup_ctx ctx;
489*1c60b9acSAndroid Build Coastguard Worker 	int ret, fd;
490*1c60b9acSAndroid Build Coastguard Worker 
491*1c60b9acSAndroid Build Coastguard Worker 	fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
492*1c60b9acSAndroid Build Coastguard Worker 	if (fd < 0)
493*1c60b9acSAndroid Build Coastguard Worker 		return 1;
494*1c60b9acSAndroid Build Coastguard Worker 
495*1c60b9acSAndroid Build Coastguard Worker 	ctx.wildcard_key = wildcard_key;
496*1c60b9acSAndroid Build Coastguard Worker 	ctx.results_owner = results_owner;
497*1c60b9acSAndroid Build Coastguard Worker 	ctx.wklen = strlen(wildcard_key);
498*1c60b9acSAndroid Build Coastguard Worker 	ctx.match = 0;
499*1c60b9acSAndroid Build Coastguard Worker 
500*1c60b9acSAndroid Build Coastguard Worker 	ret = nscookiejar_iterate(cache, fd, nsc_lookup_cb, &ctx);
501*1c60b9acSAndroid Build Coastguard Worker 		/*
502*1c60b9acSAndroid Build Coastguard Worker 		 * The cb can fail, eg, with OOM, making the whole lookup
503*1c60b9acSAndroid Build Coastguard Worker 		 * invalid and returning fail.  Caller will clean
504*1c60b9acSAndroid Build Coastguard Worker 		 * results_owner on fail.
505*1c60b9acSAndroid Build Coastguard Worker 		 */
506*1c60b9acSAndroid Build Coastguard Worker 	nsc_backing_close_unlock(cache, fd);
507*1c60b9acSAndroid Build Coastguard Worker 
508*1c60b9acSAndroid Build Coastguard Worker 	return ret == NIR_FINISH_ERROR;
509*1c60b9acSAndroid Build Coastguard Worker }
510*1c60b9acSAndroid Build Coastguard Worker 
511*1c60b9acSAndroid Build Coastguard Worker /*
512*1c60b9acSAndroid Build Coastguard Worker  * It's pretty horrible having to implement add or remove individual items by
513*1c60b9acSAndroid Build Coastguard Worker  * file regeneration, but if we don't want to keep it all in heap, and we want
514*1c60b9acSAndroid Build Coastguard Worker  * this cookie jar format, that is what we are into.
515*1c60b9acSAndroid Build Coastguard Worker  *
516*1c60b9acSAndroid Build Coastguard Worker  * Allow to optionally add a "line", optionally wildcard delete tags, and always
517*1c60b9acSAndroid Build Coastguard Worker  * delete expired entries.
518*1c60b9acSAndroid Build Coastguard Worker  *
519*1c60b9acSAndroid Build Coastguard Worker  * Although we can rely on the lws thread to be doing this, multiple processes
520*1c60b9acSAndroid Build Coastguard Worker  * may be using the cookie jar and can tread on each other.  So we use flock()
521*1c60b9acSAndroid Build Coastguard Worker  * (linux only) to get exclusive access while we are processing this.
522*1c60b9acSAndroid Build Coastguard Worker  *
523*1c60b9acSAndroid Build Coastguard Worker  * We leave the existing file alone and generate a new one alongside it, with a
524*1c60b9acSAndroid Build Coastguard Worker  * fixed name.tmp format so it can't leak, if that went OK then we unlink the
525*1c60b9acSAndroid Build Coastguard Worker  * old and rename the new.
526*1c60b9acSAndroid Build Coastguard Worker  */
527*1c60b9acSAndroid Build Coastguard Worker 
528*1c60b9acSAndroid Build Coastguard Worker struct nsc_regen_ctx {
529*1c60b9acSAndroid Build Coastguard Worker 	const char		*wildcard_key_delete;
530*1c60b9acSAndroid Build Coastguard Worker 	const void		*add_data;
531*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t		curr;
532*1c60b9acSAndroid Build Coastguard Worker 	size_t			add_size;
533*1c60b9acSAndroid Build Coastguard Worker 	int			fdt;
534*1c60b9acSAndroid Build Coastguard Worker 	char			drop;
535*1c60b9acSAndroid Build Coastguard Worker };
536*1c60b9acSAndroid Build Coastguard Worker 
537*1c60b9acSAndroid Build Coastguard Worker /* only used by nsc_regen() */
538*1c60b9acSAndroid Build Coastguard Worker 
539*1c60b9acSAndroid Build Coastguard Worker static int
nsc_regen_cb(lws_cache_nscookiejar_t * cache,void * opaque,int flags,const char * buf,size_t size)540*1c60b9acSAndroid Build Coastguard Worker nsc_regen_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
541*1c60b9acSAndroid Build Coastguard Worker 	      const char *buf, size_t size)
542*1c60b9acSAndroid Build Coastguard Worker {
543*1c60b9acSAndroid Build Coastguard Worker 	struct nsc_regen_ctx *ctx = (struct nsc_regen_ctx *)opaque;
544*1c60b9acSAndroid Build Coastguard Worker 	char tag[256];
545*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t expiry;
546*1c60b9acSAndroid Build Coastguard Worker 
547*1c60b9acSAndroid Build Coastguard Worker 	if (flags & LCN_SOL) {
548*1c60b9acSAndroid Build Coastguard Worker 
549*1c60b9acSAndroid Build Coastguard Worker 		ctx->drop = 0;
550*1c60b9acSAndroid Build Coastguard Worker 
551*1c60b9acSAndroid Build Coastguard Worker 		if (nsc_line_to_tag(buf, size, tag, sizeof(tag), &expiry))
552*1c60b9acSAndroid Build Coastguard Worker 			/* filter it out if it is unparseable */
553*1c60b9acSAndroid Build Coastguard Worker 			goto drop;
554*1c60b9acSAndroid Build Coastguard Worker 
555*1c60b9acSAndroid Build Coastguard Worker 		/* routinely track the earliest expiry */
556*1c60b9acSAndroid Build Coastguard Worker 
557*1c60b9acSAndroid Build Coastguard Worker 		if (!cache->earliest_expiry ||
558*1c60b9acSAndroid Build Coastguard Worker 		    (expiry && cache->earliest_expiry > expiry))
559*1c60b9acSAndroid Build Coastguard Worker 			cache->earliest_expiry = expiry;
560*1c60b9acSAndroid Build Coastguard Worker 
561*1c60b9acSAndroid Build Coastguard Worker 		if (expiry && expiry < ctx->curr)
562*1c60b9acSAndroid Build Coastguard Worker 			/* routinely strip anything beyond its expiry */
563*1c60b9acSAndroid Build Coastguard Worker 			goto drop;
564*1c60b9acSAndroid Build Coastguard Worker 
565*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->wildcard_key_delete)
566*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cache("%s: %s vs %s\n", __func__,
567*1c60b9acSAndroid Build Coastguard Worker 					tag, ctx->wildcard_key_delete);
568*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->wildcard_key_delete &&
569*1c60b9acSAndroid Build Coastguard Worker 		    !lws_cache_nscookiejar_tag_match(&cache->cache,
570*1c60b9acSAndroid Build Coastguard Worker 						     ctx->wildcard_key_delete,
571*1c60b9acSAndroid Build Coastguard Worker 						     tag, 0)) {
572*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cache("%s: %s matches wc delete %s\n", __func__,
573*1c60b9acSAndroid Build Coastguard Worker 					tag, ctx->wildcard_key_delete);
574*1c60b9acSAndroid Build Coastguard Worker 			goto drop;
575*1c60b9acSAndroid Build Coastguard Worker 		}
576*1c60b9acSAndroid Build Coastguard Worker 	}
577*1c60b9acSAndroid Build Coastguard Worker 
578*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->drop)
579*1c60b9acSAndroid Build Coastguard Worker 		return 0;
580*1c60b9acSAndroid Build Coastguard Worker 
581*1c60b9acSAndroid Build Coastguard Worker 	cache->cache.current_footprint += (uint64_t)size;
582*1c60b9acSAndroid Build Coastguard Worker 
583*1c60b9acSAndroid Build Coastguard Worker 	if (write(ctx->fdt, buf, /*msvc*/(unsigned int)size) != (ssize_t)size)
584*1c60b9acSAndroid Build Coastguard Worker 		return NIR_FINISH_ERROR;
585*1c60b9acSAndroid Build Coastguard Worker 
586*1c60b9acSAndroid Build Coastguard Worker 	if (flags & LCN_EOL)
587*1c60b9acSAndroid Build Coastguard Worker 		if ((size_t)write(ctx->fdt, "\n", 1) != 1)
588*1c60b9acSAndroid Build Coastguard Worker 			return NIR_FINISH_ERROR;
589*1c60b9acSAndroid Build Coastguard Worker 
590*1c60b9acSAndroid Build Coastguard Worker 	return 0;
591*1c60b9acSAndroid Build Coastguard Worker 
592*1c60b9acSAndroid Build Coastguard Worker drop:
593*1c60b9acSAndroid Build Coastguard Worker 	ctx->drop = 1;
594*1c60b9acSAndroid Build Coastguard Worker 
595*1c60b9acSAndroid Build Coastguard Worker 	return NIR_CONTINUE;
596*1c60b9acSAndroid Build Coastguard Worker }
597*1c60b9acSAndroid Build Coastguard Worker 
598*1c60b9acSAndroid Build Coastguard Worker static int
nsc_regen(lws_cache_nscookiejar_t * cache,const char * wc_delete,const void * pay,size_t pay_size)599*1c60b9acSAndroid Build Coastguard Worker nsc_regen(lws_cache_nscookiejar_t *cache, const char *wc_delete,
600*1c60b9acSAndroid Build Coastguard Worker 	  const void *pay, size_t pay_size)
601*1c60b9acSAndroid Build Coastguard Worker {
602*1c60b9acSAndroid Build Coastguard Worker 	struct nsc_regen_ctx ctx;
603*1c60b9acSAndroid Build Coastguard Worker 	char filepath[128];
604*1c60b9acSAndroid Build Coastguard Worker 	int fd, ret = 1;
605*1c60b9acSAndroid Build Coastguard Worker 
606*1c60b9acSAndroid Build Coastguard Worker 	fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
607*1c60b9acSAndroid Build Coastguard Worker 	if (fd < 0)
608*1c60b9acSAndroid Build Coastguard Worker 		return 1;
609*1c60b9acSAndroid Build Coastguard Worker 
610*1c60b9acSAndroid Build Coastguard Worker 	lws_snprintf(filepath, sizeof(filepath), "%s.tmp",
611*1c60b9acSAndroid Build Coastguard Worker 			cache->cache.info.u.nscookiejar.filepath);
612*1c60b9acSAndroid Build Coastguard Worker 	unlink(filepath);
613*1c60b9acSAndroid Build Coastguard Worker 
614*1c60b9acSAndroid Build Coastguard Worker 	if (lws_fi(&cache->cache.info.cx->fic, "cache_regen_temp_open"))
615*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
616*1c60b9acSAndroid Build Coastguard Worker 
617*1c60b9acSAndroid Build Coastguard Worker 	ctx.fdt = open(filepath, LWS_O_CREAT | LWS_O_WRONLY, 0600);
618*1c60b9acSAndroid Build Coastguard Worker 	if (ctx.fdt < 0)
619*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
620*1c60b9acSAndroid Build Coastguard Worker 
621*1c60b9acSAndroid Build Coastguard Worker 	/* magic header */
622*1c60b9acSAndroid Build Coastguard Worker 
623*1c60b9acSAndroid Build Coastguard Worker 	if (lws_fi(&cache->cache.info.cx->fic, "cache_regen_temp_write") ||
624*1c60b9acSAndroid Build Coastguard Worker 	/* other consumers insist to see this at start of cookie jar */
625*1c60b9acSAndroid Build Coastguard Worker 	    write(ctx.fdt, "# Netscape HTTP Cookie File\n", 28) != 28)
626*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
627*1c60b9acSAndroid Build Coastguard Worker 
628*1c60b9acSAndroid Build Coastguard Worker 	/* if we are adding something, put it first */
629*1c60b9acSAndroid Build Coastguard Worker 
630*1c60b9acSAndroid Build Coastguard Worker 	if (pay &&
631*1c60b9acSAndroid Build Coastguard Worker 	    write(ctx.fdt, pay, /*msvc*/(unsigned int)pay_size) !=
632*1c60b9acSAndroid Build Coastguard Worker 						    (ssize_t)pay_size)
633*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
634*1c60b9acSAndroid Build Coastguard Worker 	if (pay && write(ctx.fdt, "\n", 1u) != (ssize_t)1)
635*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
636*1c60b9acSAndroid Build Coastguard Worker 
637*1c60b9acSAndroid Build Coastguard Worker 	cache->cache.current_footprint = 0;
638*1c60b9acSAndroid Build Coastguard Worker 
639*1c60b9acSAndroid Build Coastguard Worker 	ctx.wildcard_key_delete = wc_delete;
640*1c60b9acSAndroid Build Coastguard Worker 	ctx.add_data = pay;
641*1c60b9acSAndroid Build Coastguard Worker 	ctx.add_size = pay_size;
642*1c60b9acSAndroid Build Coastguard Worker 	ctx.curr = lws_now_usecs();
643*1c60b9acSAndroid Build Coastguard Worker 	ctx.drop = 0;
644*1c60b9acSAndroid Build Coastguard Worker 
645*1c60b9acSAndroid Build Coastguard Worker 	cache->earliest_expiry = 0;
646*1c60b9acSAndroid Build Coastguard Worker 
647*1c60b9acSAndroid Build Coastguard Worker 	if (lws_fi(&cache->cache.info.cx->fic, "cache_regen_iter_fail") ||
648*1c60b9acSAndroid Build Coastguard Worker 	    nscookiejar_iterate(cache, fd, nsc_regen_cb, &ctx))
649*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
650*1c60b9acSAndroid Build Coastguard Worker 
651*1c60b9acSAndroid Build Coastguard Worker 	close(ctx.fdt);
652*1c60b9acSAndroid Build Coastguard Worker 	ctx.fdt = -1;
653*1c60b9acSAndroid Build Coastguard Worker 
654*1c60b9acSAndroid Build Coastguard Worker 	if (unlink(cache->cache.info.u.nscookiejar.filepath) == -1)
655*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: unlink %s failed\n", __func__,
656*1c60b9acSAndroid Build Coastguard Worker 			  cache->cache.info.u.nscookiejar.filepath);
657*1c60b9acSAndroid Build Coastguard Worker 	if (rename(filepath, cache->cache.info.u.nscookiejar.filepath) == -1)
658*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: rename %s failed\n", __func__,
659*1c60b9acSAndroid Build Coastguard Worker 			  cache->cache.info.u.nscookiejar.filepath);
660*1c60b9acSAndroid Build Coastguard Worker 
661*1c60b9acSAndroid Build Coastguard Worker 	if (cache->earliest_expiry)
662*1c60b9acSAndroid Build Coastguard Worker 		lws_cache_schedule(&cache->cache, expiry_cb,
663*1c60b9acSAndroid Build Coastguard Worker 				   cache->earliest_expiry);
664*1c60b9acSAndroid Build Coastguard Worker 
665*1c60b9acSAndroid Build Coastguard Worker 	ret = 0;
666*1c60b9acSAndroid Build Coastguard Worker 	goto bail;
667*1c60b9acSAndroid Build Coastguard Worker 
668*1c60b9acSAndroid Build Coastguard Worker bail1:
669*1c60b9acSAndroid Build Coastguard Worker 	if (ctx.fdt >= 0)
670*1c60b9acSAndroid Build Coastguard Worker 		close(ctx.fdt);
671*1c60b9acSAndroid Build Coastguard Worker bail:
672*1c60b9acSAndroid Build Coastguard Worker 	unlink(filepath);
673*1c60b9acSAndroid Build Coastguard Worker 
674*1c60b9acSAndroid Build Coastguard Worker 	nsc_backing_close_unlock(cache, fd);
675*1c60b9acSAndroid Build Coastguard Worker 
676*1c60b9acSAndroid Build Coastguard Worker 	return ret;
677*1c60b9acSAndroid Build Coastguard Worker }
678*1c60b9acSAndroid Build Coastguard Worker 
679*1c60b9acSAndroid Build Coastguard Worker static void
expiry_cb(lws_sorted_usec_list_t * sul)680*1c60b9acSAndroid Build Coastguard Worker expiry_cb(lws_sorted_usec_list_t *sul)
681*1c60b9acSAndroid Build Coastguard Worker {
682*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = lws_container_of(sul,
683*1c60b9acSAndroid Build Coastguard Worker 					lws_cache_nscookiejar_t, cache.sul);
684*1c60b9acSAndroid Build Coastguard Worker 
685*1c60b9acSAndroid Build Coastguard Worker 	/*
686*1c60b9acSAndroid Build Coastguard Worker 	 * regen the cookie jar without changes, so expired are removed and
687*1c60b9acSAndroid Build Coastguard Worker 	 * new earliest expired computed
688*1c60b9acSAndroid Build Coastguard Worker 	 */
689*1c60b9acSAndroid Build Coastguard Worker 	if (nsc_regen(cache, NULL, NULL, 0))
690*1c60b9acSAndroid Build Coastguard Worker 		return;
691*1c60b9acSAndroid Build Coastguard Worker 
692*1c60b9acSAndroid Build Coastguard Worker 	if (cache->earliest_expiry)
693*1c60b9acSAndroid Build Coastguard Worker 		lws_cache_schedule(&cache->cache, expiry_cb,
694*1c60b9acSAndroid Build Coastguard Worker 				   cache->earliest_expiry);
695*1c60b9acSAndroid Build Coastguard Worker }
696*1c60b9acSAndroid Build Coastguard Worker 
697*1c60b9acSAndroid Build Coastguard Worker 
698*1c60b9acSAndroid Build Coastguard Worker /* specific_key and expiry are ignored, since it must be encoded in payload */
699*1c60b9acSAndroid Build Coastguard Worker 
700*1c60b9acSAndroid Build Coastguard Worker static int
lws_cache_nscookiejar_write(struct lws_cache_ttl_lru * _c,const char * specific_key,const uint8_t * source,size_t size,lws_usec_t expiry,void ** ppvoid)701*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_write(struct lws_cache_ttl_lru *_c,
702*1c60b9acSAndroid Build Coastguard Worker 			    const char *specific_key, const uint8_t *source,
703*1c60b9acSAndroid Build Coastguard Worker 			    size_t size, lws_usec_t expiry, void **ppvoid)
704*1c60b9acSAndroid Build Coastguard Worker {
705*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
706*1c60b9acSAndroid Build Coastguard Worker 	char tag[128];
707*1c60b9acSAndroid Build Coastguard Worker 
708*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cache("%s: %s: len %d\n", __func__, _c->info.name, (int)size);
709*1c60b9acSAndroid Build Coastguard Worker 
710*1c60b9acSAndroid Build Coastguard Worker 	assert(source);
711*1c60b9acSAndroid Build Coastguard Worker 
712*1c60b9acSAndroid Build Coastguard Worker 	if (nsc_line_to_tag((const char *)source, size, tag, sizeof(tag), NULL))
713*1c60b9acSAndroid Build Coastguard Worker 		return 1;
714*1c60b9acSAndroid Build Coastguard Worker 
715*1c60b9acSAndroid Build Coastguard Worker 	if (ppvoid)
716*1c60b9acSAndroid Build Coastguard Worker 		*ppvoid = NULL;
717*1c60b9acSAndroid Build Coastguard Worker 
718*1c60b9acSAndroid Build Coastguard Worker 	if (nsc_regen(cache, tag, source, size)) {
719*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: regen failed\n", __func__);
720*1c60b9acSAndroid Build Coastguard Worker 
721*1c60b9acSAndroid Build Coastguard Worker 		return 1;
722*1c60b9acSAndroid Build Coastguard Worker 	}
723*1c60b9acSAndroid Build Coastguard Worker 
724*1c60b9acSAndroid Build Coastguard Worker 	return 0;
725*1c60b9acSAndroid Build Coastguard Worker }
726*1c60b9acSAndroid Build Coastguard Worker 
727*1c60b9acSAndroid Build Coastguard Worker struct nsc_get_ctx {
728*1c60b9acSAndroid Build Coastguard Worker 	struct lws_buflist	*buflist;
729*1c60b9acSAndroid Build Coastguard Worker 	const char		*specific_key;
730*1c60b9acSAndroid Build Coastguard Worker 	const void		**pdata;
731*1c60b9acSAndroid Build Coastguard Worker 	size_t			*psize;
732*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_ttl_lru_t	*l1;
733*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t		expiry;
734*1c60b9acSAndroid Build Coastguard Worker };
735*1c60b9acSAndroid Build Coastguard Worker 
736*1c60b9acSAndroid Build Coastguard Worker /*
737*1c60b9acSAndroid Build Coastguard Worker  * We're looking for a specific key, if found, we want to make an entry for it
738*1c60b9acSAndroid Build Coastguard Worker  * in L1 and return information about that
739*1c60b9acSAndroid Build Coastguard Worker  */
740*1c60b9acSAndroid Build Coastguard Worker 
741*1c60b9acSAndroid Build Coastguard Worker static int
nsc_get_cb(lws_cache_nscookiejar_t * cache,void * opaque,int flags,const char * buf,size_t size)742*1c60b9acSAndroid Build Coastguard Worker nsc_get_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
743*1c60b9acSAndroid Build Coastguard Worker 	   const char *buf, size_t size)
744*1c60b9acSAndroid Build Coastguard Worker {
745*1c60b9acSAndroid Build Coastguard Worker 	struct nsc_get_ctx *ctx = (struct nsc_get_ctx *)opaque;
746*1c60b9acSAndroid Build Coastguard Worker 	char tag[200];
747*1c60b9acSAndroid Build Coastguard Worker 	uint8_t *q;
748*1c60b9acSAndroid Build Coastguard Worker 
749*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->buflist)
750*1c60b9acSAndroid Build Coastguard Worker 		goto collect;
751*1c60b9acSAndroid Build Coastguard Worker 
752*1c60b9acSAndroid Build Coastguard Worker 	if (!(flags & LCN_SOL))
753*1c60b9acSAndroid Build Coastguard Worker 		return NIR_CONTINUE;
754*1c60b9acSAndroid Build Coastguard Worker 
755*1c60b9acSAndroid Build Coastguard Worker 	if (nsc_line_to_tag(buf, size, tag, sizeof(tag), &ctx->expiry)) {
756*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: can't get tag\n", __func__);
757*1c60b9acSAndroid Build Coastguard Worker 		return NIR_CONTINUE;
758*1c60b9acSAndroid Build Coastguard Worker 	}
759*1c60b9acSAndroid Build Coastguard Worker 
760*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cache("%s: %s %s\n", __func__, ctx->specific_key, tag);
761*1c60b9acSAndroid Build Coastguard Worker 
762*1c60b9acSAndroid Build Coastguard Worker 	if (strcmp(ctx->specific_key, tag)) {
763*1c60b9acSAndroid Build Coastguard Worker 		lwsl_cache("%s: no match\n", __func__);
764*1c60b9acSAndroid Build Coastguard Worker 		return NIR_CONTINUE;
765*1c60b9acSAndroid Build Coastguard Worker 	}
766*1c60b9acSAndroid Build Coastguard Worker 
767*1c60b9acSAndroid Build Coastguard Worker 	/* it's a match */
768*1c60b9acSAndroid Build Coastguard Worker 
769*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cache("%s: IS match\n", __func__);
770*1c60b9acSAndroid Build Coastguard Worker 
771*1c60b9acSAndroid Build Coastguard Worker 	if (!(flags & LCN_EOL))
772*1c60b9acSAndroid Build Coastguard Worker 		goto collect;
773*1c60b9acSAndroid Build Coastguard Worker 
774*1c60b9acSAndroid Build Coastguard Worker 	/* it all fit in the buffer, let's create it in L1 now */
775*1c60b9acSAndroid Build Coastguard Worker 
776*1c60b9acSAndroid Build Coastguard Worker 	*ctx->psize = size;
777*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->l1->info.ops->write(ctx->l1,
778*1c60b9acSAndroid Build Coastguard Worker 				     ctx->specific_key, (const uint8_t *)buf,
779*1c60b9acSAndroid Build Coastguard Worker 				     size, ctx->expiry, (void **)ctx->pdata))
780*1c60b9acSAndroid Build Coastguard Worker 		return NIR_FINISH_ERROR;
781*1c60b9acSAndroid Build Coastguard Worker 
782*1c60b9acSAndroid Build Coastguard Worker 	return NIR_FINISH_OK;
783*1c60b9acSAndroid Build Coastguard Worker 
784*1c60b9acSAndroid Build Coastguard Worker collect:
785*1c60b9acSAndroid Build Coastguard Worker 	/*
786*1c60b9acSAndroid Build Coastguard Worker 	 * it's bigger than one buffer-load, we have to stash what we're getting
787*1c60b9acSAndroid Build Coastguard Worker 	 * on a buflist and create it when we have it all
788*1c60b9acSAndroid Build Coastguard Worker 	 */
789*1c60b9acSAndroid Build Coastguard Worker 
790*1c60b9acSAndroid Build Coastguard Worker 	if (lws_buflist_append_segment(&ctx->buflist, (const uint8_t *)buf,
791*1c60b9acSAndroid Build Coastguard Worker 				       size))
792*1c60b9acSAndroid Build Coastguard Worker 		goto cleanup;
793*1c60b9acSAndroid Build Coastguard Worker 
794*1c60b9acSAndroid Build Coastguard Worker 	if (!(flags & LCN_EOL))
795*1c60b9acSAndroid Build Coastguard Worker 		return NIR_CONTINUE;
796*1c60b9acSAndroid Build Coastguard Worker 
797*1c60b9acSAndroid Build Coastguard Worker 	/* we have all the payload, create the L1 entry without payload yet */
798*1c60b9acSAndroid Build Coastguard Worker 
799*1c60b9acSAndroid Build Coastguard Worker 	*ctx->psize = size;
800*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->l1->info.ops->write(ctx->l1, ctx->specific_key, NULL,
801*1c60b9acSAndroid Build Coastguard Worker 				     lws_buflist_total_len(&ctx->buflist),
802*1c60b9acSAndroid Build Coastguard Worker 				     ctx->expiry, (void **)&q))
803*1c60b9acSAndroid Build Coastguard Worker 		goto cleanup;
804*1c60b9acSAndroid Build Coastguard Worker 	*ctx->pdata = q;
805*1c60b9acSAndroid Build Coastguard Worker 
806*1c60b9acSAndroid Build Coastguard Worker 	/* dump the buflist into the L1 cache entry */
807*1c60b9acSAndroid Build Coastguard Worker 
808*1c60b9acSAndroid Build Coastguard Worker 	do {
809*1c60b9acSAndroid Build Coastguard Worker 		uint8_t *p;
810*1c60b9acSAndroid Build Coastguard Worker 		size_t len = lws_buflist_next_segment_len(&ctx->buflist, &p);
811*1c60b9acSAndroid Build Coastguard Worker 
812*1c60b9acSAndroid Build Coastguard Worker 		memcpy(q, p, len);
813*1c60b9acSAndroid Build Coastguard Worker 		q += len;
814*1c60b9acSAndroid Build Coastguard Worker 
815*1c60b9acSAndroid Build Coastguard Worker 		lws_buflist_use_segment(&ctx->buflist, len);
816*1c60b9acSAndroid Build Coastguard Worker 	} while (ctx->buflist);
817*1c60b9acSAndroid Build Coastguard Worker 
818*1c60b9acSAndroid Build Coastguard Worker 	return NIR_FINISH_OK;
819*1c60b9acSAndroid Build Coastguard Worker 
820*1c60b9acSAndroid Build Coastguard Worker cleanup:
821*1c60b9acSAndroid Build Coastguard Worker 	lws_buflist_destroy_all_segments(&ctx->buflist);
822*1c60b9acSAndroid Build Coastguard Worker 
823*1c60b9acSAndroid Build Coastguard Worker 	return NIR_FINISH_ERROR;
824*1c60b9acSAndroid Build Coastguard Worker }
825*1c60b9acSAndroid Build Coastguard Worker 
826*1c60b9acSAndroid Build Coastguard Worker static int
lws_cache_nscookiejar_get(struct lws_cache_ttl_lru * _c,const char * specific_key,const void ** pdata,size_t * psize)827*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_get(struct lws_cache_ttl_lru *_c,
828*1c60b9acSAndroid Build Coastguard Worker 			  const char *specific_key, const void **pdata,
829*1c60b9acSAndroid Build Coastguard Worker 			  size_t *psize)
830*1c60b9acSAndroid Build Coastguard Worker {
831*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
832*1c60b9acSAndroid Build Coastguard Worker 	struct nsc_get_ctx ctx;
833*1c60b9acSAndroid Build Coastguard Worker 	int ret, fd;
834*1c60b9acSAndroid Build Coastguard Worker 
835*1c60b9acSAndroid Build Coastguard Worker 	fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
836*1c60b9acSAndroid Build Coastguard Worker 	if (fd < 0)
837*1c60b9acSAndroid Build Coastguard Worker 		return 1;
838*1c60b9acSAndroid Build Coastguard Worker 
839*1c60b9acSAndroid Build Coastguard Worker 	/* get a pointer to l1 */
840*1c60b9acSAndroid Build Coastguard Worker 	ctx.l1 = &cache->cache;
841*1c60b9acSAndroid Build Coastguard Worker 	while (ctx.l1->child)
842*1c60b9acSAndroid Build Coastguard Worker 		ctx.l1 = ctx.l1->child;
843*1c60b9acSAndroid Build Coastguard Worker 
844*1c60b9acSAndroid Build Coastguard Worker 	ctx.pdata = pdata;
845*1c60b9acSAndroid Build Coastguard Worker 	ctx.psize = psize;
846*1c60b9acSAndroid Build Coastguard Worker 	ctx.specific_key = specific_key;
847*1c60b9acSAndroid Build Coastguard Worker 	ctx.buflist = NULL;
848*1c60b9acSAndroid Build Coastguard Worker 	ctx.expiry = 0;
849*1c60b9acSAndroid Build Coastguard Worker 
850*1c60b9acSAndroid Build Coastguard Worker 	ret = nscookiejar_iterate(cache, fd, nsc_get_cb, &ctx);
851*1c60b9acSAndroid Build Coastguard Worker 
852*1c60b9acSAndroid Build Coastguard Worker 	nsc_backing_close_unlock(cache, fd);
853*1c60b9acSAndroid Build Coastguard Worker 
854*1c60b9acSAndroid Build Coastguard Worker 	return ret != NIR_FINISH_OK;
855*1c60b9acSAndroid Build Coastguard Worker }
856*1c60b9acSAndroid Build Coastguard Worker 
857*1c60b9acSAndroid Build Coastguard Worker static int
lws_cache_nscookiejar_invalidate(struct lws_cache_ttl_lru * _c,const char * wc_key)858*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_invalidate(struct lws_cache_ttl_lru *_c,
859*1c60b9acSAndroid Build Coastguard Worker 				 const char *wc_key)
860*1c60b9acSAndroid Build Coastguard Worker {
861*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
862*1c60b9acSAndroid Build Coastguard Worker 
863*1c60b9acSAndroid Build Coastguard Worker 	return nsc_regen(cache, wc_key, NULL, 0);
864*1c60b9acSAndroid Build Coastguard Worker }
865*1c60b9acSAndroid Build Coastguard Worker 
866*1c60b9acSAndroid Build Coastguard Worker static struct lws_cache_ttl_lru *
lws_cache_nscookiejar_create(const struct lws_cache_creation_info * info)867*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_create(const struct lws_cache_creation_info *info)
868*1c60b9acSAndroid Build Coastguard Worker {
869*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache;
870*1c60b9acSAndroid Build Coastguard Worker 
871*1c60b9acSAndroid Build Coastguard Worker 	cache = lws_fi(&info->cx->fic, "cache_createfail") ? NULL :
872*1c60b9acSAndroid Build Coastguard Worker 					lws_zalloc(sizeof(*cache), __func__);
873*1c60b9acSAndroid Build Coastguard Worker 	if (!cache)
874*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
875*1c60b9acSAndroid Build Coastguard Worker 
876*1c60b9acSAndroid Build Coastguard Worker 	cache->cache.info = *info;
877*1c60b9acSAndroid Build Coastguard Worker 
878*1c60b9acSAndroid Build Coastguard Worker 	/*
879*1c60b9acSAndroid Build Coastguard Worker 	 * We need to scan the file, if it exists, and find the earliest
880*1c60b9acSAndroid Build Coastguard Worker 	 * expiry while cleaning out any expired entries
881*1c60b9acSAndroid Build Coastguard Worker 	 */
882*1c60b9acSAndroid Build Coastguard Worker 	expiry_cb(&cache->cache.sul);
883*1c60b9acSAndroid Build Coastguard Worker 
884*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: create %s\n", __func__, info->name ? info->name : "?");
885*1c60b9acSAndroid Build Coastguard Worker 
886*1c60b9acSAndroid Build Coastguard Worker 	return (struct lws_cache_ttl_lru *)cache;
887*1c60b9acSAndroid Build Coastguard Worker }
888*1c60b9acSAndroid Build Coastguard Worker 
889*1c60b9acSAndroid Build Coastguard Worker static int
lws_cache_nscookiejar_expunge(struct lws_cache_ttl_lru * _c)890*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_expunge(struct lws_cache_ttl_lru *_c)
891*1c60b9acSAndroid Build Coastguard Worker {
892*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
893*1c60b9acSAndroid Build Coastguard Worker 	int r;
894*1c60b9acSAndroid Build Coastguard Worker 
895*1c60b9acSAndroid Build Coastguard Worker 	if (!cache)
896*1c60b9acSAndroid Build Coastguard Worker 		return 0;
897*1c60b9acSAndroid Build Coastguard Worker 
898*1c60b9acSAndroid Build Coastguard Worker 	r = unlink(cache->cache.info.u.nscookiejar.filepath);
899*1c60b9acSAndroid Build Coastguard Worker 	if (r)
900*1c60b9acSAndroid Build Coastguard Worker 		lwsl_warn("%s: failed to unlink %s\n", __func__,
901*1c60b9acSAndroid Build Coastguard Worker 				cache->cache.info.u.nscookiejar.filepath);
902*1c60b9acSAndroid Build Coastguard Worker 
903*1c60b9acSAndroid Build Coastguard Worker 	return r;
904*1c60b9acSAndroid Build Coastguard Worker }
905*1c60b9acSAndroid Build Coastguard Worker 
906*1c60b9acSAndroid Build Coastguard Worker static void
lws_cache_nscookiejar_destroy(struct lws_cache_ttl_lru ** _pc)907*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_destroy(struct lws_cache_ttl_lru **_pc)
908*1c60b9acSAndroid Build Coastguard Worker {
909*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)*_pc;
910*1c60b9acSAndroid Build Coastguard Worker 
911*1c60b9acSAndroid Build Coastguard Worker 	if (!cache)
912*1c60b9acSAndroid Build Coastguard Worker 		return;
913*1c60b9acSAndroid Build Coastguard Worker 
914*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_cancel(&cache->cache.sul);
915*1c60b9acSAndroid Build Coastguard Worker 
916*1c60b9acSAndroid Build Coastguard Worker 	lws_free_set_NULL(*_pc);
917*1c60b9acSAndroid Build Coastguard Worker }
918*1c60b9acSAndroid Build Coastguard Worker 
919*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
920*1c60b9acSAndroid Build Coastguard Worker 
921*1c60b9acSAndroid Build Coastguard Worker static int
nsc_dump_cb(lws_cache_nscookiejar_t * cache,void * opaque,int flags,const char * buf,size_t size)922*1c60b9acSAndroid Build Coastguard Worker nsc_dump_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
923*1c60b9acSAndroid Build Coastguard Worker 	      const char *buf, size_t size)
924*1c60b9acSAndroid Build Coastguard Worker {
925*1c60b9acSAndroid Build Coastguard Worker 	lwsl_hexdump_cache(buf, size);
926*1c60b9acSAndroid Build Coastguard Worker 
927*1c60b9acSAndroid Build Coastguard Worker 	return 0;
928*1c60b9acSAndroid Build Coastguard Worker }
929*1c60b9acSAndroid Build Coastguard Worker 
930*1c60b9acSAndroid Build Coastguard Worker static void
lws_cache_nscookiejar_debug_dump(struct lws_cache_ttl_lru * _c)931*1c60b9acSAndroid Build Coastguard Worker lws_cache_nscookiejar_debug_dump(struct lws_cache_ttl_lru *_c)
932*1c60b9acSAndroid Build Coastguard Worker {
933*1c60b9acSAndroid Build Coastguard Worker 	lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
934*1c60b9acSAndroid Build Coastguard Worker 	int fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
935*1c60b9acSAndroid Build Coastguard Worker 
936*1c60b9acSAndroid Build Coastguard Worker 	if (fd < 0)
937*1c60b9acSAndroid Build Coastguard Worker 		return;
938*1c60b9acSAndroid Build Coastguard Worker 
939*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cache("%s: %s\n", __func__, _c->info.name);
940*1c60b9acSAndroid Build Coastguard Worker 
941*1c60b9acSAndroid Build Coastguard Worker 	nscookiejar_iterate(cache, fd, nsc_dump_cb, NULL);
942*1c60b9acSAndroid Build Coastguard Worker 
943*1c60b9acSAndroid Build Coastguard Worker 	nsc_backing_close_unlock(cache, fd);
944*1c60b9acSAndroid Build Coastguard Worker }
945*1c60b9acSAndroid Build Coastguard Worker #endif
946*1c60b9acSAndroid Build Coastguard Worker 
947*1c60b9acSAndroid Build Coastguard Worker const struct lws_cache_ops lws_cache_ops_nscookiejar = {
948*1c60b9acSAndroid Build Coastguard Worker 	.create			= lws_cache_nscookiejar_create,
949*1c60b9acSAndroid Build Coastguard Worker 	.destroy		= lws_cache_nscookiejar_destroy,
950*1c60b9acSAndroid Build Coastguard Worker 	.expunge		= lws_cache_nscookiejar_expunge,
951*1c60b9acSAndroid Build Coastguard Worker 
952*1c60b9acSAndroid Build Coastguard Worker 	.write			= lws_cache_nscookiejar_write,
953*1c60b9acSAndroid Build Coastguard Worker 	.tag_match		= lws_cache_nscookiejar_tag_match,
954*1c60b9acSAndroid Build Coastguard Worker 	.lookup			= lws_cache_nscookiejar_lookup,
955*1c60b9acSAndroid Build Coastguard Worker 	.invalidate		= lws_cache_nscookiejar_invalidate,
956*1c60b9acSAndroid Build Coastguard Worker 	.get			= lws_cache_nscookiejar_get,
957*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
958*1c60b9acSAndroid Build Coastguard Worker 	.debug_dump		= lws_cache_nscookiejar_debug_dump,
959*1c60b9acSAndroid Build Coastguard Worker #endif
960*1c60b9acSAndroid Build Coastguard Worker };
961