changelog shortlog tags branches changeset files file revisions raw help

Mercurial > hg > plan9front / annotate sys/src/cmd/webfs/fs.c

changeset 4343: 6d999c39a9f0
parent: e2715ad95a8f
child: e16a172bcae6
author: cinap_lenrek@felloff.net
date: Sat, 14 Mar 2015 01:09:37 +0100
permissions: -rw-r--r--
description: webfs: do not send credentials in automatic referer url
taruti@0 1
 #include <u.h>
taruti@0 2
 #include <libc.h>
cinap_lenrek@1294 3
 #include <ctype.h>
cinap_lenrek@1294 4
 #include <fcall.h>
taruti@0 5
 #include <thread.h>
taruti@0 6
 #include <9p.h>
cinap_lenrek@1294 7
 
taruti@0 8
 #include "dat.h"
taruti@0 9
 #include "fns.h"
taruti@0 10
 
cinap_lenrek@1294 11
 typedef struct Webfid Webfid;
cinap_lenrek@1294 12
 typedef struct Client Client;
taruti@0 13
 
cinap_lenrek@1294 14
 struct Client
taruti@0 15
 {
cinap_lenrek@1294 16
 	Ref;
cinap_lenrek@1294 17
 
cinap_lenrek@1294 18
 	char	request[16];
cinap_lenrek@1294 19
 	Url	*baseurl;
cinap_lenrek@1294 20
 	Url	*url;
cinap_lenrek@1294 21
 	Key	*hdr;
cinap_lenrek@1294 22
 
cinap_lenrek@1294 23
 	int	obody;	/* body opend */
cinap_lenrek@1294 24
 	int	cbody;	/* body closed */
cinap_lenrek@1294 25
 	Buq	*qbody;
cinap_lenrek@1294 26
 };
cinap_lenrek@1294 27
 
cinap_lenrek@1294 28
 struct Webfid
cinap_lenrek@1294 29
 {
cinap_lenrek@1294 30
 	int	level;
cinap_lenrek@1294 31
 
cinap_lenrek@1294 32
 	Client	*client;
cinap_lenrek@1294 33
 	Key	*key;	/* copy for Qheader */
cinap_lenrek@1294 34
 	Buq	*buq;	/* reference for Qbody, Qpost */
taruti@0 35
 };
taruti@0 36
 
cinap_lenrek@1294 37
 enum {
cinap_lenrek@1294 38
 	Qroot,
cinap_lenrek@1294 39
 		Qrctl,
cinap_lenrek@1294 40
 		Qclone,
cinap_lenrek@1294 41
 		Qclient,
cinap_lenrek@1294 42
 			Qctl,
cinap_lenrek@1294 43
 			Qbody,
cinap_lenrek@1294 44
 			Qpost,
cinap_lenrek@1294 45
 			Qparsed,
cinap_lenrek@1294 46
 				Qurl,
cinap_lenrek@1294 47
 				Qurlschm,
cinap_lenrek@1294 48
 				Qurluser,
cinap_lenrek@1294 49
 				Qurlpass,
cinap_lenrek@1294 50
 				Qurlhost,
cinap_lenrek@1294 51
 				Qurlport,
cinap_lenrek@1294 52
 				Qurlpath,
cinap_lenrek@1294 53
 				Qurlqwry,
cinap_lenrek@1294 54
 				Qurlfrag,
cinap_lenrek@1294 55
 			Qheader,
cinap_lenrek@1294 56
 };
taruti@0 57
 
cinap_lenrek@1294 58
 static char *nametab[] = {
cinap_lenrek@1294 59
 	"/",
cinap_lenrek@1294 60
 		"ctl",
cinap_lenrek@1294 61
 		"clone",
cinap_lenrek@1294 62
 		nil,
cinap_lenrek@1294 63
 			"ctl",
cinap_lenrek@1294 64
 			"body",
cinap_lenrek@1294 65
 			"postbody",
cinap_lenrek@1294 66
 			"parsed",
cinap_lenrek@1294 67
 				"url",
cinap_lenrek@1294 68
 				"scheme",
cinap_lenrek@1294 69
 				"user",
cinap_lenrek@1294 70
 				"passwd",
cinap_lenrek@1294 71
 				"host",
cinap_lenrek@1294 72
 				"port",
cinap_lenrek@1294 73
 				"path",
cinap_lenrek@1294 74
 				"query",
cinap_lenrek@1294 75
 				"fragment",
cinap_lenrek@1294 76
 			nil,
taruti@0 77
 };
taruti@0 78
 
cinap_lenrek@3667 79
 static char *mtpt;
cinap_lenrek@3667 80
 static char *service;
cinap_lenrek@1294 81
 static long time0;
cinap_lenrek@1294 82
 static char *user;
cinap_lenrek@1479 83
 static char *agent;
cinap_lenrek@1294 84
 static Client client[64];
cinap_lenrek@1294 85
 static int nclient;
cinap_lenrek@1294 86
 
cinap_lenrek@1294 87
 #define	CLIENTID(c)	(((Client*)(c)) - client)
cinap_lenrek@1294 88
 
cinap_lenrek@1294 89
 Client*
cinap_lenrek@1294 90
 newclient(void)
cinap_lenrek@1294 91
 {
cinap_lenrek@1294 92
 	Client *cl;
cinap_lenrek@1294 93
 	int i;
cinap_lenrek@1294 94
 
cinap_lenrek@1294 95
 	for(i = 0; i < nclient; i++)
cinap_lenrek@1294 96
 		if(client[i].ref == 0)
cinap_lenrek@1294 97
 			break;
cinap_lenrek@1294 98
 	if(i >= nelem(client))
cinap_lenrek@1294 99
 		return nil;
cinap_lenrek@1294 100
 	if(i == nclient)
cinap_lenrek@1294 101
 		nclient++;
cinap_lenrek@1294 102
 	cl = &client[i];
cinap_lenrek@1294 103
 	incref(cl);
cinap_lenrek@1294 104
 
cinap_lenrek@1294 105
 	cl->request[0] = 0;
cinap_lenrek@1294 106
 	cl->baseurl = nil;
cinap_lenrek@1294 107
 	cl->url = nil;
cinap_lenrek@1294 108
 	cl->hdr = nil;
cinap_lenrek@1294 109
 	cl->qbody = nil;
cinap_lenrek@1294 110
 	
cinap_lenrek@1294 111
 	return cl;
cinap_lenrek@1294 112
 }
