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