links

lynx-like text mode web browser
git clone anongit@rnpnr.xyz:links.git
Log | Files | Refs | Feed | README | LICENSE

cookies.c (6060B)


      1 /* cookies.c
      2  * Cookies
      3  * (c) 2002 Mikulas Patocka
      4  * This file is a part of the Links program, released under GPL
      5  */
      6 
      7 #include <limits.h>
      8 
      9 #include "links.h"
     10 
     11 #define ACCEPT_NONE 0
     12 #define ACCEPT_ALL  1
     13 
     14 static int accept_cookies = ACCEPT_ALL;
     15 
     16 struct list_head all_cookies = { &all_cookies, &all_cookies };
     17 
     18 struct list_head c_domains = { &c_domains, &c_domains };
     19 
     20 struct c_server {
     21 	list_entry_1st;
     22 	int accpt;
     23 	unsigned char server[1];
     24 };
     25 
     26 static struct list_head c_servers = { &c_servers, &c_servers };
     27 
     28 static void accept_cookie(struct cookie *);
     29 
     30 void
     31 free_cookie(struct cookie *c)
     32 {
     33 	free(c->name);
     34 	free(c->value);
     35 	free(c->server);
     36 	free(c->path);
     37 	free(c->domain);
     38 	free(c);
     39 }
     40 
     41 /* sezere 1 cookie z retezce str, na zacatku nesmi byt zadne whitechars
     42  * na konci muze byt strednik nebo 0
     43  * cookie musi byt ve tvaru nazev=hodnota, kolem rovnase nesmi byt zadne mezery
     44  * (respektive mezery se budou pocitat do nazvu a do hodnoty)
     45  */
     46 int
     47 set_cookie(struct terminal *term, unsigned char *url, unsigned char *str)
     48 {
     49 	if (!accept_cookies)
     50 		return 0;
     51 	int noval = 0;
     52 	struct cookie *cookie;
     53 	struct c_server *cs = NULL;
     54 	struct list_head *lcs;
     55 	unsigned char *p, *q, *s, *server, *date, *dom;
     56 	for (p = str; *p != ';' && *p; p++)
     57 		;
     58 	for (q = str; *q != '='; q++)
     59 		if (!*q || q >= p) {
     60 			noval = 1;
     61 			break;
     62 		}
     63 	if (str == q || q + 1 == p)
     64 		return 0;
     65 	cookie = xmalloc(sizeof(struct cookie));
     66 	server = get_host_name(url);
     67 	cookie->name = memacpy(str, q - str);
     68 	cookie->value = !noval ? memacpy(q + 1, p - q - 1) : NULL;
     69 	cookie->server = stracpy(server);
     70 	date = parse_header_param(str, cast_uchar "expires", 0);
     71 	if (date) {
     72 		cookie->expires = parse_http_date(date);
     73 		free(date);
     74 	} else
     75 		cookie->expires = 0;
     76 	if (!(cookie->path = parse_header_param(str, cast_uchar "path", 0)))
     77 		cookie->path = stracpy(cast_uchar "/");
     78 	else if (cookie->path[0] != '/') {
     79 		add_to_strn(&cookie->path, cast_uchar "x");
     80 		memmove(cookie->path + 1, cookie->path,
     81 		        strlen((const char *)cookie->path) - 1);
     82 		cookie->path[0] = '/';
     83 	}
     84 	dom = parse_header_param(str, cast_uchar "domain", 0);
     85 	if (!dom)
     86 		cookie->domain = stracpy(server);
     87 	else {
     88 		cookie->domain = idn_encode_host(dom, strlen((const char *)dom),
     89 		                                 cast_uchar ".", 0);
     90 		if (!cookie->domain)
     91 			cookie->domain = stracpy(server);
     92 		free(dom);
     93 	}
     94 	if (cookie->domain[0] == '.')
     95 		memmove(cookie->domain, cookie->domain + 1,
     96 		        strlen((const char *)cookie->domain));
     97 	if ((s = parse_header_param(str, cast_uchar "secure", 0))) {
     98 		cookie->secure = 1;
     99 		free(s);
    100 	} else
    101 		cookie->secure = 0;
    102 	if (!allow_cookie_domain(server, cookie->domain)) {
    103 		free(cookie->domain);
    104 		cookie->domain = stracpy(server);
    105 	}
    106 	foreach (struct c_server, cs, lcs, c_servers)
    107 		if (!casestrcmp(cs->server, server)) {
    108 			if (cs->accpt)
    109 				goto ok;
    110 			else {
    111 				free_cookie(cookie);
    112 				free(server);
    113 				return 0;
    114 			}
    115 		}
    116 	if (!accept_cookies) {
    117 		free_cookie(cookie);
    118 		free(server);
    119 		return 1;
    120 	}
    121 ok:
    122 	accept_cookie(cookie);
    123 	free(server);
    124 	return 0;
    125 }
    126 
    127 static void
    128 accept_cookie(struct cookie *c)
    129 {
    130 	struct c_domain *cd = NULL;
    131 	struct list_head *lcd;
    132 	struct cookie *d = NULL;
    133 	struct list_head *ld;
    134 	size_t sl;
    135 	foreach (struct cookie, d, ld, all_cookies)
    136 		if (!casestrcmp(d->name, c->name)
    137 		    && !casestrcmp(d->domain, c->domain)) {
    138 			ld = ld->prev;
    139 			del_from_list(d);
    140 			free_cookie(d);
    141 		}
    142 	if (c->value && !casestrcmp(c->value, cast_uchar "deleted")) {
    143 		free_cookie(c);
    144 		return;
    145 	}
    146 	add_to_list(all_cookies, c);
    147 	foreach (struct c_domain, cd, lcd, c_domains)
    148 		if (!casestrcmp(cd->domain, c->domain))
    149 			return;
    150 	sl = strlen((const char *)c->domain);
    151 	if (sl > INT_MAX - sizeof(struct c_domain))
    152 		overalloc();
    153 	cd = xmalloc(sizeof(struct c_domain) + sl);
    154 	strcpy(cast_char cd->domain, cast_const_char c->domain);
    155 	add_to_list(c_domains, cd);
    156 }
    157 
    158 int
    159 is_in_domain(unsigned char *d, unsigned char *s)
    160 {
    161 	const int dl = strlen((const char *)d);
    162 	const int sl = strlen((const char *)s);
    163 	if (dl > sl)
    164 		return 0;
    165 	if (dl == sl)
    166 		return !casestrcmp(d, s);
    167 	if (s[sl - dl - 1] != '.')
    168 		return 0;
    169 	return !casecmp(d, s + sl - dl, dl);
    170 }
    171 
    172 int
    173 is_path_prefix(unsigned char *d, unsigned char *s)
    174 {
    175 	const int dl = strlen((const char *)d);
    176 	const int sl = strlen((const char *)s);
    177 	if (!dl)
    178 		return 1;
    179 	if (dl > sl)
    180 		return 0;
    181 	if (memcmp(d, s, dl))
    182 		return 0;
    183 	return d[dl - 1] == '/' || !s[dl] || s[dl] == '/' || s[dl] == POST_CHAR
    184 	       || s[dl] == '?' || s[dl] == '&';
    185 }
    186 
    187 int
    188 cookie_expired(struct cookie *c)
    189 {
    190 	time_t t;
    191 	errno = 0;
    192 	EINTRLOOPX(t, time(NULL), (time_t)-1);
    193 	return c->expires && c->expires < t;
    194 }
    195 
    196 size_t
    197 add_cookies(unsigned char **s, size_t l, unsigned char *url)
    198 {
    199 	int nc = 0;
    200 	struct c_domain *cd = NULL;
    201 	struct list_head *lcd;
    202 	struct cookie *c = NULL;
    203 	struct list_head *lc;
    204 	unsigned char *server = get_host_name(url);
    205 	unsigned char *data = get_url_data(url);
    206 	if (data > url)
    207 		data--;
    208 	foreach (struct c_domain, cd, lcd, c_domains)
    209 		if (is_in_domain(cd->domain, server))
    210 			goto ok;
    211 	free(server);
    212 	return l;
    213 ok:
    214 	foreachback (struct cookie, c, lc, all_cookies)
    215 		if (is_in_domain(c->domain, server))
    216 			if (is_path_prefix(c->path, data)) {
    217 				if (cookie_expired(c)) {
    218 					lc = lc->prev;
    219 					del_from_list(c);
    220 					free_cookie(c);
    221 					continue;
    222 				}
    223 				if (c->secure
    224 				    && casecmp(url, cast_uchar "https://", 8))
    225 					continue;
    226 				if (!nc) {
    227 					l = add_to_str(s, l,
    228 					               cast_uchar "Cookie: ");
    229 					nc = 1;
    230 				} else
    231 					l = add_to_str(s, l, cast_uchar "; ");
    232 				l = add_to_str(s, l, c->name);
    233 				if (c->value) {
    234 					l = add_chr_to_str(s, l, '=');
    235 					l = add_to_str(s, l, c->value);
    236 				}
    237 			}
    238 	if (nc)
    239 		l = add_to_str(s, l, cast_uchar "\r\n");
    240 	free(server);
    241 	return l;
    242 }
    243 
    244 void
    245 free_cookies(void)
    246 {
    247 	free_list(struct c_domain, c_domains);
    248 	/* !!! FIXME: save cookies */
    249 	while (!list_empty(all_cookies)) {
    250 		struct cookie *c = list_struct(all_cookies.next, struct cookie);
    251 		del_from_list(c);
    252 		free_cookie(c);
    253 	}
    254 }
    255 
    256 void
    257 init_cookies(void)
    258 {
    259 	/* !!! FIXME: read cookies */
    260 }