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, "Referer")){
415 * Referer header is often required on broken
416 * websites even if the spec makes them optional,
419 if(u = url("/", cl->url)){
421 u->host = smprint("%H", r);
425 /* do not send credentials */
426 free(u->user); u->user = nil;
427 free(u->pass); u->pass = nil;
429 if(r = smprint("%U", u)){
430 cl->hdr = addkey(cl->hdr, "Referer", r);
437 if(!lookkey(cl->hdr, "Connection"))
438 cl->hdr = addkey(cl->hdr, "Connection", "keep-alive");
440 if(agent && !lookkey(cl->hdr, "User-Agent"))
441 cl->hdr = addkey(cl->hdr, "User-Agent", agent);
443 http(m, cl->url, cl->hdr, cl->qbody, f->buq);
452 bureq(f->buq = cl->qbody, r);
459 rootgen(int i, Dir *d, void *)
468 fsmkdir(d, Qclient, &client[i]);
475 clientgen(int i, Dir *d, void *aux)
483 if(cl == nil || cl->qbody == nil)
485 for(k = cl->qbody->hdr; i > 0 && k; i--, k = k->next)
487 if(k == nil || i > 0)
497 parsedgen(int i, Dir *d, void *aux)
515 dirread9p(r, rootgen, nil);
519 dirread9p(r, clientgen, f->client);
523 dirread9p(r, parsedgen, clienturl(f->client));
527 snprint(buf, sizeof(buf), "useragent %s\ntimeout %d\n", agent, timeout);
533 snprint(buf, sizeof(buf), "%d\n", CLIENTID(f->client));
536 snprint(buf, sizeof(buf), "%s", f->key->val);
547 urlstr(buf, sizeof(buf), clienturl(f->client), f->level);
553 respond(r, "not implemented");
557 rootctl(Srv *fs, char *ctl, char *arg)
562 fprint(2, "rootctl: %q %q\n", ctl, arg);
564 if(!strcmp(ctl, "useragent")){
567 agent = estrdup(arg);
573 if(!strcmp(ctl, "flushauth")){
576 u = saneurl(url(arg, 0));
582 if(!strcmp(ctl, "timeout")){
592 /* ppreemptive authentication only basic
593 * auth supported, ctl message of the form:
596 if(!strcmp(ctl, "preauth")){
597 char *a[3], buf[256];
600 if(tokenize(arg, a, nelem(a)) != 2)
601 return "preauth - bad field count";
602 if((u = saneurl(url(a[0], 0))) == nil)
603 return "preauth - malformed url";
604 snprint(buf, sizeof(buf), "BASIC realm=\"%s\"", a[1]);
606 rc = authenticate(u, u, "GET", buf);
610 return "preauth failed";
614 return "bad ctl message";
618 clientctl(Client *cl, char *ctl, char *arg)
625 fprint(2, "clientctl: %q %q\n", ctl, arg);
627 if(!strcmp(ctl, "url")){
628 if((u = saneurl(url(arg, cl->baseurl))) == nil)
633 else if(!strcmp(ctl, "baseurl")){
634 if((u = url(arg, 0)) == nil)
635 return "bad baseurl";
636 freeurl(cl->baseurl);
639 else if(!strcmp(ctl, "request")){
641 nstrcpy(p, arg, sizeof(cl->request));
642 for(; *p && isalpha(*p); p++)
646 else if(!strcmp(ctl, "headers")){
649 while(*ctl && strchr(whitespace, *ctl))
651 if(arg = strchr(ctl, '\n'))
653 if(k = parsehdr(ctl)){
661 static char *tab[] = {
666 for(t = tab; *t; t++){
667 nstrcpy(buf, *t, sizeof(buf));
668 if(!strcmp(ctl, fshdrname(buf))){
669 cl->hdr = delkey(cl->hdr, *t);
671 cl->hdr = addkey(cl->hdr, *t, arg);
676 return "bad ctl message";
692 n = r->ofcall.count = r->ifcall.count;
694 memmove(s, r->ifcall.data, n);
695 while(n > 0 && strchr("\r\n", s[n-1]))
699 while(*t && strchr(whitespace, *t)==0)
701 while(*t && strchr(whitespace, *t))
704 t = clientctl(f->client, s, t);
706 t = rootctl(r->srv, s, t);
714 respond(r, "not implemented");
725 buflushreq(f->buq, o);
730 fsdestroyfid(Fid *fid)
738 if(f->client->qbody == f->buq){
739 f->client->obody = 0;
740 f->client->cbody = 1;
746 freeclient(f->client);
754 /* drop reference to old webfs mount */
762 postnote(PNGROUP, getpid(), "shutdown");
777 .destroyfid=fsdestroyfid,
784 fprint(2, "usage: %s [-D] [-A useragent] [-T timeout] [-m mtpt] [-s service]\n", argv0);
789 main(int argc, char *argv[])
794 fmtinstall('U', Ufmt);
795 fmtinstall('H', Hfmt);
796 fmtinstall('E', Efmt);
797 fmtinstall('[', encodefmt);
809 agent = EARGF(usage());
812 timeout = atoi(EARGF(usage()));
817 mtpt = EARGF(usage());
820 service = EARGF(usage());
832 agent = "Mozilla/5.0 (compatible; hjdicks)";
833 agent = estrdup(agent);
835 if(s = getenv("httpproxy")){
836 proxy = saneurl(url(s, 0));
837 if(proxy == nil || strcmp(proxy->scheme, "http") && strcmp(proxy->scheme, "https"))
838 sysfatal("invalid httpproxy url: %s", s);
842 postmountsrv(&fs, service, mtpt, MREPL);