Browse Source

Plan 9 from Bell Labs 2010-07-16

David du Colombier 13 years ago
parent
commit
9fb9df0ba8

+ 6 - 1
386/include/ape/stdarg.h

@@ -6,6 +6,11 @@ typedef char *va_list;
 #define va_start(list, start) list = (sizeof(start)<4 ? (char *)((int *)&(start)+1) : \
 (char *)(&(start)+1))
 #define va_end(list)
-#define va_arg(list, mode) ((mode*)(list += sizeof(mode)))[-1]
+#define va_arg(list, mode)\
+	((sizeof(mode) == 1)?\
+		((list += 4), (mode*)list)[-4]:\
+	(sizeof(mode) == 2)?\
+		((list += 4), (mode*)list)[-2]:\
+		((list += sizeof(mode)), (mode*)list)[-1])
 
 #endif /* __STDARG */

+ 10 - 3
68020/include/ape/stdarg.h

@@ -3,9 +3,16 @@
 
 typedef char *va_list;
 
-#define va_start(list, start) list = (char *)(&(start)+1)
+#define va_start(list, start) list =\
+	(sizeof(start) < 4?\
+		(char*)((int*)&(start)+1):\
+		(char*)(&(start)+1))
 #define va_end(list)
-#define va_arg(list, mode) (sizeof(mode)==1 ? ((mode *) (list += 4))[-4] : \
-sizeof(mode)==2 ? ((mode *) (list += 4))[-2] : ((mode *) (list += sizeof(mode)))[-1])
+#define va_arg(list, mode)\
+	((sizeof(mode) == 1)?\
+		((list += 4), (mode*)list)[-1]:\
+	(sizeof(mode) == 2)?\
+		((list += 4), (mode*)list)[-1]:\
+		((list += sizeof(mode)), (mode*)list)[-1])
 
 #endif /* __STDARG */

+ 9 - 6
alpha/include/ape/stdarg.h

@@ -3,15 +3,18 @@
 
 typedef char *va_list;
 
-#define va_start(list, start) list = (char *)(&(start)+1)
+#define va_start(list, start) list =\
+	(sizeof(start) < 4?\
+		(char*)((int*)&(start)+1):\
+		(char*)(&(start)+1))
 #define va_end(list)
 #define va_arg(list, mode)\
-	(sizeof(mode)==1?\
-		((mode*)(list += 4))[-1]:\
-	sizeof(mode)==2?\
-		((mode*)(list += 4))[-1]:\
+	((sizeof(mode) == 1)?\
+		((list += 4), (mode*)list)[-4]:\
+	(sizeof(mode) == 2)?\
+		((list += 4), (mode*)list)[-2]:\
 	sizeof(mode)>4?\
 		((mode*)(list = (char*)((long)(list+7) & ~7) + sizeof(mode)))[-1]:\
-		((mode*)(list += sizeof(mode)))[-1])
+		((list += sizeof(mode)), (mode*)list)[-1])
 
 #endif /* __STDARG */

+ 6 - 1
arm/include/ape/stdarg.h

@@ -6,6 +6,11 @@ typedef char *va_list;
 #define va_start(list, start) list = (sizeof(start)<4 ? (char *)((int *)&(start)+1) : \
 (char *)(&(start)+1))
 #define va_end(list)
-#define va_arg(list, mode) ((mode*)(list += sizeof(mode)))[-1]
+#define va_arg(list, mode)\
+	((sizeof(mode) == 1)?\
+		((list += 4), (mode*)list)[-4]:\
+	(sizeof(mode) == 2)?\
+		((list += 4), (mode*)list)[-2]:\
+		((list += sizeof(mode)), (mode*)list)[-1])
 
 #endif /* __STDARG */

+ 10 - 3
mips/include/ape/stdarg.h

@@ -3,9 +3,16 @@
 
 typedef char *va_list;
 
-#define va_start(list, start) list = (char *)(&(start)+1)
+#define va_start(list, start) list =\
+	(sizeof(start) < 4?\
+		(char*)((int*)&(start)+1):\
+		(char*)(&(start)+1))
 #define va_end(list)
