11 typedef struct Webfid Webfid;
12 typedef struct Client Client;
23 int obody; /* body opend */
24 int cbody; /* body closed */
33 Key *key; /* copy for Qheader */
34 Buq *buq; /* reference for Qbody, Qpost */
58 static char *nametab[] = {
82 static Client client[64];
85 #define CLIENTID(c) (((Client*)(c)) - client)
93 for(i = 0; i < nclient; i++)
94 if(client[i].ref == 0)
96 if(i >= nelem(client))
113 freeclient(Client *cl)
117 if(cl == nil || decref(cl))
120 buclose(cl->qbody, 0);
129 freeurl(cl->baseurl);
131 memset(cl, 0, sizeof(*cl));
135 clienturl(Client *cl)
139 if(cl->qbody && cl->qbody->url)
140 return cl->qbody->url;
149 if(f->level < Qclient)
151 else if(f->level < Qurl)
153 else if(f->level < Qheader)
154 return clienturl(f->client);
160 fsmkqid(Qid *q, int level, void *aux)
170 q->path = (level<<24) | (((ulong)aux ^ time0) & 0x00ffffff);
187 urlstr(char *buf, int nbuf, Url *u, int level)
192 return snprint(buf, nbuf, "%U", u);
193 if(level == Qurlpath)
194 return snprint(buf, nbuf, "%s", Upath(u));
195 if((s = (&u->scheme)[level - Qurlschm]) == nil){
199 return snprint(buf, nbuf, "%s", s);
204 fsmkdir(Dir *d, int level, void *aux)
208 memset(d, 0, sizeof(*d));
209 fsmkqid(&d->qid, level, aux);
211 d->atime = d->mtime = time0;
212 d->uid = estrdup(user);
213 d->gid = estrdup(user);
214 d->muid = estrdup(user);
215 if(d->qid.type & QTDIR)
216 d->mode |= DMDIR | 0111;
219 d->name = fshdrname(estrdup(((Key*)aux)->key));
220 d->length = strlen(((Key*)aux)->val);
223 snprint(buf, sizeof(buf), "%ld", CLIENTID(aux));
224 d->name = estrdup(buf);
235 d->name = estrdup(nametab[level]);
236 if(level >= Qurl && level <= Qurlfrag)
237 d->length = urlstr(buf, sizeof(buf), (Url*)aux, level);
246 if(r->ifcall.aname && r->ifcall.aname[0]){
247 respond(r, "invalid attach specifier");
250 f = emalloc(sizeof(*f));
252 fsmkqid(&r->fid->qid, f->level, wfaux(f));
253 r->ofcall.qid = r->fid->qid;
264 fsmkdir(&r->d, f->level, wfaux(f));
269 fswalk1(Fid *fid, char *name, Qid *qid)
274 if(!(fid->qid.type&QTDIR))
275 return "walk in non-directory";
278 if(strcmp(name, "..") == 0){
283 freeclient(f->client);
287 if(f->level > Qparsed)
293 for(i=f->level+1; i < nelem(nametab); i++){
295 if(strcmp(name, nametab[i]) == 0)
297 if(i == Qbody && strncmp(name, "body.", 5) == 0)
302 if(j >= 0 && j < nclient){
303 f->client = &client[j];
308 if(i == Qheader && f->client && f->client->qbody){
312 for(k = f->client->qbody->hdr; k; k = k->next){
313 strncpy(buf, k->key, sizeof(buf));
314 if(!strcmp(name, fshdrname(buf)))
318 /* need to copy as key is owned by qbody wich might go away */
319 f->key = addkey(0, k->key, k->val);
324 if(i >= nelem(nametab))
325 return "directory entry not found";
328 fsmkqid(qid, f->level, wfaux(f));
334 fsclone(Fid *oldfid, Fid *newfid)
339 if(o == nil || o->key || o->buq)
341 f = emalloc(sizeof(*f));
342 memmove(f, o, sizeof(*f));
359 if((cl = newclient()) == nil){
360 respond(r, "no more clients");
365 fsmkqid(&r->fid->qid, f->level, wfaux(f));
366 r->ofcall.qid = r->fid->qid;
369 if(cl->qbody && !cl->cbody){
371 respond(r, "client in use");
382 if(cl->qbody == nil){
386 respond(r, "no url set");
389 cl->qbody = bualloc(16*1024);
390 if(f->level != Qbody){
391 f->buq = bualloc(64*1024);
392 if(!lookkey(cl->hdr, "Content-Type"))
393 cl->hdr = addkey(cl->hdr, "Content-Type",
394 "application/x-www-form-urlencoded");
401 if(!lookkey(cl->hdr, "Referer")){
406 * Referer header is often required on broken
407 * websites even if the spec makes them optional,
410 if(u = url("/", cl->url)){
411 if(r = smprint("%U", u)){
412 cl->hdr = addkey(cl->hdr, "Referer", r);
419 if(!lookkey(cl->hdr, "Connection"))
420 cl->hdr = addkey(cl->hdr, "Connection", "keep-alive");
422 if(agent && !lookkey(cl->hdr, "User-Agent"))
423 cl->hdr = addkey(cl->hdr, "User-Agent", agent);
425 http(m, cl->url, cl->hdr, cl->qbody, f->buq);
434 bureq(f->buq = cl->qbody, r);
441 rootgen(int i, Dir *d, void *)
450 fsmkdir(d, Qclient, &client[i]);
457 clientgen(int i, Dir *d, void *aux)
465 if(cl == nil || cl->qbody == nil)
467 for(k = cl->qbody->hdr; i > 0 && k; i--, k = k->next)
469 if(k == nil || i > 0)
479 parsedgen(int i, Dir *d, void *aux)
497 dirread9p(r, rootgen, nil);
501 dirread9p(r, clientgen, f->client);
505 dirread9p(r, parsedgen, clienturl(f->client));
509 snprint(buf, sizeof(buf), "useragent %s\ntimeout %d\n", agent, timeout);
515 snprint(buf, sizeof(buf), "%ld\n", CLIENTID(f->client));
518 snprint(buf, sizeof(buf), "%s", f->key->val);
529 urlstr(buf, sizeof(buf), clienturl(f->client), f->level);
535 respond(r, "not implemented");
539 rootctl(char *ctl, char *arg)
544 fprint(2, "rootctl: %q %q\n", ctl, arg);
546 if(!strcmp(ctl, "useragent")){
549 agent = estrdup(arg);
555 if(!strcmp(ctl, "flushauth")){
558 u = saneurl(url(arg, 0));
564 if(!strcmp(ctl, "timeout")){
574 return "bad ctl message";
578 clientctl(Client *cl, char *ctl, char *arg)
585 fprint(2, "clientctl: %q %q\n", ctl, arg);
587 if(!strcmp(ctl, "url")){
588 if((u = saneurl(url(arg, cl->baseurl))) == nil)
593 else if(!strcmp(ctl, "baseurl")){
594 if((u = url(arg, 0)) == nil)
595 return "bad baseurl";
596 freeurl(cl->baseurl);
599 else if(!strcmp(ctl, "request")){
601 strncpy(p, arg, sizeof(cl->request));
602 for(; *p && isalpha(*p); p++)
606 else if(!strcmp(ctl, "headers")){
609 while(*ctl && strchr("\r\n\t ", *ctl))
611 if(arg = strchr(ctl, '\n'))
613 if(k = parsehdr(ctl)){
621 static char *tab[] = {
626 for(t = tab; *t; t++){
627 strncpy(buf, *t, sizeof(buf));
628 if(!strcmp(ctl, fshdrname(buf))){
629 cl->hdr = delkey(cl->hdr, *t);
631 cl->hdr = addkey(cl->hdr, *t, arg);
636 return "bad ctl message";
652 n = r->ofcall.count = r->ifcall.count;
654 memmove(s, r->ifcall.data, n);
655 while(n > 0 && strchr("\r\n", s[n-1]))
659 while(*t && strchr("\r\n\t ", *t)==0)
661 while(*t && strchr("\r\n\t ", *t))
664 t = clientctl(f->client, s, t);
674 respond(r, "not implemented");
685 buflushreq(f->buq, o);
690 fsdestroyfid(Fid *fid)
698 if(f->client->qbody == f->buq){
699 f->client->obody = 0;
700 f->client->cbody = 1;
706 freeclient(f->client);
721 .destroyfid=fsdestroyfid,
727 fprint(2, "usage: %s [-D] [-A useragent] [-T timeout] [-m mtpt] [-s srv]\n", argv0);
732 main(int argc, char *argv[])
734 char *srv, *mtpt, *s;
737 fmtinstall('U', Ufmt);
738 fmtinstall('E', Efmt);
752 agent = EARGF(usage());
755 timeout = atoi(EARGF(usage()));
760 mtpt = EARGF(usage());
763 srv = EARGF(usage());
776 agent = estrdup(agent);
778 if(s = getenv("httpproxy")){
779 proxy = saneurl(url(s, 0));
783 postmountsrv(&fs, srv, mtpt, MREPL);