diff options
author | cinap_lenrek <cinap_lenrek@rei2.9hal> | 2012-01-11 16:17:54 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@rei2.9hal> | 2012-01-11 16:17:54 +0100 |
commit | 75e1ef0ab60acb6bccc54254b82770aec5786ead (patch) | |
tree | d273fc755a20e67801aa0a13df30ab75b2883419 /sys/src/cmd/webfs/cookies.c | |
parent | 62fb4f97177d8e76f1fd49bb9d0073007b7c9bcc (diff) |
new webfs, rc based hget
Diffstat (limited to 'sys/src/cmd/webfs/cookies.c')
-rw-r--r-- | sys/src/cmd/webfs/cookies.c | 1179 |
1 files changed, 0 insertions, 1179 deletions
diff --git a/sys/src/cmd/webfs/cookies.c b/sys/src/cmd/webfs/cookies.c deleted file mode 100644 index 1738e599a..000000000 --- a/sys/src/cmd/webfs/cookies.c +++ /dev/null @@ -1,1179 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <bio.h> -#include <ndb.h> -#include <fcall.h> -#include <thread.h> -#include <9p.h> -#include <ctype.h> -#include "dat.h" -#include "fns.h" - -int cookiedebug; - -typedef struct Cookie Cookie; -typedef struct Jar Jar; - -struct Cookie -{ - /* external info */ - char* name; - char* value; - char* dom; /* starts with . */ - char* path; - char* version; - char* comment; /* optional, may be nil */ - - uint expire; /* time of expiration: ~0 means when webcookies dies */ - int secure; - int explicitdom; /* dom was explicitly set */ - int explicitpath; /* path was explicitly set */ - int netscapestyle; - - /* internal info */ - int deleted; - int mark; - int ondisk; -}; - -struct Jar -{ - Cookie *c; - int nc; - int mc; - - Qid qid; - int dirty; - char *file; - char *lockfile; -}; - -struct { - char *s; - int offset; - int ishttp; -} stab[] = { - "domain", offsetof(Cookie, dom), 1, - "path", offsetof(Cookie, path), 1, - "name", offsetof(Cookie, name), 0, - "value", offsetof(Cookie, value), 0, - "comment", offsetof(Cookie, comment), 1, - "version", offsetof(Cookie, version), 1, -}; - -struct { - char *s; - int offset; -} itab[] = { - "expire", offsetof(Cookie, expire), - "secure", offsetof(Cookie, secure), - "explicitdomain", offsetof(Cookie, explicitdom), - "explicitpath", offsetof(Cookie, explicitpath), - "netscapestyle", offsetof(Cookie, netscapestyle), -}; - -#pragma varargck type "J" Jar* -#pragma varargck type "K" Cookie* - -/* HTTP format */ -static int -jarfmt(Fmt *fp) -{ - int i; - Jar *jar; - - jar = va_arg(fp->args, Jar*); - - if(jar == nil || jar->nc == 0) - return 0; - - fmtstrcpy(fp, "Cookie: "); - if(jar->c[0].version) - fmtprint(fp, "$Version=%s; ", jar->c[0].version); - for(i=0; i<jar->nc; i++) - fmtprint(fp, "%s%s=%s", i ? "; ": "", jar->c[i].name, jar->c[i].value); - fmtstrcpy(fp, "\r\n"); - return 0; -} - -/* individual cookie */ -static int -cookiefmt(Fmt *fp) -{ - int j, k, first; - char *t; - Cookie *c; - - c = va_arg(fp->args, Cookie*); - - first = 1; - for(j=0; j<nelem(stab); j++){ - t = *(char**)((uintptr)c+stab[j].offset); - if(t == nil) - continue; - if(first) - first = 0; - else - fmtstrcpy(fp, " "); - fmtprint(fp, "%s=%q", stab[j].s, t); - } - for(j=0; j<nelem(itab); j++){ - k = *(int*)((uintptr)c+itab[j].offset); - if(k == 0) - continue; - if(first) - first = 0; - else - fmtstrcpy(fp, " "); - fmtprint(fp, "%s=%ud", itab[j].s, k); - } - return 0; -} - -/* - * sort cookies: - * - alpha by name - * - alpha by domain - * - longer paths first, then alpha by path (RFC2109 4.3.4) - */ -static int -cookiecmp(Cookie *a, Cookie *b) -{ - int i; - - if((i = strcmp(a->name, b->name)) != 0) - return i; - if((i = cistrcmp(a->dom, b->dom)) != 0) - return i; - if((i = strlen(b->path) - strlen(a->path)) != 0) - return i; - if((i = strcmp(a->path, b->path)) != 0) - return i; - return 0; -} - -static int -exactcookiecmp(Cookie *a, Cookie *b) -{ - int i; - - if((i = cookiecmp(a, b)) != 0) - return i; - if((i = strcmp(a->value, b->value)) != 0) - return i; - if(a->version || b->version){ - if(!a->version) - return -1; - if(!b->version) - return 1; - if((i = strcmp(a->version, b->version)) != 0) - return i; - } - if(a->comment || b->comment){ - if(!a->comment) - return -1; - if(!b->comment) - return 1; - if((i = strcmp(a->comment, b->comment)) != 0) - return i; - } - if((i = b->expire - a->expire) != 0) - return i; - if((i = b->secure - a->secure) != 0) - return i; - if((i = b->explicitdom - a->explicitdom) != 0) - return i; - if((i = b->explicitpath - a->explicitpath) != 0) - return i; - if((i = b->netscapestyle - a->netscapestyle) != 0) - return i; - - return 0; -} - -static void -freecookie(Cookie *c) -{ - int i; - - for(i=0; i<nelem(stab); i++) - free(*(char**)((uintptr)c+stab[i].offset)); -} - -static void -copycookie(Cookie *c) -{ - int i; - char **ps; - - for(i=0; i<nelem(stab); i++){ - ps = (char**)((uintptr)c+stab[i].offset); - if(*ps) - *ps = estrdup(*ps); - } -} - -static void -delcookie(Jar *j, Cookie *c) -{ - int i; - - j->dirty = 1; - i = c - j->c; - if(i < 0 || i >= j->nc) - abort(); - c->deleted = 1; -} - -static void -addcookie(Jar *j, Cookie *c) -{ - int i; - - if(!c->name || !c->value || !c->path || !c->dom){ - fprint(2, "not adding incomplete cookie\n"); - return; - } - - if(cookiedebug) - fprint(2, "add %K\n", c); - - for(i=0; i<j->nc; i++) - if(cookiecmp(&j->c[i], c) == 0){ - if(cookiedebug) - fprint(2, "cookie %K matches %K\n", &j->c[i], c); - if(exactcookiecmp(&j->c[i], c) == 0){ - if(cookiedebug) - fprint(2, "exactly!\n"); - j->c[i].mark = 0; - return; - } - delcookie(j, &j->c[i]); - } - - j->dirty = 1; - if(j->nc == j->mc){ - j->mc += 16; - j->c = erealloc9p(j->c, j->mc*sizeof(Cookie)); - } - j->c[j->nc] = *c; - copycookie(&j->c[j->nc]); - j->nc++; -} - -static void -purgejar(Jar *j) -{ - int i; - - for(i=j->nc-1; i>=0; i--){ - if(!j->c[i].deleted) - continue; - freecookie(&j->c[i]); - --j->nc; - j->c[i] = j->c[j->nc]; - } -} - -static void -addtojar(Jar *jar, char *line, int ondisk) -{ - Cookie c; - int i, j, nf, *pint; - char *f[20], *attr, *val, **pstr; - - memset(&c, 0, sizeof c); - c.expire = ~0; - c.ondisk = ondisk; - nf = tokenize(line, f, nelem(f)); - for(i=0; i<nf; i++){ - attr = f[i]; - if((val = strchr(attr, '=')) != nil) - *val++ = '\0'; - else - val = ""; - /* string attributes */ - for(j=0; j<nelem(stab); j++){ - if(strcmp(stab[j].s, attr) == 0){ - pstr = (char**)((uintptr)&c+stab[j].offset); - *pstr = val; - } - } - /* integer attributes */ - for(j=0; j<nelem(itab); j++){ - if(strcmp(itab[j].s, attr) == 0){ - pint = (int*)((uintptr)&c+itab[j].offset); - if(val[0]=='\0') - *pint = 1; - else - *pint = strtoul(val, 0, 0); - } - } - } - if(c.name==nil || c.value==nil || c.dom==nil || c.path==nil){ - if(cookiedebug) - fprint(2, "ignoring fractional cookie %K\n", &c); - return; - } - addcookie(jar, &c); -} - -static Jar* -newjar(void) -{ - Jar *jar; - - jar = emalloc(sizeof(Jar)); - return jar; -} - -static int -expirejar(Jar *jar, int exiting) -{ - int i, n; - uint now; - - now = time(0); - n = 0; - for(i=0; i<jar->nc; i++){ - if(jar->c[i].expire < now || (exiting && jar->c[i].expire==~0)){ - if(cookiedebug) - fprint(2, "cookie %K expired\n", &jar->c[i]); - delcookie(jar, &jar->c[i]); - n++; - } - } - return n; -} - -static void -dumpjar(Jar *jar, char *desc) -{ - int i; - Biobuf *b; - char *s; - - print("%s\n", desc); - print("\tin memory:\n"); - - for(i=0; i<jar->nc; i++) - print("\t%K%s%s%s\n", &jar->c[i], - jar->c[i].ondisk ? " ondisk" : "", - jar->c[i].deleted ? " deleted" : "", - jar->c[i].mark ? " mark" : ""); - print("\n\ton disk:\n"); - if((b = Bopen(jar->file, OREAD)) == nil){ - print("\tno file\n"); - }else{ - while((s = Brdstr(b, '\n', 1)) != nil){ - print("\t%s\n", s); - free(s); - } - Bterm(b); - } - print("\n"); -} - -static int -syncjar(Jar *jar) -{ - int i, fd; - char *line; - Dir *d; - Biobuf *b; - Qid q; - - if(jar->file==nil) - return 0; - - memset(&q, 0, sizeof q); - if((d = dirstat(jar->file)) != nil){ - q = d->qid; - if(d->qid.path != jar->qid.path || d->qid.vers != jar->qid.vers) - jar->dirty = 1; - free(d); - } - - if(jar->dirty == 0) - return 0; - - fd = -1; - for(i=0; i<50; i++){ - if((fd = create(jar->lockfile, OWRITE, DMEXCL|0666)) < 0){ - sleep(100); - continue; - } - break; - } - if(fd < 0){ - if(cookiedebug) - fprint(2, "open %s: %r", jar->lockfile); - werrstr("cannot acquire jar lock: %r"); - return -1; - } - - for(i=0; i<jar->nc; i++) /* mark is cleared by addcookie */ - jar->c[i].mark = jar->c[i].ondisk; - - if((b = Bopen(jar->file, OREAD)) == nil){ - if(cookiedebug) - fprint(2, "Bopen %s: %r", jar->file); - werrstr("cannot read cookie file %s: %r", jar->file); - close(fd); - return -1; - } - for(; (line = Brdstr(b, '\n', 1)) != nil; free(line)){ - if(*line == '#') - continue; - addtojar(jar, line, 1); - } - Bterm(b); - - for(i=0; i<jar->nc; i++) - if(jar->c[i].mark && jar->c[i].expire != ~0) - delcookie(jar, &jar->c[i]); - - purgejar(jar); - - b = Bopen(jar->file, OTRUNC|OWRITE); - if(b == nil){ - if(cookiedebug) - fprint(2, "Bopen write %s: %r", jar->file); - close(fd); - return -1; - } - Bprint(b, "# webcookies cookie jar\n"); - Bprint(b, "# comments and non-standard fields will be lost\n"); - for(i=0; i<jar->nc; i++){ - if(jar->c[i].expire == ~0) - continue; - Bprint(b, "%K\n", &jar->c[i]); - jar->c[i].ondisk = 1; - } - Bterm(b); - - jar->dirty = 0; - close(fd); - if((d = dirstat(jar->file)) != nil){ - jar->qid = d->qid; - free(d); - } - return 0; -} - -static Jar* -readjar(char *file) -{ - char *lock, *p; - Jar *jar; - - jar = newjar(); - lock = emalloc(strlen(file)+10); - strcpy(lock, file); - if((p = strrchr(lock, '/')) != nil) - p++; - else - p = lock; - memmove(p+2, p, strlen(p)+1); - p[0] = 'L'; - p[1] = '.'; - jar->lockfile = lock; - jar->file = file; - jar->dirty = 1; - - if(syncjar(jar) < 0){ - free(jar->file); - free(jar->lockfile); - free(jar); - return nil; - } - return jar; -} - -static void -closejar(Jar *jar) -{ - int i; - - if(jar == nil) - return; - expirejar(jar, 0); - - if(syncjar(jar) < 0) - fprint(2, "warning: cannot rewrite cookie jar: %r\n"); - - for(i=0; i<jar->nc; i++) - freecookie(&jar->c[i]); - - free(jar->file); - free(jar->c); - free(jar); -} - -/* - * Domain name matching is per RFC2109, section 2: - * - * Hosts names can be specified either as an IP address or a FQHN - * string. Sometimes we compare one host name with another. Host A's - * name domain-matches host B's if - * - * * both host names are IP addresses and their host name strings match - * exactly; or - * - * * both host names are FQDN strings and their host name strings match - * exactly; or - * - * * A is a FQDN string and has the form NB, where N is a non-empty name - * string, B has the form .B', and B' is a FQDN string. (So, x.y.com - * domain-matches .y.com but not y.com.) - * - * Note that domain-match is not a commutative operation: a.b.c.com - * domain-matches .c.com, but not the reverse. - * - * (This does not verify that IP addresses and FQDN's are well-formed.) - */ -static int -isdomainmatch(char *name, char *pattern) -{ - int lname, lpattern; - - if(cistrcmp(name, pattern)==0) - return 1; - - if(strcmp(ipattr(name), "dom")==0 && pattern[0]=='.'){ - lname = strlen(name); - lpattern = strlen(pattern); - /* e.g., name: www.google.com && pattern: .google.com */ - if(lname >= lpattern && cistrcmp(name+lname-lpattern, pattern)==0) - return 1; - /* e.g., name: google.com && pattern: .google.com */ - if(lpattern > lname && - cistrcmp(pattern+lpattern-lname, name) == 0) - return 1; - } - return 0; -} - -/* - * RFC2109 4.3.4: - * - domain must match - * - path in cookie must be a prefix of request path - * - cookie must not have expired - */ -static int -iscookiematch(Cookie *c, char *dom, char *path, uint now) -{ - return isdomainmatch(dom, c->dom) - && strncmp(c->path, path, strlen(c->path))==0 - && (c->expire == 0 || c->expire >= now); -} - -/* - * Produce a subjar of matching cookies. - * Secure cookies are only included if secure is set. - */ -static Jar* -cookiesearch(Jar *jar, char *dom, char *path, int issecure) -{ - int i; - Jar *j; - uint now; - - if(cookiedebug) - fprint(2, "cookiesearch %s %s %d\n", dom, path, issecure); - now = time(0); - j = newjar(); - for(i=0; i<jar->nc; i++){ - if((issecure || !jar->c[i].secure) && - iscookiematch(&jar->c[i], dom, path, now)){ - if(cookiedebug){ - fprint(2, "\t%s %s %d %s\n", jar->c[i].dom, - jar->c[i].path, jar->c[i].secure, - jar->c[i].name); - fprint(2, "\tmatched\n"); - } - addcookie(j, &jar->c[i]); - } - } - if(j->nc == 0){ - closejar(j); - werrstr("no cookies found"); - return nil; - } - qsort(j->c, j->nc, sizeof(j->c[0]), (int(*)(void*, void*))cookiecmp); - return j; -} - -/* - * RFC2109 4.3.2 security checks - */ -static char* -isbadcookie(Cookie *c, char *dom, char *path) -{ - int lcdom, ldom; - - if(strncmp(c->path, path, strlen(c->path)) != 0) - return "cookie path is not a prefix of the request path"; - - /* - * fgb says omitting this test is necessary to get some sites to work, - * but it seems dubious. - */ - if(c->explicitdom && c->dom[0] != '.') - return "cookie domain doesn't start with dot"; - - lcdom = strlen(c->dom); - if(memchr(c->dom+1, '.', lcdom-1-1) == nil) - return "cookie domain doesn't have embedded dots"; - - if(!isdomainmatch(dom, c->dom)) - return "request host does not match cookie domain"; - - ldom = strlen(dom); - if(strcmp(ipattr(dom), "dom")==0 && lcdom > ldom && - memchr(dom, '.', lcdom - ldom) != nil) - return "request host contains dots before cookie domain"; - - return 0; -} - -/* - * Sunday, 25-Jan-2002 12:24:36 GMT - * Sunday, 25 Jan 2002 12:24:36 GMT - * Sun, 25 Jan 02 12:24:36 GMT - */ -static int -isleap(int year) -{ - return year%4==0 && (year%100!=0 || year%400==0); -} - -static uint -strtotime(char *s) -{ - char *os; - int i; - Tm tm; - - static int mday[2][12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, - 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, - }; - static char *wday[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", - }; - static char *mon[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - - os = s; - /* Sunday, */ - for(i=0; i<nelem(wday); i++){ - if(cistrncmp(s, wday[i], strlen(wday[i])) == 0){ - s += strlen(wday[i]); - break; - } - if(cistrncmp(s, wday[i], 3) == 0){ - s += 3; - break; - } - } - if(i==nelem(wday)){ - if(cookiedebug) - fprint(2, "bad wday (%s)\n", os); - return -1; - } - if(*s++ != ',' || *s++ != ' '){ - if(cookiedebug) - fprint(2, "bad wday separator (%s)\n", os); - return -1; - } - - /* 25- */ - if(!isdigit(s[0]) || !isdigit(s[1]) || (s[2]!='-' && s[2]!=' ')){ - if(cookiedebug) - fprint(2, "bad day of month (%s)\n", os); - return -1; - } - tm.mday = strtol(s, 0, 10); - s += 3; - - /* Jan- */ - for(i=0; i<nelem(mon); i++) - if(cistrncmp(s, mon[i], 3) == 0){ - tm.mon = i; - s += 3; - break; - } - if(i==nelem(mon)){ - if(cookiedebug) - fprint(2, "bad month (%s)\n", os); - return -1; - } - if(s[0] != '-' && s[0] != ' '){ - if(cookiedebug) - fprint(2, "bad month separator (%s)\n", os); - return -1; - } - s++; - - /* 2002 */ - if(!isdigit(s[0]) || !isdigit(s[1])){ - if(cookiedebug) - fprint(2, "bad year (%s)\n", os); - return -1; - } - tm.year = strtol(s, 0, 10); - s += 2; - if(isdigit(s[0]) && isdigit(s[1])) - s += 2; - else{ - if(tm.year <= 68) - tm.year += 2000; - else - tm.year += 1900; - } - if(tm.mday==0 || tm.mday > mday[isleap(tm.year)][tm.mon]){ - if(cookiedebug) - fprint(2, "invalid day of month (%s)\n", os); - return -1; - } - tm.year -= 1900; - if(*s++ != ' '){ - if(cookiedebug) - fprint(2, "bad year separator (%s)\n", os); - return -1; - } - - if(!isdigit(s[0]) || !isdigit(s[1]) || s[2]!=':' - || !isdigit(s[3]) || !isdigit(s[4]) || s[5]!=':' - || !isdigit(s[6]) || !isdigit(s[7]) || s[8]!=' '){ - if(cookiedebug) - fprint(2, "bad time (%s)\n", os); - return -1; - } - - tm.hour = atoi(s); - tm.min = atoi(s+3); - tm.sec = atoi(s+6); - if(tm.hour >= 24 || tm.min >= 60 || tm.sec >= 60){ - if(cookiedebug) - fprint(2, "invalid time (%s)\n", os); - return -1; - } - s += 9; - - if(cistrcmp(s, "GMT") != 0){ - if(cookiedebug) - fprint(2, "time zone not GMT (%s)\n", os); - return -1; - } - strcpy(tm.zone, "GMT"); - tm.yday = 0; - return tm2sec(&tm); -} - -/* - * skip linear whitespace. we're a bit more lenient than RFC2616 2.2. - */ -static char* -skipspace(char *s) -{ - while(*s=='\r' || *s=='\n' || *s==' ' || *s=='\t') - s++; - return s; -} - -/* - * Try to identify old netscape headers. - * The old headers: - * - didn't allow spaces around the '=' - * - used an 'Expires' attribute - * - had no 'Version' attribute - * - had no quotes - * - allowed whitespace in values - * - apparently separated attr/value pairs with ';' exclusively - */ -static int -isnetscape(char *hdr) -{ - char *s; - - for(s=hdr; (s=strchr(s, '=')) != nil; s++){ - if(isspace(s[1]) || (s > hdr && isspace(s[-1]))) - return 0; - if(s[1]=='"') - return 0; - } - if(cistrstr(hdr, "version=")) - return 0; - return 1; -} - -/* - * Parse HTTP response headers, adding cookies to jar. - * Overwrites the headers. - */ -static char* parsecookie(Cookie*, char*, char**, int, char*, char*); -static int -parsehttp(Jar *jar, char *hdr, char *dom, char *path) -{ - static char setcookie[] = "Set-Cookie:"; - char *e, *p, *nextp; - Cookie c; - int isns, n; - - isns = isnetscape(hdr); - n = 0; - for(p=hdr; p; p=nextp){ - p = skipspace(p); - if(*p == '\0') - break; - nextp = strchr(p, '\n'); - if(nextp != nil) - *nextp++ = '\0'; - if(cistrncmp(p, setcookie, strlen(setcookie)) != 0) - continue; - if(cookiedebug) - fprint(2, "%s\n", p); - p = skipspace(p+strlen(setcookie)); - for(; *p; p=skipspace(p)){ - if((e = parsecookie(&c, p, &p, isns, dom, path)) != nil){ - if(cookiedebug) - fprint(2, "parse cookie: %s\n", e); - break; - } - if((e = isbadcookie(&c, dom, path)) != nil){ - if(cookiedebug) - fprint(2, "reject cookie: %s\n", e); - continue; - } - addcookie(jar, &c); - n++; - } - } - - return n; -} - -static char* -skipquoted(char *s) -{ - /* - * Sec 2.2 of RFC2616 defines a "quoted-string" as: - * - * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) - * qdtext = <any TEXT except <">> - * quoted-pair = "\" CHAR - * - * TEXT is any octet except CTLs, but including LWS; - * LWS is [CR LF] 1*(SP | HT); - * CHARs are ASCII octets 0-127; (NOTE: we reject 0's) - * CTLs are octets 0-31 and 127; - */ - if(*s != '"') - return s; - - for(s++; 32 <= *s && *s < 127 && *s != '"'; s++) - if(*s == '\\' && *(s+1) != '\0') - s++; - return s; -} - -static char* -skiptoken(char *s) -{ - /* - * Sec 2.2 of RFC2616 defines a "token" as - * 1*<any CHAR except CTLs or separators>; - * CHARs are ASCII octets 0-127; - * CTLs are octets 0-31 and 127; - * separators are "()<>@,;:\/[]?={}", double-quote, SP (32), and HT (9) - */ - while(32 <= *s && *s < 127 && strchr("()<>@,;:[]?={}\" \t\\", *s)==nil) - s++; - - return s; -} - -static char* -skipvalue(char *s, int isns) -{ - char *t; - - /* - * An RFC2109 value is an HTTP token or an HTTP quoted string. - * Netscape servers ignore the spec and rely on semicolons, apparently. - */ - if(isns){ - if((t = strchr(s, ';')) == nil) - t = s+strlen(s); - return t; - } - if(*s == '"') - return skipquoted(s); - return skiptoken(s); -} - -/* - * RMID=80b186bb64c03c65fab767f8; expires=Monday, 10-Feb-2003 04:44:39 GMT; - * path=/; domain=.nytimes.com - */ -static char* -parsecookie(Cookie *c, char *p, char **e, int isns, char *dom, char *path) -{ - int i, done; - char *t, *u, *attr, *val; - - memset(c, 0, sizeof *c); - c->expire = ~0; - - /* NAME=VALUE */ - t = skiptoken(p); - c->name = p; - p = skipspace(t); - if(*p != '='){ - Badname: - return "malformed cookie: no NAME=VALUE"; - } - *t = '\0'; - p = skipspace(p+1); - t = skipvalue(p, isns); - if(*t) - *t++ = '\0'; - c->value = p; - p = skipspace(t); - if(c->name[0]=='\0' || c->value[0]=='\0') - goto Badname; - - done = 0; - for(; *p && !done; p=skipspace(p)){ - attr = p; - t = skiptoken(p); - u = skipspace(t); - switch(*u){ - case '\0': - *t = '\0'; - val = p = u; - break; - case ';': - *t = '\0'; - val = ""; - p = u+1; - break; - case '=': - *t = '\0'; - val = skipspace(u+1); - p = skipvalue(val, isns); - if(*p==',') - done = 1; - if(*p) - *p++ = '\0'; - break; - case ',': - if(!isns){ - val = ""; - p = u; - *p++ = '\0'; - done = 1; - break; - } - default: - if(cookiedebug) - fprint(2, "syntax: %s\n", p); - return "syntax error"; - } - for(i=0; i<nelem(stab); i++) - if(stab[i].ishttp && cistrcmp(stab[i].s, attr)==0) - *(char**)((uintptr)c+stab[i].offset) = val; - if(cistrcmp(attr, "expires") == 0){ - if(!isns) - return "non-netscape cookie has Expires tag"; - if(!val[0]) - return "bad expires tag"; - c->expire = strtotime(val); - if(c->expire == ~0) - return "cannot parse netscape expires tag"; - } - if(cistrcmp(attr, "max-age") == 0) - c->expire = time(0)+atoi(val); - if(cistrcmp(attr, "secure") == 0) - c->secure = 1; - } - *e = p; - - if(c->dom) - c->explicitdom = 1; - else - c->dom = dom; - if(c->path) - c->explicitpath = 1; - else - c->path = path; - c->netscapestyle = isns; - - return nil; -} - -Jar *jar; - -typedef struct Aux Aux; -struct Aux -{ - char *dom; - char *path; - char *inhttp; - char *outhttp; - char *ctext; - int rdoff; -}; -enum -{ - MaxCtext = 16*1024*1024, -}; - -void -cookieopen(Req *r) -{ - char *s, *es; - int i, sz; - Aux *a; - - syncjar(jar); - a = emalloc(sizeof(Aux)); - r->fid->aux = a; - if(r->ifcall.mode&OTRUNC){ - a->ctext = emalloc(1); - a->ctext[0] = '\0'; - }else{ - sz = 256*jar->nc+1024; /* BUG should do better */ - a->ctext = emalloc(sz); - a->ctext[0] = '\0'; - s = a->ctext; - es = s+sz; - for(i=0; i<jar->nc; i++) - s = seprint(s, es, "%K\n", &jar->c[i]); - } - respond(r, nil); -} - -void -cookieread(Req *r) -{ - Aux *a; - - a = r->fid->aux; - readstr(r, a->ctext); - respond(r, nil); -} - -void -cookiewrite(Req *r) -{ - Aux *a; - int sz; - - a = r->fid->aux; - sz = r->ifcall.count+r->ifcall.offset; - if(sz > strlen(a->ctext)){ - if(sz >= MaxCtext){ - respond(r, "cookie file too large"); - return; - } - a->ctext = erealloc9p(a->ctext, sz+1); - a->ctext[sz] = '\0'; - } - memmove(a->ctext+r->ifcall.offset, r->ifcall.data, r->ifcall.count); - r->ofcall.count = r->ifcall.count; - respond(r, nil); -} - -void -cookieclunk(Fid *fid) -{ - char *p, *nextp; - Aux *a; - int i; - - a = fid->aux; - if(a == nil) - return; - for(i=0; i<jar->nc; i++) - jar->c[i].mark = 1; - for(p=a->ctext; *p; p=nextp){ - if((nextp = strchr(p, '\n')) != nil) - *nextp++ = '\0'; - else - nextp = ""; - addtojar(jar, p, 0); - } - for(i=0; i<jar->nc; i++) - if(jar->c[i].mark) - delcookie(jar, &jar->c[i]); - syncjar(jar); - free(a->dom); - free(a->path); - free(a->inhttp); - free(a->outhttp); - free(a->ctext); - free(a); -} - -void -closecookies(void) -{ - closejar(jar); -} - -void -initcookies(char *file) -{ - char *home; - - fmtinstall('J', jarfmt); - fmtinstall('K', cookiefmt); - - if(file == nil){ - home = getenv("home"); - if(home == nil) - sysfatal("no cookie file specified and no $home"); - file = emalloc(strlen(home)+30); - strcpy(file, home); - strcat(file, "/lib/webcookies"); - free(home); - } - jar = readjar(file); - if(jar == nil) - sysfatal("readjar: %r"); -} - -void -httpsetcookie(char *hdr, char *dom, char *path) -{ - char *t; - - path = estrdup(path && path[0] ? path : "/"); - if((t = strchr(path, '?')) != 0) - *t = '\0'; - t = strrchr(path, '/'); - if(t && t != path) - *t = '\0'; - parsehttp(jar, hdr, dom, path); - syncjar(jar); - free(path); -} - -char* -httpcookies(char *dom, char *path, int issecure) -{ - char *s; - Jar *j; - - syncjar(jar); - j = cookiesearch(jar, dom, path, issecure); - s = smprint("%J", j); - closejar(j); - return s; -} |