cinap_lenrek@1294 113
 
cinap_lenrek@1294 114
 void
cinap_lenrek@1294 115
 freeclient(Client *cl)
taruti@0 116
 {
cinap_lenrek@1294 117
 	Key *k;
cinap_lenrek@1294 118
 
cinap_lenrek@1294 119
 	if(cl == nil || decref(cl))
cinap_lenrek@1294 120
 		return;
cinap_lenrek@1294 121
 
cinap_lenrek@1294 122
 	buclose(cl->qbody, 0);
cinap_lenrek@1294 123
 	bufree(cl->qbody);
cinap_lenrek@1294 124
 
cinap_lenrek@1294 125
 	while(k = cl->hdr){
cinap_lenrek@1294 126
 		cl->hdr = k->next;
cinap_lenrek@1294 127
 		free(k);
cinap_lenrek@1294 128
 	}
cinap_lenrek@1294 129
 
cinap_lenrek@1294 130
 	freeurl(cl->url);
cinap_lenrek@1294 131
 	freeurl(cl->baseurl);
cinap_lenrek@1294 132
 
cinap_lenrek@1294 133
 	memset(cl, 0, sizeof(*cl));
cinap_lenrek@1294 134
 }
taruti@0 135
 
cinap_lenrek@1294 136
 static Url*
cinap_lenrek@1294 137
 clienturl(Client *cl)
cinap_lenrek@1294 138
 {
cinap_lenrek@1294 139
 	static Url nullurl;
cinap_lenrek@1294 140
 
cinap_lenrek@1294 141
 	if(cl->qbody && cl->qbody->url)
cinap_lenrek@1294 142
 		return cl->qbody->url;
cinap_lenrek@1294 143
 	if(cl->url)
cinap_lenrek@1294 144
 		return cl->url;
cinap_lenrek@1294 145
 	return &nullurl;
cinap_lenrek@1294 146
 }
cinap_lenrek@1294 147
 
cinap_lenrek@1294 148
 static void*
cinap_lenrek@1294 149
 wfaux(Webfid *f)
cinap_lenrek@1294 150
 {
cinap_lenrek@1294 151
 	if(f->level < Qclient)
cinap_lenrek@1294 152
 		return nil;
cinap_lenrek@1294 153
 	else if(f->level < Qurl)
cinap_lenrek@1294 154
 		return f->client;
cinap_lenrek@1294 155
 	else if(f->level < Qheader)
cinap_lenrek@1294 156
 		return clienturl(f->client);
cinap_lenrek@1294 157
 	else
cinap_lenrek@1294 158
 		return f->key;
cinap_lenrek@1294 159
 }
taruti@0 160
 
taruti@0 161
 static void
cinap_lenrek@1294 162
 fsmkqid(Qid *q, int level, void *aux)
cinap_lenrek@1294 163
 {
cinap_lenrek@1294 164
 	q->type = 0;
cinap_lenrek@1294 165
 	q->vers = 0;
cinap_lenrek@1294 166
 	switch(level){
cinap_lenrek@1294 167
 	case Qroot:
cinap_lenrek@1294 168
 	case Qparsed:
cinap_lenrek@1294 169
 	case Qclient:
cinap_lenrek@1294 170
 		q->type = QTDIR;
cinap_lenrek@1294 171
 	default:
cinap_lenrek@3327 172
 		q->path = (level<<24) | (((uintptr)aux ^ time0) & 0x00ffffff);
cinap_lenrek@1294 173
 	}
cinap_lenrek@1294 174
 }
cinap_lenrek@1294 175
 
cinap_lenrek@1294 176
 static char*
cinap_lenrek@1294 177
 fshdrname(char *s)
taruti@0 178
 {
cinap_lenrek@1294 179
 	char *k, *w;
cinap_lenrek@1294 180
 
cinap_lenrek@1294 181
 	for(k=w=s; *k; k++)
cinap_lenrek@1294 182
 		if(isalnum(*k))
cinap_lenrek@1294 183
 			*w++ = tolower(*k);
cinap_lenrek@1294 184
 	*w = 0;
cinap_lenrek@1294 185
 	return s;
cinap_lenrek@1294 186
 }
cinap_lenrek@1294 187
 
cinap_lenrek@1294 188
 static int
cinap_lenrek@1294 189
 urlstr(char *buf, int nbuf, Url *u, int level)
cinap_lenrek@1294 190
 {
cinap_lenrek@1294 191
 	char *s;
cinap_lenrek@1294 192
 
cinap_lenrek@1294 193
 	if(level == Qurl)
cinap_lenrek@1294 194
 		return snprint(buf, nbuf, "%U", u);
cinap_lenrek@1294 195
 	if(level == Qurlpath)
cinap_lenrek@1294 196
 		return snprint(buf, nbuf, "%s", Upath(u));
cinap_lenrek@1294 197
 	if((s = (&u->scheme)[level - Qurlschm]) == nil){
cinap_lenrek@1294 198
 		buf[0] = 0;
cinap_lenrek@1294 199
 		return 0;
cinap_lenrek@1294 200
 	}
cinap_lenrek@1294 201
 	return snprint(buf, nbuf, "%s", s);
cinap_lenrek@1294 202
 }
cinap_lenrek@1294 203
 
cinap_lenrek@1294 204
 
cinap_lenrek@1294 205
 static void
cinap_lenrek@1294 206
 fsmkdir(Dir *d, int level, void *aux)
