3
* (c) 2002 Mikulas Patocka
4
* This file is part of the Links project, released under GPL
6
* Modified by Karl Dahlke for integration with edbrowse.
14
/* These are allocated */
16
char *server, *path, *domain;
17
time_t expires; /* zero means undefined */
22
freeCookie(struct cookie *c)
31
static struct listHead cookies = { &cookies, &cookies };
33
static bool displacedCookie;
35
acceptCookie(struct cookie *c)
38
displacedCookie = false;
40
if(stringEqualCI(d->name, c->name) &&
41
stringEqualCI(d->domain, c->domain)) {
42
displacedCookie = true;
49
addToListBack(&cookies, c);
53
cookieIntoJar(const struct cookie *c)
57
static bool warn = false;
64
if(c->expires <= time(0))
65
return; /* not persistent, or out of date */
66
f = fopen(cookieFile, "a");
70
/* I have no clue what the second argument is suppose to be, */
71
/* I'm always calling it false. */
72
fprintf(f, "%s\tFALSE\t%s\t%s\t%u\t%s\t%s\n",
74
c->secure ? "TRUE" : "FALSE", (unsigned)c->expires, c->name, c->value);
76
debugPrint(3, "into jar");
79
/* Should this server really specify this domain in a cookie? */
80
/* Domain must be the trailing substring of server. */
82
domainSecurityCheck(const char *server, const char *domain)
89
if(dl > strlen(server))
91
i = strlen(server) - dl;
92
if(!stringEqualCI(server + i, domain))
94
if(i && server[i - 1] != '.')
96
nd = 2; /* number of dots */
97
if(dl > 4 && domain[dl - 4] == '.') {
98
static const char *const tld[] = {
99
"com", "edu", "net", "org", "gov", "mil", "int", "biz", NULL
101
if(stringInListCI(tld, domain + dl - 3) >= 0)
104
for(i = 0; domain[i]; i++)
109
} /* domainSecurityCheck */
111
/* Let's jump right into it - parse a cookie, as received from a website. */
113
receiveCookie(const char *url, const char *str)
116
const char *p, *q, *server;
119
debugPrint(3, "%s", str);
121
server = getHostURL(url);
122
if(server == 0 || !*server)
125
/* Cookie starts with name=value. If we can't get that, go home. */
126
for(p = str; *p != ';' && *p; p++) ;
127
for(q = str; *q != '='; q++)
133
c = allocZeroMem(sizeof (struct cookie));
134
c->name = pullString1(str, q);
137
c->value = pullString1(q, p);
139
c->value = EMPTYSTRING;
141
c->server = cloneString(server);
143
if(date = extractHeaderParam(str, "expires")) {
144
c->expires = parseHeaderDate(date);
146
} else if(date = extractHeaderParam(str, "max-age")) {
147
int n = stringIsNum(date);
149
time_t now = time(0);
150
c->expires = now + n;
155
c->path = extractHeaderParam(str, "path");
157
/* The url indicates the path for this cookie, if a path is not explicitly given */
158
const char *dir, *dirend;
159
getDirURL(url, &dir, &dirend);
160
c->path = pullString1(dir, dirend);
162
if(!c->path[0] || c->path[strlen(c->path) - 1] != '/')
163
c->path = appendString(c->path, "/");
164
if(c->path[0] != '/')
165
c->path = prependString(c->path, "/");
168
if(!(c->domain = extractHeaderParam(str, "domain")))
169
c->domain = cloneString(server);
170
if(c->domain[0] == '.')
171
strcpy(c->domain, c->domain + 1);
172
if(!domainSecurityCheck(server, c->domain)) {
174
c->domain = cloneString(server);
177
if(s = extractHeaderParam(str, "secure")) {
185
} /* receiveCookie */
187
/* I'm assuming I can read the cookie file, process it,
188
* and if necessary, write it out again, with the expired cookies deleted,
189
* all before another edbrowse process interferes.
190
* I've given it some thought, and I think I can ignore the race conditions. */
196
int n, cnt, expired, displaced;
202
if(!fileIntoMemory(cookieFile, &cbuf, &n))
207
cnt = expired = displaced = 0;
211
c = allocZeroMem(sizeof (struct cookie));
214
c->domain = cloneString(s);
220
c->path = cloneString(s);
223
c->secure = (*s == 'T');
227
c->expires = (time_t) atol(s);
231
c->name = cloneString(s);
235
c->value = cloneString(s);
238
if(c->expires < now) {
244
displaced += displacedCookie;
248
debugPrint(3, "%d persistent cookies, %d expired, %d displaced",
249
cnt, expired, displaced);
251
if(!(expired + displaced))
254
/* Pour the cookies back into the jar */
255
f = fopen(cookieFile, "w");
257
i_printfExit(MSG_NoRebCookie, cookieFile);
259
fprintf(f, "%s\tFALSE\t%s\t%s\t%u\t%s\t%s\n",
261
c->secure ? "TRUE" : "FALSE", (unsigned)c->expires, c->name, c->value);
263
} /* cookiesFromJar */
266
isInDomain(const char *d, const char *s)
273
if(!memEqualCI(d, s + j, dl))
275
if(j && s[j - 1] != '.')
281
isPathPrefix(const char *d, const char *s)
287
return !memcmp(d, s, dl);
291
sendCookies(char **s, int *l, const char *url, bool issecure)
293
const char *server = getHostURL(url);
294
const char *data = getDataURL(url);
295
int nc = 0; /* new cookie */
296
struct cookie *c, *d;
299
if(!url || !server || !data)
302
if(data > url && data[-1] == '/')
308
foreach(c, cookies) {
309
if(!isInDomain(c->domain, server))
311
if(!isPathPrefix(c->path, data))
313
if(c->expires && c->expires < now) {
321
if(c->secure && !issecure)
323
/* We're good to go. */
325
stringAndString(s, l, "Cookie: "), nc = 1;
327
stringAndString(s, l, "; ");
328
stringAndString(s, l, c->name);
329
stringAndChar(s, l, '=');
330
stringAndString(s, l, c->value);
331
debugPrint(3, "send cookie %s=%s", c->name, c->value);
335
stringAndString(s, l, eol);