-#define va_arg(list, mode) (sizeof(mode)==1 ? ((mode *) (list += 4))[-4] : \
-sizeof(mode)==2 ? ((mode *) (list += 4))[-2] : ((mode *) (list += sizeof(mode)))[-1])
+#define va_arg(list, mode)\
+	((sizeof(mode) == 1)?\
+		((list += 4), (mode*)list)[-1]:\
+	(sizeof(mode) == 2)?\
+		((list += 4), (mode*)list)[-1]:\
+		((list += sizeof(mode)), (mode*)list)[-1])
 
 #endif /* __STDARG */

+ 4 - 1
power/include/ape/stdarg.h

@@ -3,7 +3,10 @@
 
 typedef char *va_list;
 
-#define va_start(list, start) list = (char *)(&(start)+1)
+#define va_start(list, start) list =\
+	(sizeof(start) < 4?\
+		(char*)((int*)&(start)+1):\
+		(char*)(&(start)+1))
 #define va_end(list)
 #define va_arg(list, mode)\
 	((sizeof(mode) <= 4)?\

+ 10 - 3
sparc/include/ape/stdarg.h

@@ -3,9 +3,16 @@
 
 typedef char *va_list;
 
-#define va_start(list, start) list = (char *)(&(start)+1)
+#define va_start(list, start) list =\
+	(sizeof(start) < 4?\
+		(char*)((int*)&(start)+1):\
+		(char*)(&(start)+1))
 #define va_end(list)
-#define va_arg(list, mode) (sizeof(mode)==1 ? ((mode *) (list += 4))[-4] : \
-sizeof(mode)==2 ? ((mode *) (list += 4))[-2] : ((mode *) (list += sizeof(mode)))[-1])
+#define va_arg(list, mode)\
+	((sizeof(mode) == 1)?\
+		((list += 4), (mode*)list)[-1]:\
+	(sizeof(mode) == 2)?\
+		((list += 4), (mode*)list)[-1]:\
+		((list += sizeof(mode)), (mode*)list)[-1])
 
 #endif /* __STDARG */

+ 4 - 0
sys/include/httpd.h

@@ -180,6 +180,7 @@ struct HttpHead
 	char	*authuser;		/* authorization info */
 	char	*authpass;
 	HSPairs	*cookie;	/* if present, list of cookies */
+	HSPairs		*authinfo;		/* digest authorization */
 
 	/*
 	 * experimental headers
@@ -196,6 +197,9 @@ struct HConnect
 	void	*private;		/* for the library clients */
 	void	(*replog)(HConnect*, char*, ...); /* called when reply sent */
 
+	char	*scheme;		/* "http" vs. "https" */
+	char	*port;		/* may be arbitrary, i.e., neither 80 nor 443 */
+
 	HttpReq	req;
 	HttpHead head;
 

+ 1 - 1
sys/include/thread.h

@@ -61,9 +61,9 @@ struct Ref {
 
 int	alt(Alt alts[]);
 int	chanclose(Channel*);
+int	chanclosing(Channel *c);
 Channel*chancreate(int elemsize, int bufsize);
 int	chaninit(Channel *c, int elemsize, int elemcnt);
-int	chanisclosed(Channel *c);
 void	chanfree(Channel *c);
 int	chanprint(Channel *, char *, ...);
 long	decref(Ref *r);			/* returns 0 iff value is now zero */

+ 8 - 2
sys/man/2/thread

@@ -5,7 +5,7 @@ chanclose,
 chancreate,
 chanfree,
 chaninit,
-chanisclosed,
+chanclosing,
 chanprint,
 mainstacksize,
 proccreate,
@@ -126,7 +126,7 @@ int	nbsendp(Channel *c, void *v)
 int	nbsendul(Channel *c, ulong v)
 int	chanprint(Channel *c, char *fmt, ...)
 int	chanclose(Channel *c);
-int	chanisclosed(Channel *c);
+int	chanclosing(Channel *c);
 .XX
 void	procexecl(Channel *cpid, char *file, ...)
 void	procexec(Channel *cpid, char *file, char *args[])
@@ -572,6 +572,12 @@ returns \-1.
 Thread library functions do not return on failure;
 if errors occur, the entire program is aborted.
 .PP
+.I Chanclosing
+returns \-1 if no one called
+.I closed
+on the channel, and otherwise
+the number of elements still in the channel.
+.PP
 Threaded programs should use
 .I threadnotify
 in place of

+ 2 - 2
sys/man/4/httpfile

@@ -7,7 +7,7 @@ httpfile \- serve a single web file
 .B -9d
 ]
 [
-.B -b
+.B -c
 .I count
 ]
 [
@@ -69,7 +69,7 @@ option specifies an alternate network directory
 .BR /net.alt ).
 .PP
 The