cinap_lenrek@1294 207
 {
cinap_lenrek@1294 208
 	char buf[1024];
taruti@0 209
 
taruti@0 210
 	memset(d, 0, sizeof(*d));
cinap_lenrek@1294 211
 	fsmkqid(&d->qid, level, aux);
cinap_lenrek@1294 212
 	d->mode = 0444;
taruti@0 213
 	d->atime = d->mtime = time0;
cinap_lenrek@1294 214
 	d->uid = estrdup(user);
cinap_lenrek@1294 215
 	d->gid = estrdup(user);
cinap_lenrek@1294 216
 	d->muid = estrdup(user);
cinap_lenrek@1296 217
 	if(d->qid.type & QTDIR)
cinap_lenrek@1294 218
 		d->mode |= DMDIR | 0111;
cinap_lenrek@1294 219
 	switch(level){
cinap_lenrek@1294 220
 	case Qheader:
cinap_lenrek@1294 221
 		d->name = fshdrname(estrdup(((Key*)aux)->key));
cinap_lenrek@1294 222
 		d->length = strlen(((Key*)aux)->val);
cinap_lenrek@1294 223
 		break;
cinap_lenrek@1294 224
 	case Qclient:
cinap_lenrek@1294 225
 		snprint(buf, sizeof(buf), "%ld", CLIENTID(aux));
taruti@0 226
 		d->name = estrdup(buf);
cinap_lenrek@1294 227
 		break;
cinap_lenrek@1294 228
 	case Qctl:
cinap_lenrek@1294 229
 	case Qrctl:
cinap_lenrek@1294 230
 	case Qclone:
cinap_lenrek@1294 231
 		d->mode = 0666;
cinap_lenrek@1294 232
 		if(0){
cinap_lenrek@1294 233
 	case Qpost:
cinap_lenrek@1294 234
 		d->mode = 0222;
cinap_lenrek@1294 235
 		}
cinap_lenrek@1294 236
 	default:
cinap_lenrek@1294 237
 		d->name = estrdup(nametab[level]);
cinap_lenrek@1294 238
 		if(level >= Qurl && level <= Qurlfrag)
cinap_lenrek@1294 239
 			d->length = urlstr(buf, sizeof(buf), (Url*)aux, level);
taruti@0 240
 	}
cinap_lenrek@1294 241
 }
cinap_lenrek@1294 242
 
cinap_lenrek@1294 243
 static void
cinap_lenrek@1294 244
 fsattach(Req *r)
cinap_lenrek@1294 245
 {
cinap_lenrek@1294 246
 	Webfid *f;
cinap_lenrek@1294 247
 
cinap_lenrek@1294 248
 	if(r->ifcall.aname && r->ifcall.aname[0]){
cinap_lenrek@1294 249
 		respond(r, "invalid attach specifier");
cinap_lenrek@1294 250
 		return;
taruti@0 251
 	}
cinap_lenrek@1294 252
 	f = emalloc(sizeof(*f));
cinap_lenrek@1294 253
 	f->level = Qroot;
cinap_lenrek@1294 254
 	fsmkqid(&r->fid->qid, f->level, wfaux(f));
cinap_lenrek@1294 255
 	r->ofcall.qid = r->fid->qid;
cinap_lenrek@1294 256
 	r->fid->aux = f;
cinap_lenrek@1294 257
 	respond(r, nil);
taruti@0 258
 }
taruti@0 259
 
taruti@0 260
 static void
taruti@0 261
 fsstat(Req *r)
taruti@0 262
 {
cinap_lenrek@1294 263
 	Webfid *f;
cinap_lenrek@1294 264
 
cinap_lenrek@1294 265
 	f = r->fid->aux;
cinap_lenrek@1294 266
 	fsmkdir(&r->d, f->level, wfaux(f));
cinap_lenrek@1294 267
 	respond(r, nil);
cinap_lenrek@1294 268
 }
cinap_lenrek@1294 269
 
cinap_lenrek@1294 270
 static char*
cinap_lenrek@1294 271
 fswalk1(Fid *fid, char *name, Qid *qid)
cinap_lenrek@1294 272
 {
cinap_lenrek@1294 273
 	Webfid *f;
cinap_lenrek@1294 274
 	int i, j;
cinap_lenrek@1294 275
 
cinap_lenrek@1294 276
 	if(!(fid->qid.type&QTDIR))
cinap_lenrek@1294 277
 		return "walk in non-directory";
cinap_lenrek@1294 278
 
cinap_lenrek@1294 279
 	f = fid->aux;
cinap_lenrek@1294 280
 	if(strcmp(name, "..") == 0){
cinap_lenrek@1294 281
 		switch(f->level){
cinap_lenrek@1294 282
 		case Qroot:
cinap_lenrek@1294 283
 			break;
cinap_lenrek@1294 284
 		case Qclient:
cinap_lenrek@1294 285
 			freeclient(f->client);
cinap_lenrek@1294 286
 			f->client = nil;
cinap_lenrek@1294 287
 			break;
cinap_lenrek@1294 288
 		default:
cinap_lenrek@1294 289
 			if(f->level > Qparsed)
cinap_lenrek@1294 290
 				f->level = Qparsed;
cinap_lenrek@1294 291
 			else
cinap_lenrek@1294 292
 				f->level = Qclient;
cinap_lenrek@1294 293
 		}
cinap_lenrek@1294 294
 	} else {
cinap_lenrek@1294 295
 		for(i=f->level+1; i < nelem(nametab); i++){
cinap_lenrek@1294 296
 			if(nametab[i]){
cinap_lenrek@1294 297
 				if(strcmp(name, nametab[i]) == 0)
cinap_lenrek@1294 298
 					break;
cinap_lenrek@1294 299
 				if(i == Qbody && strncmp(name, "body.", 5) == 0)
cinap_lenrek@1294 300
 					break;
cinap_lenrek@1294 301
 			}
cinap_lenrek@1294 302
 			if(i == Qclient){
cinap_lenrek@1294 303
 				j = atoi(name);
cinap_lenrek@1294 304
 				if(j >= 0 && j < nclient){
cinap_lenrek@1294 305
 					f->client = &client[j];
cinap_lenrek@1294 306
 					incref(f->client);
cinap_lenrek@1294 307
 					break;
cinap_lenrek@1294 308
 				}
cinap_lenrek@1294 309
 			}
cinap_lenrek@1294 310
 			if(i == Qheader && f->client && f->client->qbody){
cinap_lenrek@1294 311
 				char buf[128];
cinap_lenrek@1294 312
 				Key *k;
cinap_lenrek@1294 313
 
cinap_lenrek@1294 314
 				for(k = f->client->qbody->hdr; k; k = k->next){
cinap_lenrek@1594 315
 					nstrcpy(buf, k->key, sizeof(buf));
cinap_lenrek@1294 316
 					if(!strcmp(name, fshdrname(buf)))
cinap_lenrek@1294 317
 						break;
cinap_lenrek@1294 318
 				}
cinap_lenrek@1294 319
 				if(k != nil){
cinap_lenrek@1294 320
 					/* need to copy as key is owned by qbody wich might go away */
cinap_lenrek@1294 321
 					f->key = addkey(0, k->key, k->val);
cinap_lenrek@1294 322
 					break;
cinap_lenrek@1294 323
 				}
cinap_lenrek@1294 324
 			}
cinap_lenrek@1294 325
 		}
cinap_lenrek@1294 326
 		if(i >= nelem(nametab))
cinap_lenrek@1294 327
 			return "directory entry not found";
cinap_lenrek@1294 328
 		f->level = i;
cinap_lenrek@1294 329
 	}
cinap_lenrek@1294 330
 	fsmkqid(qid, f->level, wfaux(f));
cinap_lenrek@1294 331
 	fid->qid = *qid;
cinap_lenrek@1294 332
 	return nil;
cinap_lenrek@1294 333
 }
