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 nstrcpy(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");
402 * some sites give a 403 Forbidden if we dont include
403 * a meaningless Accept header in the request.
405 if(!lookkey(cl->hdr, "Accept"))
406 cl->hdr = addkey(cl->hdr, "Accept", "*/*");
408 if(!lookkey(cl->hdr, "Referer")){
413 * Referer header is often required on broken
414 * websites even if the spec makes them optional,
417 if(u = url("/", cl->url)){
418 if(r = smprint("%U", u)){
419 cl->hdr = addkey(cl->hdr, "Referer", r);
426 if(!lookkey(cl->hdr, "Connection"))
427 cl->hdr = addkey(cl->hdr, "Connection", "keep-alive");
429 if(agent && !lookkey(cl->hdr, "User-Agent"))
430 cl->hdr = addkey(cl->hdr, "User-Agent", agent);
432 http(m, cl->url, cl->hdr, cl->qbody, f->buq);
441 bureq(f->buq = cl->qbody, r);
448 rootgen(int i, Dir *d, void *)
457 fsmkdir(d, Qclient, &client[i]);
464 clientgen(int i, Dir *d, void *aux)
472 if(cl == nil || cl->qbody == nil)
474 for(k = cl->qbody->hdr; i > 0 && k; i--, k = k->next)
476 if(k == nil || i > 0)
486 parsedgen(int i, Dir *d, void *aux)
504 dirread9p(r, rootgen, nil);
508 dirread9p(r, clientgen, f->client);
512 dirread9p(r, parsedgen, clienturl(f->client));
516 snprint(buf, sizeof(buf), "useragent %s\ntimeout %d\n", agent, timeout);
522 snprint(buf, sizeof(buf), "%ld\n", CLIENTID(f->client));
525 snprint(buf, sizeof(buf), "%s", f->key->val);
536 urlstr(buf, sizeof(buf), clienturl(f->client), f->level);
542 respond(r, "not implemented");
546 rootctl(Srv *fs, char *ctl, char *arg)
551 fprint(2, "rootctl: %q %q\n", ctl, arg);
553 if(!strcmp(ctl, "useragent")){
556 agent = estrdup(arg);
562 if(!strcmp(ctl, "flushauth")){
565 u = saneurl(url(arg, 0));
571 if(!strcmp(ctl, "timeout")){
581 /* ppreemptive authentication only basic
582 * auth supported, ctl message of the form:
585 if(!strcmp(ctl, "preauth")){
586 char *a[3], buf[256];
589 if(tokenize(arg, a, nelem(a)) != 2)
590 return "preauth - bad field count";
591 if((u = saneurl(url(a[0], 0))) == nil)
592 return "preauth - malformed url";
593 snprint(buf, sizeof(buf), "BASIC realm=\"%s\"", a[1]);
595 rc = authenticate(u, u, "GET", buf);
599 return "preauth failed";
603 return "bad ctl message";
607 clientctl(Client *cl, char *ctl, char *arg)
614 fprint(2, "clientctl: %q %q\n", ctl, arg);
616 if(!strcmp(ctl, "url")){
617 if((u = saneurl(url(arg, cl->baseurl))) == nil)
622 else if(!strcmp(ctl, "baseurl")){
623 if((u = url(arg, 0)) == nil)
624 return "bad baseurl";
625 freeurl(cl->baseurl);
628 else if(!strcmp(ctl, "request")){
630 nstrcpy(p, arg, sizeof(cl->request));
631 for(; *p && isalpha(*p); p++)
635 else if(!strcmp(ctl, "headers")){
638 while(*ctl && strchr(whitespace, *ctl))
640 if(arg = strchr(ctl, '\n'))
642 if(k = parsehdr(ctl)){
650 static char *tab[] = {
655 for(t = tab; *t; t++){
656 nstrcpy(buf, *t, sizeof(buf));
657 if(!strcmp(ctl, fshdrname(buf))){
658 cl->hdr = delkey(cl->hdr, *t);
660 cl->hdr = addkey(cl->hdr, *t, arg);
665 return "bad ctl message";
681 n = r->ofcall.count = r->ifcall.count;
683 memmove(s, r->ifcall.data, n);
684 while(n > 0 && strchr("\r\n", s[n-1]))
688 while(*t && strchr(whitespace, *t)==0)
690 while(*t && strchr(whitespace, *t))
693 t = clientctl(f->client, s, t);
695 t = rootctl(r->srv, s, t);
703 respond(r, "not implemented");
714 buflushreq(f->buq, o);
719 fsdestroyfid(Fid *fid)
727 if(f->client->qbody == f->buq){
728 f->client->obody = 0;
729 f->client->cbody = 1;
735 freeclient(f->client);
750 .destroyfid=fsdestroyfid,
756 fprint(2, "usage: %s [-D] [-A useragent] [-T timeout] [-m mtpt] [-s srv]\n", argv0);
761 main(int argc, char *argv[])
763 char *srv, *mtpt, *s;
766 fmtinstall('U', Ufmt);
767 fmtinstall('E', Efmt);
781 agent = EARGF(usage());
784 timeout = atoi(EARGF(usage()));
789 mtpt = EARGF(usage());
792 srv = EARGF(usage());
805 agent = estrdup(agent);
807 if(s = getenv("httpproxy")){
808 proxy = saneurl(url(s, 0));
812 postmountsrv(&fs, srv, mtpt, MREPL);