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[] = {
84 static Client client[64];
87 #define CLIENTID(c) ((int)(((Client*)(c)) - client))
95 for(i = 0; i < nclient; i++)
96 if(client[i].ref == 0)
98 if(i >= nelem(client))
115 freeclient(Client *cl)
119 if(cl == nil || decref(cl))
122 buclose(cl->qbody, 0);
131 freeurl(cl->baseurl);
133 memset(cl, 0, sizeof(*cl));
137 clienturl(Client *cl)
141 if(cl->qbody && cl->qbody->url)
142 return cl->qbody->url;
151 if(f->level < Qclient)
153 else if(f->level < Qurl)
155 else if(f->level < Qheader)
156 return clienturl(f->client);
162 fsmkqid(Qid *q, int level, void *aux)
172 q->path = (level<<24) | (((uintptr)aux ^ time0) & 0x00ffffff);
189 urlstr(char *buf, int nbuf, Url *u, int level)
194 return snprint(buf, nbuf, "%U", u);
195 if(level == Qurlpath)
196 return snprint(buf, nbuf, "%s", Upath(u));
197 if((s = (&u->scheme)[level - Qurlschm]) == nil){
201 return snprint(buf, nbuf, "%s", s);
206 fsmkdir(Dir *d, int level, void *aux)
210 memset(d, 0, sizeof(*d));
211 fsmkqid(&d->qid, level, aux);
213 d->atime = d->mtime = time0;
214 d->uid = estrdup(user);
215 d->gid = estrdup(user);
216 d->muid = estrdup(user);
217 if(d->qid.type & QTDIR)
218 d->mode |= DMDIR | 0111;
221 d->name = fshdrname(estrdup(((Key*)aux)->key));
222 d->length = strlen(((Key*)aux)->val);
225 snprint(buf, sizeof(buf), "%d", CLIENTID(aux));
226 d->name = estrdup(buf);
237 d->name = estrdup(nametab[level]);
238 if(level >= Qurl && level <= Qurlfrag)
239 d->length = urlstr(buf, sizeof(buf), (Url*)aux, level);
248 if(r->ifcall.aname && r->ifcall.aname[0]){
249 respond(r, "invalid attach specifier");
252 f = emalloc(sizeof(*f));
254 fsmkqid(&r->fid->qid, f->level, wfaux(f));
255 r->ofcall.qid = r->fid->qid;
266 fsmkdir(&r->d, f->level, wfaux(f));
271 fswalk1(Fid *fid, char *name, Qid *qid)
276 if(!(fid->qid.type&QTDIR))
277 return "walk in non-directory";
280 if(strcmp(name, "..") == 0){
285 freeclient(f->client);
289 if(f->level > Qparsed)
295 for(i=f->level+1; i < nelem(nametab); i++){
297 if(strcmp(name, nametab[i]) == 0)
299 if(i == Qbody && strncmp(name, "body.", 5) == 0)
304 if(j >= 0 && j < nclient){
305 f->client = &client[j];
310 if(i == Qheader && f->client && f->client->qbody){
314 for(k = f->client->qbody->hdr; k; k = k->next){
315 nstrcpy(buf, k->key, sizeof(buf));
316 if(!strcmp(name, fshdrname(buf)))
320 /* need to copy as key is owned by qbody wich might go away */
321 f->key = addkey(0, k->key, k->val);
326 if(i >= nelem(nametab))
327 return "directory entry not found";
330 fsmkqid(qid, f->level, wfaux(f));
336 fsclone(Fid *oldfid, Fid *newfid)
341 if(o == nil || o->key || o->buq)
343 f = emalloc(sizeof(*f));
344 memmove(f, o, sizeof(*f));
361 if((cl = newclient()) == nil){
362 respond(r, "no more clients");
367 fsmkqid(&r->fid->qid, f->level, wfaux(f));
368 r->ofcall.qid = r->fid->qid;
371 if(cl->qbody && !cl->cbody){
373 respond(r, "client in use");
384 if(cl->qbody == nil){
388 respond(r, "no url set");
391 cl->qbody = bualloc(16*1024);
392 if(f->level != Qbody){
393 f->buq = bualloc(64*1024);
394 if(!lookkey(cl->hdr, "Content-Type"))
395 cl->hdr = addkey(cl->hdr, "Content-Type",
396 "application/x-www-form-urlencoded");
404 * some sites give a 403 Forbidden if we dont include
405 * a meaningless Accept header in the request.
407 if(!lookkey(cl->hdr, "Accept"))
408 cl->hdr = addkey(cl->hdr, "Accept", "*/*");
410 if(!lookkey(cl->hdr, "Connection"))
411 cl->hdr = addkey(cl->hdr, "Connection", "keep-alive");
413 if(agent && !lookkey(cl->hdr, "User-Agent"))
414 cl->hdr = addkey(cl->hdr, "User-Agent", agent);
416 http(m, cl->url, cl->hdr, cl->qbody, f->buq);
425 bureq(f->buq = cl->qbody, r);
432 rootgen(int i, Dir *d, void *)
441 fsmkdir(d, Qclient, &client[i]);
448 clientgen(int i, Dir *d, void *aux)
456 if(cl == nil || cl->qbody == nil)
458 for(k = cl->qbody->hdr; i > 0 && k; i--, k = k->next)
460 if(k == nil || i > 0)
470 parsedgen(int i, Dir *d, void *aux)
488 dirread9p(r, rootgen, nil);
492 dirread9p(r, clientgen, f->client);
496 dirread9p(r, parsedgen, clienturl(f->client));
500 snprint(buf, sizeof(buf), "useragent %s\ntimeout %d\n", agent, timeout);
506 snprint(buf, sizeof(buf), "%d\n", CLIENTID(f->client));
509 snprint(buf, sizeof(buf), "%s", f->key->val);
520 urlstr(buf, sizeof(buf), clienturl(f->client), f->level);
526 respond(r, "not implemented");
530 rootctl(Srv *fs, char *ctl, char *arg)
535 fprint(2, "rootctl: %q %q\n", ctl, arg);
537 if(!strcmp(ctl, "useragent")){
540 agent = estrdup(arg);
546 if(!strcmp(ctl, "flushauth")){
549 u = saneurl(url(arg, 0));
555 if(!strcmp(ctl, "timeout")){
565 /* ppreemptive authentication only basic
566 * auth supported, ctl message of the form:
569 if(!strcmp(ctl, "preauth")){
570 char *a[3], buf[256];
573 if(tokenize(arg, a, nelem(a)) != 2)
574 return "preauth - bad field count";
575 if((u = saneurl(url(a[0], 0))) == nil)
576 return "preauth - malformed url";
577 snprint(buf, sizeof(buf), "BASIC realm=\"%s\"", a[1]);
579 rc = authenticate(u, u, "GET", buf);
583 return "preauth failed";
587 return "bad ctl message";
591 clientctl(Client *cl, char *ctl, char *arg)
598 fprint(2, "clientctl: %q %q\n", ctl, arg);
600 if(!strcmp(ctl, "url")){
601 if((u = saneurl(url(arg, cl->baseurl))) == nil)
606 else if(!strcmp(ctl, "baseurl")){
607 if((u = url(arg, 0)) == nil)
608 return "bad baseurl";
609 freeurl(cl->baseurl);
612 else if(!strcmp(ctl, "request")){
614 nstrcpy(p, arg, sizeof(cl->request));
615 for(; *p && isalpha(*p); p++)
619 else if(!strcmp(ctl, "headers")){
622 while(*ctl && strchr(whitespace, *ctl))
624 if(arg = strchr(ctl, '\n'))
626 if(k = parsehdr(ctl)){
634 static char *tab[] = {
639 for(t = tab; *t; t++){
640 nstrcpy(buf, *t, sizeof(buf));
641 if(!strcmp(ctl, fshdrname(buf))){
642 cl->hdr = delkey(cl->hdr, *t);
644 cl->hdr = addkey(cl->hdr, *t, arg);
649 return "bad ctl message";
665 n = r->ofcall.count = r->ifcall.count;
667 memmove(s, r->ifcall.data, n);
668 while(n > 0 && strchr("\r\n", s[n-1]))
672 while(*t && strchr(whitespace, *t)==0)
674 while(*t && strchr(whitespace, *t))
677 t = clientctl(f->client, s, t);
679 t = rootctl(r->srv, s, t);
687 respond(r, "not implemented");
698 buflushreq(f->buq, o);
703 fsdestroyfid(Fid *fid)
711 if(f->client->qbody == f->buq){
712 f->client->obody = 0;
713 f->client->cbody = 1;
719 freeclient(f->client);
727 /* drop reference to old webfs mount */
735 postnote(PNGROUP, getpid(), "shutdown");
750 .destroyfid=fsdestroyfid,
757 fprint(2, "usage: %s [-Dd] [-A useragent] [-T timeout] [-m mtpt] [-s service]\n", argv0);
762 main(int argc, char *argv[])
767 fmtinstall('U', Ufmt);
768 fmtinstall('N', Nfmt);
769 fmtinstall('E', Efmt);
770 fmtinstall('[', encodefmt);
771 fmtinstall('H', encodefmt);
783 agent = EARGF(usage());
786 timeout = atoi(EARGF(usage()));
791 mtpt = EARGF(usage());
794 service = EARGF(usage());
806 agent = "Mozilla/5.0 (compatible; hjdicks)";
807 agent = estrdup(agent);
809 if(s = getenv("httpproxy")){
810 proxy = saneurl(url(s, 0));
811 if(proxy == nil || strcmp(proxy->scheme, "http") && strcmp(proxy->scheme, "https"))
812 sysfatal("invalid httpproxy url: %s", s);
816 postmountsrv(&fs, service, mtpt, MREPL);