cinap_lenrek@1294 334
 
cinap_lenrek@1294 335
 static char*
cinap_lenrek@1294 336
 fsclone(Fid *oldfid, Fid *newfid)
cinap_lenrek@1294 337
 {
cinap_lenrek@1294 338
 	Webfid *f, *o;
cinap_lenrek@1294 339
 
cinap_lenrek@1294 340
 	o = oldfid->aux;
cinap_lenrek@1294 341
 	if(o == nil || o->key || o->buq)
cinap_lenrek@1294 342
 		return "bad fid";
cinap_lenrek@1294 343
 	f = emalloc(sizeof(*f));
cinap_lenrek@1294 344
 	memmove(f, o, sizeof(*f));
cinap_lenrek@1294 345
 	if(f->client)
cinap_lenrek@1294 346
 		incref(f->client);
cinap_lenrek@1294 347
 	newfid->aux = f;
cinap_lenrek@1294 348
 	return nil;
cinap_lenrek@1294 349
 }
cinap_lenrek@1294 350
 
cinap_lenrek@1294 351
 static void
cinap_lenrek@1294 352
 fsopen(Req *r)
cinap_lenrek@1294 353
 {
cinap_lenrek@1294 354
 	Webfid *f;
cinap_lenrek@1294 355
 	Client *cl;
cinap_lenrek@1294 356
 
cinap_lenrek@1294 357
 	f = r->fid->aux;
cinap_lenrek@1294 358
 	cl = f->client;
cinap_lenrek@1294 359
 	switch(f->level){
cinap_lenrek@1294 360
 	case Qclone:
cinap_lenrek@1294 361
 		if((cl = newclient()) == nil){
cinap_lenrek@1294 362
 			respond(r, "no more clients");
cinap_lenrek@1294 363
 			return;
cinap_lenrek@1294 364
 		}
cinap_lenrek@1294 365
 		f->level = Qctl;
cinap_lenrek@1294 366
 		f->client = cl;
cinap_lenrek@1294 367
 		fsmkqid(&r->fid->qid, f->level, wfaux(f));
cinap_lenrek@1294 368
 		r->ofcall.qid = r->fid->qid;
cinap_lenrek@1294 369
 		break;
cinap_lenrek@1294 370
 	case Qpost:
cinap_lenrek@1294 371
 		if(cl->qbody && !cl->cbody){
cinap_lenrek@1294 372
 		Inuse:
cinap_lenrek@1294 373
 			respond(r, "client in use");
cinap_lenrek@1294 374
 			return;
cinap_lenrek@1294 375
 		}
cinap_lenrek@1294 376
 	case Qbody:
cinap_lenrek@1294 377
 		if(cl->obody)
cinap_lenrek@1294 378
 			goto Inuse;
cinap_lenrek@1294 379
 		if(cl->cbody){
cinap_lenrek@1294 380
 			bufree(cl->qbody);
cinap_lenrek@1294 381
 			cl->qbody = nil;
cinap_lenrek@1294 382
 			cl->cbody = 0;
cinap_lenrek@1294 383
 		}
cinap_lenrek@1294 384
 		if(cl->qbody == nil){
cinap_lenrek@1294 385
 			char *m;
cinap_lenrek@1294 386
 
cinap_lenrek@1294 387
 			if(cl->url == nil){
cinap_lenrek@1294 388
 				respond(r, "no url set");
cinap_lenrek@1294 389
 				return;
cinap_lenrek@1294 390
 			}
cinap_lenrek@1294 391
 			cl->qbody = bualloc(16*1024);
cinap_lenrek@1294 392
 			if(f->level != Qbody){
cinap_lenrek@1294 393
 				f->buq = bualloc(64*1024);
cinap_lenrek@1294 394
 				if(!lookkey(cl->hdr, "Content-Type"))
cinap_lenrek@1294 395
 					cl->hdr = addkey(cl->hdr, "Content-Type", 
cinap_lenrek@1294 396
 						"application/x-www-form-urlencoded");
cinap_lenrek@1294 397
 				m = "POST";
cinap_lenrek@1294 398
 			} else
cinap_lenrek@1294 399
 				m = "GET";
cinap_lenrek@1294 400
 			if(cl->request[0])
cinap_lenrek@1294 401
 				m = cl->request;
cinap_lenrek@1495 402
 
cinap_lenrek@1677 403
 			/*
cinap_lenrek@1677 404
 			 * some sites give a 403 Forbidden if we dont include
cinap_lenrek@1678 405
 			 * a meaningless Accept header in the request.
cinap_lenrek@1677 406
 			 */
cinap_lenrek@1677 407
 			if(!lookkey(cl->hdr, "Accept"))
cinap_lenrek@1677 408
 				cl->hdr = addkey(cl->hdr, "Accept", "*/*");
cinap_lenrek@1677 409
 
cinap_lenrek@1495 410
 			if(!lookkey(cl->hdr, "Referer")){
cinap_lenrek@1495 411
 				char *r;
cinap_lenrek@1495 412
 				Url *u;
cinap_lenrek@1495 413
 
cinap_lenrek@1495 414
 				/*
cinap_lenrek@1495 415
 				 * Referer header is often required on broken
cinap_lenrek@1495 416
 				 * websites even if the spec makes them optional,
cinap_lenrek@1495 417
 				 * so we make one up.
cinap_lenrek@1495 418
 				 */
cinap_lenrek@1495 419
 				if(u = url("/", cl->url)){
cinap_lenrek@3119 420
 					if(r = u->host){
cinap_lenrek@3119 421
 						u->host = smprint("%H", r);
cinap_lenrek@3119 422
 						free(r);
cinap_lenrek@3119 423
 					}
cinap_lenrek@4343 424
 
cinap_lenrek@4343 425
 					/* do not send credentials */
cinap_lenrek@4343 426
 					free(u->user); u->user = nil;
cinap_lenrek@4343 427
 					free(u->pass); u->pass = nil;
cinap_lenrek@4343 428
 
cinap_lenrek@1495 429
 					if(r = smprint("%U", u)){
cinap_lenrek@1495 430
 						cl->hdr = addkey(cl->hdr, "Referer", r);
cinap_lenrek@1495 431
 						free(r);
cinap_lenrek@1495 432
 					}
cinap_lenrek@1495 433
 					freeurl(u);
cinap_lenrek@1495 434
 				}
cinap_lenrek@1495 435
 			}
cinap_lenrek@1495 436
 
cinap_lenrek@1294 437
 			if(!lookkey(cl->hdr, "Connection"))
cinap_lenrek@1294 438
 				cl->hdr = addkey(cl->hdr, "Connection", "keep-alive");
cinap_lenrek@1495 439
 
cinap_lenrek@1479 440
 			if(agent && !lookkey(cl->hdr, "User-Agent"))
cinap_lenrek@1479 441
 				cl->hdr = addkey(cl->hdr, "User-Agent", agent);
cinap_lenrek@1495 442
 
cinap_lenrek@1294 443
 			http(m, cl->url, cl->hdr, cl->qbody, f->buq);
cinap_lenrek@1294 444
 			cl->request[0] = 0;
cinap_lenrek@1294 445
 			cl->url = nil;
cinap_lenrek@1294 446
 			cl->hdr = nil;
cinap_lenrek@1294 447
 		}
cinap_lenrek@1294 448
 		if(f->buq)
cinap_lenrek@1294 449
 			break;
cinap_lenrek@1294 450
 		cl->obody = 1;
cinap_lenrek@1294 451
 		incref(cl->qbody);
cinap_lenrek@1294 452
 		bureq(f->buq = cl->qbody, r);
cinap_lenrek@1294 453
 		return;
cinap_lenrek@1294 454
 	}
taruti@0 455
 	respond(r, nil);
taruti@0 456
 }
