19a747e4fSDavid du Colombier #include <u.h> 29a747e4fSDavid du Colombier #include <libc.h> 39a747e4fSDavid du Colombier #include <bio.h> 49a747e4fSDavid du Colombier #include <ip.h> 59a747e4fSDavid du Colombier #include <plumb.h> 69a747e4fSDavid du Colombier #include <thread.h> 79a747e4fSDavid du Colombier #include <fcall.h> 89a747e4fSDavid du Colombier #include <9p.h> 99a747e4fSDavid du Colombier #include "dat.h" 109a747e4fSDavid du Colombier #include "fns.h" 119a747e4fSDavid du Colombier 129a747e4fSDavid du Colombier int nclient; 139a747e4fSDavid du Colombier Client **client; 149a747e4fSDavid du Colombier 159a747e4fSDavid du Colombier static void clientthread(void*); 169a747e4fSDavid du Colombier int 179a747e4fSDavid du Colombier newclient(int plumbed) 189a747e4fSDavid du Colombier { 199a747e4fSDavid du Colombier int i; 209a747e4fSDavid du Colombier Client *c; 219a747e4fSDavid du Colombier 229a747e4fSDavid du Colombier for(i=0; i<nclient; i++) 239a747e4fSDavid du Colombier if(client[i]->ref==0) 249a747e4fSDavid du Colombier return i; 259a747e4fSDavid du Colombier 269a747e4fSDavid du Colombier c = emalloc(sizeof(Client)); 279a747e4fSDavid du Colombier c->plumbed = plumbed; 289a747e4fSDavid du Colombier c->creq = chancreate(sizeof(Req*), 8); 299a747e4fSDavid du Colombier threadcreate(clientthread, c, STACK); 309a747e4fSDavid du Colombier 319a747e4fSDavid du Colombier c->io = ioproc(); 329a747e4fSDavid du Colombier c->num = nclient; 339a747e4fSDavid du Colombier c->ctl = globalctl; 349a747e4fSDavid du Colombier clonectl(&c->ctl); 359a747e4fSDavid du Colombier if(nclient%16 == 0) 369a747e4fSDavid du Colombier client = erealloc(client, (nclient+16)*sizeof(client[0])); 379a747e4fSDavid du Colombier client[nclient++] = c; 389a747e4fSDavid du Colombier return nclient-1; 399a747e4fSDavid du Colombier } 409a747e4fSDavid du Colombier 419a747e4fSDavid du Colombier void 429a747e4fSDavid du Colombier closeclient(Client *c) 439a747e4fSDavid du Colombier { 449a747e4fSDavid du Colombier if(--c->ref == 0){ 45*6b6b9ac8SDavid du Colombier if(c->bodyopened){ 469a747e4fSDavid du Colombier if(c->url && c->url->close) 479a747e4fSDavid du Colombier (*c->url->close)(c); 48*6b6b9ac8SDavid du Colombier c->bodyopened = 0; 49*6b6b9ac8SDavid du Colombier } 509a747e4fSDavid du Colombier free(c->contenttype); 519a747e4fSDavid du Colombier c->contenttype = nil; 529a747e4fSDavid du Colombier free(c->postbody); 539a747e4fSDavid du Colombier c->postbody = nil; 549a747e4fSDavid du Colombier freeurl(c->url); 559a747e4fSDavid du Colombier c->url = nil; 569a747e4fSDavid du Colombier free(c->redirect); 579a747e4fSDavid du Colombier c->redirect = nil; 589a747e4fSDavid du Colombier c->npostbody = 0; 599a747e4fSDavid du Colombier c->havepostbody = 0; 609a747e4fSDavid du Colombier c->bodyopened = 0; 619a747e4fSDavid du Colombier } 629a747e4fSDavid du Colombier } 639a747e4fSDavid du Colombier 649a747e4fSDavid du Colombier void 659a747e4fSDavid du Colombier clonectl(Ctl *c) 669a747e4fSDavid du Colombier { 679a747e4fSDavid du Colombier if(c->useragent) 689a747e4fSDavid du Colombier c->useragent = estrdup(c->useragent); 699a747e4fSDavid du Colombier } 709a747e4fSDavid du Colombier 719a747e4fSDavid du Colombier void 729a747e4fSDavid du Colombier clientbodyopen(Client *c, Req *r) 739a747e4fSDavid du Colombier { 749a747e4fSDavid du Colombier char e[ERRMAX], *next; 759a747e4fSDavid du Colombier int i; 769a747e4fSDavid du Colombier Url *u; 779a747e4fSDavid du Colombier 789a747e4fSDavid du Colombier next = nil; 799a747e4fSDavid du Colombier for(i=0; i<=c->ctl.redirectlimit; i++){ 80d9306527SDavid du Colombier if(c->url == nil){ 81d9306527SDavid du Colombier werrstr("nil url"); 82d9306527SDavid du Colombier goto Error; 83d9306527SDavid du Colombier } 84d9306527SDavid du Colombier if(c->url->open == nil){ 85d9306527SDavid du Colombier werrstr("unsupported url type"); 86d9306527SDavid du Colombier goto Error; 87d9306527SDavid du Colombier } 889a747e4fSDavid du Colombier if(fsdebug) 899a747e4fSDavid du Colombier fprint(2, "try %s\n", c->url->url); 909a747e4fSDavid du Colombier if(c->url->open(c, c->url) < 0){ 919a747e4fSDavid du Colombier Error: 929a747e4fSDavid du Colombier if(next) 939a747e4fSDavid du Colombier fprint(2, "next %s (but for error)\n", next); 949a747e4fSDavid du Colombier free(next); 959a747e4fSDavid du Colombier rerrstr(e, sizeof e); 969a747e4fSDavid du Colombier c->iobusy = 0; 979a747e4fSDavid du Colombier if(r != nil) 989a747e4fSDavid du Colombier r->fid->omode = -1; 999a747e4fSDavid du Colombier closeclient(c); /* not opening */ 1009a747e4fSDavid du Colombier if(r != nil) 1019a747e4fSDavid du Colombier respond(r, e); 1029a747e4fSDavid du Colombier return; 1039a747e4fSDavid du Colombier } 1049a747e4fSDavid du Colombier if(!c->redirect) 1059a747e4fSDavid du Colombier break; 1069a747e4fSDavid du Colombier next = c->redirect; 1079a747e4fSDavid du Colombier c->redirect = nil; 1089a747e4fSDavid du Colombier if(i==c->ctl.redirectlimit){ 1099a747e4fSDavid du Colombier werrstr("redirect limit reached"); 1109a747e4fSDavid du Colombier goto Error; 1119a747e4fSDavid du Colombier } 1129a747e4fSDavid du Colombier if((u = parseurl(next, c->url)) == nil) 1139a747e4fSDavid du Colombier goto Error; 1149a747e4fSDavid du Colombier if(urldebug) 1159a747e4fSDavid du Colombier fprint(2, "parseurl %s got scheme %d\n", next, u->ischeme); 1169a747e4fSDavid du Colombier if(u->ischeme == USunknown){ 1179a747e4fSDavid du Colombier werrstr("redirect with unknown URL scheme"); 1189a747e4fSDavid du Colombier goto Error; 1199a747e4fSDavid du Colombier } 1209a747e4fSDavid du Colombier if(u->ischeme == UScurrent){ 1219a747e4fSDavid du Colombier werrstr("redirect to URL relative to current document"); 1229a747e4fSDavid du Colombier goto Error; 1239a747e4fSDavid du Colombier } 1249a747e4fSDavid du Colombier freeurl(c->url); 1259a747e4fSDavid du Colombier c->url = u; 1269a747e4fSDavid du Colombier } 1279a747e4fSDavid du Colombier free(next); 1289a747e4fSDavid du Colombier c->iobusy = 0; 1299a747e4fSDavid du Colombier if(r != nil) 1309a747e4fSDavid du Colombier respond(r, nil); 1319a747e4fSDavid du Colombier } 1329a747e4fSDavid du Colombier 1339a747e4fSDavid du Colombier void 1349a747e4fSDavid du Colombier plumburl(char *url, char *base) 1359a747e4fSDavid du Colombier { 1369a747e4fSDavid du Colombier int i; 1379a747e4fSDavid du Colombier Client *c; 1389a747e4fSDavid du Colombier 1399a747e4fSDavid du Colombier i = newclient(1); 1409a747e4fSDavid du Colombier c = client[i]; 1419a747e4fSDavid du Colombier c->ref++; 1429a747e4fSDavid du Colombier if(base != nil) 1439a747e4fSDavid du Colombier c->baseurl = parseurl(base, nil); 1449a747e4fSDavid du Colombier c->url = parseurl(url, c->baseurl); 1459a747e4fSDavid du Colombier sendp(c->creq, nil); 1469a747e4fSDavid du Colombier } 1479a747e4fSDavid du Colombier 1489a747e4fSDavid du Colombier void 1499a747e4fSDavid du Colombier clientbodyread(Client *c, Req *r) 1509a747e4fSDavid du Colombier { 1519a747e4fSDavid du Colombier char e[ERRMAX]; 1529a747e4fSDavid du Colombier 153d9306527SDavid du Colombier if(c->url->read == nil){ 154d9306527SDavid du Colombier respond(r, "unsupported url type"); 155d9306527SDavid du Colombier return; 156d9306527SDavid du Colombier } 1579a747e4fSDavid du Colombier if(c->url->read(c, r) < 0){ 1589a747e4fSDavid du Colombier rerrstr(e, sizeof e); 1599a747e4fSDavid du Colombier c->iobusy = 0; 1609a747e4fSDavid du Colombier respond(r, e); 161d9306527SDavid du Colombier return; 1629a747e4fSDavid du Colombier } 1639a747e4fSDavid du Colombier c->iobusy = 0; 1649a747e4fSDavid du Colombier respond(r, nil); 1659a747e4fSDavid du Colombier } 1669a747e4fSDavid du Colombier 1679a747e4fSDavid du Colombier static void 1689a747e4fSDavid du Colombier clientthread(void *a) 1699a747e4fSDavid du Colombier { 1709a747e4fSDavid du Colombier Client *c; 1719a747e4fSDavid du Colombier Req *r; 1729a747e4fSDavid du Colombier 1739a747e4fSDavid du Colombier c = a; 1749a747e4fSDavid du Colombier if(c->plumbed) { 1759a747e4fSDavid du Colombier recvp(c->creq); 1769a747e4fSDavid du Colombier clientbodyopen(c, nil); 1779a747e4fSDavid du Colombier replumb(c); 1789a747e4fSDavid du Colombier } 1799a747e4fSDavid du Colombier while((r = recvp(c->creq)) != nil){ 1809a747e4fSDavid du Colombier if(fsdebug) 1819a747e4fSDavid du Colombier fprint(2, "clientthread %F\n", &r->ifcall); 1829a747e4fSDavid du Colombier switch(r->ifcall.type){ 1839a747e4fSDavid du Colombier case Topen: 1849a747e4fSDavid du Colombier if(c->plumbed) { 1859a747e4fSDavid du Colombier c->plumbed = 0; 1869a747e4fSDavid du Colombier c->ref--; /* from plumburl() */ 1879a747e4fSDavid du Colombier respond(r, nil); 1889a747e4fSDavid du Colombier } 1899a747e4fSDavid du Colombier else 1909a747e4fSDavid du Colombier clientbodyopen(c, r); 1919a747e4fSDavid du Colombier break; 1929a747e4fSDavid du Colombier case Tread: 1939a747e4fSDavid du Colombier clientbodyread(c, r); 1949a747e4fSDavid du Colombier break; 1959a747e4fSDavid du Colombier case Tflush: 1969a747e4fSDavid du Colombier respond(r, nil); 1979a747e4fSDavid du Colombier } 1989a747e4fSDavid du Colombier if(fsdebug) 1999a747e4fSDavid du Colombier fprint(2, "clientthread finished req\n"); 2009a747e4fSDavid du Colombier } 2019a747e4fSDavid du Colombier } 2029a747e4fSDavid du Colombier 2039a747e4fSDavid du Colombier enum 2049a747e4fSDavid du Colombier { 2059a747e4fSDavid du Colombier Bool, 2069a747e4fSDavid du Colombier Int, 2079a747e4fSDavid du Colombier String, 2089a747e4fSDavid du Colombier XUrl, 2099a747e4fSDavid du Colombier Fn, 2109a747e4fSDavid du Colombier }; 2119a747e4fSDavid du Colombier 2129a747e4fSDavid du Colombier typedef struct Ctab Ctab; 2139a747e4fSDavid du Colombier struct Ctab { 2149a747e4fSDavid du Colombier char *name; 2159a747e4fSDavid du Colombier int type; 2169a747e4fSDavid du Colombier void *offset; 2179a747e4fSDavid du Colombier }; 2189a747e4fSDavid du Colombier 2199a747e4fSDavid du Colombier Ctab ctltab[] = { 2209a747e4fSDavid du Colombier "acceptcookies", Bool, (void*)offsetof(Ctl, acceptcookies), 2219a747e4fSDavid du Colombier "sendcookies", Bool, (void*)offsetof(Ctl, sendcookies), 2229a747e4fSDavid du Colombier "redirectlimit", Int, (void*)offsetof(Ctl, redirectlimit), 2239a747e4fSDavid du Colombier "useragent", String, (void*)offsetof(Ctl, useragent), 2249a747e4fSDavid du Colombier }; 2259a747e4fSDavid du Colombier 2269a747e4fSDavid du Colombier Ctab globaltab[] = { 2279a747e4fSDavid du Colombier "chatty9p", Int, &chatty9p, 2289a747e4fSDavid du Colombier "fsdebug", Int, &fsdebug, 2299a747e4fSDavid du Colombier "cookiedebug", Int, &cookiedebug, 2309a747e4fSDavid du Colombier "urldebug", Int, &urldebug, 2319a747e4fSDavid du Colombier "httpdebug", Int, &httpdebug, 2329a747e4fSDavid du Colombier }; 2339a747e4fSDavid du Colombier 2349a747e4fSDavid du Colombier Ctab clienttab[] = { 2359a747e4fSDavid du Colombier "baseurl", XUrl, (void*)offsetof(Client, baseurl), 2369a747e4fSDavid du Colombier "url", XUrl, (void*)offsetof(Client, url), 2379a747e4fSDavid du Colombier }; 2389a747e4fSDavid du Colombier 2399a747e4fSDavid du Colombier static Ctab* 2409a747e4fSDavid du Colombier findcmd(char *cmd, Ctab *tab, int ntab) 2419a747e4fSDavid du Colombier { 2429a747e4fSDavid du Colombier int i; 2439a747e4fSDavid du Colombier 2449a747e4fSDavid du Colombier for(i=0; i<ntab; i++) 2459a747e4fSDavid du Colombier if(strcmp(tab[i].name, cmd) == 0) 2469a747e4fSDavid du Colombier return &tab[i]; 2479a747e4fSDavid du Colombier return nil; 2489a747e4fSDavid du Colombier } 2499a747e4fSDavid du Colombier 2509a747e4fSDavid du Colombier static void 2519a747e4fSDavid du Colombier parseas(Req *r, char *arg, int type, void *a) 2529a747e4fSDavid du Colombier { 2539a747e4fSDavid du Colombier Url *u; 2549a747e4fSDavid du Colombier char e[ERRMAX]; 2559a747e4fSDavid du Colombier 2569a747e4fSDavid du Colombier switch(type){ 2579a747e4fSDavid du Colombier case Bool: 2589a747e4fSDavid du Colombier if(strcmp(arg, "on")==0 || strcmp(arg, "1")==0) 2599a747e4fSDavid du Colombier *(int*)a = 1; 2609a747e4fSDavid du Colombier else 2619a747e4fSDavid du Colombier *(int*)a = 0; 2629a747e4fSDavid du Colombier break; 2639a747e4fSDavid du Colombier case String: 2649a747e4fSDavid du Colombier free(*(char**)a); 2659a747e4fSDavid du Colombier *(char**)a = estrdup(arg); 2669a747e4fSDavid du Colombier break; 2679a747e4fSDavid du Colombier case XUrl: 2689a747e4fSDavid du Colombier u = parseurl(arg, nil); 2699a747e4fSDavid du Colombier if(u == nil){ 2709a747e4fSDavid du Colombier snprint(e, sizeof e, "parseurl: %r"); 2719a747e4fSDavid du Colombier respond(r, e); 2729a747e4fSDavid du Colombier return; 2739a747e4fSDavid du Colombier } 2749a747e4fSDavid du Colombier freeurl(*(Url**)a); 2759a747e4fSDavid du Colombier *(Url**)a = u; 2769a747e4fSDavid du Colombier break; 2779a747e4fSDavid du Colombier case Int: 2789a747e4fSDavid du Colombier if(strcmp(arg, "on")==0) 2799a747e4fSDavid du Colombier *(int*)a = 1; 2809a747e4fSDavid du Colombier else 2819a747e4fSDavid du Colombier *(int*)a = atoi(arg); 2829a747e4fSDavid du Colombier break; 2839a747e4fSDavid du Colombier } 2849a747e4fSDavid du Colombier respond(r, nil); 2859a747e4fSDavid du Colombier } 2869a747e4fSDavid du Colombier 2879a747e4fSDavid du Colombier int 2889a747e4fSDavid du Colombier ctlwrite(Req *r, Ctl *ctl, char *cmd, char *arg) 2899a747e4fSDavid du Colombier { 2909a747e4fSDavid du Colombier void *a; 2919a747e4fSDavid du Colombier Ctab *t; 2929a747e4fSDavid du Colombier 2939a747e4fSDavid du Colombier if((t = findcmd(cmd, ctltab, nelem(ctltab))) == nil) 2949a747e4fSDavid du Colombier return 0; 2959a747e4fSDavid du Colombier a = (void*)((ulong)ctl+(int)t->offset); 2969a747e4fSDavid du Colombier parseas(r, arg, t->type, a); 2979a747e4fSDavid du Colombier return 1; 2989a747e4fSDavid du Colombier } 2999a747e4fSDavid du Colombier 3009a747e4fSDavid du Colombier int 3019a747e4fSDavid du Colombier clientctlwrite(Req *r, Client *c, char *cmd, char *arg) 3029a747e4fSDavid du Colombier { 3039a747e4fSDavid du Colombier void *a; 3049a747e4fSDavid du Colombier Ctab *t; 3059a747e4fSDavid du Colombier 3069a747e4fSDavid du Colombier if((t = findcmd(cmd, clienttab, nelem(clienttab))) == nil) 3079a747e4fSDavid du Colombier return 0; 3089a747e4fSDavid du Colombier a = (void*)((ulong)c+(int)t->offset); 3099a747e4fSDavid du Colombier parseas(r, arg, t->type, a); 3109a747e4fSDavid du Colombier return 1; 3119a747e4fSDavid du Colombier } 3129a747e4fSDavid du Colombier 3139a747e4fSDavid du Colombier int 3149a747e4fSDavid du Colombier globalctlwrite(Req *r, char *cmd, char *arg) 3159a747e4fSDavid du Colombier { 3169a747e4fSDavid du Colombier void *a; 3179a747e4fSDavid du Colombier Ctab *t; 3189a747e4fSDavid du Colombier 3199a747e4fSDavid du Colombier if((t = findcmd(cmd, globaltab, nelem(globaltab))) == nil) 3209a747e4fSDavid du Colombier return 0; 3219a747e4fSDavid du Colombier a = t->offset; 3229a747e4fSDavid du Colombier parseas(r, arg, t->type, a); 3239a747e4fSDavid du Colombier return 1; 3249a747e4fSDavid du Colombier } 3259a747e4fSDavid du Colombier 3269a747e4fSDavid du Colombier static void 3279a747e4fSDavid du Colombier ctlfmt(Ctl *c, char *s) 3289a747e4fSDavid du Colombier { 3299a747e4fSDavid du Colombier int i; 3309a747e4fSDavid du Colombier void *a; 3319a747e4fSDavid du Colombier char *t; 3329a747e4fSDavid du Colombier 3339a747e4fSDavid du Colombier for(i=0; i<nelem(ctltab); i++){ 3349a747e4fSDavid du Colombier a = (void*)((ulong)c+(int)ctltab[i].offset); 3359a747e4fSDavid du Colombier switch(ctltab[i].type){ 3369a747e4fSDavid du Colombier case Bool: 3379a747e4fSDavid du Colombier s += sprint(s, "%s %s\n", ctltab[i].name, *(int*)a ? "on" : "off"); 3389a747e4fSDavid du Colombier break; 3399a747e4fSDavid du Colombier case Int: 3409a747e4fSDavid du Colombier s += sprint(s, "%s %d\n", ctltab[i].name, *(int*)a); 3419a747e4fSDavid du Colombier break; 3429a747e4fSDavid du Colombier case String: 3439a747e4fSDavid du Colombier t = *(char**)a; 3449a747e4fSDavid du Colombier if(t != nil) 3459a747e4fSDavid du Colombier s += sprint(s, "%s %.*s%s\n", ctltab[i].name, utfnlen(t, 100), t, strlen(t)>100 ? "..." : ""); 3469a747e4fSDavid du Colombier break; 3479a747e4fSDavid du Colombier } 3489a747e4fSDavid du Colombier } 3499a747e4fSDavid du Colombier } 3509a747e4fSDavid du Colombier 3519a747e4fSDavid du Colombier void 3529a747e4fSDavid du Colombier ctlread(Req *r, Client *c) 3539a747e4fSDavid du Colombier { 3549a747e4fSDavid du Colombier char buf[1024]; 3559a747e4fSDavid du Colombier 3569a747e4fSDavid du Colombier sprint(buf, "%11d \n", c->num); 3579a747e4fSDavid du Colombier ctlfmt(&c->ctl, buf+strlen(buf)); 3589a747e4fSDavid du Colombier readstr(r, buf); 3599a747e4fSDavid du Colombier respond(r, nil); 3609a747e4fSDavid du Colombier } 3619a747e4fSDavid du Colombier 3629a747e4fSDavid du Colombier void 3639a747e4fSDavid du Colombier globalctlread(Req *r) 3649a747e4fSDavid du Colombier { 3659a747e4fSDavid du Colombier char buf[1024], *s; 3669a747e4fSDavid du Colombier int i; 3679a747e4fSDavid du Colombier 3689a747e4fSDavid du Colombier s = buf; 3699a747e4fSDavid du Colombier for(i=0; i<nelem(globaltab); i++) 3709a747e4fSDavid du Colombier s += sprint(s, "%s %d\n", globaltab[i].name, *(int*)globaltab[i].offset); 3719a747e4fSDavid du Colombier ctlfmt(&globalctl, s); 3729a747e4fSDavid du Colombier readstr(r, buf); 3739a747e4fSDavid du Colombier respond(r, nil); 3749a747e4fSDavid du Colombier } 375