2011-03-30 12:46:40 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2012-01-11 15:17:54 +00:00
|
|
|
#include <ctype.h>
|
2011-03-30 12:46:40 +00:00
|
|
|
#include <fcall.h>
|
2012-01-11 15:17:54 +00:00
|
|
|
#include <thread.h>
|
2011-03-30 12:46:40 +00:00
|
|
|
#include <9p.h>
|
2012-01-11 15:17:54 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
typedef struct Webfid Webfid;
|
|
|
|
typedef struct Client Client;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
struct Client
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
Ref;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
char request[16];
|
|
|
|
Url *baseurl;
|
|
|
|
Url *url;
|
|
|
|
Key *hdr;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
int obody; /* body opend */
|
|
|
|
int cbody; /* body closed */
|
|
|
|
Buq *qbody;
|
|
|
|
};
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
struct Webfid
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
int level;
|
|
|
|
|
|
|
|
Client *client;
|
|
|
|
Key *key; /* copy for Qheader */
|
|
|
|
Buq *buq; /* reference for Qbody, Qpost */
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
enum {
|
|
|
|
Qroot,
|
|
|
|
Qrctl,
|
|
|
|
Qclone,
|
|
|
|
Qclient,
|
|
|
|
Qctl,
|
|
|
|
Qbody,
|
|
|
|
Qpost,
|
|
|
|
Qparsed,
|
|
|
|
Qurl,
|
|
|
|
Qurlschm,
|
|
|
|
Qurluser,
|
|
|
|
Qurlpass,
|
|
|
|
Qurlhost,
|
|
|
|
Qurlport,
|
|
|
|
Qurlpath,
|
|
|
|
Qurlqwry,
|
|
|
|
Qurlfrag,
|
|
|
|
Qheader,
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static char *nametab[] = {
|
|
|
|
"/",
|
|
|
|
"ctl",
|
|
|
|
"clone",
|
|
|
|
nil,
|
|
|
|
"ctl",
|
|
|
|
"body",
|
|
|
|
"postbody",
|
|
|
|
"parsed",
|
|
|
|
"url",
|
|
|
|
"scheme",
|
|
|
|
"user",
|
|
|
|
"passwd",
|
|
|
|
"host",
|
|
|
|
"port",
|
|
|
|
"path",
|
|
|
|
"query",
|
|
|
|
"fragment",
|
|
|
|
nil,
|
|
|
|
};
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-06-04 15:45:08 +00:00
|
|
|
static char *mtpt;
|
|
|
|
static char *service;
|
2012-01-11 15:17:54 +00:00
|
|
|
static long time0;
|
|
|
|
static char *user;
|
2012-03-25 04:55:29 +00:00
|
|
|
static char *agent;
|
2012-01-11 15:17:54 +00:00
|
|
|
static Client client[64];
|
|
|
|
static int nclient;
|
|
|
|
|
2016-01-07 03:44:13 +00:00
|
|
|
#define CLIENTID(c) ((int)(((Client*)(c)) - client))
|
2012-01-11 15:17:54 +00:00
|
|
|
|
|
|
|
Client*
|
|
|
|
newclient(void)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
Client *cl;
|
|
|
|
int i;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
for(i = 0; i < nclient; i++)
|
|
|
|
if(client[i].ref == 0)
|
|
|
|
break;
|
|
|
|
if(i >= nelem(client))
|
|
|
|
return nil;
|
|
|
|
if(i == nclient)
|
|
|
|
nclient++;
|
|
|
|
cl = &client[i];
|
|
|
|
incref(cl);
|
|
|
|
|
|
|
|
cl->request[0] = 0;
|
|
|
|
cl->baseurl = nil;
|
|
|
|
cl->url = nil;
|
|
|
|
cl->hdr = nil;
|
|
|
|
cl->qbody = nil;
|
|
|
|
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
freeclient(Client *cl)
|
|
|
|
{
|
|
|
|
Key *k;
|
|
|
|
|
|
|
|
if(cl == nil || decref(cl))
|
|
|
|
return;
|
|
|
|
|
|
|
|
buclose(cl->qbody, 0);
|
|
|
|
bufree(cl->qbody);
|
|
|
|
|
|
|
|
while(k = cl->hdr){
|
|
|
|
cl->hdr = k->next;
|
|
|
|
free(k);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
|
|
|
|
freeurl(cl->url);
|
|
|
|
freeurl(cl->baseurl);
|
|
|
|
|
|
|
|
memset(cl, 0, sizeof(*cl));
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static Url*
|
|
|
|
clienturl(Client *cl)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
static Url nullurl;
|
|
|
|
|
|
|
|
if(cl->qbody && cl->qbody->url)
|
|
|
|
return cl->qbody->url;
|
|
|
|
if(cl->url)
|
|
|
|
return cl->url;
|
|
|
|
return &nullurl;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static void*
|
|
|
|
wfaux(Webfid *f)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
if(f->level < Qclient)
|
|
|
|
return nil;
|
|
|
|
else if(f->level < Qurl)
|
|
|
|
return f->client;
|
|
|
|
else if(f->level < Qheader)
|
|
|
|
return clienturl(f->client);
|
|
|
|
else
|
|
|
|
return f->key;
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static void
|
|
|
|
fsmkqid(Qid *q, int level, void *aux)
|
|
|
|
{
|
|
|
|
q->type = 0;
|
|
|
|
q->vers = 0;
|
|
|
|
switch(level){
|
|
|
|
case Qroot:
|
|
|
|
case Qparsed:
|
|
|
|
case Qclient:
|
|
|
|
q->type = QTDIR;
|
|
|
|
default:
|
2014-02-14 13:14:17 +00:00
|
|
|
q->path = (level<<24) | (((uintptr)aux ^ time0) & 0x00ffffff);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static char*
|
|
|
|
fshdrname(char *s)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
char *k, *w;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
for(k=w=s; *k; k++)
|
|
|
|
if(isalnum(*k))
|
|
|
|
*w++ = tolower(*k);
|
|
|
|
*w = 0;
|
|
|
|
return s;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-01-11 15:17:54 +00:00
|
|
|
urlstr(char *buf, int nbuf, Url *u, int level)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
char *s;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
if(level == Qurl)
|
|
|
|
return snprint(buf, nbuf, "%U", u);
|
|
|
|
if(level == Qurlpath)
|
|
|
|
return snprint(buf, nbuf, "%s", Upath(u));
|
|
|
|
if((s = (&u->scheme)[level - Qurlschm]) == nil){
|
|
|
|
buf[0] = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
return snprint(buf, nbuf, "%s", s);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
static void
|
2012-01-11 15:17:54 +00:00
|
|
|
fsmkdir(Dir *d, int level, void *aux)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
char buf[1024];
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
memset(d, 0, sizeof(*d));
|
|
|
|
fsmkqid(&d->qid, level, aux);
|
|
|
|
d->mode = 0444;
|
|
|
|
d->atime = d->mtime = time0;
|
|
|
|
d->uid = estrdup(user);
|
|
|
|
d->gid = estrdup(user);
|
|
|
|
d->muid = estrdup(user);
|
2012-01-12 14:15:25 +00:00
|
|
|
if(d->qid.type & QTDIR)
|
2012-01-11 15:17:54 +00:00
|
|
|
d->mode |= DMDIR | 0111;
|
|
|
|
switch(level){
|
|
|
|
case Qheader:
|
|
|
|
d->name = fshdrname(estrdup(((Key*)aux)->key));
|
|
|
|
d->length = strlen(((Key*)aux)->val);
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
|
|
|
case Qclient:
|
2016-01-07 03:44:13 +00:00
|
|
|
snprint(buf, sizeof(buf), "%d", CLIENTID(aux));
|
2012-01-11 15:17:54 +00:00
|
|
|
d->name = estrdup(buf);
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
|
|
|
case Qctl:
|
2012-01-11 15:17:54 +00:00
|
|
|
case Qrctl:
|
|
|
|
case Qclone:
|
|
|
|
d->mode = 0666;
|
|
|
|
if(0){
|
|
|
|
case Qpost:
|
|
|
|
d->mode = 0222;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
default:
|
|
|
|
d->name = estrdup(nametab[level]);
|
|
|
|
if(level >= Qurl && level <= Qurlfrag)
|
|
|
|
d->length = urlstr(buf, sizeof(buf), (Url*)aux, level);
|
|
|
|
}
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static void
|
|
|
|
fsattach(Req *r)
|
|
|
|
{
|
|
|
|
Webfid *f;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
if(r->ifcall.aname && r->ifcall.aname[0]){
|
|
|
|
respond(r, "invalid attach specifier");
|
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
f = emalloc(sizeof(*f));
|
|
|
|
f->level = Qroot;
|
|
|
|
fsmkqid(&r->fid->qid, f->level, wfaux(f));
|
|
|
|
r->ofcall.qid = r->fid->qid;
|
|
|
|
r->fid->aux = f;
|
|
|
|
respond(r, nil);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-01-11 15:17:54 +00:00
|
|
|
fsstat(Req *r)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
Webfid *f;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
f = r->fid->aux;
|
|
|
|
fsmkdir(&r->d, f->level, wfaux(f));
|
|
|
|
respond(r, nil);
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static char*
|
|
|
|
fswalk1(Fid *fid, char *name, Qid *qid)
|
|
|
|
{
|
|
|
|
Webfid *f;
|
|
|
|
int i, j;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
if(!(fid->qid.type&QTDIR))
|
|
|
|
return "walk in non-directory";
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
f = fid->aux;
|
|
|
|
if(strcmp(name, "..") == 0){
|
|
|
|
switch(f->level){
|
|
|
|
case Qroot:
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
2012-01-11 15:17:54 +00:00
|
|
|
case Qclient:
|
|
|
|
freeclient(f->client);
|
|
|
|
f->client = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
2012-01-11 15:17:54 +00:00
|
|
|
default:
|
|
|
|
if(f->level > Qparsed)
|
|
|
|
f->level = Qparsed;
|
|
|
|
else
|
|
|
|
f->level = Qclient;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
} else {
|
|
|
|
for(i=f->level+1; i < nelem(nametab); i++){
|
|
|
|
if(nametab[i]){
|
|
|
|
if(strcmp(name, nametab[i]) == 0)
|
|
|
|
break;
|
|
|
|
if(i == Qbody && strncmp(name, "body.", 5) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(i == Qclient){
|
|
|
|
j = atoi(name);
|
|
|
|
if(j >= 0 && j < nclient){
|
|
|
|
f->client = &client[j];
|
|
|
|
incref(f->client);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(i == Qheader && f->client && f->client->qbody){
|
|
|
|
char buf[128];
|
|
|
|
Key *k;
|
|
|
|
|
|
|
|
for(k = f->client->qbody->hdr; k; k = k->next){
|
2012-05-18 18:25:50 +00:00
|
|
|
nstrcpy(buf, k->key, sizeof(buf));
|
2012-01-11 15:17:54 +00:00
|
|
|
if(!strcmp(name, fshdrname(buf)))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(k != nil){
|
|
|
|
/* need to copy as key is owned by qbody wich might go away */
|
|
|
|
f->key = addkey(0, k->key, k->val);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
if(i >= nelem(nametab))
|
|
|
|
return "directory entry not found";
|
|
|
|
f->level = i;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
fsmkqid(qid, f->level, wfaux(f));
|
|
|
|
fid->qid = *qid;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
fsclone(Fid *oldfid, Fid *newfid)
|
|
|
|
{
|
|
|
|
Webfid *f, *o;
|
|
|
|
|
|
|
|
o = oldfid->aux;
|
|
|
|
if(o == nil || o->key || o->buq)
|
|
|
|
return "bad fid";
|
|
|
|
f = emalloc(sizeof(*f));
|
|
|
|
memmove(f, o, sizeof(*f));
|
|
|
|
if(f->client)
|
|
|
|
incref(f->client);
|
|
|
|
newfid->aux = f;
|
|
|
|
return nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fsopen(Req *r)
|
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
Webfid *f;
|
|
|
|
Client *cl;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
f = r->fid->aux;
|
|
|
|
cl = f->client;
|
|
|
|
switch(f->level){
|
|
|
|
case Qclone:
|
|
|
|
if((cl = newclient()) == nil){
|
|
|
|
respond(r, "no more clients");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
f->level = Qctl;
|
|
|
|
f->client = cl;
|
|
|
|
fsmkqid(&r->fid->qid, f->level, wfaux(f));
|
|
|
|
r->ofcall.qid = r->fid->qid;
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
2012-01-11 15:17:54 +00:00
|
|
|
case Qpost:
|
|
|
|
if(cl->qbody && !cl->cbody){
|
|
|
|
Inuse:
|
|
|
|
respond(r, "client in use");
|
|
|
|
return;
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
case Qbody:
|
2012-01-11 15:17:54 +00:00
|
|
|
if(cl->obody)
|
|
|
|
goto Inuse;
|
|
|
|
if(cl->cbody){
|
|
|
|
bufree(cl->qbody);
|
|
|
|
cl->qbody = nil;
|
|
|
|
cl->cbody = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
if(cl->qbody == nil){
|
|
|
|
char *m;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
if(cl->url == nil){
|
|
|
|
respond(r, "no url set");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cl->qbody = bualloc(16*1024);
|
|
|
|
if(f->level != Qbody){
|
|
|
|
f->buq = bualloc(64*1024);
|
|
|
|
if(!lookkey(cl->hdr, "Content-Type"))
|
|
|
|
cl->hdr = addkey(cl->hdr, "Content-Type",
|
|
|
|
"application/x-www-form-urlencoded");
|
|
|
|
m = "POST";
|
|
|
|
} else
|
|
|
|
m = "GET";
|
|
|
|
if(cl->request[0])
|
|
|
|
m = cl->request;
|
2012-04-03 06:32:21 +00:00
|
|
|
|
2012-06-28 12:32:09 +00:00
|
|
|
/*
|
|
|
|
* some sites give a 403 Forbidden if we dont include
|
2012-06-28 15:56:19 +00:00
|
|
|
* a meaningless Accept header in the request.
|
2012-06-28 12:32:09 +00:00
|
|
|
*/
|
|
|
|
if(!lookkey(cl->hdr, "Accept"))
|
|
|
|
cl->hdr = addkey(cl->hdr, "Accept", "*/*");
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
if(!lookkey(cl->hdr, "Connection"))
|
|
|
|
cl->hdr = addkey(cl->hdr, "Connection", "keep-alive");
|
2012-04-03 06:32:21 +00:00
|
|
|
|
2012-03-25 04:55:29 +00:00
|
|
|
if(agent && !lookkey(cl->hdr, "User-Agent"))
|
|
|
|
cl->hdr = addkey(cl->hdr, "User-Agent", agent);
|
2012-04-03 06:32:21 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
http(m, cl->url, cl->hdr, cl->qbody, f->buq);
|
|
|
|
cl->request[0] = 0;
|
|
|
|
cl->url = nil;
|
|
|
|
cl->hdr = nil;
|
|
|
|
}
|
|
|
|
if(f->buq)
|
|
|
|
break;
|
|
|
|
cl->obody = 1;
|
|
|
|
incref(cl->qbody);
|
|
|
|
bureq(f->buq = cl->qbody, r);
|
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
respond(r, nil);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static int
|
|
|
|
rootgen(int i, Dir *d, void *)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
i += Qroot+1;
|
|
|
|
if(i < Qclient){
|
|
|
|
fsmkdir(d, i, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
i -= Qclient;
|
|
|
|
if(i < nclient){
|
|
|
|
fsmkdir(d, Qclient, &client[i]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
clientgen(int i, Dir *d, void *aux)
|
|
|
|
{
|
|
|
|
i += Qclient+1;
|
|
|
|
if(i > Qparsed){
|
|
|
|
Client *cl = aux;
|
|
|
|
Key *k;
|
|
|
|
|
|
|
|
i -= Qparsed+1;
|
|
|
|
if(cl == nil || cl->qbody == nil)
|
|
|
|
return -1;
|
|
|
|
for(k = cl->qbody->hdr; i > 0 && k; i--, k = k->next)
|
|
|
|
;
|
|
|
|
if(k == nil || i > 0)
|
|
|
|
return -1;
|
|
|
|
i = Qheader;
|
|
|
|
aux = k;
|
|
|
|
}
|
|
|
|
fsmkdir(d, i, aux);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
parsedgen(int i, Dir *d, void *aux)
|
|
|
|
{
|
|
|
|
i += Qparsed+1;
|
|
|
|
if(i > Qurlfrag)
|
|
|
|
return -1;
|
|
|
|
fsmkdir(d, i, aux);
|
|
|
|
return 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-01-11 15:17:54 +00:00
|
|
|
fsread(Req *r)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
char buf[1024];
|
|
|
|
Webfid *f;
|
|
|
|
|
|
|
|
f = r->fid->aux;
|
|
|
|
switch(f->level){
|
|
|
|
case Qroot:
|
|
|
|
dirread9p(r, rootgen, nil);
|
|
|
|
respond(r, nil);
|
|
|
|
return;
|
|
|
|
case Qclient:
|
|
|
|
dirread9p(r, clientgen, f->client);
|
|
|
|
respond(r, nil);
|
|
|
|
return;
|
|
|
|
case Qparsed:
|
|
|
|
dirread9p(r, parsedgen, clienturl(f->client));
|
|
|
|
respond(r, nil);
|
|
|
|
return;
|
|
|
|
case Qrctl:
|
2012-05-16 15:00:19 +00:00
|
|
|
snprint(buf, sizeof(buf), "useragent %s\ntimeout %d\n", agent, timeout);
|
2012-01-11 15:17:54 +00:00
|
|
|
String:
|
|
|
|
readstr(r, buf);
|
|
|
|
respond(r, nil);
|
|
|
|
return;
|
|
|
|
case Qctl:
|
2016-01-07 03:44:13 +00:00
|
|
|
snprint(buf, sizeof(buf), "%d\n", CLIENTID(f->client));
|
2012-01-11 15:17:54 +00:00
|
|
|
goto String;
|
|
|
|
case Qheader:
|
|
|
|
snprint(buf, sizeof(buf), "%s", f->key->val);
|
|
|
|
goto String;
|
|
|
|
case Qurl:
|
|
|
|
case Qurlschm:
|
|
|
|
case Qurluser:
|
|
|
|
case Qurlpass:
|
|
|
|
case Qurlhost:
|
|
|
|
case Qurlport:
|
|
|
|
case Qurlpath:
|
|
|
|
case Qurlqwry:
|
|
|
|
case Qurlfrag:
|
|
|
|
urlstr(buf, sizeof(buf), clienturl(f->client), f->level);
|
|
|
|
goto String;
|
|
|
|
case Qbody:
|
|
|
|
bureq(f->buq, r);
|
2011-03-30 12:46:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
respond(r, "not implemented");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
2013-01-11 23:16:07 +00:00
|
|
|
rootctl(Srv *fs, char *ctl, char *arg)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
Url *u;
|
|
|
|
|
|
|
|
if(debug)
|
|
|
|
fprint(2, "rootctl: %q %q\n", ctl, arg);
|
|
|
|
|
2012-03-25 04:55:29 +00:00
|
|
|
if(!strcmp(ctl, "useragent")){
|
|
|
|
free(agent);
|
|
|
|
if(arg && *arg)
|
|
|
|
agent = estrdup(arg);
|
|
|
|
else
|
|
|
|
agent = nil;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
if(!strcmp(ctl, "flushauth")){
|
|
|
|
u = nil;
|
|
|
|
if(arg && *arg)
|
|
|
|
u = saneurl(url(arg, 0));
|
|
|
|
flushauth(u, 0);
|
|
|
|
freeurl(u);
|
|
|
|
return nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-03-25 04:55:29 +00:00
|
|
|
|
2012-05-16 15:00:19 +00:00
|
|
|
if(!strcmp(ctl, "timeout")){
|
|
|
|
if(arg && *arg)
|
|
|
|
timeout = atoi(arg);
|
|
|
|
else
|
|
|
|
timeout = 0;
|
|
|
|
if(timeout < 0)
|
|
|
|
timeout = 0;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2013-01-11 23:16:07 +00:00
|
|
|
/* ppreemptive authentication only basic
|
|
|
|
* auth supported, ctl message of the form:
|
|
|
|
* preauth url realm
|
|
|
|
*/
|
|
|
|
if(!strcmp(ctl, "preauth")){
|
|
|
|
char *a[3], buf[256];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if(tokenize(arg, a, nelem(a)) != 2)
|
|
|
|
return "preauth - bad field count";
|
|
|
|
if((u = saneurl(url(a[0], 0))) == nil)
|
|
|
|
return "preauth - malformed url";
|
|
|
|
snprint(buf, sizeof(buf), "BASIC realm=\"%s\"", a[1]);
|
|
|
|
srvrelease(fs);
|
|
|
|
rc = authenticate(u, u, "GET", buf);
|
|
|
|
srvacquire(fs);
|
|
|
|
freeurl(u);
|
|
|
|
if(rc == -1)
|
|
|
|
return "preauth failed";
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
return "bad ctl message";
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
static char*
|
|
|
|
clientctl(Client *cl, char *ctl, char *arg)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
Url *u;
|
|
|
|
Key *k;
|
|
|
|
|
|
|
|
if(debug)
|
|
|
|
fprint(2, "clientctl: %q %q\n", ctl, arg);
|
|
|
|
|
|
|
|
if(!strcmp(ctl, "url")){
|
|
|
|
if((u = saneurl(url(arg, cl->baseurl))) == nil)
|
|
|
|
return "bad url";
|
|
|
|
freeurl(cl->url);
|
|
|
|
cl->url = u;
|
|
|
|
}
|
|
|
|
else if(!strcmp(ctl, "baseurl")){
|
|
|
|
if((u = url(arg, 0)) == nil)
|
|
|
|
return "bad baseurl";
|
|
|
|
freeurl(cl->baseurl);
|
|
|
|
cl->baseurl = u;
|
|
|
|
}
|
|
|
|
else if(!strcmp(ctl, "request")){
|
|
|
|
p = cl->request;
|
2012-05-18 18:25:50 +00:00
|
|
|
nstrcpy(p, arg, sizeof(cl->request));
|
2012-01-11 15:17:54 +00:00
|
|
|
for(; *p && isalpha(*p); p++)
|
|
|
|
*p = toupper(*p);
|
|
|
|
*p = 0;
|
|
|
|
}
|
|
|
|
else if(!strcmp(ctl, "headers")){
|
|
|
|
while(arg && *arg){
|
|
|
|
ctl = arg;
|
2012-07-19 21:34:37 +00:00
|
|
|
while(*ctl && strchr(whitespace, *ctl))
|
2012-01-11 15:17:54 +00:00
|
|
|
ctl++;
|
|
|
|
if(arg = strchr(ctl, '\n'))
|
|
|
|
*arg++ = 0;
|
|
|
|
if(k = parsehdr(ctl)){
|
|
|
|
k->next = cl->hdr;
|
|
|
|
cl->hdr = k;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
char buf[128], **t;
|
|
|
|
static char *tab[] = {
|
|
|
|
"User-Agent",
|
|
|
|
"Content-Type",
|
|
|
|
nil,
|
|
|
|
};
|
|
|
|
for(t = tab; *t; t++){
|
2012-05-18 18:25:50 +00:00
|
|
|
nstrcpy(buf, *t, sizeof(buf));
|
2012-01-11 15:17:54 +00:00
|
|
|
if(!strcmp(ctl, fshdrname(buf))){
|
|
|
|
cl->hdr = delkey(cl->hdr, *t);
|
|
|
|
if(arg && *arg)
|
|
|
|
cl->hdr = addkey(cl->hdr, *t, arg);
|
|
|
|
break;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
if(*t == nil)
|
|
|
|
return "bad ctl message";
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fswrite(Req *r)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
Webfid *f;
|
|
|
|
char *s, *t;
|
|
|
|
|
|
|
|
f = r->fid->aux;
|
|
|
|
switch(f->level){
|
|
|
|
case Qrctl:
|
|
|
|
case Qctl:
|
|
|
|
n = r->ofcall.count = r->ifcall.count;
|
|
|
|
s = emalloc(n+1);
|
|
|
|
memmove(s, r->ifcall.data, n);
|
|
|
|
while(n > 0 && strchr("\r\n", s[n-1]))
|
|
|
|
n--;
|
|
|
|
s[n] = 0;
|
|
|
|
t = s;
|
2012-07-19 21:34:37 +00:00
|
|
|
while(*t && strchr(whitespace, *t)==0)
|
2012-01-11 15:17:54 +00:00
|
|
|
t++;
|
2012-07-19 21:34:37 +00:00
|
|
|
while(*t && strchr(whitespace, *t))
|
2012-01-11 15:17:54 +00:00
|
|
|
*t++ = 0;
|
|
|
|
if(f->level == Qctl)
|
|
|
|
t = clientctl(f->client, s, t);
|
|
|
|
else
|
2013-01-11 23:16:07 +00:00
|
|
|
t = rootctl(r->srv, s, t);
|
2012-01-11 15:17:54 +00:00
|
|
|
free(s);
|
|
|
|
respond(r, t);
|
|
|
|
return;
|
|
|
|
case Qpost:
|
|
|
|
bureq(f->buq, r);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
respond(r, "not implemented");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fsflush(Req *r)
|
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
Webfid *f;
|
|
|
|
Req *o;
|
|
|
|
|
|
|
|
if(o = r->oldreq)
|
|
|
|
if(f = o->fid->aux)
|
|
|
|
buflushreq(f->buq, o);
|
|
|
|
respond(r, nil);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-01-11 15:17:54 +00:00
|
|
|
fsdestroyfid(Fid *fid)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2012-01-11 15:17:54 +00:00
|
|
|
Webfid *f;
|
|
|
|
|
|
|
|
if(f = fid->aux){
|
|
|
|
fid->aux = nil;
|
|
|
|
if(f->buq){
|
|
|
|
buclose(f->buq, 0);
|
|
|
|
if(f->client->qbody == f->buq){
|
|
|
|
f->client->obody = 0;
|
|
|
|
f->client->cbody = 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
bufree(f->buq);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2012-01-11 15:17:54 +00:00
|
|
|
if(f->key)
|
|
|
|
free(f->key);
|
|
|
|
freeclient(f->client);
|
|
|
|
free(f);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:45:08 +00:00
|
|
|
static void
|
|
|
|
fsstart(Srv*)
|
|
|
|
{
|
|
|
|
/* drop reference to old webfs mount */
|
|
|
|
if(mtpt != nil)
|
|
|
|
unmount(nil, mtpt);
|
|
|
|
}
|
|
|
|
|
2016-02-08 18:35:26 +00:00
|
|
|
static void
|
|
|
|
fsend(Srv*)
|
|
|
|
{
|
|
|
|
postnote(PNGROUP, getpid(), "shutdown");
|
|
|
|
exits(nil);
|
|
|
|
}
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
Srv fs =
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-06-04 15:45:08 +00:00
|
|
|
.start=fsstart,
|
2012-01-11 15:17:54 +00:00
|
|
|
.attach=fsattach,
|
|
|
|
.stat=fsstat,
|
|
|
|
.walk1=fswalk1,
|
|
|
|
.clone=fsclone,
|
|
|
|
.open=fsopen,
|
|
|
|
.read=fsread,
|
|
|
|
.write=fswrite,
|
|
|
|
.flush=fsflush,
|
|
|
|
.destroyfid=fsdestroyfid,
|
2016-02-08 18:35:26 +00:00
|
|
|
.end=fsend,
|
2012-01-11 15:17:54 +00:00
|
|
|
};
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
void
|
2012-01-11 15:17:54 +00:00
|
|
|
usage(void)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2018-01-31 18:09:11 +00:00
|
|
|
fprint(2, "usage: %s [-Dd] [-A useragent] [-T timeout] [-m mtpt] [-s service]\n", argv0);
|
2012-01-11 15:17:54 +00:00
|
|
|
exits("usage");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-01-11 15:17:54 +00:00
|
|
|
main(int argc, char *argv[])
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-06-04 15:45:08 +00:00
|
|
|
char *s;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
quotefmtinstall();
|
|
|
|
fmtinstall('U', Ufmt);
|
2016-04-15 21:54:00 +00:00
|
|
|
fmtinstall('N', Nfmt);
|
2013-11-24 20:28:48 +00:00
|
|
|
fmtinstall('E', Efmt);
|
2015-03-12 16:26:49 +00:00
|
|
|
fmtinstall('[', encodefmt);
|
2016-04-15 21:54:00 +00:00
|
|
|
fmtinstall('H', encodefmt);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
mtpt = "/mnt/web";
|
|
|
|
user = getuser();
|
|
|
|
time0 = time(0);
|
2012-05-16 15:00:19 +00:00
|
|
|
timeout = 10000;
|
2012-01-11 15:17:54 +00:00
|
|
|
|
|
|
|
ARGBEGIN {
|
|
|
|
case 'D':
|
|
|
|
chatty9p++;
|
|
|
|
break;
|
2012-05-16 15:00:19 +00:00
|
|
|
case 'A':
|
|
|
|
agent = EARGF(usage());
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
timeout = atoi(EARGF(usage()));
|
|
|
|
if(timeout < 0)
|
|
|
|
timeout = 0;
|
|
|
|
break;
|
2012-01-11 15:17:54 +00:00
|
|
|
case 'm':
|
|
|
|
mtpt = EARGF(usage());
|
|
|
|
break;
|
|
|
|
case 's':
|
2014-06-04 15:45:08 +00:00
|
|
|
service = EARGF(usage());
|
2012-01-11 15:17:54 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
debug++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
} ARGEND;
|
|
|
|
|
|
|
|
rfork(RFNOTEG);
|
|
|
|
|
2012-05-16 15:00:19 +00:00
|
|
|
if(agent == nil)
|
2014-05-09 16:22:51 +00:00
|
|
|
agent = "Mozilla/5.0 (compatible; hjdicks)";
|
2012-05-16 15:00:19 +00:00
|
|
|
agent = estrdup(agent);
|
|
|
|
|
2012-01-11 15:17:54 +00:00
|
|
|
if(s = getenv("httpproxy")){
|
|
|
|
proxy = saneurl(url(s, 0));
|
2015-02-23 06:27:19 +00:00
|
|
|
if(proxy == nil || strcmp(proxy->scheme, "http") && strcmp(proxy->scheme, "https"))
|
|
|
|
sysfatal("invalid httpproxy url: %s", s);
|
2012-01-11 15:17:54 +00:00
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
2014-06-04 15:45:08 +00:00
|
|
|
postmountsrv(&fs, service, mtpt, MREPL);
|
2016-02-08 18:35:26 +00:00
|
|
|
exits(nil);
|
2012-01-11 15:17:54 +00:00
|
|
|
}
|