taruti@0 457
 
taruti@0 458
 static int
cinap_lenrek@1294 459
 rootgen(int i, Dir *d, void *)
taruti@0 460
 {
taruti@0 461
 	i += Qroot+1;
taruti@0 462
 	if(i < Qclient){
cinap_lenrek@1294 463
 		fsmkdir(d, i, 0);
taruti@0 464
 		return 0;
taruti@0 465
 	}
taruti@0 466
 	i -= Qclient;
taruti@0 467
 	if(i < nclient){
cinap_lenrek@1294 468
 		fsmkdir(d, Qclient, &client[i]);
taruti@0 469
 		return 0;
taruti@0 470
 	}
taruti@0 471
 	return -1;
taruti@0 472
 }
taruti@0 473
 
taruti@0 474
 static int
taruti@0 475
 clientgen(int i, Dir *d, void *aux)
taruti@0 476
 {
cinap_lenrek@1294 477
 	i += Qclient+1;
cinap_lenrek@1294 478
 	if(i > Qparsed){
cinap_lenrek@1294 479
 		Client *cl = aux;
cinap_lenrek@1294 480
 		Key *k;
taruti@0 481
 
cinap_lenrek@1294 482
 		i -= Qparsed+1;
cinap_lenrek@1294 483
 		if(cl == nil || cl->qbody == nil)
cinap_lenrek@1294 484
 			return -1;
cinap_lenrek@1294 485
 		for(k = cl->qbody->hdr; i > 0 && k; i--, k = k->next)
cinap_lenrek@1294 486
 			;
cinap_lenrek@1294 487
 		if(k == nil || i > 0)
cinap_lenrek@1294 488
 			return -1;
cinap_lenrek@1294 489
 		i = Qheader;
cinap_lenrek@1294 490
 		aux = k;
taruti@0 491
 	}
cinap_lenrek@1294 492
 	fsmkdir(d, i, aux);
cinap_lenrek@1294 493
 	return 0;
taruti@0 494
 }
taruti@0 495
 
taruti@0 496
 static int
taruti@0 497
 parsedgen(int i, Dir *d, void *aux)
taruti@0 498
 {
taruti@0 499
 	i += Qparsed+1;
cinap_lenrek@1294 500
 	if(i > Qurlfrag)
cinap_lenrek@1294 501
 		return -1;
cinap_lenrek@1294 502
 	fsmkdir(d, i, aux);
cinap_lenrek@1294 503
 	return 0;
taruti@0 504
 }
taruti@0 505
 
taruti@0 506
 static void
taruti@0 507
 fsread(Req *r)
taruti@0 508
 {
cinap_lenrek@1294 509
 	char buf[1024];
cinap_lenrek@1294 510
 	Webfid *f;
taruti@0 511
 
cinap_lenrek@1294 512
 	f = r->fid->aux;
cinap_lenrek@1294 513
 	switch(f->level){
taruti@0 514
 	case Qroot:
taruti@0 515
 		dirread9p(r, rootgen, nil);
taruti@0 516
 		respond(r, nil);
cinap_lenrek@1294 517
 		return;
taruti@0 518
 	case Qclient:
cinap_lenrek@1294 519
 		dirread9p(r, clientgen, f->client);
cinap_lenrek@1294 520
 		respond(r, nil);
cinap_lenrek@1294 521
 		return;
cinap_lenrek@1294 522
 	case Qparsed:
cinap_lenrek@1294 523
 		dirread9p(r, parsedgen, clienturl(f->client));
taruti@0 524
 		respond(r, nil);
cinap_lenrek@1294 525
 		return;
cinap_lenrek@1294 526
 	case Qrctl:
cinap_lenrek@1590 527
 		snprint(buf, sizeof(buf), "useragent %s\ntimeout %d\n", agent, timeout);
cinap_lenrek@1294 528
 	String:
cinap_lenrek@1294 529
 		readstr(r, buf);
cinap_lenrek@1294 530
 		respond(r, nil);
cinap_lenrek@1294 531
 		return;
taruti@0 532
 	case Qctl:
cinap_lenrek@1294 533
 		snprint(buf, sizeof(buf), "%ld\n", CLIENTID(f->client));
cinap_lenrek@1294 534
 		goto String;
cinap_lenrek@1294 535
 	case Qheader:
cinap_lenrek@1294 536
 		snprint(buf, sizeof(buf), "%s", f->key->val);
cinap_lenrek@1294 537
 		goto String;
cinap_lenrek@1294 538
 	case Qurl:
cinap_lenrek@1294 539
 	case Qurlschm:
cinap_lenrek@1294 540
 	case Qurluser:
cinap_lenrek@1294 541
 	case Qurlpass:
cinap_lenrek@1294 542
 	case Qurlhost:
cinap_lenrek@1294 543
 	case Qurlport:
cinap_lenrek@1294 544
 	case Qurlpath:
cinap_lenrek@1294 545
 	case Qurlqwry:
cinap_lenrek@1294 546
 	case Qurlfrag:
cinap_lenrek@1294 547
 		urlstr(buf, sizeof(buf), clienturl(f->client), f->level);
cinap_lenrek@1294 548
 		goto String;
taruti@0 549
 	case Qbody:
cinap_lenrek@1294 550
 		bureq(f->buq, r);
cinap_lenrek@1294 551
 		return;
cinap_lenrek@1294 552
 	}
cinap_lenrek@1294 553
 	respond(r, "not implemented");
cinap_lenrek@1294 554
 }
cinap_lenrek@1294 555
 
cinap_lenrek@1294 556
 static char*
cinap_lenrek@2276 557
 rootctl(Srv *fs, char *ctl, char *arg)
cinap_lenrek@1294 558
 {
cinap_lenrek@1294 559
 	Url *u;
cinap_lenrek@1294 560
 
cinap_lenrek@1294 561
 	if(debug)
cinap_lenrek@1294 562
 		fprint(2, "rootctl: %q %q\n", ctl, arg);
taruti@0 563
 
cinap_lenrek@1479 564
 	if(!strcmp(ctl, "useragent")){
cinap_lenrek@1479 565
 		free(agent);
cinap_lenrek@1479 566
 		if(arg && *arg)
cinap_lenrek@1479 567
 			agent = estrdup(arg);
cinap_lenrek@1479 568
 		else
cinap_lenrek@1479 569
 			agent = nil;
cinap_lenrek@1479 570
 		return nil;
cinap_lenrek@1479 571
 	}
cinap_lenrek@1479 572
 
cinap_lenrek@1294 573
 	if(!strcmp(ctl, "flushauth")){
cinap_lenrek@1294 574
 		u = nil;
cinap_lenrek@1294 575
 		if(arg && *arg)
cinap_lenrek@1294 576
 			u = saneurl(url(arg, 0));
cinap_lenrek@1294 577
 		flushauth(u, 0);
cinap_lenrek@1294 578
 		freeurl(u);
cinap_lenrek@1294 579
 		return nil;
cinap_lenrek@1294 580
 	}
cinap_lenrek@1479 581
 
cinap_lenrek@1590 582
 	if(!strcmp(ctl, "timeout")){
cinap_lenrek@1590 583
 		if(arg && *arg)
cinap_lenrek@1590 584
 			timeout = atoi(arg);
cinap_lenrek@1590 585
 		else
cinap_lenrek@1590 586
 			timeout = 0;
cinap_lenrek@1590 587
 		if(timeout < 0)
cinap_lenrek@1590 588
 			timeout = 0;
cinap_lenrek@1590 589
 		return nil;
cinap_lenrek@1590 590
 	}
cinap_lenrek@1590 591
 
cinap_lenrek@2276 592
 	/* ppreemptive authentication only basic
cinap_lenrek@2276 593
 	 * auth supported, ctl message of the form:
cinap_lenrek@2276 594
 	 *    preauth url realm
cinap_lenrek@2276 595
 	 */
cinap_lenrek@2276 596
 	if(!strcmp(ctl, "preauth")){
cinap_lenrek@2276 597
 		char *a[3], buf[256];
cinap_lenrek@2276 598
 		int rc;
cinap_lenrek@2276 599
 
cinap_lenrek@2276 600
 		if(tokenize(arg, a, nelem(a)) != 2)
cinap_lenrek@2276 601
 			return "preauth - bad field count";
cinap_lenrek@2276 602
 		if((u = saneurl(url(a[0], 0))) == nil)
cinap_lenrek@2276 603
 			return "preauth - malformed url";
cinap_lenrek@2276 604
 		snprint(buf, sizeof(buf), "BASIC realm=\"%s\"", a[1]);
cinap_lenrek@2276 605
 		srvrelease(fs);
cinap_lenrek@2276 606
 		rc = authenticate(u, u, "GET", buf);
cinap_lenrek@2276 607
 		srvacquire(fs);
cinap_lenrek@2276 608
 		freeurl(u);
cinap_lenrek@2276 609
 		if(rc == -1)
cinap_lenrek@2276 610
 			return "preauth failed";
cinap_lenrek@2276 611
 		return nil;
cinap_lenrek@2276 612
 	}
cinap_lenrek@2276 613
 
cinap_lenrek@1294 614
 	return "bad ctl message";
cinap_lenrek@1294 615
 }
cinap_lenrek@1294 616
 
cinap_lenrek@1294 617
 static char*
cinap_lenrek@1294 618
 clientctl(Client *cl, char *ctl, char *arg)
cinap_lenrek@1294 619
 {
cinap_lenrek@1294 620
 	char *p;
cinap_lenrek@1294 621
 	Url *u;
cinap_lenrek@1294 622
 	Key *k;
cinap_lenrek@1294 623
 
cinap_lenrek@1294 624
 	if(debug)
cinap_lenrek@1294 625
 		fprint(2, "clientctl: %q %q\n", ctl, arg);
taruti@0 626
 
cinap_lenrek@1294 627
 	if(!strcmp(ctl, "url")){
cinap_lenrek@1294 628
 		if((u = saneurl(url(arg, cl->baseurl))) == nil)
cinap_lenrek@1294 629
 			return "bad url";
cinap_lenrek@1294 630
 		freeurl(cl->url);
cinap_lenrek@1294 631
 		cl->url = u;
cinap_lenrek@1294 632
 	}
cinap_lenrek@1294 633
 	else if(!strcmp(ctl, "baseurl")){
cinap_lenrek@1294 634
 		if((u = url(arg, 0)) == nil)
cinap_lenrek@1294 635
 			return "bad baseurl";
cinap_lenrek@1294 636
 		freeurl(cl->baseurl);
cinap_lenrek@1294 637
 		cl->baseurl = u;
cinap_lenrek@1294 638
 	}
cinap_lenrek@1294 639
 	else if(!strcmp(ctl, "request")){
cinap_lenrek@1294 640
 		p = cl->request;
cinap_lenrek@1594 641
 		nstrcpy(p, arg, sizeof(cl->request));
cinap_lenrek@1294 642
 		for(; *p && isalpha(*p); p++)
cinap_lenrek@1294 643
 			*p = toupper(*p);
cinap_lenrek@1294 644
 		*p = 0;
taruti@0 645
 	}
cinap_lenrek@1294 646
 	else if(!strcmp(ctl, "headers")){
cinap_lenrek@1294 647
 		while(arg && *arg){
cinap_lenrek@1294 648
 			ctl = arg;
cinap_lenrek@1751 649
 			while(*ctl && strchr(whitespace, *ctl))
cinap_lenrek@1294 650
 				ctl++;
cinap_lenrek@1294 651
 			if(arg = strchr(ctl, '\n'))
cinap_lenrek@1294 652
 				*arg++ = 0;
cinap_lenrek@1294 653
 			if(k = parsehdr(ctl)){
cinap_lenrek@1294 654
 				k->next = cl->hdr;
cinap_lenrek@1294 655
 				cl->hdr = k;
cinap_lenrek@1294 656
 			}
cinap_lenrek@1294 657
 		}
cinap_lenrek@1294 658
 	}
cinap_lenrek@1294 659
 	else {
cinap_lenrek@1294 660
 		char buf[128], **t;
cinap_lenrek@1294 661
 		static char *tab[] = {
cinap_lenrek@1294 662
 			"User-Agent",
cinap_lenrek@1294 663
 			"Content-Type",
cinap_lenrek@1294 664
 			nil,
cinap_lenrek@1294 665
 		};
cinap_lenrek@1294 666
 		for(t = tab; *t; t++){
cinap_lenrek@1594 667
 			nstrcpy(buf, *t, sizeof(buf));
cinap_lenrek@1294 668
 			if(!strcmp(ctl, fshdrname(buf))){
cinap_lenrek@1294 669
 				cl->hdr = delkey(cl->hdr, *t);
cinap_lenrek@1294 670
 				if(arg && *arg)
cinap_lenrek@1294 671
 					cl->hdr = addkey(cl->hdr, *t, arg);
cinap_lenrek@1294 672
 				break;
cinap_lenrek@1294 673
 			}
cinap_lenrek@1294 674
 		}
cinap_lenrek@1294 675
 		if(*t == nil)
cinap_lenrek@1294 676
 			return "bad ctl message";
cinap_lenrek@1294 677
 	}
cinap_lenrek@1294 678
 	return nil;
taruti@0 679
 }
taruti@0 680
 
taruti@0 681
 static void
taruti@0 682
 fswrite(Req *r)
taruti@0 683
 {
cinap_lenrek@1294 684
 	int n;
cinap_lenrek@1294 685
 	Webfid *f;
cinap_lenrek@1294 686
 	char *s, *t;
taruti@0 687
 
cinap_lenrek@1294 688
 	f = r->fid->aux;
cinap_lenrek@1294 689
 	switch(f->level){
cinap_lenrek@1294 690
 	case Qrctl:
taruti@0 691
 	case Qctl:
cinap_lenrek@1294 692
 		n = r->ofcall.count = r->ifcall.count;
cinap_lenrek@1294 693
 		s = emalloc(n+1);
cinap_lenrek@1294 694
 		memmove(s, r->ifcall.data, n);
cinap_lenrek@1294 695
 		while(n > 0 && strchr("\r\n", s[n-1]))
cinap_lenrek@1294 696
 			n--;
cinap_lenrek@1294 697
 		s[n] = 0;
cinap_lenrek@1294 698
 		t = s;
cinap_lenrek@1751 699
 		while(*t && strchr(whitespace, *t)==0)
cinap_lenrek@1294 700
 			t++;
cinap_lenrek@1751 701
 		while(*t && strchr(whitespace, *t))
cinap_lenrek@1294 702
 			*t++ = 0;
cinap_lenrek@1294 703
 		if(f->level == Qctl)
cinap_lenrek@1294 704
 			t = clientctl(f->client, s, t);
cinap_lenrek@1294 705
 		else
cinap_lenrek@2276 706
 			t = rootctl(r->srv, s, t);
cinap_lenrek@1294 707
 		free(s);
cinap_lenrek@1294 708
 		respond(r, t);
cinap_lenrek@1294 709
 		return;
cinap_lenrek@1294 710
 	case Qpost:
cinap_lenrek@1294 711
 		bureq(f->buq, r);
cinap_lenrek@1294 712
 		return;
taruti@0 713
 	}
cinap_lenrek@1294 714
 	respond(r, "not implemented");
taruti@0 715
 }
taruti@0 716
 
taruti@0 717
 static void
cinap_lenrek@1294 718
 fsflush(Req *r)
taruti@0 719
 {
cinap_lenrek@1294 720
 	Webfid *f;
cinap_lenrek@1294 721
 	Req *o;
taruti@0 722
 
cinap_lenrek@1294 723
 	if(o = r->oldreq)
cinap_lenrek@1294 724
 	if(f = o->fid->aux)
cinap_lenrek@1294 725
 		buflushreq(f->buq, o);
cinap_lenrek@1294 726
 	respond(r, nil);
taruti@0 727
 }
taruti@0 728
 
taruti@0 729
 static void
taruti@0 730
 fsdestroyfid(Fid *fid)
