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 - 2019 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
25*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
26*1c60b9acSAndroid Build Coastguard Worker
27*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
28*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-misc-lwsac.h"
29*1c60b9acSAndroid Build Coastguard Worker
30*1c60b9acSAndroid Build Coastguard Worker /*
31*1c60b9acSAndroid Build Coastguard Worker * Helper for caching a file in memory in a lac, but also to check at intervals
32*1c60b9acSAndroid Build Coastguard Worker * no less than 5s if the file is still fresh.
33*1c60b9acSAndroid Build Coastguard Worker *
34*1c60b9acSAndroid Build Coastguard Worker * Set *cache to NULL the first time before calling.
35*1c60b9acSAndroid Build Coastguard Worker *
36*1c60b9acSAndroid Build Coastguard Worker * You should call this each time before using the cache... if it's
37*1c60b9acSAndroid Build Coastguard Worker *
38*1c60b9acSAndroid Build Coastguard Worker * - less than 5s since the last freshness check, and
39*1c60b9acSAndroid Build Coastguard Worker * - the file is already in memory
40*1c60b9acSAndroid Build Coastguard Worker *
41*1c60b9acSAndroid Build Coastguard Worker * it just returns with *cache left alone; this costs very little. You should
42*1c60b9acSAndroid Build Coastguard Worker * call `lwsac_use_cached_file_start()` and `lwsac_use_cached_file_end()`
43*1c60b9acSAndroid Build Coastguard Worker * to lock the cache against deletion while you are using it.
44*1c60b9acSAndroid Build Coastguard Worker *
45*1c60b9acSAndroid Build Coastguard Worker * If it's
46*1c60b9acSAndroid Build Coastguard Worker *
47*1c60b9acSAndroid Build Coastguard Worker * - at least 5s since the last freshness check, and
48*1c60b9acSAndroid Build Coastguard Worker * - the file timestamp has changed
49*1c60b9acSAndroid Build Coastguard Worker *
50*1c60b9acSAndroid Build Coastguard Worker * then
51*1c60b9acSAndroid Build Coastguard Worker *
52*1c60b9acSAndroid Build Coastguard Worker * - the file is reloaded into a new lac and *cache set to that
53*1c60b9acSAndroid Build Coastguard Worker *
54*1c60b9acSAndroid Build Coastguard Worker * - the old cache lac, if any, is detached (so it will be freed when its
55*1c60b9acSAndroid Build Coastguard Worker * reference count reaches zero, or immediately if nobody has it)
56*1c60b9acSAndroid Build Coastguard Worker *
57*1c60b9acSAndroid Build Coastguard Worker * Note the call can fail due to OOM or filesystem issue at any time.
58*1c60b9acSAndroid Build Coastguard Worker *
59*1c60b9acSAndroid Build Coastguard Worker *
60*1c60b9acSAndroid Build Coastguard Worker * After the LAC header there is stored a `struct cached_file_info` and then
61*1c60b9acSAndroid Build Coastguard Worker * the raw file contents. *
62*1c60b9acSAndroid Build Coastguard Worker *
63*1c60b9acSAndroid Build Coastguard Worker * [LAC header]
64*1c60b9acSAndroid Build Coastguard Worker * [struct cached_file_info]
65*1c60b9acSAndroid Build Coastguard Worker * [file contents] <--- *cache is set to here
66*1c60b9acSAndroid Build Coastguard Worker *
67*1c60b9acSAndroid Build Coastguard Worker * The api returns a lwsac_cached_file_t type offset to point to the file
68*1c60b9acSAndroid Build Coastguard Worker * contents. Helpers for reference counting and freeing are also provided
69*1c60b9acSAndroid Build Coastguard Worker * that take that type and know how to correct it back to operate on the LAC.
70*1c60b9acSAndroid Build Coastguard Worker */
71*1c60b9acSAndroid Build Coastguard Worker
72*1c60b9acSAndroid Build Coastguard Worker #define cache_file_to_lac(c) ((struct lwsac *)((char *)c - \
73*1c60b9acSAndroid Build Coastguard Worker sizeof(struct cached_file_info) - \
74*1c60b9acSAndroid Build Coastguard Worker sizeof(struct lwsac_head) - \
75*1c60b9acSAndroid Build Coastguard Worker sizeof(struct lwsac)))
76*1c60b9acSAndroid Build Coastguard Worker
77*1c60b9acSAndroid Build Coastguard Worker void
lwsac_use_cached_file_start(lwsac_cached_file_t cache)78*1c60b9acSAndroid Build Coastguard Worker lwsac_use_cached_file_start(lwsac_cached_file_t cache)
79*1c60b9acSAndroid Build Coastguard Worker {
80*1c60b9acSAndroid Build Coastguard Worker struct lwsac *lac = cache_file_to_lac(cache);
81*1c60b9acSAndroid Build Coastguard Worker struct lwsac_head *lachead = (struct lwsac_head *)&lac->head[1];
82*1c60b9acSAndroid Build Coastguard Worker
83*1c60b9acSAndroid Build Coastguard Worker lachead->refcount++;
84*1c60b9acSAndroid Build Coastguard Worker // lwsl_debug("%s: html refcount: %d\n", __func__, lachead->refcount);
85*1c60b9acSAndroid Build Coastguard Worker }
86*1c60b9acSAndroid Build Coastguard Worker
87*1c60b9acSAndroid Build Coastguard Worker void
lwsac_use_cached_file_end(lwsac_cached_file_t * cache)88*1c60b9acSAndroid Build Coastguard Worker lwsac_use_cached_file_end(lwsac_cached_file_t *cache)
89*1c60b9acSAndroid Build Coastguard Worker {
90*1c60b9acSAndroid Build Coastguard Worker struct lwsac *lac;
91*1c60b9acSAndroid Build Coastguard Worker struct lwsac_head *lachead;
92*1c60b9acSAndroid Build Coastguard Worker
93*1c60b9acSAndroid Build Coastguard Worker if (!cache || !*cache)
94*1c60b9acSAndroid Build Coastguard Worker return;
95*1c60b9acSAndroid Build Coastguard Worker
96*1c60b9acSAndroid Build Coastguard Worker lac = cache_file_to_lac(*cache);
97*1c60b9acSAndroid Build Coastguard Worker lachead = (struct lwsac_head *)&lac->head[1];
98*1c60b9acSAndroid Build Coastguard Worker
99*1c60b9acSAndroid Build Coastguard Worker if (!lachead->refcount)
100*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: html refcount zero on entry\n", __func__);
101*1c60b9acSAndroid Build Coastguard Worker
102*1c60b9acSAndroid Build Coastguard Worker if (lachead->refcount && !--lachead->refcount && lachead->detached) {
103*1c60b9acSAndroid Build Coastguard Worker *cache = NULL; /* not usable any more */
104*1c60b9acSAndroid Build Coastguard Worker lwsac_free(&lac);
105*1c60b9acSAndroid Build Coastguard Worker }
106*1c60b9acSAndroid Build Coastguard Worker }
107*1c60b9acSAndroid Build Coastguard Worker
108*1c60b9acSAndroid Build Coastguard Worker void
lwsac_use_cached_file_detach(lwsac_cached_file_t * cache)109*1c60b9acSAndroid Build Coastguard Worker lwsac_use_cached_file_detach(lwsac_cached_file_t *cache)
110*1c60b9acSAndroid Build Coastguard Worker {
111*1c60b9acSAndroid Build Coastguard Worker struct lwsac *lac = cache_file_to_lac(*cache);
112*1c60b9acSAndroid Build Coastguard Worker struct lwsac_head *lachead = NULL;
113*1c60b9acSAndroid Build Coastguard Worker
114*1c60b9acSAndroid Build Coastguard Worker if (lac) {
115*1c60b9acSAndroid Build Coastguard Worker lachead = (struct lwsac_head *)&lac->head[1];
116*1c60b9acSAndroid Build Coastguard Worker
117*1c60b9acSAndroid Build Coastguard Worker lachead->detached = 1;
118*1c60b9acSAndroid Build Coastguard Worker if (lachead->refcount)
119*1c60b9acSAndroid Build Coastguard Worker return;
120*1c60b9acSAndroid Build Coastguard Worker }
121*1c60b9acSAndroid Build Coastguard Worker
122*1c60b9acSAndroid Build Coastguard Worker *cache = NULL;
123*1c60b9acSAndroid Build Coastguard Worker lwsac_free(&lac);
124*1c60b9acSAndroid Build Coastguard Worker }
125*1c60b9acSAndroid Build Coastguard Worker
126*1c60b9acSAndroid Build Coastguard Worker int
lwsac_cached_file(const char * filepath,lwsac_cached_file_t * cache,size_t * len)127*1c60b9acSAndroid Build Coastguard Worker lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, size_t *len)
128*1c60b9acSAndroid Build Coastguard Worker {
129*1c60b9acSAndroid Build Coastguard Worker struct cached_file_info *info = NULL;
130*1c60b9acSAndroid Build Coastguard Worker lwsac_cached_file_t old = *cache;
131*1c60b9acSAndroid Build Coastguard Worker struct lwsac *lac = NULL;
132*1c60b9acSAndroid Build Coastguard Worker time_t t = time(NULL);
133*1c60b9acSAndroid Build Coastguard Worker unsigned char *a;
134*1c60b9acSAndroid Build Coastguard Worker struct stat s;
135*1c60b9acSAndroid Build Coastguard Worker size_t all;
136*1c60b9acSAndroid Build Coastguard Worker ssize_t rd;
137*1c60b9acSAndroid Build Coastguard Worker int fd;
138*1c60b9acSAndroid Build Coastguard Worker
139*1c60b9acSAndroid Build Coastguard Worker if (old) { /* we already have a cached copy of it */
140*1c60b9acSAndroid Build Coastguard Worker
141*1c60b9acSAndroid Build Coastguard Worker info = (struct cached_file_info *)((*cache) - sizeof(*info));
142*1c60b9acSAndroid Build Coastguard Worker
143*1c60b9acSAndroid Build Coastguard Worker if (t - info->last_confirm < 5)
144*1c60b9acSAndroid Build Coastguard Worker /* we checked it as fresh less than 5s ago, use old */
145*1c60b9acSAndroid Build Coastguard Worker return 0;
146*1c60b9acSAndroid Build Coastguard Worker }
147*1c60b9acSAndroid Build Coastguard Worker
148*1c60b9acSAndroid Build Coastguard Worker /*
149*1c60b9acSAndroid Build Coastguard Worker * ...it's been 5s, we should check again on the filesystem
150*1c60b9acSAndroid Build Coastguard Worker * that the file hasn't changed
151*1c60b9acSAndroid Build Coastguard Worker */
152*1c60b9acSAndroid Build Coastguard Worker
153*1c60b9acSAndroid Build Coastguard Worker fd = open(filepath, O_RDONLY);
154*1c60b9acSAndroid Build Coastguard Worker if (fd < 0) {
155*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: cannot open %s\n", __func__, filepath);
156*1c60b9acSAndroid Build Coastguard Worker
157*1c60b9acSAndroid Build Coastguard Worker return 1;
158*1c60b9acSAndroid Build Coastguard Worker }
159*1c60b9acSAndroid Build Coastguard Worker
160*1c60b9acSAndroid Build Coastguard Worker if (fstat(fd, &s)) {
161*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: cannot stat %s\n", __func__, filepath);
162*1c60b9acSAndroid Build Coastguard Worker
163*1c60b9acSAndroid Build Coastguard Worker goto bail;
164*1c60b9acSAndroid Build Coastguard Worker }
165*1c60b9acSAndroid Build Coastguard Worker
166*1c60b9acSAndroid Build Coastguard Worker if (old && s.st_mtime == info->s.st_mtime) {
167*1c60b9acSAndroid Build Coastguard Worker /* it still seems to be the same as our cached one */
168*1c60b9acSAndroid Build Coastguard Worker info->last_confirm = t;
169*1c60b9acSAndroid Build Coastguard Worker
170*1c60b9acSAndroid Build Coastguard Worker close(fd);
171*1c60b9acSAndroid Build Coastguard Worker
172*1c60b9acSAndroid Build Coastguard Worker return 0;
173*1c60b9acSAndroid Build Coastguard Worker }
174*1c60b9acSAndroid Build Coastguard Worker
175*1c60b9acSAndroid Build Coastguard Worker /*
176*1c60b9acSAndroid Build Coastguard Worker * we either didn't cache it yet, or it has changed since we cached
177*1c60b9acSAndroid Build Coastguard Worker * it... reload in a new lac and then detach the old lac.
178*1c60b9acSAndroid Build Coastguard Worker */
179*1c60b9acSAndroid Build Coastguard Worker
180*1c60b9acSAndroid Build Coastguard Worker all = sizeof(*info) + (unsigned long)s.st_size + 2;
181*1c60b9acSAndroid Build Coastguard Worker
182*1c60b9acSAndroid Build Coastguard Worker info = lwsac_use(&lac, all, all);
183*1c60b9acSAndroid Build Coastguard Worker if (!info)
184*1c60b9acSAndroid Build Coastguard Worker goto bail;
185*1c60b9acSAndroid Build Coastguard Worker
186*1c60b9acSAndroid Build Coastguard Worker info->s = s;
187*1c60b9acSAndroid Build Coastguard Worker info->last_confirm = t;
188*1c60b9acSAndroid Build Coastguard Worker
189*1c60b9acSAndroid Build Coastguard Worker a = (unsigned char *)(info + 1);
190*1c60b9acSAndroid Build Coastguard Worker
191*1c60b9acSAndroid Build Coastguard Worker *len = (unsigned long)s.st_size;
192*1c60b9acSAndroid Build Coastguard Worker a[s.st_size] = '\0';
193*1c60b9acSAndroid Build Coastguard Worker
194*1c60b9acSAndroid Build Coastguard Worker rd = read(fd, a, (unsigned long)s.st_size);
195*1c60b9acSAndroid Build Coastguard Worker if (rd != s.st_size) {
196*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: cannot read %s (%d)\n", __func__, filepath,
197*1c60b9acSAndroid Build Coastguard Worker (int)rd);
198*1c60b9acSAndroid Build Coastguard Worker goto bail1;
199*1c60b9acSAndroid Build Coastguard Worker }
200*1c60b9acSAndroid Build Coastguard Worker
201*1c60b9acSAndroid Build Coastguard Worker close(fd);
202*1c60b9acSAndroid Build Coastguard Worker
203*1c60b9acSAndroid Build Coastguard Worker *cache = (lwsac_cached_file_t)a;
204*1c60b9acSAndroid Build Coastguard Worker if (old)
205*1c60b9acSAndroid Build Coastguard Worker lwsac_use_cached_file_detach(&old);
206*1c60b9acSAndroid Build Coastguard Worker
207*1c60b9acSAndroid Build Coastguard Worker return 0;
208*1c60b9acSAndroid Build Coastguard Worker
209*1c60b9acSAndroid Build Coastguard Worker bail1:
210*1c60b9acSAndroid Build Coastguard Worker lwsac_free(&lac);
211*1c60b9acSAndroid Build Coastguard Worker
212*1c60b9acSAndroid Build Coastguard Worker bail:
213*1c60b9acSAndroid Build Coastguard Worker close(fd);
214*1c60b9acSAndroid Build Coastguard Worker
215*1c60b9acSAndroid Build Coastguard Worker return 1;
216*1c60b9acSAndroid Build Coastguard Worker }
217*1c60b9acSAndroid Build Coastguard Worker
218*1c60b9acSAndroid Build Coastguard Worker #endif
219