git: 9front

Download patch

ref: 7070f8918191851e84f799eb0f285fc21dd9d6b2
parent: 540eb468cedb22e4ea6261e4b192576611c07092
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Nov 12 07:03:51 EST 2014

httpfile: use webfs, fix 9p flushes

we can improve performance alot by using webfs which
does http keep alives for us, so connection setup
overhead is eleminated.

fix 9p flushes and double frees.

--- a/sys/man/4/httpfile
+++ b/sys/man/4/httpfile
@@ -22,10 +22,6 @@
 .B -s
 .I srvname
 ]
-[
-.B -x
-.I net
-]
 .I url
 .SH DESCRIPTION
 .I Httpfile
@@ -63,12 +59,6 @@
 and disables the default mount.
 .PP
 The
-.B -x
-option specifies an alternate network directory
-.RI ( e.g., 
-.BR /net.alt ).
-.PP
-The
 .B -c
 option sets the number of file blocks kept cached in memory (default 32).
 .SH EXAMPLE
@@ -75,9 +65,9 @@
 Mount an ISO image on a web server:
 .IP
 .EX
-ip/httpfile http://www.9grid.de/plan9/plan9.iso
+ip/httpfile http://www.r-36.net/9front/9front.iso
 9660srv
-mount /srv/9660 /n/iso plan9.iso
+mount /srv/9660 /n/iso 9front.iso
 .EE
 .SH SOURCE
 .B /sys/src/cmd/ip/httpfile.c
--- a/sys/src/cmd/ip/httpfile.c
+++ b/sys/src/cmd/ip/httpfile.c
@@ -2,13 +2,9 @@
 
 #include <u.h>
 #include <libc.h>
-#include <bio.h>
-#include <ndb.h>
 #include <thread.h>
 #include <fcall.h>
 #include <9p.h>
-#include <mp.h>
-#include <libsec.h>
 
 enum
 {
@@ -16,13 +12,9 @@
 	Stacksize = 8192,
 };
 
-char *host;
-char *file;
-char *port;
-char *url;
-char *get;
-char *user;
-char *net = "net";
+char *user, *url, *file;
+char webconn[64];
+int webctlfd = -1;
 
 vlong size;
 int usetls;
@@ -33,7 +25,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: httpfile [-Dd] [-c count] [-f file] [-m mtpt] [-s srvname] [-x net] url\n");
+	fprint(2, "usage: httpfile [-Dd] [-c count] [-f file] [-m mtpt] [-s srvname] url\n");
 	exits("usage");
 }
 
@@ -92,10 +84,10 @@
 
 	if(l->first == nil)
 		l->end = &l->first;
-	*l->end = b;
+	b->lastuse = time(0);
 	b->link = nil;
+	*l->end = b;
 	l->end = &b->link;
-	b->lastuse = time(0);
 }
 
 void
@@ -108,7 +100,6 @@
 			*l = r->aux;
 			if(*l == nil)
 				b->erq = l;
-			free(r);
 			return;
 		}
 	}
@@ -119,18 +110,21 @@
 {
 	Block **l, **oldest, *b;
 
-	if(cache->first == nil)
-		return;
-
 	oldest = nil;
-	for(l=&cache->first; *l; l=&(*l)->link)
-		if(oldest == nil || (*oldest)->lastuse > (*l)->lastuse)
+	for(l=&cache->first; (b=*l) != nil; l=&b->link){
+		if(b->rq != nil)	/* dont touch block when still requests queued */
+			continue;
+		if(b->rq != nil && (oldest == nil || (*oldest)->lastuse > b->lastuse))
 			oldest = l;
+	}
 
+	if(oldest == nil)
+		return;
+
 	b = *oldest;
-	*oldest = (*oldest)->link;
-	if(*oldest == nil)
+	if((*oldest = b->link) == nil)
 		cache->end = oldest;
+
 	free(b->p);
 	free(b);
 	ncache--;
@@ -142,7 +136,7 @@
 	Block *b;
 
 	for(b = s->first; b != nil; b = b->link){
-		if(b->off <= off && off < b->off + Blocksize){
+		if(off >= b->off && off < b->off + b->len){
 			if(debug)
 				print("found: %lld -> %lld\n", off, b->off);
 			b->lastuse = time(0);
@@ -149,7 +143,6 @@
 			return b;
 		}
 	}
-
 	return nil;
 }
 
@@ -158,11 +151,9 @@
 {
 	int d, n;
 
-	b->lastuse = time(0);
-
 	n = r->ifcall.count;
 	d = r->ifcall.offset - b->off;
-	if(b->off + d + n > b->off + b->len)
+	if(d + n > b->len)
 		n = b->len - d;
 	if(debug)
 		print("Reading from: %p %d %d\n", b->p, d, n);
@@ -181,73 +172,38 @@
 	threadexitsall("done");
 }
 
-int
-dotls(int fd)
+static int
+readfile(int fd, char *buf, int nbuf)
 {
-	TLSconn conn;
+	int r, n;
 
-	memset(&conn, 0, sizeof(conn));
-	if((fd=tlsClient(fd, &conn)) < 0)
-		sysfatal("tlsclient: %r");
-	free(conn.cert);
-	free(conn.sessionID);
-	return fd;
+	for(n = 0; n < nbuf; n += r)
+		if((r = read(fd, buf + n, nbuf - n)) <= 0)
+			break;
+	return n;
 }
 
-char*
-nocr(char *s)
+static int
+readstring(int fd, char *buf, int nbuf)
 {
-	char *r, *w;
+	int n;
 
-	for(r=w=s; *r; r++)
-		if(*r != '\r')
-			*w++ = *r;
-	*w = 0;
-	return s;
-}
-
-char*
-readhttphdr(Biobuf *netbio, vlong *size)
-{
-	char *s, *stat;
-
-	stat = nil;
-	while((s = Brdstr(netbio, '\n', 1)) != nil && s[0] != '\r'
-			&& s[0] != '\0'){
-		if(stat == nil)
-			stat = estrdup9p(s);
-		if(strncmp(s, "Content-Length: ", 16) == 0 && size != nil)
-			*size = atoll(s + 16);
-		free(s);
+	if((n = readfile(fd, buf, nbuf-1)) < 0){
+		buf[0] = '\0';
+		return -1;
 	}
-	if(stat)
-		nocr(stat);
-
-	return stat;
+	if(n > 0 && buf[n-1] == '\n')
+		n--;
+	buf[n] = '\0';
+	return n;
 }
 
-int
-dialhttp(Biobuf *netbio)
-{
-	int netfd;
-
-	netfd = dial(netmkaddr(host, net, port), 0, 0, 0);
-	if(netfd < 0)
-		sysfatal("dial: %r");
-	if(usetls)
-		netfd = dotls(netfd);
-	Binit(netbio, netfd, OREAD);
-
-	return netfd;
-}
-
 uchar*
 getrange(Block *b)
 {
+	char buf[128];
+	int fd, cfd;
 	uchar *data;
-	char *status;
-	int netfd;
-	static Biobuf netbio;
 
 	b->len = Blocksize;
 	if(b->off + b->len > size)
@@ -256,45 +212,45 @@
 	if(debug)
 		print("getrange: %lld %lld\n", b->off, b->len);
 
-	netfd = dialhttp(&netbio);
+	if(fprint(webctlfd, "url %s\n", url) < 0)
+		return nil;
+	if(fprint(webctlfd, "request GET\n") < 0)
+		return nil;
+	if(fprint(webctlfd, "headers Range: bytes=%lld-%lld\n", b->off, b->off+b->len-1) < 0)
+		return nil;
 
-	fprint(netfd, 
-		"GET %s HTTP/1.1\r\n"
-		"Host: %s\r\n"
-		"Accept-Encoding:\r\n"
-		"Range: bytes=%lld-%lld\r\n"
-		"\r\n",
-		get, host, b->off, b->off+b->len-1);
-	Bflush(&netbio);
-
-	status = readhttphdr(&netbio, nil);
-	if(status == nil)
+	/* start the request */
+	snprint(buf, sizeof(buf), "%s/body", webconn);
+	if((fd = open(buf, OREAD)) < 0)
 		return nil;
 
-	/*
-	 * Some servers (e.g., www.google.com) return 200 OK
-	 * when you ask for the entire page in one range.
-	 */
-	if(strstr(status, "206 Partial Content")==nil
-	&& (b->off!=0 || b->len!=size || strstr(status, "200 OK")==nil)){
-		free(status);
-		close(netfd);
-		werrstr("did not get requested range");
+	/* verify content-range response header */ 
+	snprint(buf, sizeof(buf), "%s/contentrange", webconn);
+	if((cfd = open(buf, OREAD)) < 0){
+		close(fd);
 		return nil;
 	}
-	free(status);
+	if(readstring(cfd, buf, sizeof(buf)) <= 0){
+Badrange:
+		close(cfd);
+		close(fd);
+		return nil;
+	}
+	if(cistrncmp(buf, "bytes ", 6) != 0)
+		goto Badrange;
+	if(strtoll(buf + 6, nil, 10) != b->off)
+		goto Badrange;
+	close(cfd);
 
+	/* read body data */
 	data = emalloc9p(b->len);
-	if(Bread(&netbio, data, b->len) != b->len){
+	if(readfile(fd, (char*)data, b->len) != b->len){
+		close(fd);
 		free(data);
-		close(netfd);
-		werrstr("not enough bytes read");
 		return nil;
 	}
-
+	close(fd);
 	b->p = data;
-
-	close(netfd);
 	return data;
 }
 
@@ -303,7 +259,7 @@
 {
 	Block *b;
 
-	threadsetname("httpfilereadproc");
+	threadsetname("httpfilereadproc %s", url);
 
 	for(;;){
 		b = recvp(httpchan);
@@ -413,29 +369,27 @@
 vlong
 getfilesize(void)
 {
-	char *status;
-	vlong size;
-	int netfd;
-	static Biobuf netbio;
+	char buf[128];
+	int fd, cfd;
 
-	netfd = dialhttp(&netbio);
-
-	fprint(netfd, 
-		"HEAD %s HTTP/1.1\r\n"
-		"Host: %s\r\n"
-		"Accept-Encoding:\r\n"
-		"\r\n",
-		get, host);
-
-	status = readhttphdr(&netbio, &size);
-	if(strstr(status, "200 OK") == nil){
-		werrstr("%s", status);
-		size = -1;
+	if(fprint(webctlfd, "url %s\n", url) < 0)
+		return -1;
+	if(fprint(webctlfd, "request HEAD\n") < 0)
+		return -1;
+	snprint(buf, sizeof(buf), "%s/body", webconn);
+	if((fd = open(buf, OREAD)) < 0)
+		return -1;
+	snprint(buf, sizeof(buf), "%s/contentlength", webconn);
+	cfd = open(buf, OREAD);
+	close(fd);
+	if(cfd < 0)
+		return -1;
+	if(readstring(cfd, buf, sizeof(buf)) <= 0){
+		close(cfd);
+		return -1;
 	}
-	free(status);
-
-	close(netfd);
-	return size;
+	close(cfd);
+	return strtoll(buf, nil, 10);
 }
 
 void
@@ -443,7 +397,8 @@
 {
 	Block *b;
 
-	if(r->ifcall.offset > size){
+	if(r->ifcall.offset >= size){
+		r->ofcall.count = 0;
 		respond(r, nil);
 		return;
 	}
@@ -476,7 +431,7 @@
 finishthread(void*)
 {
 	Block *b;
-	Req *r, *nextr;
+	Req *r;
 
 	threadsetname("finishthread");
 
@@ -488,11 +443,11 @@
 		if(ncache >= mcache)
 			evictblock(&cache);
 		addblock(&cache, b);
-		for(r=b->rq; r; r=nextr){
-			nextr = r->aux;
+		while((r = b->rq) != nil){
+			b->rq = r->aux;
+			r->aux = nil;
 			readfrom(r, b);
 		}
-		b->rq = nil;
 		if(inprogress.first)
 			sendp(httpchan, inprogress.first);
 	}
@@ -501,7 +456,7 @@
 void
 fsnetproc(void*)
 {
-	Req *r;
+	Req *r, *o;
 	Block *b;
 
 	threadcreate(finishthread, nil, 8192);
@@ -512,9 +467,11 @@
 		r = recvp(reqchan);
 		switch(r->ifcall.type){
 		case Tflush:
-			b = findblock(&inprogress, r->ifcall.offset);
-			delreq(b, r->oldreq);
-			respond(r->oldreq, "interrupted");
+			o = r->oldreq;
+			b = findblock(&inprogress, o->ifcall.offset);
+			if(b != nil)
+				delreq(b, o);
+			respond(o, "interrupted");
 			respond(r, nil);
 			break;
 		case Tread:
@@ -569,7 +526,7 @@
 void
 threadmain(int argc, char **argv)
 {
-	char *defport, *mtpt, *srvname, *p;
+	char *mtpt, *srvname, *p;
 
 	mtpt = nil;
 	srvname = nil;
@@ -592,9 +549,6 @@
 	case 'f':
 		file = EARGF(usage());
 		break;
-	case 'x':
-		net = smprint("%s/net", EARGF(usage()));
-		break;
 	default:
 		usage();
 	}ARGEND;
@@ -608,36 +562,21 @@
 		mcache = 32;
 
 	time0 = time(0);
-	host = url = estrdup9p(argv[0]);
-
-	defport = nil;
-	if(!cistrncmp(url, "https://", 8)){
-		host += 8;
-		usetls = 1;
-		defport = "https";
-	}else if(!cistrncmp(url, "http://", 7)){
-		host += 7;
-		defport = "http";
-	}else
-		sysfatal("unsupported url: %s", url);
-
-	if((p = strchr(host, '/')) != nil){
-		get = estrdup9p(p);
-		*p = '\0';
-	}else
-		get = "/";
-
-	port = strchr(host, ':');
-	if(port != nil)
-		*port++ = '\0';
-	else
-		port = defport;
-
+	url = estrdup9p(argv[0]);
 	if(file == nil){
-		file = strrchr(get, '/')+1;
-		if(*file == 0)
+		file = strrchr(url, '/');
+		if(file == nil || file[1] == '\0')
 			file = "index";
+		else
+			file++;
 	}
+
+	snprint(webconn, sizeof(webconn), "/mnt/web/clone");
+	if((webctlfd = open(webconn, ORDWR)) < 0)
+		sysfatal("open: %r");
+	p = strrchr(webconn, '/')+1;
+	if(readstring(webctlfd, p, webconn+sizeof(webconn)-p) <= 0)
+		sysfatal("read: %r");
 
 	tab[Qfile].name = file;
 	user = getuser();
--