-.B -b
+.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:

+ 17 - 59
sys/man/8/httpd

@@ -1,12 +1,14 @@
 .TH HTTPD 8
 .SH NAME
-httpd, mirror, save, imagemap, man2html, webls \- HTTP server
+httpd, save, imagemap, man2html, webls \- HTTP server
 .SH SYNOPSIS
 .B ip/httpd/httpd
 .RB [ -a
 .IR srvaddr ]
 .RB [ -c
-.IR cert ]
+.I cert
+.RB [ -C
+.IR certchain ]]
 .RB [ -d
 .IR domain ]
 .RB [ -n
@@ -14,20 +16,6 @@ httpd, mirror, save, imagemap, man2html, webls \- HTTP server
 .RB [ -w
 .IR webroot ]
 .PP
-.B ip/httpd/mirror
-.RB [ -b
-.IR inbuf ]
-.RB [ -d
-.IR domain ]
-.RB [ -r
-.IR remoteip ]
-.RB [ -w
-.IR webroot ]
-.RB [ -N
-.IR netdir ]
-.I method version uri
-.RI [ search ]
-.PP
 .B ip/httpd/save
 .RB [ -b
 .IR inbuf ]
@@ -41,47 +29,15 @@ httpd, mirror, save, imagemap, man2html, webls \- HTTP server
 .IR netdir ]
 .I method version uri
 .RI [ search ]
-.PP
+.br
 .B ip/httpd/imagemap
-.RB [ -b
-.IR inbuf ]
-.RB [ -d
-.IR domain ]
-.RB [ -r
-.IR remoteip ]
-.RB [ -w
-.IR webroot ]
-.RB [ -N
-.IR netdir ]
-.I method version uri
-.PP
+.I ...
+.br
 .B ip/httpd/man2html
-.RB [ -b
-.IR inbuf ]
-.RB [ -d
-.IR domain ]
-.RB [ -r
-.IR remoteip ]
-.RB [ -w
-.IR webroot ]
-.RB [ -N
-.IR netdir ]
-.I method version uri
-.RI [ search ]
-.PP
+.I ...
+.br
 .B ip/httpd/webls
-.RB [ -b
-.IR inbuf ]
-.RB [ -d
-.IR domain ]
-.RB [ -r
-.IR remoteip ]
-.RB [ -w
-.IR webroot ]
-.RB [ -N
-.IR netdir ]
-.I method version uri
-.RI [ search ]
+.I ...
 .SH DESCRIPTION
 .I Httpd
 serves the
@@ -102,6 +58,11 @@ option, then the service is instead
 .BR tcp!*!https .
 There should already be a factotum
 holding the corresponding private key.
+If the specified certificate has been signed
+by a certificate authority, the
+.B -C
+option may be used to specify a file
+containing a chain of signed certificates.
 .PP
 .I Httpd
 supports only the GET and HEAD methods of the HTTP protocol;
@@ -210,6 +171,7 @@ If the requested URI begins with
 executes the file
 .BI /bin/ip/httpd/ server
 to finish servicing the request.
+All the auxiliaries take the same arguments.
 .IR Method
 and
 .IR version
@@ -228,10 +190,6 @@ See
 .B httpd.h
 in that directory and existing magic commands for more details.
 .PP
-.I Mirror
-is a trivial server that just returns the method, URI, any search,
-the headers, and the message body sent by the client.
-.PP
 .I Save
 writes a line to
 .BI /usr/web/save/ uri .data
@@ -245,7 +203,7 @@ It is used to record form submissions.
 .PP
 .I Imagemap
 processes an HTML imagemap query.
-It looks up a the point
+It looks up the point
 .I search
 in the image map file given by 
 .IR uri ,

+ 14 - 1
sys/man/8/mk9660

@@ -14,6 +14,10 @@ dump9660, mk9660 \- create an ISO-9660 CD image
 .I bootfile
 ]
 [
+.B -B
+.I bootfile
+]
+[
 .B -p
 .I proto
 ]
@@ -178,7 +182,16 @@ That is, the boot floppy image must be listed in the
 file already:
 the
 .B -b
