📄 cookies.c
字号:
if((issecure || !jar->c[i].secure) && iscookiematch(&jar->c[i], dom, path, now)){ if(cookiedebug) 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(*)(const void*, const void*))cookiecmp); return j;}/* * RFC2109 4.3.2 security checks */static char*isbadcookie(Cookie *c, char *dom, char *path){ if(strncmp(c->path, path, strlen(c->path)) != 0) return "cookie path is not a prefix of the request path"; if(c->explicitdom && c->dom[0] != '.') return "cookie domain doesn't start with dot"; if(memchr(c->dom+1, '.', strlen(c->dom)-1-1) == nil) return "cookie domain doesn't have embedded dots"; if(!isdomainmatch(dom, c->dom)) return "request host does not match cookie domain"; if(strcmp(ipattr(dom), "dom")==0 && memchr(dom, '.', strlen(dom)-strlen(c->dom)) != 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 intisleap(int year){ return year%4==0 && (year%100!=0 || year%400==0);}static uintstrtotime(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 intisnetscape(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. May overwrite path. */static char* parsecookie(Cookie*, char*, char**, int, char*, char*);static intparsehttp(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; c->expire = ~0; memset(c, 0, sizeof *c); /* 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; } if(c->dom) c->explicitdom = 1; else c->dom = dom; if(c->path) c->explicitpath = 1; else{ c->path = path; if((t = strchr(c->path, '?')) != 0) *t = '\0'; if((t = strrchr(c->path, '/')) != 0) *t = '\0'; } c->netscapestyle = isns; *e = p; return nil;}Jar *jar;typedef struct Aux Aux;struct Aux{ char *dom; char *path; char *inhttp; char *outhttp; char *ctext; int rdoff;};enum{ AuxBuf = 4096, MaxCtext = 16*1024*1024,};voidcookieopen(Req *r){ char *s, *es; int i, sz; Aux *a; syncjar(jar); a = emalloc9p(sizeof(Aux)); r->fid->aux = a; if(r->ifcall.mode&OTRUNC){ a->ctext = emalloc9p(1); a->ctext[0] = '\0'; }else{ sz = 256*jar->nc+1024; /* BUG should do better */ a->ctext = emalloc9p(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);}voidcookieread(Req *r){ Aux *a; a = r->fid->aux; readstr(r, a->ctext); respond(r, nil);}voidcookiewrite(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);}voidcookieclunk(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);}voidclosecookies(void){ closejar(jar);}voidinitcookies(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 = emalloc9p(strlen(home)+30); strcpy(file, home); strcat(file, "/lib/webcookies"); } jar = readjar(file); if(jar == nil) sysfatal("readjar: %r");}voidhttpsetcookie(char *hdr, char *dom, char *path){ if(path == nil) path = "/"; parsehttp(jar, hdr, dom, path); syncjar(jar);}char*httpcookies(char *dom, char *path, int issecure){ char buf[1024]; Jar *j; syncjar(jar); j = cookiesearch(jar, dom, path, issecure); snprint(buf, sizeof buf, "%J", j); closejar(j); return estrdup(buf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -