1*9a747e4fSDavid du Colombier #include <u.h> 2*9a747e4fSDavid du Colombier #include <libc.h> 3*9a747e4fSDavid du Colombier #include <bio.h> 4*9a747e4fSDavid du Colombier #include <ip.h> 5*9a747e4fSDavid du Colombier #include <plumb.h> 6*9a747e4fSDavid du Colombier #include <thread.h> 7*9a747e4fSDavid du Colombier #include <fcall.h> 8*9a747e4fSDavid du Colombier #include <9p.h> 9*9a747e4fSDavid du Colombier #include "dat.h" 10*9a747e4fSDavid du Colombier #include "fns.h" 11*9a747e4fSDavid du Colombier 12*9a747e4fSDavid du Colombier int nclient; 13*9a747e4fSDavid du Colombier Client **client; 14*9a747e4fSDavid du Colombier 15*9a747e4fSDavid du Colombier static void clientthread(void*); 16*9a747e4fSDavid du Colombier int 17*9a747e4fSDavid du Colombier newclient(int plumbed) 18*9a747e4fSDavid du Colombier { 19*9a747e4fSDavid du Colombier int i; 20*9a747e4fSDavid du Colombier Client *c; 21*9a747e4fSDavid du Colombier 22*9a747e4fSDavid du Colombier for(i=0; i<nclient; i++) 23*9a747e4fSDavid du Colombier if(client[i]->ref==0) 24*9a747e4fSDavid du Colombier return i; 25*9a747e4fSDavid du Colombier 26*9a747e4fSDavid du Colombier c = emalloc(sizeof(Client)); 27*9a747e4fSDavid du Colombier c->plumbed = plumbed; 28*9a747e4fSDavid du Colombier c->creq = chancreate(sizeof(Req*), 8); 29*9a747e4fSDavid du Colombier threadcreate(clientthread, c, STACK); 30*9a747e4fSDavid du Colombier 31*9a747e4fSDavid du Colombier c->io = ioproc(); 32*9a747e4fSDavid du Colombier c->num = nclient; 33*9a747e4fSDavid du Colombier c->ctl = globalctl; 34*9a747e4fSDavid du Colombier clonectl(&c->ctl); 35*9a747e4fSDavid du Colombier if(nclient%16 == 0) 36*9a747e4fSDavid du Colombier client = erealloc(client, (nclient+16)*sizeof(client[0])); 37*9a747e4fSDavid du Colombier client[nclient++] = c; 38*9a747e4fSDavid du Colombier return nclient-1; 39*9a747e4fSDavid du Colombier } 40*9a747e4fSDavid du Colombier 41*9a747e4fSDavid du Colombier void 42*9a747e4fSDavid du Colombier closeclient(Client *c) 43*9a747e4fSDavid du Colombier { 44*9a747e4fSDavid du Colombier if(--c->ref == 0){ 45*9a747e4fSDavid du Colombier if(c->bodyopened) 46*9a747e4fSDavid du Colombier if(c->url && c->url->close) 47*9a747e4fSDavid du Colombier (*c->url->close)(c); 48*9a747e4fSDavid du Colombier free(c->contenttype); 49*9a747e4fSDavid du Colombier c->contenttype = nil; 50*9a747e4fSDavid du Colombier free(c->postbody); 51*9a747e4fSDavid du Colombier c->postbody = nil; 52*9a747e4fSDavid du Colombier freeurl(c->url); 53*9a747e4fSDavid du Colombier c->url = nil; 54*9a747e4fSDavid du Colombier free(c->redirect); 55*9a747e4fSDavid du Colombier c->redirect = nil; 56*9a747e4fSDavid du Colombier c->npostbody = 0; 57*9a747e4fSDavid du Colombier c->havepostbody = 0; 58*9a747e4fSDavid du Colombier c->bodyopened = 0; 59*9a747e4fSDavid du Colombier } 60*9a747e4fSDavid du Colombier } 61*9a747e4fSDavid du Colombier 62*9a747e4fSDavid du Colombier void 63*9a747e4fSDavid du Colombier clonectl(Ctl *c) 64*9a747e4fSDavid du Colombier { 65*9a747e4fSDavid du Colombier if(c->useragent) 66*9a747e4fSDavid du Colombier c->useragent = estrdup(c->useragent); 67*9a747e4fSDavid du Colombier } 68*9a747e4fSDavid du Colombier 69*9a747e4fSDavid du Colombier void 70*9a747e4fSDavid du Colombier clientbodyopen(Client *c, Req *r) 71*9a747e4fSDavid du Colombier { 72*9a747e4fSDavid du Colombier char e[ERRMAX], *next; 73*9a747e4fSDavid du Colombier int i; 74*9a747e4fSDavid du Colombier Url *u; 75*9a747e4fSDavid du Colombier 76*9a747e4fSDavid du Colombier next = nil; 77*9a747e4fSDavid du Colombier for(i=0; i<=c->ctl.redirectlimit; i++){ 78*9a747e4fSDavid du Colombier if(fsdebug) 79*9a747e4fSDavid du Colombier fprint(2, "try %s\n", c->url->url); 80*9a747e4fSDavid du Colombier if(c->url->open(c, c->url) < 0){ 81*9a747e4fSDavid du Colombier Error: 82*9a747e4fSDavid du Colombier if(next) 83*9a747e4fSDavid du Colombier fprint(2, "next %s (but for error)\n", next); 84*9a747e4fSDavid du Colombier free(next); 85*9a747e4fSDavid du Colombier rerrstr(e, sizeof e); 86*9a747e4fSDavid du Colombier c->iobusy = 0; 87*9a747e4fSDavid du Colombier if(r != nil) 88*9a747e4fSDavid du Colombier r->fid->omode = -1; 89*9a747e4fSDavid du Colombier closeclient(c); /* not opening */ 90*9a747e4fSDavid du Colombier if(r != nil) 91*9a747e4fSDavid du Colombier respond(r, e); 92*9a747e4fSDavid du Colombier return; 93*9a747e4fSDavid du Colombier } 94*9a747e4fSDavid du Colombier if(!c->redirect) 95*9a747e4fSDavid du Colombier break; 96*9a747e4fSDavid du Colombier next = c->redirect; 97*9a747e4fSDavid du Colombier c->redirect = nil; 98*9a747e4fSDavid du Colombier if(i==c->ctl.redirectlimit){ 99*9a747e4fSDavid du Colombier werrstr("redirect limit reached"); 100*9a747e4fSDavid du Colombier goto Error; 101*9a747e4fSDavid du Colombier } 102*9a747e4fSDavid du Colombier if((u = parseurl(next, c->url)) == nil) 103*9a747e4fSDavid du Colombier goto Error; 104*9a747e4fSDavid du Colombier if(urldebug) 105*9a747e4fSDavid du Colombier fprint(2, "parseurl %s got scheme %d\n", next, u->ischeme); 106*9a747e4fSDavid du Colombier if(u->ischeme == USunknown){ 107*9a747e4fSDavid du Colombier werrstr("redirect with unknown URL scheme"); 108*9a747e4fSDavid du Colombier goto Error; 109*9a747e4fSDavid du Colombier } 110*9a747e4fSDavid du Colombier if(u->ischeme == UScurrent){ 111*9a747e4fSDavid du Colombier werrstr("redirect to URL relative to current document"); 112*9a747e4fSDavid du Colombier goto Error; 113*9a747e4fSDavid du Colombier } 114*9a747e4fSDavid du Colombier freeurl(c->url); 115*9a747e4fSDavid du Colombier c->url = u; 116*9a747e4fSDavid du Colombier } 117*9a747e4fSDavid du Colombier free(next); 118*9a747e4fSDavid du Colombier c->iobusy = 0; 119*9a747e4fSDavid du Colombier if(r != nil) 120*9a747e4fSDavid du Colombier respond(r, nil); 121*9a747e4fSDavid du Colombier } 122*9a747e4fSDavid du Colombier 123*9a747e4fSDavid du Colombier void 124*9a747e4fSDavid du Colombier plumburl(char *url, char *base) 125*9a747e4fSDavid du Colombier { 126*9a747e4fSDavid du Colombier int i; 127*9a747e4fSDavid du Colombier Client *c; 128*9a747e4fSDavid du Colombier 129*9a747e4fSDavid du Colombier i = newclient(1); 130*9a747e4fSDavid du Colombier c = client[i]; 131*9a747e4fSDavid du Colombier c->ref++; 132*9a747e4fSDavid du Colombier if(base != nil) 133*9a747e4fSDavid du Colombier c->baseurl = parseurl(base, nil); 134*9a747e4fSDavid du Colombier c->url = parseurl(url, c->baseurl); 135*9a747e4fSDavid du Colombier sendp(c->creq, nil); 136*9a747e4fSDavid du Colombier } 137*9a747e4fSDavid du Colombier 138*9a747e4fSDavid du Colombier void 139*9a747e4fSDavid du Colombier clientbodyread(Client *c, Req *r) 140*9a747e4fSDavid du Colombier { 141*9a747e4fSDavid du Colombier char e[ERRMAX]; 142*9a747e4fSDavid du Colombier 143*9a747e4fSDavid du Colombier if(c->url->read(c, r) < 0){ 144*9a747e4fSDavid du Colombier rerrstr(e, sizeof e); 145*9a747e4fSDavid du Colombier c->iobusy = 0; 146*9a747e4fSDavid du Colombier respond(r, e); 147*9a747e4fSDavid du Colombier } 148*9a747e4fSDavid du Colombier c->iobusy = 0; 149*9a747e4fSDavid du Colombier respond(r, nil); 150*9a747e4fSDavid du Colombier } 151*9a747e4fSDavid du Colombier 152*9a747e4fSDavid du Colombier static void 153*9a747e4fSDavid du Colombier clientthread(void *a) 154*9a747e4fSDavid du Colombier { 155*9a747e4fSDavid du Colombier Client *c; 156*9a747e4fSDavid du Colombier Req *r; 157*9a747e4fSDavid du Colombier 158*9a747e4fSDavid du Colombier c = a; 159*9a747e4fSDavid du Colombier if(c->plumbed) { 160*9a747e4fSDavid du Colombier recvp(c->creq); 161*9a747e4fSDavid du Colombier clientbodyopen(c, nil); 162*9a747e4fSDavid du Colombier replumb(c); 163*9a747e4fSDavid du Colombier } 164*9a747e4fSDavid du Colombier while((r = recvp(c->creq)) != nil){ 165*9a747e4fSDavid du Colombier if(fsdebug) 166*9a747e4fSDavid du Colombier fprint(2, "clientthread %F\n", &r->ifcall); 167*9a747e4fSDavid du Colombier switch(r->ifcall.type){ 168*9a747e4fSDavid du Colombier case Topen: 169*9a747e4fSDavid du Colombier if(c->plumbed) { 170*9a747e4fSDavid du Colombier c->plumbed = 0; 171*9a747e4fSDavid du Colombier c->ref--; /* from plumburl() */ 172*9a747e4fSDavid du Colombier respond(r, nil); 173*9a747e4fSDavid du Colombier } 174*9a747e4fSDavid du Colombier else 175*9a747e4fSDavid du Colombier clientbodyopen(c, r); 176*9a747e4fSDavid du Colombier break; 177*9a747e4fSDavid du Colombier case Tread: 178*9a747e4fSDavid du Colombier clientbodyread(c, r); 179*9a747e4fSDavid du Colombier break; 180*9a747e4fSDavid du Colombier case Tflush: 181*9a747e4fSDavid du Colombier respond(r, nil); 182*9a747e4fSDavid du Colombier } 183*9a747e4fSDavid du Colombier if(fsdebug) 184*9a747e4fSDavid du Colombier fprint(2, "clientthread finished req\n"); 185*9a747e4fSDavid du Colombier } 186*9a747e4fSDavid du Colombier } 187*9a747e4fSDavid du Colombier 188*9a747e4fSDavid du Colombier enum 189*9a747e4fSDavid du Colombier { 190*9a747e4fSDavid du Colombier Bool, 191*9a747e4fSDavid du Colombier Int, 192*9a747e4fSDavid du Colombier String, 193*9a747e4fSDavid du Colombier XUrl, 194*9a747e4fSDavid du Colombier Fn, 195*9a747e4fSDavid du Colombier }; 196*9a747e4fSDavid du Colombier 197*9a747e4fSDavid du Colombier typedef struct Ctab Ctab; 198*9a747e4fSDavid du Colombier struct Ctab { 199*9a747e4fSDavid du Colombier char *name; 200*9a747e4fSDavid du Colombier int type; 201*9a747e4fSDavid du Colombier void *offset; 202*9a747e4fSDavid du Colombier }; 203*9a747e4fSDavid du Colombier 204*9a747e4fSDavid du Colombier Ctab ctltab[] = { 205*9a747e4fSDavid du Colombier "acceptcookies", Bool, (void*)offsetof(Ctl, acceptcookies), 206*9a747e4fSDavid du Colombier "sendcookies", Bool, (void*)offsetof(Ctl, sendcookies), 207*9a747e4fSDavid du Colombier "redirectlimit", Int, (void*)offsetof(Ctl, redirectlimit), 208*9a747e4fSDavid du Colombier "useragent", String, (void*)offsetof(Ctl, useragent), 209*9a747e4fSDavid du Colombier }; 210*9a747e4fSDavid du Colombier 211*9a747e4fSDavid du Colombier Ctab globaltab[] = { 212*9a747e4fSDavid du Colombier "chatty9p", Int, &chatty9p, 213*9a747e4fSDavid du Colombier "fsdebug", Int, &fsdebug, 214*9a747e4fSDavid du Colombier "cookiedebug", Int, &cookiedebug, 215*9a747e4fSDavid du Colombier "urldebug", Int, &urldebug, 216*9a747e4fSDavid du Colombier "httpdebug", Int, &httpdebug, 217*9a747e4fSDavid du Colombier }; 218*9a747e4fSDavid du Colombier 219*9a747e4fSDavid du Colombier Ctab clienttab[] = { 220*9a747e4fSDavid du Colombier "baseurl", XUrl, (void*)offsetof(Client, baseurl), 221*9a747e4fSDavid du Colombier "url", XUrl, (void*)offsetof(Client, url), 222*9a747e4fSDavid du Colombier }; 223*9a747e4fSDavid du Colombier 224*9a747e4fSDavid du Colombier static Ctab* 225*9a747e4fSDavid du Colombier findcmd(char *cmd, Ctab *tab, int ntab) 226*9a747e4fSDavid du Colombier { 227*9a747e4fSDavid du Colombier int i; 228*9a747e4fSDavid du Colombier 229*9a747e4fSDavid du Colombier for(i=0; i<ntab; i++) 230*9a747e4fSDavid du Colombier if(strcmp(tab[i].name, cmd) == 0) 231*9a747e4fSDavid du Colombier return &tab[i]; 232*9a747e4fSDavid du Colombier return nil; 233*9a747e4fSDavid du Colombier } 234*9a747e4fSDavid du Colombier 235*9a747e4fSDavid du Colombier static void 236*9a747e4fSDavid du Colombier parseas(Req *r, char *arg, int type, void *a) 237*9a747e4fSDavid du Colombier { 238*9a747e4fSDavid du Colombier Url *u; 239*9a747e4fSDavid du Colombier char e[ERRMAX]; 240*9a747e4fSDavid du Colombier 241*9a747e4fSDavid du Colombier switch(type){ 242*9a747e4fSDavid du Colombier case Bool: 243*9a747e4fSDavid du Colombier if(strcmp(arg, "on")==0 || strcmp(arg, "1")==0) 244*9a747e4fSDavid du Colombier *(int*)a = 1; 245*9a747e4fSDavid du Colombier else 246*9a747e4fSDavid du Colombier *(int*)a = 0; 247*9a747e4fSDavid du Colombier break; 248*9a747e4fSDavid du Colombier case String: 249*9a747e4fSDavid du Colombier free(*(char**)a); 250*9a747e4fSDavid du Colombier *(char**)a = estrdup(arg); 251*9a747e4fSDavid du Colombier break; 252*9a747e4fSDavid du Colombier case XUrl: 253*9a747e4fSDavid du Colombier u = parseurl(arg, nil); 254*9a747e4fSDavid du Colombier if(u == nil){ 255*9a747e4fSDavid du Colombier snprint(e, sizeof e, "parseurl: %r"); 256*9a747e4fSDavid du Colombier respond(r, e); 257*9a747e4fSDavid du Colombier return; 258*9a747e4fSDavid du Colombier } 259*9a747e4fSDavid du Colombier freeurl(*(Url**)a); 260*9a747e4fSDavid du Colombier *(Url**)a = u; 261*9a747e4fSDavid du Colombier break; 262*9a747e4fSDavid du Colombier case Int: 263*9a747e4fSDavid du Colombier if(strcmp(arg, "on")==0) 264*9a747e4fSDavid du Colombier *(int*)a = 1; 265*9a747e4fSDavid du Colombier else 266*9a747e4fSDavid du Colombier *(int*)a = atoi(arg); 267*9a747e4fSDavid du Colombier break; 268*9a747e4fSDavid du Colombier } 269*9a747e4fSDavid du Colombier respond(r, nil); 270*9a747e4fSDavid du Colombier } 271*9a747e4fSDavid du Colombier 272*9a747e4fSDavid du Colombier int 273*9a747e4fSDavid du Colombier ctlwrite(Req *r, Ctl *ctl, char *cmd, char *arg) 274*9a747e4fSDavid du Colombier { 275*9a747e4fSDavid du Colombier void *a; 276*9a747e4fSDavid du Colombier Ctab *t; 277*9a747e4fSDavid du Colombier 278*9a747e4fSDavid du Colombier if((t = findcmd(cmd, ctltab, nelem(ctltab))) == nil) 279*9a747e4fSDavid du Colombier return 0; 280*9a747e4fSDavid du Colombier a = (void*)((ulong)ctl+(int)t->offset); 281*9a747e4fSDavid du Colombier parseas(r, arg, t->type, a); 282*9a747e4fSDavid du Colombier return 1; 283*9a747e4fSDavid du Colombier } 284*9a747e4fSDavid du Colombier 285*9a747e4fSDavid du Colombier int 286*9a747e4fSDavid du Colombier clientctlwrite(Req *r, Client *c, char *cmd, char *arg) 287*9a747e4fSDavid du Colombier { 288*9a747e4fSDavid du Colombier void *a; 289*9a747e4fSDavid du Colombier Ctab *t; 290*9a747e4fSDavid du Colombier 291*9a747e4fSDavid du Colombier if((t = findcmd(cmd, clienttab, nelem(clienttab))) == nil) 292*9a747e4fSDavid du Colombier return 0; 293*9a747e4fSDavid du Colombier a = (void*)((ulong)c+(int)t->offset); 294*9a747e4fSDavid du Colombier parseas(r, arg, t->type, a); 295*9a747e4fSDavid du Colombier return 1; 296*9a747e4fSDavid du Colombier } 297*9a747e4fSDavid du Colombier 298*9a747e4fSDavid du Colombier int 299*9a747e4fSDavid du Colombier globalctlwrite(Req *r, char *cmd, char *arg) 300*9a747e4fSDavid du Colombier { 301*9a747e4fSDavid du Colombier void *a; 302*9a747e4fSDavid du Colombier Ctab *t; 303*9a747e4fSDavid du Colombier 304*9a747e4fSDavid du Colombier if((t = findcmd(cmd, globaltab, nelem(globaltab))) == nil) 305*9a747e4fSDavid du Colombier return 0; 306*9a747e4fSDavid du Colombier a = t->offset; 307*9a747e4fSDavid du Colombier parseas(r, arg, t->type, a); 308*9a747e4fSDavid du Colombier return 1; 309*9a747e4fSDavid du Colombier } 310*9a747e4fSDavid du Colombier 311*9a747e4fSDavid du Colombier static void 312*9a747e4fSDavid du Colombier ctlfmt(Ctl *c, char *s) 313*9a747e4fSDavid du Colombier { 314*9a747e4fSDavid du Colombier int i; 315*9a747e4fSDavid du Colombier void *a; 316*9a747e4fSDavid du Colombier char *t; 317*9a747e4fSDavid du Colombier 318*9a747e4fSDavid du Colombier for(i=0; i<nelem(ctltab); i++){ 319*9a747e4fSDavid du Colombier a = (void*)((ulong)c+(int)ctltab[i].offset); 320*9a747e4fSDavid du Colombier switch(ctltab[i].type){ 321*9a747e4fSDavid du Colombier case Bool: 322*9a747e4fSDavid du Colombier s += sprint(s, "%s %s\n", ctltab[i].name, *(int*)a ? "on" : "off"); 323*9a747e4fSDavid du Colombier break; 324*9a747e4fSDavid du Colombier case Int: 325*9a747e4fSDavid du Colombier s += sprint(s, "%s %d\n", ctltab[i].name, *(int*)a); 326*9a747e4fSDavid du Colombier break; 327*9a747e4fSDavid du Colombier case String: 328*9a747e4fSDavid du Colombier t = *(char**)a; 329*9a747e4fSDavid du Colombier if(t != nil) 330*9a747e4fSDavid du Colombier s += sprint(s, "%s %.*s%s\n", ctltab[i].name, utfnlen(t, 100), t, strlen(t)>100 ? "..." : ""); 331*9a747e4fSDavid du Colombier break; 332*9a747e4fSDavid du Colombier } 333*9a747e4fSDavid du Colombier } 334*9a747e4fSDavid du Colombier } 335*9a747e4fSDavid du Colombier 336*9a747e4fSDavid du Colombier void 337*9a747e4fSDavid du Colombier ctlread(Req *r, Client *c) 338*9a747e4fSDavid du Colombier { 339*9a747e4fSDavid du Colombier char buf[1024]; 340*9a747e4fSDavid du Colombier 341*9a747e4fSDavid du Colombier sprint(buf, "%11d \n", c->num); 342*9a747e4fSDavid du Colombier ctlfmt(&c->ctl, buf+strlen(buf)); 343*9a747e4fSDavid du Colombier readstr(r, buf); 344*9a747e4fSDavid du Colombier respond(r, nil); 345*9a747e4fSDavid du Colombier } 346*9a747e4fSDavid du Colombier 347*9a747e4fSDavid du Colombier void 348*9a747e4fSDavid du Colombier globalctlread(Req *r) 349*9a747e4fSDavid du Colombier { 350*9a747e4fSDavid du Colombier char buf[1024], *s; 351*9a747e4fSDavid du Colombier int i; 352*9a747e4fSDavid du Colombier 353*9a747e4fSDavid du Colombier s = buf; 354*9a747e4fSDavid du Colombier for(i=0; i<nelem(globaltab); i++) 355*9a747e4fSDavid du Colombier s += sprint(s, "%s %d\n", globaltab[i].name, *(int*)globaltab[i].offset); 356*9a747e4fSDavid du Colombier ctlfmt(&globalctl, s); 357*9a747e4fSDavid du Colombier readstr(r, buf); 358*9a747e4fSDavid du Colombier respond(r, nil); 359*9a747e4fSDavid du Colombier } 360