-flag just creates a pointer to it.
+option just creates a pointer to it.
+.PP
+The
+.B -B
+option is similar to
+.B -b
+but the created CD image is marked as having a non-floppy-emulation
+boot block.
+This gives the program in the boot block full (ATA) LBA access
+to the CD filesystem, not just the initial blocks that would fit on a floppy.
 .PP
 The
 .B -D

+ 8 - 0
sys/src/9/pc/uartpci.c

@@ -144,6 +144,14 @@ uartpcipnp(void)
 				break;
 			}
 			break;
+		case (0x9505<<16)|0x1415:	/* Oxford Semi OXuPCI952 */
+			name = "SATAGear-IOI-102";  /* PciSVID=1415, PciSID=0 */
+			if (uartpci(ctlrno, p, 0, 1, 14745600, name, 8) != nil)
+				ctlrno++;
+			if (uartpci(ctlrno, p, 1, 1, 14745600, name, 8) != nil)
+				ctlrno++;
+			uart = nil;		/* don't ctlrno++ below */
+			break;
 		case (0x9050<<16)|0x10B5:	/* Perle PCI-Fast4 series */
 		case (0x9030<<16)|0x10B5:	/* Perle Ultraport series */
 			/*

+ 15 - 8
sys/src/ape/lib/bsd/gettimeofday.c

@@ -25,15 +25,22 @@ be2vlong(vlong *to, uchar *f)
 int
 gettimeofday(struct timeval *tp, struct timezone *tzp)
 {
-	int f;
 	uchar b[8];
 	vlong t;
-
-	memset(b, 0, sizeof b);
-	f = _OPEN("/dev/bintime", 0);
-	if(f >= 0) {
-		_PREAD(f, b, sizeof(b), 0);
-		_CLOSE(f);
+	int opened;
+	static int fd = -1;
+
+	opened = 0;
+	for(;;) {
+		if(fd < 0)
+			if(opened++ ||
+			    (fd = _OPEN("/dev/bintime", OREAD|OCEXEC)) < 0)
+				return 0;
+		if(_PREAD(fd, b, sizeof b, 0) == sizeof b)
+			break;		/* leave fd open for future use */
+		/* short read, perhaps try again */
+		_CLOSE(fd);
+		fd = -1;
 	}
 	be2vlong(&t, b);
 
@@ -41,7 +48,7 @@ gettimeofday(struct timeval *tp, struct timezone *tzp)
 	tp->tv_usec = (t/1000)%1000000;
 
 	if(tzp) {
-		tzp->tz_minuteswest = 240;
+		tzp->tz_minuteswest = 4*60;	/* BUG */
 		tzp->tz_dsttime = 1;
 	}
 

+ 9 - 5
sys/src/cmd/ip/httpd/httpd.c

@@ -15,7 +15,6 @@ struct Strings
 };
 
 char	*netdir;
-char	*webroot;
 char	*HTTPLOG = "httpd/log";
 
 static	char		netdirb[256];
@@ -143,7 +142,7 @@ becomenone(char *namespace)
 }
 
 static HConnect*
-mkconnect(void)
+mkconnect(char *scheme, char *port)
 {
 	HConnect *c;
 
@@ -151,6 +150,8 @@ mkconnect(void)
 	c->hpos = c->header;
 	c->hstop = c->header;
 	c->replog = writelog;
+	c->scheme = scheme;
+	c->port = port;
 	return c;
 }
 
@@ -169,7 +170,7 @@ dolisten(char *address)
 	HSPriv *hp;
 	HConnect *c;
 	NetConnInfo *nci;
-	char ndir[NETPATHLEN], dir[NETPATHLEN], *p;
+	char ndir[NETPATHLEN], dir[NETPATHLEN], *p, *scheme;
 	int ctl, nctl, data, t, ok, spotchk;
 	TLSconn conn;
 
@@ -222,7 +223,9 @@ dolisten(char *address)
 				if (certchain != nil)
 					conn.chain = certchain;
 				data = tlsServer(data, &conn);
-			}
+				scheme = "https";
+			}else
+				scheme = "http";
 			if(data < 0){
 				syslog(0, HTTPLOG, "can't open %s/data: %r", ndir);
 				exits(nil);
@@ -235,7 +238,7 @@ dolisten(char *address)
 			close(nctl);
 
 			nci = getnetconninfo(ndir, -1);
-			c = mkconnect();
+			c = mkconnect(scheme, nci->lserv);
 			hp = mkhspriv();
 			hp->remotesys = nci->rsys;
 			hp->remoteserv = nci->rserv;
@@ -365,6 +368,7 @@ magic:
 		}
 		hp = c->private;
 		execl(c->xferbuf, magic, "-d", hmydomain, "-w", webroot,
+			"-s", c->scheme, "-p", c->port,
 			"-r", hp->remotesys, "-N", netdir, "-b", hb,
 			"-L", logfd0, logfd1, "-R", c->header,
 			c->req.meth, vers, uri, c->req.search, nil);

+ 2 - 0
sys/src/cmd/ip/httpd/httpsrv.h

@@ -75,3 +75,5 @@ void			writelog(HConnect*, char*, ...);
 
 /* authorize.c */
 int authorize(HConnect*, char*);
+
+char *webroot;

+ 11 - 2
sys/src/cmd/ip/httpd/init.c

@@ -6,8 +6,9 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-b inbuf] [-d domain] [-r remoteip] [-w webroot]"
-		" [-N netdir] [-L logfd0 logfd1] [-R reqline]"
+	fprint(2, "usage: %s [-b inbuf] [-d domain] [-p localport]"
+		" [-r remoteip] [-s uri-scheme] [-w webroot]"
+		" [-L logfd0 logfd1] [-N netdir] [-R reqline]"
 		" method version uri [search]\n", argv0);
 	exits("usage");
 }
@@ -28,6 +29,8 @@ init(int argc, char **argv)
 	hinit(&connect.hout, 1, Hwrite);
 	hmydomain = nil;
 	connect.replog = writelog;
+	connect.scheme = "http";
+	connect.port = "80";
 	connect.private = &priv;
 	priv.remotesys = nil;
 	priv.remoteserv = nil;
@@ -42,9 +45,15 @@ init(int argc, char **argv)
 	case 'd':
 		hmydomain = EARGF(usage());
 		break;
+	case 'p':
+		connect.port = EARGF(usage());
+		break;
 	case 'r':
 		priv.remotesys = EARGF(usage());
 		break;
+	case 's':
+		connect.scheme = EARGF(usage());
+		break;
 	case 'w':
 		webroot = EARGF(usage());
 		break;

+ 1 - 1
sys/src/cmd/ip/httpd/webls.c

@@ -323,7 +323,7 @@ main(int argc, char **argv)
 		exits("failed");
 	}
 
-	bind("/usr/web", "/", MREPL);
+	bind(webroot, "/", MREPL);
 
 	if(connect->req.search != nil)
 		dosearch(connect->req.search);

+ 14 - 1
sys/src/cmd/ip/httpd/wikipost.c

