xref: /plan9/sys/src/libhttpd/hio.c (revision e02f7f02bd837384880240d3ead0b1c0930eacbe)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <httpd.h>
480ee5cbfSDavid du Colombier 
580ee5cbfSDavid du Colombier static	char	hstates[] = "nrewE";
680ee5cbfSDavid du Colombier static	char	hxfers[] = " x";
77ef45392SDavid du Colombier static int _hflush(Hio*, int, int);
880ee5cbfSDavid du Colombier 
980ee5cbfSDavid du Colombier int
hinit(Hio * h,int fd,int mode)1080ee5cbfSDavid du Colombier hinit(Hio *h, int fd, int mode)
1180ee5cbfSDavid du Colombier {
1280ee5cbfSDavid du Colombier 	if(fd == -1 || mode != Hread && mode != Hwrite)
1380ee5cbfSDavid du Colombier 		return -1;
1480ee5cbfSDavid du Colombier 	h->hh = nil;
1580ee5cbfSDavid du Colombier 	h->fd = fd;
1680ee5cbfSDavid du Colombier 	h->seek = 0;
1780ee5cbfSDavid du Colombier 	h->state = mode;
1880ee5cbfSDavid du Colombier 	h->start = h->buf + 16;		/* leave space for chunk length */
1980ee5cbfSDavid du Colombier 	h->stop = h->pos = h->start;
2080ee5cbfSDavid du Colombier 	if(mode == Hread){
2180ee5cbfSDavid du Colombier 		h->bodylen = ~0UL;
2280ee5cbfSDavid du Colombier 		*h->pos = '\0';
2380ee5cbfSDavid du Colombier 	}else
2480ee5cbfSDavid du Colombier 		h->stop = h->start + Hsize;
2580ee5cbfSDavid du Colombier 	return 0;
2680ee5cbfSDavid du Colombier }
2780ee5cbfSDavid du Colombier 
2880ee5cbfSDavid du Colombier int
hiserror(Hio * h)2980ee5cbfSDavid du Colombier hiserror(Hio *h)
3080ee5cbfSDavid du Colombier {
3180ee5cbfSDavid du Colombier 	return h->state == Herr;
3280ee5cbfSDavid du Colombier }
3380ee5cbfSDavid du Colombier 
3480ee5cbfSDavid du Colombier int
hgetc(Hio * h)3580ee5cbfSDavid du Colombier hgetc(Hio *h)
3680ee5cbfSDavid du Colombier {
3780ee5cbfSDavid du Colombier 	uchar *p;
3880ee5cbfSDavid du Colombier 
3980ee5cbfSDavid du Colombier 	p = h->pos;
4080ee5cbfSDavid du Colombier 	if(p < h->stop){
4180ee5cbfSDavid du Colombier 		h->pos = p + 1;
4280ee5cbfSDavid du Colombier 		return *p;
4380ee5cbfSDavid du Colombier 	}
4480ee5cbfSDavid du Colombier 	p -= UTFmax;
4580ee5cbfSDavid du Colombier 	if(p < h->start)
4680ee5cbfSDavid du Colombier 		p = h->start;
4780ee5cbfSDavid du Colombier 	if(!hreadbuf(h, p) || h->pos == h->stop)
4880ee5cbfSDavid du Colombier 		return -1;
4980ee5cbfSDavid du Colombier 	return *h->pos++;
5080ee5cbfSDavid du Colombier }
5180ee5cbfSDavid du Colombier 
5280ee5cbfSDavid du Colombier int
hungetc(Hio * h)5380ee5cbfSDavid du Colombier hungetc(Hio *h)
5480ee5cbfSDavid du Colombier {
5580ee5cbfSDavid du Colombier 	if(h->state == Hend)
5680ee5cbfSDavid du Colombier 		h->state = Hread;
5780ee5cbfSDavid du Colombier 	else if(h->state == Hread)
5880ee5cbfSDavid du Colombier 		h->pos--;
5980ee5cbfSDavid du Colombier 	if(h->pos < h->start || h->state != Hread){
6080ee5cbfSDavid du Colombier 		h->state = Herr;
6180ee5cbfSDavid du Colombier 		h->pos = h->stop;
6280ee5cbfSDavid du Colombier 		return -1;
6380ee5cbfSDavid du Colombier 	}
6480ee5cbfSDavid du Colombier 	return 0;
6580ee5cbfSDavid du Colombier }
6680ee5cbfSDavid du Colombier 
6780ee5cbfSDavid du Colombier /*
6880ee5cbfSDavid du Colombier  * fill the buffer, saving contents from vsave onwards.
6980ee5cbfSDavid du Colombier  * nothing is saved if vsave is nil.
7080ee5cbfSDavid du Colombier  * returns the beginning of the buffer.
7180ee5cbfSDavid du Colombier  *
7280ee5cbfSDavid du Colombier  * understands message body sizes and chunked transfer encoding
7380ee5cbfSDavid du Colombier  */
7480ee5cbfSDavid du Colombier void *
hreadbuf(Hio * h,void * vsave)7580ee5cbfSDavid du Colombier hreadbuf(Hio *h, void *vsave)
7680ee5cbfSDavid du Colombier {
7780ee5cbfSDavid du Colombier 	Hio *hh;
7880ee5cbfSDavid du Colombier 	uchar *save;
7980ee5cbfSDavid du Colombier 	int c, in, cpy, dpos;
8080ee5cbfSDavid du Colombier 
8180ee5cbfSDavid du Colombier 	save = vsave;
8280ee5cbfSDavid du Colombier 	if(save && (save < h->start || save > h->stop)
8380ee5cbfSDavid du Colombier 	|| h->state != Hread && h->state != Hend){
8480ee5cbfSDavid du Colombier 		h->state = Herr;
8580ee5cbfSDavid du Colombier 		h->pos = h->stop;
8680ee5cbfSDavid du Colombier 		return nil;
8780ee5cbfSDavid du Colombier 	}
8880ee5cbfSDavid du Colombier 
8980ee5cbfSDavid du Colombier 	dpos = 0;
9080ee5cbfSDavid du Colombier 	if(save && h->pos > save)
9180ee5cbfSDavid du Colombier 		dpos = h->pos - save;
9280ee5cbfSDavid du Colombier 	cpy = 0;
9380ee5cbfSDavid du Colombier 	if(save){
9480ee5cbfSDavid du Colombier 		cpy = h->stop - save;
9580ee5cbfSDavid du Colombier 		memmove(h->start, save, cpy);
9680ee5cbfSDavid du Colombier 	}
9780ee5cbfSDavid du Colombier 	h->seek += h->stop - h->start - cpy;
9880ee5cbfSDavid du Colombier 	h->pos = h->start + dpos;
9980ee5cbfSDavid du Colombier 
10080ee5cbfSDavid du Colombier 	in = Hsize - cpy;
10180ee5cbfSDavid du Colombier 	if(h->state == Hend)
10280ee5cbfSDavid du Colombier 		in = 0;
10380ee5cbfSDavid du Colombier 	else if(in > h->bodylen)
10480ee5cbfSDavid du Colombier 		in = h->bodylen;
10580ee5cbfSDavid du Colombier 
10680ee5cbfSDavid du Colombier 	/*
10780ee5cbfSDavid du Colombier 	 * for chunked encoding, fill buffer,
10880ee5cbfSDavid du Colombier 	 * then read in new chunk length and wipe out that line
10980ee5cbfSDavid du Colombier 	 */
11080ee5cbfSDavid du Colombier 	hh = h->hh;
11180ee5cbfSDavid du Colombier 	if(hh != nil){
11280ee5cbfSDavid du Colombier 		if(!in && h->xferenc && h->state != Hend){
11380ee5cbfSDavid du Colombier 			if(h->xferenc == 2){
11480ee5cbfSDavid du Colombier 				c = hgetc(hh);
11580ee5cbfSDavid du Colombier 				if(c == '\r')
11680ee5cbfSDavid du Colombier 					c = hgetc(hh);
11780ee5cbfSDavid du Colombier 				if(c != '\n'){
11880ee5cbfSDavid du Colombier 					h->pos = h->stop;
11980ee5cbfSDavid du Colombier 					h->state = Herr;
12080ee5cbfSDavid du Colombier 					return nil;
12180ee5cbfSDavid du Colombier 				}
12280ee5cbfSDavid du Colombier 			}
12380ee5cbfSDavid du Colombier 			h->xferenc = 2;
12480ee5cbfSDavid du Colombier 			in = 0;
12580ee5cbfSDavid du Colombier 			while((c = hgetc(hh)) != '\n'){
12680ee5cbfSDavid du Colombier 				if(c >= '0' && c <= '9')
12780ee5cbfSDavid du Colombier 					c -= '0';
12880ee5cbfSDavid du Colombier 				else if(c >= 'a' && c <= 'f')
12980ee5cbfSDavid du Colombier 					c -= 'a' - 10;
13080ee5cbfSDavid du Colombier 				else if(c >= 'A' && c <= 'F')
13180ee5cbfSDavid du Colombier 					c -= 'A' - 10;
13280ee5cbfSDavid du Colombier 				else
13380ee5cbfSDavid du Colombier 					break;
13480ee5cbfSDavid du Colombier 				in = in * 16 + c;
13580ee5cbfSDavid du Colombier 			}
13680ee5cbfSDavid du Colombier 			while(c != '\n'){
13780ee5cbfSDavid du Colombier 				if(c < 0){
13880ee5cbfSDavid du Colombier 					h->pos = h->stop;
13980ee5cbfSDavid du Colombier 					h->state = Herr;
14080ee5cbfSDavid du Colombier 					return nil;
14180ee5cbfSDavid du Colombier 				}
14280ee5cbfSDavid du Colombier 				c = hgetc(hh);
14380ee5cbfSDavid du Colombier 			}
14480ee5cbfSDavid du Colombier 			h->bodylen = in;
14580ee5cbfSDavid du Colombier 
14680ee5cbfSDavid du Colombier 			in = Hsize - cpy;
14780ee5cbfSDavid du Colombier 			if(in > h->bodylen)
14880ee5cbfSDavid du Colombier 				in = h->bodylen;
14980ee5cbfSDavid du Colombier 		}
15080ee5cbfSDavid du Colombier 		if(in){
15180ee5cbfSDavid du Colombier 			while(hh->pos + in > hh->stop){
15280ee5cbfSDavid du Colombier 				if(hreadbuf(hh, hh->pos) == nil){
15380ee5cbfSDavid du Colombier 					h->pos = h->stop;
15480ee5cbfSDavid du Colombier 					h->state = Herr;
15580ee5cbfSDavid du Colombier 					return nil;
15680ee5cbfSDavid du Colombier 				}
15780ee5cbfSDavid du Colombier 			}
15880ee5cbfSDavid du Colombier 			memmove(h->start + cpy, hh->pos, in);
15980ee5cbfSDavid du Colombier 			hh->pos += in;
16080ee5cbfSDavid du Colombier 		}
1617ef45392SDavid du Colombier 	}else if(in){
1627ef45392SDavid du Colombier 		if((in = read(h->fd, h->start + cpy, in)) < 0){
16380ee5cbfSDavid du Colombier 			h->state = Herr;
16480ee5cbfSDavid du Colombier 			h->pos = h->stop;
16580ee5cbfSDavid du Colombier 			return nil;
16680ee5cbfSDavid du Colombier 		}
1677ef45392SDavid du Colombier 	}
16880ee5cbfSDavid du Colombier 	if(in == 0)
16980ee5cbfSDavid du Colombier 		h->state = Hend;
17080ee5cbfSDavid du Colombier 
17180ee5cbfSDavid du Colombier 	h->bodylen -= in;
17280ee5cbfSDavid du Colombier 
17380ee5cbfSDavid du Colombier 	h->stop = h->start + cpy + in;
17480ee5cbfSDavid du Colombier 	*h->stop = '\0';
17580ee5cbfSDavid du Colombier 	if(h->pos == h->stop)
17680ee5cbfSDavid du Colombier 		return nil;
17780ee5cbfSDavid du Colombier 	return h->start;
17880ee5cbfSDavid du Colombier }
17980ee5cbfSDavid du Colombier 
18080ee5cbfSDavid du Colombier int
hbuflen(Hio * h,void * p)18180ee5cbfSDavid du Colombier hbuflen(Hio *h, void *p)
18280ee5cbfSDavid du Colombier {
18380ee5cbfSDavid du Colombier 	return h->stop - (uchar*)p;
18480ee5cbfSDavid du Colombier }
18580ee5cbfSDavid du Colombier 
18680ee5cbfSDavid du Colombier /*
18780ee5cbfSDavid du Colombier  * prepare to receive a message body
18880ee5cbfSDavid du Colombier  * len is the content length (~0 => unspecified)
18980ee5cbfSDavid du Colombier  * te is the transfer encoding
19080ee5cbfSDavid du Colombier  * returns < 0 if setup failed
19180ee5cbfSDavid du Colombier  */
19280ee5cbfSDavid du Colombier Hio*
hbodypush(Hio * hh,ulong len,HFields * te)19380ee5cbfSDavid du Colombier hbodypush(Hio *hh, ulong len, HFields *te)
19480ee5cbfSDavid du Colombier {
19580ee5cbfSDavid du Colombier 	Hio *h;
19680ee5cbfSDavid du Colombier 	int xe;
19780ee5cbfSDavid du Colombier 
19880ee5cbfSDavid du Colombier 	if(hh->state != Hread)
19980ee5cbfSDavid du Colombier 		return nil;
20080ee5cbfSDavid du Colombier 	xe = 0;
20180ee5cbfSDavid du Colombier 	if(te != nil){
20280ee5cbfSDavid du Colombier 		if(te->params != nil || te->next != nil)
20380ee5cbfSDavid du Colombier 			return nil;
20480ee5cbfSDavid du Colombier 		if(cistrcmp(te->s, "chunked") == 0){
20580ee5cbfSDavid du Colombier 			xe = 1;
20680ee5cbfSDavid du Colombier 			len = 0;
2079a747e4fSDavid du Colombier 		}else if(cistrcmp(te->s, "identity") == 0){
20880ee5cbfSDavid du Colombier 			;
2099a747e4fSDavid du Colombier 		}else
21080ee5cbfSDavid du Colombier 			return nil;
21180ee5cbfSDavid du Colombier 	}
21280ee5cbfSDavid du Colombier 
21380ee5cbfSDavid du Colombier 	h = malloc(sizeof *h);
21480ee5cbfSDavid du Colombier 	if(h == nil)
21580ee5cbfSDavid du Colombier 		return nil;
21680ee5cbfSDavid du Colombier 
21780ee5cbfSDavid du Colombier 	h->hh = hh;
21880ee5cbfSDavid du Colombier 	h->fd = -1;
21980ee5cbfSDavid du Colombier 	h->seek = 0;
22080ee5cbfSDavid du Colombier 	h->state = Hread;
22180ee5cbfSDavid du Colombier 	h->xferenc = xe;
22280ee5cbfSDavid du Colombier 	h->start = h->buf + 16;		/* leave space for chunk length */
22380ee5cbfSDavid du Colombier 	h->stop = h->pos = h->start;
22480ee5cbfSDavid du Colombier 	*h->pos = '\0';
22580ee5cbfSDavid du Colombier 	h->bodylen = len;
22680ee5cbfSDavid du Colombier 	return h;
22780ee5cbfSDavid du Colombier }
22880ee5cbfSDavid du Colombier 
22980ee5cbfSDavid du Colombier /*
23080ee5cbfSDavid du Colombier  * dump the state of the io buffer into a string
23180ee5cbfSDavid du Colombier  */
23280ee5cbfSDavid du Colombier char *
hunload(Hio * h)23380ee5cbfSDavid du Colombier hunload(Hio *h)
23480ee5cbfSDavid du Colombier {
23580ee5cbfSDavid du Colombier 	uchar *p, *t, *stop, *buf;
23680ee5cbfSDavid du Colombier 	int ne, n, c;
23780ee5cbfSDavid du Colombier 
23880ee5cbfSDavid du Colombier 	stop = h->stop;
23980ee5cbfSDavid du Colombier 	ne = 0;
24080ee5cbfSDavid du Colombier 	for(p = h->pos; p < stop; p++){
24180ee5cbfSDavid du Colombier 		c = *p;
24280ee5cbfSDavid du Colombier 		if(c == 0x80)
24380ee5cbfSDavid du Colombier 			ne++;
24480ee5cbfSDavid du Colombier 	}
24580ee5cbfSDavid du Colombier 	p = h->pos;
24680ee5cbfSDavid du Colombier 
24780ee5cbfSDavid du Colombier 	n = (stop - p) + ne + 3;
24880ee5cbfSDavid du Colombier 	buf = mallocz(n, 1);
24980ee5cbfSDavid du Colombier 	if(buf == nil)
25080ee5cbfSDavid du Colombier 		return nil;
25180ee5cbfSDavid du Colombier 	buf[0] = hstates[h->state];
25280ee5cbfSDavid du Colombier 	buf[1] = hxfers[h->xferenc];
25380ee5cbfSDavid du Colombier 
25480ee5cbfSDavid du Colombier 	t = &buf[2];
25580ee5cbfSDavid du Colombier 	for(; p < stop; p++){
25680ee5cbfSDavid du Colombier 		c = *p;
25780ee5cbfSDavid du Colombier 		if(c == 0 || c == 0x80){
25880ee5cbfSDavid du Colombier 			*t++ = 0x80;
25980ee5cbfSDavid du Colombier 			if(c == 0x80)
26080ee5cbfSDavid du Colombier 				*t++ = 0x80;
26180ee5cbfSDavid du Colombier 		}else
26280ee5cbfSDavid du Colombier 			*t++ = c;
26380ee5cbfSDavid du Colombier 	}
26480ee5cbfSDavid du Colombier 	*t++ = '\0';
26580ee5cbfSDavid du Colombier 	if(t != buf + n)
26680ee5cbfSDavid du Colombier 		return nil;
26780ee5cbfSDavid du Colombier 	return (char*)buf;
26880ee5cbfSDavid du Colombier }
26980ee5cbfSDavid du Colombier 
27080ee5cbfSDavid du Colombier /*
27180ee5cbfSDavid du Colombier  * read the io buffer state from a string
27280ee5cbfSDavid du Colombier  */
27380ee5cbfSDavid du Colombier int
hload(Hio * h,char * buf)27480ee5cbfSDavid du Colombier hload(Hio *h, char *buf)
27580ee5cbfSDavid du Colombier {
27680ee5cbfSDavid du Colombier 	uchar *p, *t, *stop;
27780ee5cbfSDavid du Colombier 	char *s;
27880ee5cbfSDavid du Colombier 	int c;
27980ee5cbfSDavid du Colombier 
28080ee5cbfSDavid du Colombier 	s = strchr(hstates, buf[0]);
28180ee5cbfSDavid du Colombier 	if(s == nil)
2827ef45392SDavid du Colombier 		return -1;
28380ee5cbfSDavid du Colombier 	h->state = s - hstates;
28480ee5cbfSDavid du Colombier 
28580ee5cbfSDavid du Colombier 	s = strchr(hxfers, buf[1]);
28680ee5cbfSDavid du Colombier 	if(s == nil)
2877ef45392SDavid du Colombier 		return -1;
28880ee5cbfSDavid du Colombier 	h->xferenc = s - hxfers;
28980ee5cbfSDavid du Colombier 
29080ee5cbfSDavid du Colombier 	t = h->start;
29180ee5cbfSDavid du Colombier 	stop = t + Hsize;
29280ee5cbfSDavid du Colombier 	for(p = (uchar*)&buf[2]; c = *p; p++){
29380ee5cbfSDavid du Colombier 		if(c == 0x80){
29480ee5cbfSDavid du Colombier 			if(p[1] != 0x80)
29580ee5cbfSDavid du Colombier 				c = 0;
29680ee5cbfSDavid du Colombier 			else
2979a747e4fSDavid du Colombier 				p++;
29880ee5cbfSDavid du Colombier 		}
29980ee5cbfSDavid du Colombier 		*t++ = c;
30080ee5cbfSDavid du Colombier 		if(t >= stop)
3017ef45392SDavid du Colombier 			return -1;
30280ee5cbfSDavid du Colombier 	}
30380ee5cbfSDavid du Colombier 	*t = '\0';
30480ee5cbfSDavid du Colombier 	h->pos = h->start;
30580ee5cbfSDavid du Colombier 	h->stop = t;
30680ee5cbfSDavid du Colombier 	h->seek = 0;
3077ef45392SDavid du Colombier 	return 0;
30880ee5cbfSDavid du Colombier }
30980ee5cbfSDavid du Colombier 
31080ee5cbfSDavid du Colombier void
hclose(Hio * h)31180ee5cbfSDavid du Colombier hclose(Hio *h)
31280ee5cbfSDavid du Colombier {
31380ee5cbfSDavid du Colombier 	if(h->fd >= 0){
3149a747e4fSDavid du Colombier 		if(h->state == Hwrite)
31580ee5cbfSDavid du Colombier 			hxferenc(h, 0);
31680ee5cbfSDavid du Colombier 		close(h->fd);
31780ee5cbfSDavid du Colombier 	}
31880ee5cbfSDavid du Colombier 	h->stop = h->pos = nil;
31980ee5cbfSDavid du Colombier 	h->fd = -1;
32080ee5cbfSDavid du Colombier }
32180ee5cbfSDavid du Colombier 
32280ee5cbfSDavid du Colombier /*
32380ee5cbfSDavid du Colombier  * flush the buffer and possibly change encoding modes
32480ee5cbfSDavid du Colombier  */
32580ee5cbfSDavid du Colombier int
hxferenc(Hio * h,int on)32680ee5cbfSDavid du Colombier hxferenc(Hio *h, int on)
32780ee5cbfSDavid du Colombier {
32880ee5cbfSDavid du Colombier 	if(h->xferenc && !on && h->pos != h->start)
32980ee5cbfSDavid du Colombier 		hflush(h);
3307ef45392SDavid du Colombier 	if(_hflush(h, 1, 0) < 0)
33180ee5cbfSDavid du Colombier 		return -1;
33280ee5cbfSDavid du Colombier 	h->xferenc = !!on;
33380ee5cbfSDavid du Colombier 	return 0;
33480ee5cbfSDavid du Colombier }
33580ee5cbfSDavid du Colombier 
33680ee5cbfSDavid du Colombier int
hputc(Hio * h,int c)33780ee5cbfSDavid du Colombier hputc(Hio *h, int c)
33880ee5cbfSDavid du Colombier {
33980ee5cbfSDavid du Colombier 	uchar *p;
34080ee5cbfSDavid du Colombier 
34180ee5cbfSDavid du Colombier 	p = h->pos;
34280ee5cbfSDavid du Colombier 	if(p < h->stop){
34380ee5cbfSDavid du Colombier 		h->pos = p + 1;
34480ee5cbfSDavid du Colombier 		return *p = c;
34580ee5cbfSDavid du Colombier 	}
34680ee5cbfSDavid du Colombier 	if(hflush(h) < 0)
34780ee5cbfSDavid du Colombier 		return -1;
34880ee5cbfSDavid du Colombier 	return *h->pos++ = c;
34980ee5cbfSDavid du Colombier }
35080ee5cbfSDavid du Colombier 
3513ff48bf5SDavid du Colombier static int
fmthflush(Fmt * f)3529a747e4fSDavid du Colombier fmthflush(Fmt *f)
3539a747e4fSDavid du Colombier {
3549a747e4fSDavid du Colombier 	Hio *h;
3559a747e4fSDavid du Colombier 
3569a747e4fSDavid du Colombier 	h = f->farg;
3579a747e4fSDavid du Colombier 	h->pos = f->to;
3589a747e4fSDavid du Colombier 	if(hflush(h) < 0)
3599a747e4fSDavid du Colombier 		return 0;
3609a747e4fSDavid du Colombier 	f->stop = h->stop;
3619a747e4fSDavid du Colombier 	f->to = h->pos;
3629a747e4fSDavid du Colombier 	f->start = h->pos;
3639a747e4fSDavid du Colombier 	return 1;
3649a747e4fSDavid du Colombier }
3659a747e4fSDavid du Colombier 
3669a747e4fSDavid du Colombier int
hvprint(Hio * h,char * fmt,va_list args)3679a747e4fSDavid du Colombier hvprint(Hio *h, char *fmt, va_list args)
3689a747e4fSDavid du Colombier {
3699a747e4fSDavid du Colombier 	int n;
3709a747e4fSDavid du Colombier 	Fmt f;
3719a747e4fSDavid du Colombier 
3729a747e4fSDavid du Colombier 	f.runes = 0;
3739a747e4fSDavid du Colombier 	f.stop = h->stop;
3749a747e4fSDavid du Colombier 	f.to = h->pos;
3759a747e4fSDavid du Colombier 	f.start = h->pos;
3769a747e4fSDavid du Colombier 	f.flush = fmthflush;
3779a747e4fSDavid du Colombier 	f.farg = h;
3789a747e4fSDavid du Colombier 	f.nfmt = 0;
3797ef45392SDavid du Colombier //	fmtlocaleinit(&f, nil, nil, nil);
3807ef45392SDavid du Colombier 	n = fmtvprint(&f, fmt, args);
3819a747e4fSDavid du Colombier 	h->pos = f.to;
3829a747e4fSDavid du Colombier 	return n;
3839a747e4fSDavid du Colombier }
3849a747e4fSDavid du Colombier 
3859a747e4fSDavid du Colombier int
hprint(Hio * h,char * fmt,...)38680ee5cbfSDavid du Colombier hprint(Hio *h, char *fmt, ...)
38780ee5cbfSDavid du Colombier {
38880ee5cbfSDavid du Colombier 	int n;
38980ee5cbfSDavid du Colombier 	va_list arg;
39080ee5cbfSDavid du Colombier 
39180ee5cbfSDavid du Colombier 	va_start(arg, fmt);
3929a747e4fSDavid du Colombier 	n = hvprint(h, fmt, arg);
39380ee5cbfSDavid du Colombier 	va_end(arg);
39480ee5cbfSDavid du Colombier 	return n;
39580ee5cbfSDavid du Colombier }
39680ee5cbfSDavid du Colombier 
397b7327ca2SDavid du Colombier static int
_hflush(Hio * h,int force,int dolength)3987ef45392SDavid du Colombier _hflush(Hio *h, int force, int dolength)
39980ee5cbfSDavid du Colombier {
40080ee5cbfSDavid du Colombier 	uchar *s;
40180ee5cbfSDavid du Colombier 	int w;
40280ee5cbfSDavid du Colombier 
403*e02f7f02SDavid du Colombier 	if(h == nil)
404*e02f7f02SDavid du Colombier 		return -1;
40580ee5cbfSDavid du Colombier 	if(h->state != Hwrite){
40680ee5cbfSDavid du Colombier 		h->state = Herr;
40780ee5cbfSDavid du Colombier 		h->stop = h->pos;
40880ee5cbfSDavid du Colombier 		return -1;
40980ee5cbfSDavid du Colombier 	}
41080ee5cbfSDavid du Colombier 	s = h->start;
41180ee5cbfSDavid du Colombier 	w = h->pos - s;
4127ef45392SDavid du Colombier 	if(w == 0 && !force)
4137ef45392SDavid du Colombier 		return 0;
41480ee5cbfSDavid du Colombier 	if(h->xferenc){
41580ee5cbfSDavid du Colombier 		*--s = '\n';
41680ee5cbfSDavid du Colombier 		*--s = '\r';
41780ee5cbfSDavid du Colombier 		do{
41880ee5cbfSDavid du Colombier 			*--s = "0123456789abcdef"[w & 0xf];
41980ee5cbfSDavid du Colombier 			w >>= 4;
42080ee5cbfSDavid du Colombier 		}while(w);
42180ee5cbfSDavid du Colombier 		h->pos[0] = '\r';
42280ee5cbfSDavid du Colombier 		h->pos[1] = '\n';
42380ee5cbfSDavid du Colombier 		w = &h->pos[2] - s;
42480ee5cbfSDavid du Colombier 	}
425b7327ca2SDavid du Colombier 	if(dolength)
426b7327ca2SDavid du Colombier 		fprint(h->fd, "Content-Length: %d\r\n\r\n", w);
42780ee5cbfSDavid du Colombier 	if(write(h->fd, s, w) != w){
42880ee5cbfSDavid du Colombier 		h->state = Herr;
42980ee5cbfSDavid du Colombier 		h->stop = h->pos;
43080ee5cbfSDavid du Colombier 		return -1;
43180ee5cbfSDavid du Colombier 	}
43280ee5cbfSDavid du Colombier 	h->seek += w;
43380ee5cbfSDavid du Colombier 	h->pos = h->start;
43480ee5cbfSDavid du Colombier 	return 0;
43580ee5cbfSDavid du Colombier }
43680ee5cbfSDavid du Colombier 
43780ee5cbfSDavid du Colombier int
hflush(Hio * h)438b7327ca2SDavid du Colombier hflush(Hio *h)
439b7327ca2SDavid du Colombier {
4407ef45392SDavid du Colombier 	return _hflush(h, 0, 0);
441b7327ca2SDavid du Colombier }
442b7327ca2SDavid du Colombier 
443b7327ca2SDavid du Colombier int
hlflush(Hio * h)444b7327ca2SDavid du Colombier hlflush(Hio* h)
445b7327ca2SDavid du Colombier {
4467ef45392SDavid du Colombier 	return _hflush(h, 0, 1);
447b7327ca2SDavid du Colombier }
448b7327ca2SDavid du Colombier 
449b7327ca2SDavid du Colombier int
hwrite(Hio * h,void * vbuf,int len)45080ee5cbfSDavid du Colombier hwrite(Hio *h, void *vbuf, int len)
45180ee5cbfSDavid du Colombier {
4527ef45392SDavid du Colombier 	uchar *buf;
45380ee5cbfSDavid du Colombier 	int n, m;
45480ee5cbfSDavid du Colombier 
45580ee5cbfSDavid du Colombier 	buf = vbuf;
45680ee5cbfSDavid du Colombier 	n = len;
45780ee5cbfSDavid du Colombier 	if(n < 0 || h->state != Hwrite){
45880ee5cbfSDavid du Colombier 		h->state = Herr;
45980ee5cbfSDavid du Colombier 		h->stop = h->pos;
46080ee5cbfSDavid du Colombier 		return -1;
46180ee5cbfSDavid du Colombier 	}
4627ef45392SDavid du Colombier 	if(h->pos + n >= h->stop){
4637ef45392SDavid du Colombier 		if(h->start != h->pos)
4647ef45392SDavid du Colombier 			if(hflush(h) < 0)
4657ef45392SDavid du Colombier 				return -1;
4667ef45392SDavid du Colombier 		while(h->pos + n >= h->stop){
4677ef45392SDavid du Colombier 			m = h->stop - h->pos;
4687ef45392SDavid du Colombier 			if(h->xferenc){
4697ef45392SDavid du Colombier 				memmove(h->pos, buf, m);
4707ef45392SDavid du Colombier 				h->pos += m;
4717ef45392SDavid du Colombier 				if(hflush(h) < 0)
4727ef45392SDavid du Colombier 					return -1;
4737ef45392SDavid du Colombier 			}else{
4747ef45392SDavid du Colombier 				if(write(h->fd, buf, m) != m){
4757ef45392SDavid du Colombier 					h->state = Herr;
4767ef45392SDavid du Colombier 					h->stop = h->pos;
4777ef45392SDavid du Colombier 					return -1;
4787ef45392SDavid du Colombier 				}
4797ef45392SDavid du Colombier 				h->seek += m;
4807ef45392SDavid du Colombier 			}
4817ef45392SDavid du Colombier 			n -= m;
48280ee5cbfSDavid du Colombier 			buf += m;
48380ee5cbfSDavid du Colombier 		}
48480ee5cbfSDavid du Colombier 	}
4857ef45392SDavid du Colombier 	memmove(h->pos, buf, n);
4867ef45392SDavid du Colombier 	h->pos += n;
48780ee5cbfSDavid du Colombier 	return len;
48880ee5cbfSDavid du Colombier }
489