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