@@ -117,9 +117,22 @@ unhttp(char *s)
 void
 mountwiki(HConnect *c, char *service)
 {
-	char buf[64];
+	char buf[128];
 	int fd;
 
+	/* already in (possibly private) namespace? */
+	snprint(buf, sizeof buf, "/mnt/wiki.%s/new", service);
+	if (access(buf, AREAD) == 0){
+		if (bind(buf, "/mnt/wiki", MREPL) < 0){
+			syslog(0, LOG, "%s bind /mnt/wiki failed: %r",
+				hp->remotesys);
+			hfail(c, HNotFound);
+			exits("bind /mnt/wiki failed");
+		}
+		return;
+	}
+
+	/* old way: public wikifs from /srv */
 	snprint(buf, sizeof buf, "/srv/wiki.%s", service);
 	if((fd = open(buf, ORDWR)) < 0){
 		syslog(0, LOG, "%s open %s failed: %r", buf, hp->remotesys);

+ 1 - 1
sys/src/cmd/ip/httpfile.c

@@ -33,7 +33,7 @@ int mcache;
 void
 usage(void)
 {
-	fprint(2, "usage: httpfile [-Dd] [-b count] [-f file] [-m mtpt] [-s srvname] [-x net] url\n");
+	fprint(2, "usage: httpfile [-Dd] [-c count] [-f file] [-m mtpt] [-s srvname] [-x net] url\n");
 	exits("usage");
 }
 

+ 126 - 0
sys/src/cmd/tcs/conv_gbk.c

@@ -0,0 +1,126 @@
+#ifdef	PLAN9
+#include	<u.h>
+#include	<libc.h>
+#include	<bio.h>
+#else
+#include	<stdio.h>
+#include	<unistd.h>
+#include	"plan9.h"
+#endif
+#include	"hdr.h"
+#include	"conv.h"
+#include	"gbk.h"
+
+static void
+gbkproc(int c, Rune **r, long input_loc)
+{
+	static enum { state0, state1 } state = state0;
+	static int lastc;
+	long ch, cold = c;
+
+	switch(state)
+	{
+	case state0:	/* idle state */
+		if(c < 0)
+			return;
+		if(c >= 0x80){
+			lastc = c;
+			state = state1;
+			return;
+		}
+		emit(c);
+		return;
+
+	case state1:	/* seen a font spec */
+		ch = -1;
+		c = lastc<<8 | c;
+		if(c >= GBKMIN && c < GBKMAX)
+			ch = tabgbk[c - GBKMIN];
+		if(ch < 0){
+			nerrors++;
+			if(squawk)
+				EPR "%s: bad gbk glyph %d (from 0x%x,0x%lx) near byte %ld in %s\n", argv0, (c & 0xFF), lastc, cold, input_loc, file);
+			if(!clean)
+				emit(BADMAP);
+			state = state0;
+			return;
+		}
+		emit(ch);
+		state = state0;
+	}
+}
+
+void
+gbk_in(int fd, long *notused, struct convert *out)
+{
+	Rune ob[N];
+	Rune *r, *re;
+	uchar ibuf[N];
+	int n, i;
+	long nin;
+
+	USED(notused);
+	r = ob;
+	re = ob+N-3;
+	nin = 0;
+	while((n = read(fd, ibuf, sizeof ibuf)) > 0){
+		for(i = 0; i < n; i++){
+			gbkproc(ibuf[i], &r, nin++);
+			if(r >= re){
+				OUT(out, ob, r-ob);
+				r = ob;
+			}
+		}
+		if(r > ob){
+			OUT(out, ob, r-ob);
+			r = ob;
+		}
+	}
+	gbkproc(-1, &r, nin);
+	if(r > ob)
+		OUT(out, ob, r-ob);
+	OUT(out, ob, 0);
+}
+
+
+void
+gbk_out(Rune *base, int n, long *notused)
+{
+	char *p;
+	int i;
+	Rune r;
+	static int first = 1;
+
+	USED(notused);
+	if(first){
+		first = 0;
+		for(i = 0; i < NRUNE; i++)
+			tab[i] = -1;
+		for(i = GBKMIN; i < GBKMAX; i++)
+			tab[tabgbk[i-GBKMIN]] = i;
+	}
+	nrunes += n;
+	p = obuf;
+	for(i = 0; i < n; i++){
+		r = base[i];
+		if(r < 0x80)
+			*p++ = r;
+		else {
+			if(tab[r] != -1){
+				r = tab[r];
+				*p++ = (r>>8) & 0xFF;
+				*p++ = r & 0xFF;
+				continue;
+			}
+			if(squawk)
+				EPR "%s: rune 0x%x not in output cs\n", argv0, r);
+			nerrors++;
+			if(clean)
+				continue;
+			*p++ = BYTEBADMAP;
+		}
+	}
+	noutput += p-obuf;
+	if(p > obuf)
+		write(1, obuf, p-obuf);
+}

+ 2 - 1
sys/src/cmd/webfs/http.c

@@ -491,7 +491,8 @@ httpopen(Client *c, Url *url)
 		}
 		c->authenticate = hs->credentials;
 		hs->credentials = nil;