taruti@0 731
 {
cinap_lenrek@1294 732
 	Webfid *f;
taruti@0 733
 
cinap_lenrek@1294 734
 	if(f = fid->aux){
cinap_lenrek@1294 735
 		fid->aux = nil;
cinap_lenrek@1294 736
 		if(f->buq){
cinap_lenrek@1294 737
 			buclose(f->buq, 0);
cinap_lenrek@1294 738
 			if(f->client->qbody == f->buq){
cinap_lenrek@1294 739
 				f->client->obody = 0;
cinap_lenrek@1294 740
 				f->client->cbody = 1;
taruti@0 741
 			}
cinap_lenrek@1294 742
 			bufree(f->buq);
taruti@0 743
 		}
cinap_lenrek@1294 744
 		if(f->key)
cinap_lenrek@1294 745
 			free(f->key);
cinap_lenrek@1294 746
 		freeclient(f->client);
cinap_lenrek@1294 747
 		free(f);
taruti@0 748
 	}
taruti@0 749
 }
taruti@0 750
 
cinap_lenrek@3667 751
 static void
cinap_lenrek@3667 752
 fsstart(Srv*)
cinap_lenrek@3667 753
 {
cinap_lenrek@3667 754
 	/* drop reference to old webfs mount */
cinap_lenrek@3667 755
 	if(mtpt != nil)
cinap_lenrek@3667 756
 		unmount(nil, mtpt);
cinap_lenrek@3667 757
 }
cinap_lenrek@3667 758
 
taruti@0 759
 Srv fs = 
taruti@0 760
 {
cinap_lenrek@3667 761
 	.start=fsstart,
cinap_lenrek@1294 762
 	.attach=fsattach,
cinap_lenrek@1294 763
 	.stat=fsstat,
cinap_lenrek@1294 764
 	.walk1=fswalk1,
cinap_lenrek@1294 765
 	.clone=fsclone,
cinap_lenrek@1294 766
 	.open=fsopen,
cinap_lenrek@1294 767
 	.read=fsread,
cinap_lenrek@1294 768
 	.write=fswrite,
cinap_lenrek@1294 769
 	.flush=fsflush,
cinap_lenrek@1294 770
 	.destroyfid=fsdestroyfid,
taruti@0 771
 };
taruti@0 772
 
cinap_lenrek@1294 773
 void
cinap_lenrek@1294 774
 usage(void)
cinap_lenrek@1294 775
 {
cinap_lenrek@3667 776
 	fprint(2, "usage: %s [-D] [-A useragent] [-T timeout] [-m mtpt] [-s service]\n", argv0);
cinap_lenrek@1294 777
 	exits("usage");
cinap_lenrek@1294 778
 }
cinap_lenrek@1294 779
 
cinap_lenrek@1294 780
 void
cinap_lenrek@1294 781
 main(int argc, char *argv[])
cinap_lenrek@1294 782
 {
cinap_lenrek@3667 783
 	char *s;
cinap_lenrek@1294 784
 
cinap_lenrek@1294 785
 	quotefmtinstall();
cinap_lenrek@1294 786
 	fmtinstall('U', Ufmt);
cinap_lenrek@3119 787
 	fmtinstall('H', Hfmt);
cinap_lenrek@1294 788
 	fmtinstall('E', Efmt);
cinap_lenrek@4336 789
 	fmtinstall('[', encodefmt);
cinap_lenrek@1294 790
 
cinap_lenrek@1294 791
 	mtpt = "/mnt/web";
cinap_lenrek@1294 792
 	user = getuser();
cinap_lenrek@1294 793
 	time0 = time(0);
cinap_lenrek@1590 794
 	timeout = 10000;
cinap_lenrek@1294 795
 
cinap_lenrek@1294 796
 	ARGBEGIN {
cinap_lenrek@1294 797
 	case 'D':
cinap_lenrek@1294 798
 		chatty9p++;
cinap_lenrek@1294 799
 		break;
cinap_lenrek@1590 800
 	case 'A':
cinap_lenrek@1590 801
 		agent = EARGF(usage());
cinap_lenrek@1590 802
 		break;
cinap_lenrek@1590 803
 	case 'T':
cinap_lenrek@1590 804
 		timeout = atoi(EARGF(usage()));
cinap_lenrek@1590 805
 		if(timeout < 0)
cinap_lenrek@1590 806
 			timeout = 0;
cinap_lenrek@1590 807
 		break;
cinap_lenrek@1294 808
 	case 'm':
cinap_lenrek@1294 809
 		mtpt = EARGF(usage());
cinap_lenrek@1294 810
 		break;
cinap_lenrek@1294 811
 	case 's':
cinap_lenrek@3667 812
 		service = EARGF(usage());
cinap_lenrek@1294 813
 		break;
cinap_lenrek@1294 814
 	case 'd':
cinap_lenrek@1294 815
 		debug++;
cinap_lenrek@1294 816
 		break;
cinap_lenrek@1294 817
 	default:
cinap_lenrek@1294 818
 		usage();
cinap_lenrek@1294 819
 	} ARGEND;
cinap_lenrek@1294 820
 
cinap_lenrek@1294 821
 	rfork(RFNOTEG);
cinap_lenrek@1294 822
 
cinap_lenrek@1590 823
 	if(agent == nil)
cinap_lenrek@3608 824
 		agent = "Mozilla/5.0 (compatible; hjdicks)";
cinap_lenrek@1590 825
 	agent = estrdup(agent);
cinap_lenrek@1590 826
 
cinap_lenrek@1294 827
 	if(s = getenv("httpproxy")){
cinap_lenrek@1294 828
 		proxy = saneurl(url(s, 0));
cinap_lenrek@4292 829
 		if(proxy == nil || strcmp(proxy->scheme, "http") && strcmp(proxy->scheme, "https"))
cinap_lenrek@4292 830
 			sysfatal("invalid httpproxy url: %s", s);
cinap_lenrek@1294 831
 		free(s);
cinap_lenrek@1294 832
 	}
cinap_lenrek@1294 833
 
cinap_lenrek@3667 834
 	postmountsrv(&fs, service, mtpt, MREPL);
cinap_lenrek@2910 835
 	exits(0);
cinap_lenrek@1294 836
 }