summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2014-11-12 12:03:51 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2014-11-12 12:03:51 +0100
commitc79dc3263e6242182421a99c384e70124e7e544a (patch)
tree7e0291142ac50eb098a54420eb1f9f0fa13483e9
parent5540ca6b68dd964376e6f436de82ef81cecb2979 (diff)
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.
-rw-r--r--sys/man/4/httpfile14
-rw-r--r--sys/src/cmd/ip/httpfile.c283
2 files changed, 113 insertions, 184 deletions
diff --git a/sys/man/4/httpfile b/sys/man/4/httpfile
index b7cd36551..0947814ac 100644
--- a/sys/man/4/httpfile
+++ b/sys/man/4/httpfile
@@ -22,10 +22,6 @@ httpfile \- serve a single web file
.B -s
.I srvname
]
-[
-.B -x
-.I net
-]
.I url
.SH DESCRIPTION
.I Httpfile
@@ -63,21 +59,15 @@ to post the 9P service as
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
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
diff --git a/sys/src/cmd/ip/httpfile.c b/sys/src/cmd/ip/httpfile.c
index b28cd63eb..b5c1dbdfc 100644
--- 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 @@ enum
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 @@ int mcache;
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 @@ addblock(Blocklist *l, Block *b)
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 @@ delreq(Block *b, Req *r)
*l = r->aux;
if(*l == nil)
b->erq = l;
- free(r);
return;
}
}
@@ -119,18 +110,21 @@ evictblock(Blocklist *cache)
{
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,14 +136,13 @@ findblock(Blocklist *s, vlong off)
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);
return b;
}
}
-
return nil;
}
@@ -158,11 +151,9 @@ readfrom(Req *r, Block *b)
{
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 @@ hangupclient(Srv*)
threadexitsall("done");
}
-int
-dotls(int fd)
-{
- TLSconn conn;
-
- memset(&conn, 0, sizeof(conn));
- if((fd=tlsClient(fd, &conn)) < 0)
- sysfatal("tlsclient: %r");
- free(conn.cert);
- free(conn.sessionID);
- return fd;
-}
-
-char*
-nocr(char *s)
+static int
+readfile(int fd, char *buf, int nbuf)
{
- char *r, *w;
+ int r, n;
- for(r=w=s; *r; r++)
- if(*r != '\r')
- *w++ = *r;
- *w = 0;
- return s;
+ for(n = 0; n < nbuf; n += r)
+ if((r = read(fd, buf + n, nbuf - n)) <= 0)
+ break;
+ return n;
}
-char*
-readhttphdr(Biobuf *netbio, vlong *size)
+static int
+readstring(int fd, char *buf, int nbuf)
{
- char *s, *stat;
+ int n;
- 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;
-}
-
-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;
+ if(n > 0 && buf[n-1] == '\n')
+ n--;
+ buf[n] = '\0';
+ return n;
}
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 @@ getrange(Block *b)
if(debug)
print("getrange: %lld %lld\n", b->off, b->len);
- netfd = dialhttp(&netbio);
-
- 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);
+ 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;
- 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;
+ }
+ if(readstring(cfd, buf, sizeof(buf)) <= 0){
+Badrange:
+ close(cfd);
+ close(fd);
return nil;
}
- free(status);
+ 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 @@ httpfilereadproc(void*)
{
Block *b;
- threadsetname("httpfilereadproc");
+ threadsetname("httpfilereadproc %s", url);
for(;;){
b = recvp(httpchan);
@@ -413,29 +369,27 @@ fswalk1(Fid *fid, char *name, Qid *qid)
vlong
getfilesize(void)
{
- char *status;
- vlong size;
- int netfd;
- static Biobuf netbio;
-
- 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;
+ char buf[128];
+ int fd, cfd;
+
+ 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 @@ fileread(Req *r)
{
Block *b;
- if(r->ifcall.offset > size){
+ if(r->ifcall.offset >= size){
+ r->ofcall.count = 0;
respond(r, nil);
return;
}
@@ -476,7 +431,7 @@ void
finishthread(void*)
{
Block *b;
- Req *r, *nextr;
+ Req *r;
threadsetname("finishthread");
@@ -488,11 +443,11 @@ finishthread(void*)
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 @@ finishthread(void*)
void
fsnetproc(void*)
{
- Req *r;
+ Req *r, *o;
Block *b;
threadcreate(finishthread, nil, 8192);
@@ -512,9 +467,11 @@ fsnetproc(void*)
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 @@ Srv fs =
void
threadmain(int argc, char **argv)
{
- char *defport, *mtpt, *srvname, *p;
+ char *mtpt, *srvname, *p;
mtpt = nil;
srvname = nil;
@@ -592,9 +549,6 @@ threadmain(int argc, char **argv)
case 'f':
file = EARGF(usage());
break;
- case 'x':
- net = smprint("%s/net", EARGF(usage()));
- break;
default:
usage();
}ARGEND;
@@ -608,37 +562,22 @@ threadmain(int argc, char **argv)
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();
size = getfilesize();