-	}
+	}else if(c->authenticate)
+		c->authenticate = 0;
 	if(redirect){
 		if(!hs->location){
 			werrstr("redirection without Location: header");

+ 47 - 4
sys/src/libhttpd/parse.c

@@ -566,6 +566,30 @@ mimerange(Hlex *h, char *)
 	h->c->head.range = mimeranges(h, h->c->head.range);
 }
 
+/*
+ * parse it like cookies
+ */
+static void
+authdigest(Hlex *h, char *)
+{
+	char *s;
+	HSPairs *p;
+
+	p = nil;
+	for(;;){
+		while(lex(h) != Word)
+			if(h->tok != ';' && h->tok != ',')
+				goto breakout;
+		s = hstrdup(h->c, h->wordval);
+		while (lex(h) != Word && h->tok != QString)
+			if (h->tok != '=')
+				goto breakout;
+		p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
+	}
+breakout:
+	h->c->head.authinfo = hrevspairs(p);
+}
+
 /*
  * note: netscape and ie through versions 4.7 and 4
  * support only basic authorization, so that is all that is supported here
@@ -575,14 +599,11 @@ mimerange(Hlex *h, char *)
  * username ":" password
  */
 static void
-mimeauthorization(Hlex *h, char *)
+authbasic(Hlex *h, char *)
 {
 	char *up, *p;
 	int n;
 
-	if(lex(h) != Word || cistrcmp(h->wordval, "basic") != 0)
-		return;
-
 	n = lexbase64(h);
 	if(!n)
 		return;
@@ -611,6 +632,28 @@ mimeauthorization(Hlex *h, char *)
 	}
 }
 
+/*
+ * "Authorization" ":" "Basic" | "Digest" ...
+ */
+static void
+mimeauthorization(Hlex *h, char *)
+{
+	int i;
+	static MimeHead authparser[] = {
+		{ "basic", authbasic },
+		{ "digest", authdigest },
+	};
+
+	if(lex(h) != Word)
+		return;
+
+	for (i = 0; i < nelem(authparser); i++)
+		if (cistrcmp(h->wordval, authparser[i].name) == 0) {
+			(*authparser[i].parse)(h, nil);
+			break;
+		}
+}
+
 static void
 mimeagent(Hlex *h, char *)
 {

+ 9 - 12
sys/src/libhttpd/parsereq.c

@@ -143,18 +143,18 @@ parseuri(HConnect *c, char *uri)
 	char *urihost, *p;
 
 	urihost = nil;
-	if(uri[0] != '/'){
-		if(cistrncmp(uri, "http://", 7) != 0){
-			ss.s1 = nil;
-			ss.s2 = nil;
+	ss.s1 = ss.s2 = nil;
+	if(uri[0] != '/')
+		if(cistrncmp(uri, "http://", 7) == 0)
+			uri += 5;		/* skip http: */
+		else if (cistrncmp(uri, "https://", 8) == 0)
+			uri += 6;		/* skip https: */
+		else
 			return ss;
-		}
-		uri += 5;	/* skip http: */
-	}
 
 	/*
 	 * anything starting with // is a host name or number
-	 * hostnames constists of letters, digits, - and .
+	 * hostnames consists of letters, digits, - and .
 	 * for now, just ignore any port given
 	 */
 	if(uri[0] == '/' && uri[1] == '/'){
@@ -171,11 +171,8 @@ parseuri(HConnect *c, char *uri)
 			*p = '\0';
 	}
 
-	if(uri[0] != '/' || uri[1] == '/'){
-		ss.s1 = nil;
-		ss.s2 = nil;
+	if(uri[0] != '/' || uri[1] == '/')
 		return ss;
-	}
 
 	ss.s1 = uri;
 	ss.s2 = hlower(urihost);

+ 17 - 7
sys/src/libhttpd/redirected.c

@@ -7,13 +7,15 @@ int
 hredirected(HConnect *c, char *how, char *uri)
 {
 	Hio *hout;
-	char *s, *ss, *host;
+	char *s, *ss, *scheme, *host;
+	char sayport[NETPATHLEN];
 	int n;
 
+	scheme = c->scheme? c->scheme: "http";
 	host = c->head.host;
-	if(strchr(uri, ':')){
+	if(strchr(uri, ':') != nil)
 		host = "";
-	}else if(uri[0] != '/'){
+	else if(uri[0] != '/'){
 		s = strrchr(c->req.uri, '/');
 		if(s != nil)
 			*s = '\0';
@@ -24,6 +26,13 @@ hredirected(HConnect *c, char *how, char *uri)
 			*s = '/';
 	}
 
+	if((strcmp(scheme, "http") == 0 && atoi(c->port) == 80) ||
+	   (strcmp(scheme, "https") == 0 && atoi(c->port) == 443) ||
+	    strchr(host, ':') != nil)
+		sayport[0] = '\0';
+	else
+		snprint(sayport, sizeof sayport, ":%s", c->port);
+
 	n = snprint(c->xferbuf, HBufSize, 
 			"<head><title>Redirection</title></head>\r\n"
 			"<body><h1>Redirection</h1>\r\n"
@@ -38,7 +47,8 @@ hredirected(HConnect *c, char *how, char *uri)
 	if(host == nil || host[0] == 0)
 		hprint(hout, "Location: %U\r\n", uri);
 	else
-		hprint(hout, "Location: http://%U%U\r\n", host, uri);
+		hprint(hout, "Location: %s://%U%s%U\r\n",
+			scheme, host, sayport, uri);
 	if(c->head.closeit)
 		hprint(hout, "Connection: close\r\n");
 	else if(!http11(c))
@@ -48,12 +58,12 @@ hredirected(HConnect *c, char *how, char *uri)
 	if(strcmp(c->req.meth, "HEAD") != 0)
 		hwrite(hout, c->xferbuf, n);
 
-	if(c->replog){
+	if(c->replog)
 		if(host == nil || host[0] == 0)
 			c->replog(c, "Reply: %s\nRedirect: %U\n", how, uri);
 		else
-			c->replog(c, "Reply: %s\nRedirect: http://%U%U\n", how, host, uri);
-	}
+			c->replog(c, "Reply: %s\nRedirect: %s://%U%s%U\n",
+				how, scheme, host, sayport, uri);
 	return hflush(hout);
 }
 

+ 41 - 25
sys/src/libthread/channel.c

@@ -224,7 +224,7 @@ int
 chanclose(Channel *c)
 {
 	Alt *a;
-	int i, s, some;
+	int i, s;
 
 	s = _procsplhi();	/* note handlers; see :/^alt */
 	lock(&chanlock);
@@ -235,31 +235,29 @@ chanclose(Channel *c)
 		return -1;
 	}
 	c->closed = 1;		/* Being closed */
-
 	/*
-	 * locate entries that will fail due to close
+	 * Locate entries that will fail due to close
 	 * (send, and receive if nothing buffered) and wake them up.
-	 * Continue doing so until we make a full pass with no work,
-	 * otherwise we might miss alts being made while the lock is released.
-	 * We hope that this is O(2n) and not O(n*n).
+	 * the situation cannot change because all queries
+	 * should be committed by now and new ones will find the channel
+	 * closed.  We still need to take the lock during the iteration
+	 * because we can wake threads on qentrys we have not seen yet
+	 * as in alt and there would be a race in the access to *a.
 	 */
-	do{
-		some = 0;
-		for(i = 0; i < c->nentry; i++){
-			if((a = c->qentry[i]) == nil || *a->tag != nil)
-				continue;
-			if(a->op != CHANSND && (a->op != CHANRCV || c->n != 0))
-				continue;
-			*a->tag = c;
-			unlock(&chanlock);
-			_procsplx(s);
-			while(_threadrendezvous(a->tag, Closed) == Intred)
-				;
-			s = _procsplhi();
-			lock(&chanlock);
-			some++;
-		}
-	}while(some);
+	for(i = 0; i < c->nentry; i++){
+		if((a = c->qentry[i]) == nil || *a->tag != nil)
+			continue;
+
+		if(a->op != CHANSND && (a->op != CHANRCV || c->n != 0))
+			continue;
+		*a->tag = c;
+		unlock(&chanlock);
+		_procsplx(s);
+		while(_threadrendezvous(a->tag, Closed) == Intred)
+			;
+		s = _procsplhi();
+		lock(&chanlock);
+	}
 
 	c->closed = 2;		/* Fully closed */
 	if(c->freed)
@@ -269,12 +267,30 @@ chanclose(Channel *c)
 	return 0;
 }
 
+int
+chanclosing(Channel *c)
+{
+	int n, s;
+
+	s = _procsplhi();	/* note handlers; see :/^alt */
+	lock(&chanlock);
+	if(c->closed == 0)
+		n = -1;
+	else
+		n = c->n;
+	unlock(&chanlock);
+	_procsplx(s);
+	return n;
+}
+
+/*
+ * superseded by chanclosing
 int
 chanisclosed(Channel *c)
 {
-	/* No need to get the lock */
-	return c->closed != 0;
+	return chanisclosing(c) >= 0;
 }
+ */
 
 static int
 runop(int op, Channel *c, void *v, int nb)